diff --git a/src/wp-admin/customize.php b/src/wp-admin/customize.php index 9be60c7e74..e3ea406f28 100644 --- a/src/wp-admin/customize.php +++ b/src/wp-admin/customize.php @@ -175,7 +175,9 @@ do_action( 'customize_controls_print_scripts' );
render_panel_templates(); + $wp_customize->render_section_templates(); $wp_customize->render_control_templates(); /** @@ -259,28 +261,38 @@ do_action( 'customize_controls_print_scripts' ); // Prepare Customize Setting objects to pass to JavaScript. foreach ( $wp_customize->settings() as $id => $setting ) { - $settings['settings'][ $id ] = array( - 'value' => $setting->js_value(), - 'transport' => $setting->transport, - 'dirty' => $setting->dirty, - ); + if ( $setting->check_capabilities() ) { + $settings['settings'][ $id ] = array( + 'value' => $setting->js_value(), + 'transport' => $setting->transport, + 'dirty' => $setting->dirty, + ); + } } // Prepare Customize Control objects to pass to JavaScript. foreach ( $wp_customize->controls() as $id => $control ) { - $settings['controls'][ $id ] = $control->json(); + if ( $control->check_capabilities() ) { + $settings['controls'][ $id ] = $control->json(); + } } // Prepare Customize Section objects to pass to JavaScript. foreach ( $wp_customize->sections() as $id => $section ) { - $settings['sections'][ $id ] = $section->json(); + if ( $section->check_capabilities() ) { + $settings['sections'][ $id ] = $section->json(); + } } // Prepare Customize Panel objects to pass to JavaScript. - foreach ( $wp_customize->panels() as $id => $panel ) { - $settings['panels'][ $id ] = $panel->json(); - foreach ( $panel->sections as $section_id => $section ) { - $settings['sections'][ $section_id ] = $section->json(); + foreach ( $wp_customize->panels() as $panel_id => $panel ) { + if ( $panel->check_capabilities() ) { + $settings['panels'][ $panel_id ] = $panel->json(); + foreach ( $panel->sections as $section_id => $section ) { + if ( $section->check_capabilities() ) { + $settings['sections'][ $section_id ] = $section->json(); + } + } } } diff --git a/src/wp-admin/js/customize-controls.js b/src/wp-admin/js/customize-controls.js index 7ed309572a..2d7f3bad4a 100644 --- a/src/wp-admin/js/customize-controls.js +++ b/src/wp-admin/js/customize-controls.js @@ -156,6 +156,7 @@ Container = api.Class.extend({ defaultActiveArguments: { duration: 'fast', completeCallback: $.noop }, defaultExpandedArguments: { duration: 'fast', completeCallback: $.noop }, + containerType: 'container', /** * @since 4.1.0 @@ -168,7 +169,11 @@ container.id = id; container.params = {}; $.extend( container, options || {} ); + container.templateSelector = 'customize-' + container.containerType + '-' + container.params.type; container.container = $( container.params.content ); + if ( 0 === container.container.length ) { + container.container = $( container.getContainer() ); + } container.deferred = { embedded: new $.Deferred() @@ -191,7 +196,9 @@ container.onChangeExpanded( expanded, args ); }); - container.attachEvents(); + container.deferred.embedded.done( function () { + container.attachEvents(); + }); api.utils.bubbleChildValueChanges( container, [ 'priority', 'active' ] ); @@ -366,7 +373,26 @@ * Bring the container into view and then expand this and bring it into view * @param {Object} [params] */ - focus: focus + focus: focus, + + /** + * Return the container html, generated from its JS template, if it exists. + * + * @since 4.3.0 + */ + getContainer: function () { + var template, + container = this; + + if ( 0 !== $( '#tmpl-' + container.templateSelector ).length ) { + template = wp.template( container.templateSelector ); + if ( template && container.container ) { + return $.trim( template( container.params ) ); + } + } + + return ''; + } }); /** @@ -376,6 +402,7 @@ * @augments wp.customize.Class */ api.Section = Container.extend({ + containerType: 'section', /** * @since 4.1.0 @@ -977,6 +1004,8 @@ * @augments wp.customize.Class */ api.Panel = Container.extend({ + containerType: 'panel', + /** * @since 4.1.0 * @@ -1003,6 +1032,7 @@ if ( ! panel.container.parent().is( parentContainer ) ) { parentContainer.append( panel.container ); + panel.renderContent(); } panel.deferred.embedded.resolve(); }, @@ -1045,6 +1075,7 @@ } event.preventDefault(); // Keep this AFTER the key filter above + meta = panel.container.find( '.panel-meta' ); if ( meta.hasClass( 'cannot-expand' ) ) { return; } @@ -1169,6 +1200,26 @@ panelTitle.focus(); container.scrollTop( 0 ); } + }, + + /** + * Render the panel from its JS template, if it exists. + * + * The panel's container must already exist in the DOM. + * + * @since 4.3.0 + */ + renderContent: function () { + var template, + panel = this; + + // Add the content to the container. + if ( 0 !== $( '#tmpl-' + panel.templateSelector + '-content' ).length ) { + template = wp.template( panel.templateSelector + '-content' ); + if ( template && panel.container ) { + panel.container.find( '.accordion-sub-container' ).html( template( panel.params ) ); + } + } } }); diff --git a/src/wp-includes/class-wp-customize-manager.php b/src/wp-includes/class-wp-customize-manager.php index 98539b0294..47c0407f56 100644 --- a/src/wp-includes/class-wp-customize-manager.php +++ b/src/wp-includes/class-wp-customize-manager.php @@ -60,7 +60,25 @@ final class WP_Customize_Manager { protected $customized; /** - * Controls that may be rendered from JS templates. + * Panel types that may be rendered from JS templates. + * + * @since 4.3.0 + * @access protected + * @var array + */ + protected $registered_panel_types = array(); + + /** + * Section types that may be rendered from JS templates. + * + * @since 4.3.0 + * @access protected + * @var array + */ + protected $registered_section_types = array(); + + /** + * Control types that may be rendered from JS templates. * * @since 4.1.0 * @access protected @@ -612,19 +630,29 @@ final class WP_Customize_Manager { } foreach ( $this->settings as $id => $setting ) { - $settings['values'][ $id ] = $setting->js_value(); + if ( $setting->check_capabilities() ) { + $settings['values'][ $id ] = $setting->js_value(); + } } - foreach ( $this->panels as $id => $panel ) { - $settings['activePanels'][ $id ] = $panel->active(); - foreach ( $panel->sections as $id => $section ) { - $settings['activeSections'][ $id ] = $section->active(); + foreach ( $this->panels as $panel_id => $panel ) { + if ( $panel->check_capabilities() ) { + $settings['activePanels'][ $panel_id ] = $panel->active(); + foreach ( $panel->sections as $section_id => $section ) { + if ( $section->check_capabilities() ) { + $settings['activeSections'][ $section_id ] = $section->active(); + } + } } } foreach ( $this->sections as $id => $section ) { - $settings['activeSections'][ $id ] = $section->active(); + if ( $section->check_capabilities() ) { + $settings['activeSections'][ $id ] = $section->active(); + } } foreach ( $this->controls as $id => $control ) { - $settings['activeControls'][ $id ] = $control->active(); + if ( $control->check_capabilities() ) { + $settings['activeControls'][ $id ] = $control->active(); + } } ?> @@ -964,6 +992,34 @@ final class WP_Customize_Manager { unset( $this->panels[ $id ] ); } + /** + * Register a customize panel type. + * + * Registered types are eligible to be rendered via JS and created dynamically. + * + * @since 4.3.0 + * @access public + * + * @param string $panel Name of a custom panel which is a subclass of + * {@see WP_Customize_Panel}. + */ + public function register_panel_type( $panel ) { + $this->registered_panel_types[] = $panel; + } + + /** + * Render JS templates for all registered panel types. + * + * @since 4.3.0 + * @access public + */ + public function render_panel_templates() { + foreach ( $this->registered_panel_types as $panel_type ) { + $panel = new $panel_type( $this, 'temp', array() ); + $panel->print_template(); + } + } + /** * Add a customize section. * @@ -1005,6 +1061,34 @@ final class WP_Customize_Manager { unset( $this->sections[ $id ] ); } + /** + * Register a customize section type. + * + * Registered types are eligible to be rendered via JS and created dynamically. + * + * @since 4.3.0 + * @access public + * + * @param string $section Name of a custom section which is a subclass of + * {@see WP_Customize_Section}. + */ + public function register_section_type( $section ) { + $this->registered_section_types[] = $section; + } + + /** + * Render JS templates for all registered section types. + * + * @since 4.3.0 + * @access public + */ + public function render_section_templates() { + foreach ( $this->registered_section_types as $section_type ) { + $section = new $section_type( $this, 'temp', array() ); + $section->print_template(); + } + } + /** * Add a customize control. * @@ -1176,7 +1260,10 @@ final class WP_Customize_Manager { */ public function register_controls() { - /* Control Types (custom control classes) */ + /* Panel, Section, and Control Types */ + $this->register_panel_type( 'WP_Customize_Panel' ); + $this->register_section_type( 'WP_Customize_Section' ); + $this->register_section_type( 'WP_Customize_Sidebar_Section' ); $this->register_control_type( 'WP_Customize_Color_Control' ); $this->register_control_type( 'WP_Customize_Media_Control' ); $this->register_control_type( 'WP_Customize_Upload_Control' ); diff --git a/src/wp-includes/class-wp-customize-panel.php b/src/wp-includes/class-wp-customize-panel.php index f977f06867..14a47b4e17 100644 --- a/src/wp-includes/class-wp-customize-panel.php +++ b/src/wp-includes/class-wp-customize-panel.php @@ -214,7 +214,7 @@ class WP_Customize_Panel { * @return array The array to be exported to the client as JSON. */ public function json() { - $array = wp_array_slice_assoc( (array) $this, array( 'title', 'description', 'priority', 'type' ) ); + $array = wp_array_slice_assoc( (array) $this, array( 'id', 'title', 'description', 'priority', 'type' ) ); $array['content'] = $this->get_content(); $array['active'] = $this->active(); $array['instanceNumber'] = $this->instance_number; @@ -289,48 +289,92 @@ class WP_Customize_Panel { } /** - * Render the panel container, and then its contents. + * Render the panel container, and then its contents (via `this->render_content()`) in a subclass. + * + * Panel containers are now rendered in JS by default, see {@see WP_Customize_Panel::print_template()}. * * @since 4.0.0 * @access protected */ - protected function render() { - $classes = 'accordion-section control-section control-panel control-panel-' . $this->type; + protected function render() {} + + /** + * Render the panel UI in a subclass. + * + * Panel contents are now rendered in JS by default, see {@see WP_Customize_Panel::print_template()}. + * + * @since 4.1.0 + * @access protected + */ + protected function render_content() {} + + /** + * Render the panel's JS templates. + * + * This function is only run for panel types that have been registered with + * {@see WP_Customize_Manager::register_panel_type()}. + * + * @since 4.3.0 + */ + public function print_template() { ?> -description; ?>
- + <# if ( data.description ) { #> +{{{ data.description }}}
+ <# } #>