Make WordPress Core

Ticket #28709: 28709.wip.2.diff

File 28709.wip.2.diff, 21.3 KB (added by westonruter, 10 years ago)

https://github.com/xwpco/wordpress-develop/compare/01050a4d20849a9c92505bab535a6aad2ce201ca...da6a3db755dbfc5d12876b35c80771e7aaa75453 https://github.com/xwpco/wordpress-develop/pull/29

  • src/wp-admin/customize.php

    diff --git src/wp-admin/customize.php src/wp-admin/customize.php
    index 3cfa0c7..2ce23b4 100644
    do_action( 'customize_controls_print_scripts' ); 
    160160                                <?php endif; ?>
    161161                        </div>
    162162
    163                         <div id="customize-theme-controls"><ul>
    164                                 <?php
    165                                 foreach ( $wp_customize->containers() as $container ) {
    166                                         $container->maybe_render();
    167                                 }
    168                                 ?>
    169                         </ul></div>
     163                        <div id="customize-theme-controls">
     164                                <ul><?php // Panels and sections are managed here via JavaScript ?></ul>
     165                        </div>
    170166                </div>
    171167                </div>
    172168
    do_action( 'customize_controls_print_scripts' ); 
    249245                ),
    250246                'settings' => array(),
    251247                'controls' => array(),
     248                'panels'   => array(),
     249                'sections' => array(),
    252250                'nonce'    => array(
    253251                        'save'    => wp_create_nonce( 'save-customize_' . $wp_customize->get_stylesheet() ),
    254252                        'preview' => wp_create_nonce( 'preview-customize_' . $wp_customize->get_stylesheet() )
    do_action( 'customize_controls_print_scripts' ); 
    263261                );
    264262        }
    265263
    266         // Prepare Customize Control objects to pass to Javascript.
     264        // Prepare Customize Control objects to pass to JavaScript.
    267265        foreach ( $wp_customize->controls() as $id => $control ) {
    268                 $control->to_json();
    269                 $settings['controls'][ $id ] = $control->json;
     266                $settings['controls'][ $id ] = $control->json();
     267        }
     268
     269        // Prepare Customize Section objects to pass to JavaScript.
     270        foreach ( $wp_customize->sections() as $id => $section ) {
     271                $settings['sections'][ $id ] = $section->json();
     272        }
     273
     274        // Prepare Customize Panel objects to pass to JavaScript.
     275        foreach ( $wp_customize->panels() as $id => $panel ) {
     276                $settings['panels'][ $id ] = $panel->json();
     277                foreach ( $panel->sections as $section_id => $section ) {
     278                        $settings['sections'][ $section_id ] = $section->json();
     279                }
    270280        }
    271281
    272282        ?>
  • src/wp-admin/js/accordion.js

    diff --git src/wp-admin/js/accordion.js src/wp-admin/js/accordion.js
    index 6cb1c1c..63e14e8 100644
     
    5858                });
    5959        });
    6060
    61         var sectionContent = $( '.accordion-section-content' );
    62 
    6361        /**
    6462         * Close the current accordion section and open a new one.
    6563         *
     
    6967        function accordionSwitch ( el ) {
    7068                var section = el.closest( '.accordion-section' ),
    7169                        siblings = section.closest( '.accordion-container' ).find( '.open' ),
    72                         content = section.find( sectionContent );
     70                        content = section.find( '.accordion-section-content' );
    7371
    7472                // This section has no content and cannot be expanded.
    7573                if ( section.hasClass( 'cannot-expand' ) ) {
     
    8785                        content.toggle( true ).slideToggle( 150 );
    8886                } else {
    8987                        siblings.removeClass( 'open' );
    90                         siblings.find( sectionContent ).show().slideUp( 150 );
     88                        siblings.find( '.accordion-section-content' ).show().slideUp( 150 );
    9189                        content.toggle( false ).slideToggle( 150 );
    9290                        section.toggleClass( 'open' );
    9391                }
     
    125123                } else {
    126124                        // Close all open sections in any accordion level.
    127125                        siblings.removeClass( 'open' );
    128                         siblings.find( sectionContent ).show().slideUp( 0 );
     126                        siblings.find( '.accordion-section-content' ).show().slideUp( 0 );
    129127                        content.show( 0, function() {
    130128                                position = content.offset().top;
    131129                                scroll = container.scrollTop();
  • src/wp-admin/js/customize-controls.js

    diff --git src/wp-admin/js/customize-controls.js src/wp-admin/js/customize-controls.js
    index 85b171d..9edc973 100644
     
    11/* globals _wpCustomizeHeader, _wpMediaViewsL10n */
    22(function( exports, $ ){
    3         var api = wp.customize;
     3        var bubbleChildValueChanges, api = wp.customize;
    44
    55        /**
    66         * @constructor
     
    3131        });
    3232
    3333        /**
     34         * Watch all changes to Value properties, and bubble changes to parent Values instance
     35         *
     36         * @param instance
     37         */
     38        bubbleChildValueChanges = function ( instance ) {
     39                $.each( instance, function ( key, value ) {
     40                        if ( value && value.extended && value.extended( api.Value ) ) {
     41                                value.bind( function () {
     42                                        if ( instance.parent ) {
     43                                                instance.parent.trigger( 'change', instance );
     44                                        }
     45                                } );
     46                        }
     47                } );
     48        };
     49
     50        /**
     51         * @constructor
     52         * @augments wp.customize.Class
     53         */
     54        api.Section = api.Class.extend({
     55
     56                /**
     57                 * @param {String} id
     58                 * @param {Array} options
     59                 */
     60                initialize: function ( id, options ) {
     61                        var section = this;
     62                        section.id = id;
     63                        section.params = {};
     64                        $.extend( section, options || {} );
     65                        section.panel = new api.Value();
     66                        section.container = $( section.params.content );
     67                        section.priority = new api.Value( section.params.priority || 100 );
     68                        section.panel.bind( function ( id ) {
     69                                $( section.container ).toggleClass( 'control-subsection', !! id );
     70                        });
     71                        section.panel.set( section.params.panel || '' );
     72                        section.active = new api.Value( true ); // @todo pass from params; value is whether sections is not empty
     73                        section.active.bind( function ( active ) {
     74                                section.toggle( active );
     75                        } );
     76                        section.toggle( section.active() );
     77                        bubbleChildValueChanges( this );
     78                },
     79
     80                /**
     81                 *
     82                 */
     83                embed: function ( readyCallback ) {
     84                        var panel_id,
     85                                section = this;
     86
     87                        panel_id = this.panel.get();
     88                        if ( ! panel_id ) {
     89                                $( '#customize-theme-controls > ul' ).append( section.container );
     90                                readyCallback();
     91                        } else {
     92                                api.panel( panel_id, function ( panel ) {
     93                                        panel.embed();
     94                                        panel.container.find( 'ul:first' ).append( section.container );
     95                                        readyCallback();
     96                                } );
     97                        }
     98                },
     99
     100                /**
     101                 * Get the controls that are associated with this section.
     102                 *
     103                 * @returns {Array}
     104                 */
     105                controls: function () {
     106                        var section = this,
     107                                controls = [];
     108                        api.control.each( function ( control ) {
     109                                if ( control.section.get() === section.id ) {
     110                                        controls.push( control );
     111                                }
     112                        } );
     113                        controls.sort( function ( a, b ) {
     114                                return a.priority() - b.priority();
     115                        } );
     116                        return controls;
     117                },
     118
     119                /**
     120                 * Callback for change to the section's active state.
     121                 *
     122                 * Override function for custom behavior for the section being active/inactive.
     123                 *
     124                 * @param {Boolean} active
     125                 */
     126                toggle: function ( active ) {
     127                        if ( active ) {
     128                                this.container.slideDown();
     129                        } else {
     130                                this.container.slideUp();
     131                        }
     132                },
     133
     134                /**
     135                 * Bring the containing panel into view and then expand this section and bring it into view
     136                 */
     137                focus: function () {
     138                        throw new Error( 'Not implemented yet' );
     139                }
     140        });
     141
     142        /**
     143         * @constructor
     144         * @augments wp.customize.Class
     145         */
     146        api.Panel = api.Class.extend({
     147                initialize: function ( id, options ) {
     148                        var panel = this;
     149                        panel.id = id;
     150                        panel.params = {};
     151                        $.extend( panel, options || {} );
     152                        panel.priority = new api.Value( panel.params.priority || 160 ); // @todo What if the priority gets changed dynamically?
     153                        panel.container = $( panel.params.content );
     154                        panel.active = new api.Value( true ); // @todo pass from params; value is whether sections is not empty
     155                        panel.active.bind( function ( active ) {
     156                                panel.toggle( active );
     157                        } );
     158                        panel.toggle( panel.active() );
     159                        bubbleChildValueChanges( this );
     160                },
     161
     162                /**
     163                 *
     164                 */
     165                embed: function ( readyCallback ) {
     166                        $( '#customize-theme-controls > ul' ).append( this.container );
     167                        if ( readyCallback ) {
     168                                readyCallback();
     169                        }
     170                },
     171
     172                /**
     173                 * Get the controls that are associated with this section.
     174                 *
     175                 * @returns {Array}
     176                 */
     177                sections: function () {
     178                        var panel = this,
     179                                sections = [];
     180                        api.section.each( function ( section ) {
     181                                if ( section.panel.get() === panel.id ) {
     182                                        sections.push( section );
     183                                }
     184                        } );
     185                        sections.sort( function ( a, b ) {
     186                                return a.priority() - b.priority();
     187                        } );
     188                        return sections;
     189                },
     190
     191                /**
     192                 * Callback for change to the panel's active state.
     193                 *
     194                 * Override function for custom behavior for the control being active/inactive.
     195                 *
     196                 * @param {Boolean} active
     197                 */
     198                toggle: function ( active ) {
     199                        if ( active ) {
     200                                this.container.slideDown();
     201                        } else {
     202                                // @todo Need to first exit out of the Panel
     203                                this.container.slideUp();
     204                        }
     205                }
     206        });
     207
     208        /**
    34209         * @constructor
    35210         * @augments wp.customize.Class
    36211         */
     
    44219
    45220                        this.id = id;
    46221                        this.selector = '#customize-control-' + id.replace( /\]/g, '' ).replace( /\[/g, '-' );
    47                         this.container = $( this.selector );
     222                        this.container = this.params.content ? $( this.params.content ) : $( this.selector );
     223
     224                        this.section = new api.Value( this.params.section );
     225                        this.priority = new api.Value( this.params.priority || 10 );
    48226                        this.active = new api.Value( this.params.active );
    49227
    50228                        settings = $.map( this.params.settings, function( value ) {
     
    60238                                }
    61239
    62240                                control.setting = control.settings['default'] || null;
    63                                 control.ready();
     241                                control.embed( function () {
     242                                        control.ready();
     243                                } );
    64244                        }) );
    65245
    66246                        control.elements = [];
     
    74254
    75255                                if ( node.is(':radio') ) {
    76256                                        name = node.prop('name');
    77                                         if ( radios[ name ] )
     257                                        if ( radios[ name ] ) {
    78258                                                return;
     259                                        }
    79260
    80261                                        radios[ name ] = true;
    81262                                        node = nodes.filter( '[name="' + name + '"]' );
     
    93274                                control.toggle( active );
    94275                        } );
    95276                        control.toggle( control.active() );
     277
     278                        bubbleChildValueChanges( this );
     279                },
     280
     281                /**
     282                 * @param {Function} [readyCallback] Callback to fire when the embedding is done.
     283                 */
     284                embed: function ( readyCallback ) {
     285                        var section_id,
     286                                control = this;
     287
     288                        section_id = control.section.get();
     289                        if ( ! section_id ) {
     290                                throw new Error( 'A control must have an associated section.' );
     291                        }
     292
     293                        // Defer until the associated section is available
     294                        api.section( section_id, function ( section ) {
     295                                section.embed( function () {
     296                                        section.container.find( 'ul:first' ).append( control.container );
     297                                        readyCallback();
     298                                } );
     299                        } );
    96300                },
    97301
    98302                /**
     
    101305                ready: function() {},
    102306
    103307                /**
     308                 * Bring the containing section and panel into view and then this control into view, focusing on the first input
     309                 */
     310                focus: function () {
     311                        throw new Error( 'Not implemented yet' );
     312                },
     313
     314                /**
    104315                 * Callback for change to the control's active state.
    105316                 *
    106317                 * Override function for custom behavior for the control being active/inactive.
     
    575786
    576787        // Create the collection of Control objects.
    577788        api.control = new api.Values({ defaultConstructor: api.Control });
     789        api.section = new api.Values({ defaultConstructor: api.Section });
     790        api.panel = new api.Values({ defaultConstructor: api.Panel });
    578791
    579792        /**
    580793         * @constructor
     
    9791192                image:  api.ImageControl,
    9801193                header: api.HeaderControl
    9811194        };
     1195        api.panelConstructor = {};
     1196        api.sectionConstructor = {};
    9821197
    9831198        $( function() {
    9841199                api.settings = window._wpCustomizeSettings;
     
    10911306                        $.extend( this.nonce, nonce );
    10921307                });
    10931308
     1309                // Create Settings
    10941310                $.each( api.settings.settings, function( id, data ) {
    10951311                        api.create( id, id, data.value, {
    10961312                                transport: data.transport,
     
    10981314                        } );
    10991315                });
    11001316
     1317                // Create Panels
     1318                $.each( api.settings.panels, function ( id, data ) {
     1319                        var constructor = api.panelConstructor[ data.type ] || api.Panel,
     1320                                panel;
     1321
     1322                        panel = new constructor( id, {
     1323                                params: data
     1324                        } );
     1325                        api.panel.add( id, panel );
     1326                });
     1327
     1328                // Create Sections
     1329                $.each( api.settings.sections, function ( id, data ) {
     1330                        var constructor = api.sectionConstructor[ data.type ] || api.Section,
     1331                                section;
     1332
     1333                        section = new constructor( id, {
     1334                                params: data
     1335                        } );
     1336                        api.section.add( id, section );
     1337                });
     1338
     1339                // Create Controls
     1340                // @todo factor this out
    11011341                $.each( api.settings.controls, function( id, data ) {
    11021342                        var constructor = api.controlConstructor[ data.type ] || api.Control,
    11031343                                control;
    11041344
    1105                         control = api.control.add( id, new constructor( id, {
     1345                        control = new constructor( id, {
    11061346                                params: data,
    11071347                                previewer: api.previewer
    1108                         } ) );
     1348                        } );
     1349                        api.control.add( id, control );
    11091350                });
    11101351
     1352                /**
     1353                 * Sort panels, sections, controls by priorities. Hide empty sections and panels.
     1354                 */
     1355                api.reflowPaneContents = _.bind( function () {
     1356
     1357                        var appendContainer, rootNodes = [];
     1358
     1359                        api.panel.each( function ( panel ) {
     1360                                rootNodes.push( panel );
     1361
     1362                                // Toggle display
     1363                                var activeCount = 0,
     1364                                        sections = panel.sections();
     1365                                _( sections ).each( function ( section ) {
     1366                                        if ( section.active && section.active() ) {
     1367                                                activeCount += 1;
     1368                                        }
     1369                                } );
     1370                                panel.toggle( 0 !== activeCount ); // @todo This is not sticking
     1371
     1372                                // Sort sections
     1373                                appendContainer = panel.container.find( 'ul:first' );
     1374                                _.chain( sections ).reverse().each( function ( section ) {
     1375                                        appendContainer.append( section.container );
     1376                                } );
     1377                        } );
     1378
     1379                        api.section.each( function ( section ) {
     1380                                var activeCount = 0,
     1381                                        controls = section.controls();
     1382                                _( controls ).each( function ( control ) {
     1383                                        if ( control.active && control.active() ) {
     1384                                                activeCount += 1;
     1385                                        }
     1386                                } );
     1387                                section.toggle( 0 !== activeCount );
     1388
     1389                                if ( ! section.panel() ) {
     1390                                        rootNodes.push( section );
     1391                                }
     1392
     1393                                // Sort controls
     1394                                appendContainer = section.container.find( 'ul:first' );
     1395                                _.chain( controls ).reverse().each( function ( control ) {
     1396                                        appendContainer.append( control.container );
     1397                                } );
     1398                        } );
     1399
     1400                        // Sort the root elements
     1401                        rootNodes.sort( function ( a, b ) {
     1402                                return a.priority() - b.priority();
     1403                        } );
     1404                        appendContainer = $( '#customize-theme-controls > ul' );
     1405                        _.chain( rootNodes ).each( function ( rootNode ) {
     1406                                appendContainer.append( rootNode.container );
     1407                        } );
     1408                }, api );
     1409                api.reflowPaneContents = _.debounce( api.reflowPaneContents, 100 );
     1410                $( [ api.panel, api.section, api.control ] ).each( function ( i, values ) {
     1411                        values.bind( 'add', api.reflowPaneContents );
     1412                        values.bind( 'change', api.reflowPaneContents );
     1413                        values.bind( 'remove', api.reflowPaneContents );
     1414                } );
     1415                api.bind( 'ready', api.reflowPaneContents );
     1416
    11111417                // Check if preview url is valid and load the preview frame.
    11121418                if ( api.previewer.previewUrl() ) {
    11131419                        api.previewer.refresh();
  • src/wp-includes/class-wp-customize-control.php

    diff --git src/wp-includes/class-wp-customize-control.php src/wp-includes/class-wp-customize-control.php
    index 7ae21c8..4a5985f 100644
    class WP_Customize_Control { 
    7474        public $input_attrs = array();
    7575
    7676        /**
     77         * @deprecated It is better to just call the json() method
    7778         * @access public
    7879         * @var array
    7980         */
    class WP_Customize_Control { 
    219220
    220221                $this->json['type'] = $this->type;
    221222                $this->json['active'] = $this->active();
     223                $this->json['section'] = $this->section;
     224                $this->json['content'] = $this->get_content();
     225        }
     226
     227        /**
     228         * Get the data to export to the client via JSON.
     229         *
     230         * @since 4.1.0
     231         *
     232         * @return array
     233         */
     234        public function json() {
     235                $this->to_json();
     236                return $this->json;
    222237        }
    223238
    224239        /**
    class WP_Customize_Control { 
    242257        }
    243258
    244259        /**
     260         * Get the control's content for insertion into the Customizer pane.
     261         *
     262         * @since 4.1.0
     263         *
     264         * @return string
     265         */
     266        public final function get_content() {
     267                ob_start();
     268                $this->maybe_render();
     269                $template = trim( ob_get_contents() );
     270                ob_end_clean();
     271                return $template;
     272        }
     273
     274        /**
    245275         * Check capabilities and render the control.
    246276         *
    247277         * @since 3.4.0
  • src/wp-includes/class-wp-customize-manager.php

    diff --git src/wp-includes/class-wp-customize-manager.php src/wp-includes/class-wp-customize-manager.php
    index c658198..bf0963c 100644
    final class WP_Customize_Manager { 
    878878
    879879                        if ( ! $section->panel ) {
    880880                                // Top-level section.
    881                                 $sections[] = $section;
     881                                $sections[ $section->id ] = $section;
    882882                        } else {
    883883                                // This section belongs to a panel.
    884884                                if ( isset( $this->panels [ $section->panel ] ) ) {
    885                                         $this->panels[ $section->panel ]->sections[] = $section;
     885                                        $this->panels[ $section->panel ]->sections[ $section->id ] = $section;
    886886                                }
    887887                        }
    888888                }
    final class WP_Customize_Manager { 
    899899                                continue;
    900900                        }
    901901
    902                         usort( $panel->sections, array( $this, '_cmp_priority' ) );
    903                         $panels[] = $panel;
     902                        uasort( $panel->sections, array( $this, '_cmp_priority' ) );
     903                        $panels[ $panel->id ] = $panel;
    904904                }
    905905                $this->panels = $panels;
    906906
  • src/wp-includes/class-wp-customize-panel.php

    diff --git src/wp-includes/class-wp-customize-panel.php src/wp-includes/class-wp-customize-panel.php
    index 8f85049..fdbe5b4 100644
    class WP_Customize_Panel { 
    8383        public $sections;
    8484
    8585        /**
     86         * @since 4.1.0
     87         * @access public
     88         * @var string
     89         */
     90        public $type;
     91
     92        /**
    8693         * Constructor.
    8794         *
    8895         * Any supplied $args override class property defaults.
    class WP_Customize_Panel { 
    110117        }
    111118
    112119        /**
     120         * Gather the parameters passed to client JavaScript via JSON.
     121         *
     122         * @since 4.1.0
     123         *
     124         * @return array The array to be exported to the client as JSON
     125         */
     126        public function json() {
     127                $array = wp_array_slice_assoc( (array) $this, array( 'title', 'description', 'priority', 'type' ) );
     128                $array['content'] = $this->get_content();
     129                return $array;
     130        }
     131
     132        /**
    113133         * Checks required user capabilities and whether the theme has the
    114134         * feature support required by the panel.
    115135         *
    class WP_Customize_Panel { 
    130150        }
    131151
    132152        /**
     153         * Get the panel's content template for insertion into the Customizer pane.
     154         *
     155         * @since 4.1.0
     156         *
     157         * @return string
     158         */
     159        public final function get_content() {
     160                ob_start();
     161                $this->maybe_render();
     162                $template = trim( ob_get_contents() );
     163                ob_end_clean();
     164                return $template;
     165        }
     166
     167        /**
    133168         * Check capabilities and render the panel.
    134169         *
    135170         * @since 4.0.0
    class WP_Customize_Panel { 
    175210                                <span class="screen-reader-text"><?php _e( 'Press return or enter to open this panel' ); ?></span>
    176211                        </h3>
    177212                        <ul class="accordion-sub-container control-panel-content">
    178                                 <li class="accordion-section control-section<?php if ( empty( $this->description ) ) echo ' cannot-expand'; ?>">
     213                                <li class="panel-meta accordion-section control-section<?php if ( empty( $this->description ) ) echo ' cannot-expand'; ?>">
    179214                                        <div class="accordion-section-title" tabindex="0">
    180215                                                <span class="preview-notice"><?php
    181216                                                        /* translators: %s is the site/panel title in the Customizer */
    class WP_Customize_Panel { 
    188223                                                </div>
    189224                                        <?php endif; ?>
    190225                                </li>
    191                                 <?php
    192                                 foreach ( $this->sections as $section ) {
    193                                         $section->maybe_render();
    194                                 }
    195                                 ?>
     226
    196227                        </ul>
    197228                </li>
    198229                <?php
  • src/wp-includes/class-wp-customize-section.php

    diff --git src/wp-includes/class-wp-customize-section.php src/wp-includes/class-wp-customize-section.php
    index d740ddb..a905f32 100644
    class WP_Customize_Section { 
    9292        public $controls;
    9393
    9494        /**
     95         * @since 4.1.0
     96         * @access public
     97         * @var string
     98         */
     99        public $type;
     100
     101        /**
    95102         * Constructor.
    96103         *
    97104         * Any supplied $args override class property defaults.
    class WP_Customize_Section { 
    118125        }
    119126
    120127        /**
     128         * Gather the parameters passed to client JavaScript via JSON.
     129         *
     130         * @since 4.1.0
     131         *
     132         * @return array The array to be exported to the client as JSON
     133         */
     134        public function json() {
     135                $array = wp_array_slice_assoc( (array) $this, array( 'title', 'description', 'priority', 'panel', 'type' ) );
     136                $array['content'] = $this->get_content();
     137                return $array;
     138        }
     139
     140        /**
    121141         * Checks required user capabilities and whether the theme has the
    122142         * feature support required by the section.
    123143         *
    class WP_Customize_Section { 
    136156        }
    137157
    138158        /**
     159         * Get the section's content template for insertion into the Customizer pane.
     160         *
     161         * @since 4.1.0
     162         *
     163         * @return string
     164         */
     165        public final function get_content() {
     166                ob_start();
     167                $this->maybe_render();
     168                $template = trim( ob_get_contents() );
     169                ob_end_clean();
     170                return $template;
     171        }
     172
     173        /**
    139174         * Check capabilities and render the section.
    140175         *
    141176         * @since 3.4.0
    class WP_Customize_Section { 
    172207         */
    173208        protected function render() {
    174209                $classes = 'control-section accordion-section';
    175                 if ( $this->panel ) {
    176                         $classes .= ' control-subsection';
    177                 }
    178210                ?>
    179211                <li id="accordion-section-<?php echo esc_attr( $this->id ); ?>" class="<?php echo esc_attr( $classes ); ?>">
    180212                        <h3 class="accordion-section-title" tabindex="0">
    class WP_Customize_Section { 
    183215                        </h3>
    184216                        <ul class="accordion-section-content">
    185217                                <?php if ( ! empty( $this->description ) ) : ?>
    186                                 <li><p class="description customize-section-description"><?php echo $this->description; ?></p></li>
     218                                        <li class="customize-section-description-container">
     219                                                <p class="description customize-section-description"><?php echo $this->description; ?></p>
     220                                        </li>
    187221                                <?php endif; ?>
    188                                 <?php
    189                                 foreach ( $this->controls as $control )
    190                                         $control->maybe_render();
    191                                 ?>
    192222                        </ul>
    193223                </li>
    194224                <?php
  • src/wp-includes/js/customize-base.js

    diff --git src/wp-includes/js/customize-base.js src/wp-includes/js/customize-base.js
    index 6c41b40..13d6189 100644
    window.wp = window.wp || {}; 
    183183                        to = this.validate( to );
    184184
    185185                        // Bail if the sanitized value is null or unchanged.
    186                         if ( null === to || this._value === to )
     186                        if ( null === to || this._value === to ) { // @todo why bail if null?
    187187                                return this;
     188                        }
    188189
    189190                        this._value = to;
    190191