Skip to main content
1 of 4
dingo_d
  • 1.9k
  • 1
  • 25
  • 45

Customizer active callback live toggle controls

So I've enabled the option to not show controls if the one control is not active, but the issue is that this works only when you refresh the customizer page.

In my example I have a boxed body control, which is a checkbox (although I used the custom control to style it a bit differently, you can find code here). If it's disabled the associated controls that can change the boxed body border width, color, background color etc. are all hidden. If you enable the boxed body you need to refresh the page to see those controls, which is UX disaster. The code is:

add_action( 'customize_register', 'mytheme_customize_register' );
/**
 * Register customizer settings
 *
 * @see add_action('customize_register',$func)
 * @param  \WP_Customize_Manager $wp_customize WP Customize object.
 * @since 1.0.0
 */
function mytheme_customize_register( WP_Customize_Manager $wp_customize ) {

    /**
    Boxed Body
    */
    $wp_customize->add_setting( 'boxed_body', array(
        'default'           => false,
        'transport'         => 'postMessage',
        'sanitize_callback' => 'mytheme_checkbox_sanitization',
    ) );
    $wp_customize->add_control(new Toggle_Checkbox_Custom_Control( $wp_customize, 'boxed_body', array(
        'label'       => esc_html__( 'Boxed Body', 'mytheme' ),
        'description' => esc_html__( 'Check this to enable boxed body layout', 'mytheme' ),
        'type'        => 'checkbox',
        'section'     => 'section_general',
    ) ) );

    /**
     * Callback function for boxed body choice
     *
     * @param  object $control Control object.
     * @return boolean
     */
    function boxed_body_choice( $control ) {
        if ( 1 === $control->manager->get_setting( 'boxed_body' )->value() ) {
            return true;
        } else {
            return false;
        }
    }

    /**
    Boxed Body Border Color
    */
    $wp_customize->add_setting( 'boxed_body_border_color', array(
        'default'           => '',
        'transport'         => 'postMessage',
        'sanitize_callback' => 'sanitize_hex_color',
    ) );
    $wp_customize->add_control(new WP_Customize_Color_Control( $wp_customize, 'boxed_body_border_color', array(
        'label'    => esc_html__( 'Boxed Body Border Color', 'mytheme' ),
        'settings' => 'boxed_body_border_color',
        'section'  => 'section_general',
        'active_callback' => 'boxed_body_choice',
    ) ) );

}

add_action( 'customize_preview_init', 'mytheme_customizer_live_preview' );
/**
 * Live preview script enqueue
 *
 * @since 1.0.0
 */
function mytheme_customizer_live_preview() {
    wp_enqueue_script( 'mytheme-themecustomizer', get_template_directory_uri() . '/inc/customizer/js/customizer.js?v=' . rand(), array( 'jquery', 'customize-preview' ), '', true );
}

I've tried following Weston Ruter's example on contextual controls here and gist, but no luck. I've added in my customizer.js

(function($) {

    // Add callback for when the boxed_body setting is toggled.
    wp.customize( 'boxed_body', function(setting) {
        var isBoxedBodyToggled, linkSettingValueToControlActiveState;

        /**
         * Determine whether the boxed body associated options should be displayed.
         *
         * @returns {boolean} Is toggled?
         */
        isBoxedBodyToggled = function() {
            return '' !== setting.get();
        };

        /**
         * Update a control's active state according to the boxed_body setting's value.
         *
         * @param {wp.customize.Control} control Boxed body control.
         */
        linkSettingValueToControlActiveState = function( control ) {
            var setActiveState = function() {
                control.active.set( isBoxedBodyToggled() );
            };

            // FYI: With the following we can eliminate all of our PHP active_callback code.
            control.active.validate = isBoxedBodyToggled;

            // Set initial active state.
            setActiveState();

            /*
             * Update activate state whenever the setting is changed.
             * Even when the setting does have a refresh transport where the
             * server-side active callback will manage the active state upon
             * refresh, having this JS management of the active state will
             * ensure that controls will have their visibility toggled
             * immediately instead of waiting for the preview to load.
             * This is especially important if the setting has a postMessage
             * transport where changing the setting wouldn't normally cause
             * the preview to refresh and thus the server-side active_callbacks
             * would not get invoked.
             */
            setting.bind( setActiveState );
        };

        // Call linkSettingValueToControlActiveState on the site title and tagline controls when they exist.
        wp.customize.control( 'boxed_body_border_width', linkSettingValueToControlActiveState );
        wp.customize.control( 'boxed_body_border_color', linkSettingValueToControlActiveState );
        wp.customize.control( 'boxed_body_border_style', linkSettingValueToControlActiveState );
        wp.customize.control( 'boxed_body_bg_image', linkSettingValueToControlActiveState );
        wp.customize.control( 'boxed_body_bg_image_repeat', linkSettingValueToControlActiveState );
        wp.customize.control( 'boxed_body_bg_image_size', linkSettingValueToControlActiveState );
        wp.customize.control( 'boxed_body_bg_image_position', linkSettingValueToControlActiveState );
        wp.customize.control( 'boxed_body_bg_image_attachment', linkSettingValueToControlActiveState );

    });

})(jQuery);

But on customizer refresh I get

Uncaught TypeError: wp.customize.control is not a function(…)

On the

wp.customize.control( 'boxed_body_border_width', linkSettingValueToControlActiveState );

And the toggle won't hide or show the controls. I've made some changes to fit the custom toggle control, so I'm not checking against 'blank' but rather '' in the isBoxedBodyToggled function.

When I fiddle in DevTools I can see that wp.customize is a function, not an object. In the example this should be an object (I guess).

Any help would be appreciated.

dingo_d
  • 1.9k
  • 1
  • 25
  • 45