Add/remove controls dynamically based on other settings in Customizer

I need to add/remove controls dynamically in Customizer. Say I have a field No of pages and its value is 3. I want to render 3 dropdown pages controls. And when its value is changed, I want to add/remove controls accordingly.

Currently I am hacking it through PHP. Like looping the controls based on the numbers. Demerit of this approach is that, when number is changed, I have to save Customizer value and refresh the whole customizer page to reflect new controls.

I am looking for approach which would remove saving and refreshing of the page. I believe I need to dive into Customizer JS API. I would appreciate if someone would point me to right direction.

1 Answer
1

Ok so you can check out my repo with some custom controls

https://github.com/dingo-d/wordpress-theme-customizer-extra-custom-controls

I’ve adapted the contextual controls by Weston Ruters guide here:

Dependently-Contextual Customizer Controls

In my example in the repo I have the boxed body checkbox control that toggles boxed body.

You’ll need to enqueue a script to put the js code in

add_action( 'customize_controls_enqueue_scripts', 'mytheme_customizer_control_toggle' );

/**
 * 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 );
}

And in your customizer-contextual.js you’ll have something like:

( 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 ) );

You are targeting the control name (in this case it’s 'boxed body'), inside it you can check if that controle has active state or not, and accordingly set the ‘visibility’ of the other linked controls.

You can also toggle this change in the preview screeen by hooking to customize_preview_init hook

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 );
}

Inside customizer.js you’ll have something like:

(function($, api) {
    'use strict';

    // Boxed Body Toggle.
    api( 'boxed_body', function(value) {
        value.bind(function(newval) {
            if (newval) {
                $( 'body' ).wrapInner( '<div class="boxed_body_wrapper" />' );
            } else {
                $( '.boxed_body_wrapper' ).contents().unwrap();
            }
        });
    });

})(jQuery, wp.customize);

Hope this helps 🙂

Leave a Comment