Customizer active callback live toggle controls

The answer was to ‘decouple’ live preview and contextual control. If I place them together, I cannot use the same action hook – live won’t work on customize_controls_enqueue_scripts and contextual control won’t work on customize_preview_init.

So the answer is:

add_action( 'customize_controls_enqueue_scripts', 'mytheme_customizer_control_toggle' );
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' ), false );
}

/**
 * Custom contextual controls
 *
 * @since 1.0.0
 */
function mytheme_customizer_control_toggle() {
    wp_enqueue_script( 'mytheme-contextualcontrols', get_template_directory_uri() . '/inc/customizer/js/customizer-contextual.js?v=' . rand(), array( 'customize-controls' ), false );
}

The contextual control code is

( function( api ) {
    'use strict';

    api( '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 {api.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.
        api.control( 'boxed_body_border_width', linkSettingValueToControlActiveState );
        api.control( 'boxed_body_border_color', linkSettingValueToControlActiveState );
        api.control( 'boxed_body_border_style', linkSettingValueToControlActiveState );
    });

}( wp.customize ) );

The issue I have now is that my custom control doesn’t work properly, but this is a different issue that I can easily solve.

Thanks to Weston Ruter for pointing me in the right direction 🙂

WORKING EDIT

For some reason, the above code only toggled the controls once, so I rewrote it like this

( function( api ) {
    'use strict';

    api.bind( 'ready', function() {

        api( 'boxed_body', function(setting) {
            var linkSettingValueToControlActiveState;

            /**
             * Update a control's active state according to the boxed_body setting's value.
             *
             * @param {api.Control} control Boxed body control.
             */
            linkSettingValueToControlActiveState = function( control ) {
                var visibility = function() {
                    if ( true === setting.get() || 1 === setting.get() ) {
                        control.container.slideDown( 180 );
                    } else {
                        control.container.slideUp( 180 );
                    }
                };

                // Set initial active state.
                visibility();
                //Update activate state whenever the setting is changed.
                setting.bind( visibility );
            };

            // Call linkSettingValueToControlActiveState on the border controls when they exist.
            api.control( 'boxed_body_border_width', linkSettingValueToControlActiveState );
            api.control( 'boxed_body_border_color', linkSettingValueToControlActiveState );
            api.control( 'boxed_body_border_style', linkSettingValueToControlActiveState );
        });

    });

}( wp.customize ) );

And this seems to be working fine. I used the Twenty Seventeen as a guide, they toggle the custom color scheme in a similar way.

Leave a Comment