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.

Built from https://develop.svn.wordpress.org/trunk@36689


git-svn-id: http://core.svn.wordpress.org/trunk@36656 1a063a9b-81f0-0310-95a4-ce76da25c4cd
This commit is contained in:
Weston Ruter 2016-02-24 18:28:28 +00:00
parent f170058209
commit 2214f69e43
7 changed files with 73 additions and 32 deletions

View File

@ -1521,18 +1521,25 @@
settings = $.map( control.params.settings, function( value ) {
return value;
});
api.apply( api, settings.concat( function () {
var key;
if ( 0 === settings.length ) {
control.setting = null;
control.settings = {};
for ( key in control.params.settings ) {
control.settings[ key ] = api( control.params.settings[ key ] );
}
control.setting = control.settings['default'] || null;
control.embed();
}) );
} else {
api.apply( api, settings.concat( function() {
var key;
control.settings = {};
for ( key in control.params.settings ) {
control.settings[ key ] = api( control.params.settings[ key ] );
}
control.setting = control.settings['default'] || null;
control.embed();
}) );
}
// After the control is embedded on the page, invoke the "ready" method.
control.deferred.embedded.done( function () {

File diff suppressed because one or more lines are too long

View File

@ -64,6 +64,18 @@ class WP_Customize_Control {
*/
public $setting = 'default';
/**
* Capability required to use this control.
*
* Normally this is empty and the capability is derived from the capabilities
* of the associated `$settings`.
*
* @since 4.5.0
* @access public
* @var string
*/
public $capability;
/**
* @access public
* @var int
@ -187,7 +199,7 @@ class WP_Customize_Control {
$this->instance_number = self::$instance_count;
// Process settings.
if ( empty( $this->settings ) ) {
if ( ! isset( $this->settings ) ) {
$this->settings = $id;
}
@ -196,7 +208,7 @@ class WP_Customize_Control {
foreach ( $this->settings as $key => $setting ) {
$settings[ $key ] = $this->manager->get_setting( $setting );
}
} else {
} else if ( is_string( $this->settings ) ) {
$this->setting = $this->manager->get_setting( $this->settings );
$settings['default'] = $this->setting;
}
@ -299,21 +311,32 @@ class WP_Customize_Control {
}
/**
* Check if the theme supports the control and check user capabilities.
* Checks if the user can use this control.
*
* Returns false if the user cannot manipulate one of the associated settings,
* or if one of the associated settings does not exist. Also returns false if
* the associated section does not exist or if its capability check returns
* false.
*
* @since 3.4.0
*
* @return bool False if theme doesn't support the control or user doesn't have the required permissions, otherwise true.
*/
final public function check_capabilities() {
if ( ! empty( $this->capability ) && ! current_user_can( $this->capability ) ) {
return false;
}
foreach ( $this->settings as $setting ) {
if ( ! $setting->check_capabilities() )
if ( ! $setting || ! $setting->check_capabilities() ) {
return false;
}
}
$section = $this->manager->get_section( $this->section );
if ( isset( $section ) && ! $section->check_capabilities() )
if ( isset( $section ) && ! $section->check_capabilities() ) {
return false;
}
return true;
}

View File

@ -606,28 +606,20 @@ final class WP_Customize_Nav_Menus {
'priority' => 999,
) ) );
$this->manager->add_setting( 'new_menu_name', array(
'type' => 'new_menu',
'default' => '',
'transport' => isset( $this->manager->selective_refresh ) ? 'postMessage' : 'refresh',
) );
$this->manager->add_control( 'new_menu_name', array(
'label' => '',
'section' => 'add_menu',
'type' => 'text',
'settings' => array(),
'input_attrs' => array(
'class' => 'menu-name-field',
'placeholder' => __( 'New menu name' ),
),
) );
$this->manager->add_setting( 'create_new_menu', array(
'type' => 'new_menu',
) );
$this->manager->add_control( new WP_Customize_New_Menu_Control( $this->manager, 'create_new_menu', array(
'section' => 'add_menu',
'section' => 'add_menu',
'settings' => array(),
) ) );
}
@ -851,6 +843,8 @@ final class WP_Customize_Nav_Menus {
'type' => 'nav_menu_instance',
'render_callback' => array( $this, 'render_nav_menu_partial' ),
'container_inclusive' => true,
'settings' => array(), // Empty because the nav menu instance may relate to a menu or a location.
'capability' => 'edit_theme_options',
)
);
}

View File

@ -1485,16 +1485,18 @@ final class WP_Customize_Widgets {
*/
public function customize_dynamic_partial_args( $partial_args, $partial_id ) {
if ( preg_match( '/^widget\[.+\]$/', $partial_id ) ) {
if ( preg_match( '/^widget\[(?P<widget_id>.+)\]$/', $partial_id, $matches ) ) {
if ( false === $partial_args ) {
$partial_args = array();
}
$partial_args = array_merge(
$partial_args,
array(
'type' => 'widget',
'render_callback' => array( $this, 'render_widget_partial' ),
'type' => 'widget',
'render_callback' => array( $this, 'render_widget_partial' ),
'container_inclusive' => true,
'settings' => array( $this->get_setting_id( $matches['widget_id'] ) ),
'capability' => 'edit_theme_options',
)
);
}

View File

@ -89,6 +89,18 @@ class WP_Customize_Partial {
*/
public $primary_setting;
/**
* Capability required to edit this partial.
*
* Normally this is empty and the capability is derived from the capabilities
* of the associated `$settings`.
*
* @since 4.5.0
* @access public
* @var string
*/
public $capability;
/**
* Render callback.
*
@ -157,7 +169,7 @@ class WP_Customize_Partial {
}
// Process settings.
if ( empty( $this->settings ) ) {
if ( ! isset( $this->settings ) ) {
$this->settings = array( $id );
} else if ( is_string( $this->settings ) ) {
$this->settings = array( $this->settings );
@ -299,6 +311,9 @@ class WP_Customize_Partial {
* or if one of the associated settings does not exist.
*/
final public function check_capabilities() {
if ( ! empty( $this->capability ) && ! current_user_can( $this->capability ) ) {
return false;
}
foreach ( $this->settings as $setting_id ) {
$setting = $this->component->manager->get_setting( $setting_id );
if ( ! $setting || ! $setting->check_capabilities() ) {

View File

@ -4,7 +4,7 @@
*
* @global string $wp_version
*/
$wp_version = '4.5-alpha-36688';
$wp_version = '4.5-alpha-36689';
/**
* Holds the WordPress DB revision, increments when changes are made to the WordPress DB schema.