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.