Make WordPress Core

Changeset 36689


Ignore:
Timestamp:
02/24/2016 06:27:45 PM (9 years ago)
Author:
westonruter
Message:

Customize: Allow controls to be registered without any associated settings.

  • Improves parity between partials and controls. A partial or control can be settingless if instantiated with settings param as empty array (otherwise, if null, then the partial/control ID is used).
  • Eliminate need to create dummy settings that serve no purpose except to place a control in the UI.
  • Removes dummy settings for create_new_menu and new_menu_name.
  • Introduces WP_Customize_Control::$capability and WP_Customize_Partial::$capability, and if set checks them in the respective check_capabilities() methods.
  • Prevents PHP fatal error from happening when non-existing settings are provided to control: "Call to a member function check_capabilities() on a non-object".
  • Fixes issue where nav menu items and widgets were no longer working with selective refresh because cap check was failing.

See #27355.
Fixes #35926.

Location:
trunk
Files:
1 added
8 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/wp-admin/js/customize-controls.js

    r36586 r36689  
    15221522                return value;
    15231523            });
    1524             api.apply( api, settings.concat( function () {
    1525                 var key;
    1526 
     1524
     1525            if ( 0 === settings.length ) {
     1526                control.setting = null;
    15271527                control.settings = {};
    1528                 for ( key in control.params.settings ) {
    1529                     control.settings[ key ] = api( control.params.settings[ key ] );
    1530                 }
    1531 
    1532                 control.setting = control.settings['default'] || null;
    1533 
    15341528                control.embed();
    1535             }) );
     1529            } else {
     1530                api.apply( api, settings.concat( function() {
     1531                    var key;
     1532
     1533                    control.settings = {};
     1534                    for ( key in control.params.settings ) {
     1535                        control.settings[ key ] = api( control.params.settings[ key ] );
     1536                    }
     1537
     1538                    control.setting = control.settings['default'] || null;
     1539
     1540                    control.embed();
     1541                }) );
     1542            }
    15361543
    15371544            // After the control is embedded on the page, invoke the "ready" method.
  • trunk/src/wp-includes/class-wp-customize-control.php

    r36114 r36689  
    6464     */
    6565    public $setting = 'default';
     66
     67    /**
     68     * Capability required to use this control.
     69     *
     70     * Normally this is empty and the capability is derived from the capabilities
     71     * of the associated `$settings`.
     72     *
     73     * @since 4.5.0
     74     * @access public
     75     * @var string
     76     */
     77    public $capability;
    6678
    6779    /**
     
    188200
    189201        // Process settings.
    190         if ( empty( $this->settings ) ) {
     202        if ( ! isset( $this->settings ) ) {
    191203            $this->settings = $id;
    192204        }
     
    197209                $settings[ $key ] = $this->manager->get_setting( $setting );
    198210            }
    199         } else {
     211        } else if ( is_string( $this->settings ) ) {
    200212            $this->setting = $this->manager->get_setting( $this->settings );
    201213            $settings['default'] = $this->setting;
     
    300312
    301313    /**
    302      * Check if the theme supports the control and check user capabilities.
     314     * Checks if the user can use this control.
     315     *
     316     * Returns false if the user cannot manipulate one of the associated settings,
     317     * or if one of the associated settings does not exist. Also returns false if
     318     * the associated section does not exist or if its capability check returns
     319     * false.
    303320     *
    304321     * @since 3.4.0
     
    307324     */
    308325    final public function check_capabilities() {
     326        if ( ! empty( $this->capability ) && ! current_user_can( $this->capability ) ) {
     327            return false;
     328        }
     329
    309330        foreach ( $this->settings as $setting ) {
    310             if ( ! $setting->check_capabilities() )
     331            if ( ! $setting || ! $setting->check_capabilities() ) {
    311332                return false;
     333            }
    312334        }
    313335
    314336        $section = $this->manager->get_section( $this->section );
    315         if ( isset( $section ) && ! $section->check_capabilities() )
     337        if ( isset( $section ) && ! $section->check_capabilities() ) {
    316338            return false;
     339        }
    317340
    318341        return true;
  • trunk/src/wp-includes/class-wp-customize-nav-menus.php

    r36676 r36689  
    607607        ) ) );
    608608
    609         $this->manager->add_setting( 'new_menu_name', array(
    610             'type'      => 'new_menu',
    611             'default'   => '',
    612             'transport' => isset( $this->manager->selective_refresh ) ? 'postMessage' : 'refresh',
    613         ) );
    614 
    615609        $this->manager->add_control( 'new_menu_name', array(
    616610            'label'       => '',
    617611            'section'     => 'add_menu',
    618612            'type'        => 'text',
     613            'settings'    => array(),
    619614            'input_attrs' => array(
    620615                'class'       => 'menu-name-field',
     
    623618        ) );
    624619
    625         $this->manager->add_setting( 'create_new_menu', array(
    626             'type' => 'new_menu',
    627         ) );
    628 
    629620        $this->manager->add_control( new WP_Customize_New_Menu_Control( $this->manager, 'create_new_menu', array(
    630             'section' => 'add_menu',
     621            'section'  => 'add_menu',
     622            'settings' => array(),
    631623        ) ) );
    632624    }
     
    852844                    'render_callback'     => array( $this, 'render_nav_menu_partial' ),
    853845                    'container_inclusive' => true,
     846                    'settings'            => array(), // Empty because the nav menu instance may relate to a menu or a location.
     847                    'capability'          => 'edit_theme_options',
    854848                )
    855849            );
  • trunk/src/wp-includes/class-wp-customize-widgets.php

    r36623 r36689  
    14861486    public function customize_dynamic_partial_args( $partial_args, $partial_id ) {
    14871487
    1488         if ( preg_match( '/^widget\[.+\]$/', $partial_id ) ) {
     1488        if ( preg_match( '/^widget\[(?P<widget_id>.+)\]$/', $partial_id, $matches ) ) {
    14891489            if ( false === $partial_args ) {
    14901490                $partial_args = array();
     
    14931493                $partial_args,
    14941494                array(
    1495                     'type' => 'widget',
    1496                     'render_callback' => array( $this, 'render_widget_partial' ),
     1495                    'type'                => 'widget',
     1496                    'render_callback'     => array( $this, 'render_widget_partial' ),
    14971497                    'container_inclusive' => true,
     1498                    'settings'            => array( $this->get_setting_id( $matches['widget_id'] ) ),
     1499                    'capability'          => 'edit_theme_options',
    14981500                )
    14991501            );
  • trunk/src/wp-includes/customize/class-wp-customize-partial.php

    r36643 r36689  
    9191
    9292    /**
     93     * Capability required to edit this partial.
     94     *
     95     * Normally this is empty and the capability is derived from the capabilities
     96     * of the associated `$settings`.
     97     *
     98     * @since 4.5.0
     99     * @access public
     100     * @var string
     101     */
     102    public $capability;
     103
     104    /**
    93105     * Render callback.
    94106     *
     
    158170
    159171        // Process settings.
    160         if ( empty( $this->settings ) ) {
     172        if ( ! isset( $this->settings ) ) {
    161173            $this->settings = array( $id );
    162174        } else if ( is_string( $this->settings ) ) {
     
    300312     */
    301313    final public function check_capabilities() {
     314        if ( ! empty( $this->capability ) && ! current_user_can( $this->capability ) ) {
     315            return false;
     316        }
    302317        foreach ( $this->settings as $setting_id ) {
    303318            $setting = $this->component->manager->get_setting( $setting_id );
  • trunk/tests/phpunit/tests/customize/partial.php

    r36643 r36689  
    326326        ) );
    327327        $this->assertFalse( $partial->check_capabilities() );
     328
     329        $partial = new WP_Customize_Partial( $this->selective_refresh, 'no_setting', array(
     330            'settings' => array(),
     331        ) );
     332        $this->assertTrue( $partial->check_capabilities() );
     333
     334        $partial = new WP_Customize_Partial( $this->selective_refresh, 'no_setting', array(
     335            'settings' => array(),
     336            'capability' => 'top_secret_clearance',
     337        ) );
     338        $this->assertFalse( $partial->check_capabilities() );
     339
     340        $partial = new WP_Customize_Partial( $this->selective_refresh, 'no_setting', array(
     341            'settings' => array(),
     342            'capability' => 'edit_theme_options',
     343        ) );
     344        $this->assertTrue( $partial->check_capabilities() );
    328345    }
    329346
  • trunk/tests/qunit/fixtures/customize-menus.js

    r36586 r36689  
    395395    'instanceNumber': 46
    396396};
    397 window._wpCustomizeSettings.settings.new_menu_name = {
    398     'value': '',
    399     'transport': 'postMessage',
    400     'dirty': false
    401 };
    402397
    403398// From nav-menu.js
  • trunk/tests/qunit/wp-admin/js/customize-controls.js

    r36532 r36689  
    9999        var control = wp.customize.control( 'fixture-control' );
    100100        equal( control.section(), 'fixture-section' );
     101    } );
     102
     103    module( 'Customizer control without associated settings' );
     104    test( 'Control can be created without settings', function() {
     105        var control = new wp.customize.Control( 'settingless', {
     106            params: {
     107                content: jQuery( '<li class="settingless">Hello World</li>' ),
     108                section: 'fixture-section'
     109            }
     110        } );
     111        wp.customize.control.add( control.id, control );
     112        equal( control.deferred.embedded.state(), 'resolved' );
     113        ok( null === control.setting );
     114        ok( jQuery.isEmptyObject( control.settings ) );
    101115    } );
    102116
Note: See TracChangeset for help on using the changeset viewer.