diff --git a/src/wp-admin/js/customize-controls.js b/src/wp-admin/js/customize-controls.js index ede6a867ea..22b3975e9d 100644 --- a/src/wp-admin/js/customize-controls.js +++ b/src/wp-admin/js/customize-controls.js @@ -37,6 +37,7 @@ this.id = id; this.selector = '#customize-control-' + id.replace( /\]/g, '' ).replace( /\[/g, '-' ); this.container = $( this.selector ); + this.active = new api.Value( this.params.active ); settings = $.map( this.params.settings, function( value ) { return value; @@ -79,10 +80,30 @@ element.set( setting() ); }); }); + + control.active.bind( function ( active ) { + control.toggle( active ); + } ); + control.toggle( control.active() ); }, ready: function() {}, + /** + * Callback for change to the control's active state. + * + * Override function for custom behavior for the control being active/inactive. + * + * @param {Boolean} active + */ + toggle: function ( active ) { + if ( active ) { + this.container.slideDown(); + } else { + this.container.slideUp(); + } + }, + dropdownInit: function() { var control = this, statuses = this.container.find('.dropdown-status'), @@ -563,6 +584,26 @@ this.bind( 'ready', this._ready ); + this.bind( 'ready', function ( data ) { + if ( ! data || ! data.activeControls ) { + return; + } + + // Any controls not even registered on the previewed URL are not active either + api.control.each( function ( control ) { + if ( typeof data.activeControls[ control.id ] === 'undefined' ) { + data.activeControls[ control.id ] = false; + } + } ); + + $.each( data.activeControls, function ( id, active ) { + var control = api.control( id ); + if ( control ) { + control.active( active ); + } + } ); + } ); + this.request = $.ajax( this.previewUrl(), { type: 'POST', data: this.query, diff --git a/src/wp-admin/js/customize-widgets.js b/src/wp-admin/js/customize-widgets.js index 3ba7df8919..51aec941a2 100644 --- a/src/wp-admin/js/customize-widgets.js +++ b/src/wp-admin/js/customize-widgets.js @@ -751,13 +751,6 @@ } } ); - // Update widget control to indicate whether it is currently rendered - api.previewer.bind( 'rendered-widgets', function( renderedWidgets ) { - var isRendered = !! renderedWidgets[self.params.widget_id]; - - self.container.toggleClass( 'widget-rendered', isRendered ); - } ); - formSyncHandler = api.Widgets.formSyncHandlers[ this.params.widget_id_base ]; if ( formSyncHandler ) { $( document ).on( 'widget-synced', function( e, widget ) { @@ -768,6 +761,17 @@ } }, + /** + * Update widget control to indicate whether it is currently rendered. + * + * Overrides api.Control.toggle() + * + * @param {Boolean} active + */ + toggle: function ( active ) { + this.container.toggleClass( 'widget-rendered', active ); + }, + /** * Set up event handlers for widget removal */ @@ -1418,32 +1422,38 @@ } ); // Update the model with whether or not the sidebar is rendered - api.previewer.bind( 'rendered-sidebars', function( renderedSidebars ) { - var isRendered = !! renderedSidebars[self.params.sidebar_id]; - - registeredSidebar.set( 'is_rendered', isRendered ); + self.active.bind( function ( active ) { + registeredSidebar.set( 'is_rendered', active ); } ); + }, - // Show the sidebar section when it becomes visible - registeredSidebar.on( 'change:is_rendered', function( ) { - var sectionSelector = '#accordion-section-sidebar-widgets-' + this.get( 'id' ), $section; + /** + * Show the sidebar section when it becomes visible. + * + * Overrides api.Control.toggle() + * + * @param {Boolean} active + */ + toggle: function ( active ) { + var $section, sectionSelector; - $section = $( sectionSelector ); - if ( this.get( 'is_rendered' ) ) { - $section.stop().slideDown( function() { - $( this ).css( 'height', 'auto' ); // so that the .accordion-section-content won't overflow - } ); + sectionSelector = '#accordion-section-sidebar-widgets-' + this.params.sidebar_id; + $section = $( sectionSelector ); - } else { - // Make sure that hidden sections get closed first - if ( $section.hasClass( 'open' ) ) { - // it would be nice if accordionSwitch() in accordion.js was public - $section.find( '.accordion-section-title' ).trigger( 'click' ); - } + if ( active ) { + $section.stop().slideDown( function() { + $( this ).css( 'height', 'auto' ); // so that the .accordion-section-content won't overflow + } ); - $section.stop().slideUp(); + } else { + // Make sure that hidden sections get closed first + if ( $section.hasClass( 'open' ) ) { + // it would be nice if accordionSwitch() in accordion.js was public + $section.find( '.accordion-section-title' ).trigger( 'click' ); } - } ); + + $section.stop().slideUp(); + } }, /** diff --git a/src/wp-includes/class-wp-customize-control.php b/src/wp-includes/class-wp-customize-control.php index 48c3791611..a1748e74a2 100644 --- a/src/wp-includes/class-wp-customize-control.php +++ b/src/wp-includes/class-wp-customize-control.php @@ -85,6 +85,19 @@ class WP_Customize_Control { */ public $type = 'text'; + /** + * Callback + * + * @since 4.0.0 + * + * @access public + * @see WP_Customize_Control::active() + * @var callable Callback is called with one argument, the instance of + * WP_Customize_Control, and returns bool to indicate whether + * the control is active (such as it relates to the URL + * currently being previewed). + */ + public $active_callback = ''; /** * Constructor. @@ -102,16 +115,21 @@ class WP_Customize_Control { public function __construct( $manager, $id, $args = array() ) { $keys = array_keys( get_object_vars( $this ) ); foreach ( $keys as $key ) { - if ( isset( $args[ $key ] ) ) + if ( isset( $args[ $key ] ) ) { $this->$key = $args[ $key ]; + } } $this->manager = $manager; $this->id = $id; + if ( empty( $this->active_callback ) ) { + $this->active_callback = array( $this, 'active_callback' ); + } // Process settings. - if ( empty( $this->settings ) ) + if ( empty( $this->settings ) ) { $this->settings = $id; + } $settings = array(); if ( is_array( $this->settings ) ) { @@ -132,6 +150,41 @@ class WP_Customize_Control { */ public function enqueue() {} + /** + * Check whether control is active to current customizer preview. + * + * @since 4.0.0 + * + * @return bool + */ + public final function active() { + $control = $this; + $active = call_user_func( $this->active_callback, $this ); + + /** + * Filter response of WP_Customize_Control::active(). + * + * @since 4.0.0 + * + * @param bool $active + * @param WP_Customize_Control $control + */ + $active = apply_filters( 'customize_control_active', $active, $control ); + + return $active; + } + + /** + * Default callback used when invoking WP_Customize_Control::active(). + * + * Subclasses can override this with their specific logic, or they may + * provide an 'active_callback' argument to the constructor. + * + * @return bool + */ + public function active_callback() { + return true; + } /** * Fetch a setting's value. @@ -143,8 +196,9 @@ class WP_Customize_Control { * @return mixed The requested setting's value, if the setting exists. */ public final function value( $setting_key = 'default' ) { - if ( isset( $this->settings[ $setting_key ] ) ) + if ( isset( $this->settings[ $setting_key ] ) ) { return $this->settings[ $setting_key ]->value(); + } } /** @@ -159,6 +213,7 @@ class WP_Customize_Control { } $this->json['type'] = $this->type; + $this->json['active'] = $this->active(); } /** @@ -256,7 +311,7 @@ class WP_Customize_Control { echo $this->get_link( $setting_key ); } - /** + /** * Render the custom attributes for the control's input element. * * @since 4.0.0 @@ -995,6 +1050,13 @@ class WP_Widget_Area_Customize_Control extends WP_Customize_Control { manager->widgets->is_sidebar_rendered( $this->sidebar_id ); + } } /** @@ -1035,5 +1097,12 @@ class WP_Widget_Form_Customize_Control extends WP_Customize_Control { $args = wp_list_widget_controls_dynamic_sidebar( array( 0 => $args, 1 => $widget['params'][0] ) ); echo $this->manager->widgets->get_widget_control( $args ); } + + /** + * @return bool + */ + function active_callback() { + return $this->manager->widgets->is_widget_rendered( $this->widget_id ); + } } diff --git a/src/wp-includes/class-wp-customize-manager.php b/src/wp-includes/class-wp-customize-manager.php index bdd79bab66..4929d150ab 100644 --- a/src/wp-includes/class-wp-customize-manager.php +++ b/src/wp-includes/class-wp-customize-manager.php @@ -475,7 +475,8 @@ final class WP_Customize_Manager { public function customize_preview_settings() { $settings = array( 'values' => array(), - 'channel' => esc_js( $_POST['customize_messenger_channel'] ), + 'channel' => wp_unslash( $_POST['customize_messenger_channel'] ), + 'activeControls' => array(), ); if ( 2 == $this->nonce_tick ) { @@ -488,6 +489,9 @@ final class WP_Customize_Manager { foreach ( $this->settings as $id => $setting ) { $settings['values'][ $id ] = $setting->js_value(); } + foreach ( $this->controls as $id => $control ) { + $settings['activeControls'][ $id ] = $control->active(); + } ?>