Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions src/wp-admin/includes/ajax-actions.php
Original file line number Diff line number Diff line change
Expand Up @@ -1527,7 +1527,7 @@ function wp_ajax_edit_comment() {
function wp_ajax_add_menu_item() {
check_ajax_referer( 'add-menu_item', 'menu-settings-column-nonce' );

if ( ! current_user_can( 'edit_theme_options' ) ) {
if ( ! current_user_can( 'manage_nav_menus' ) ) {
wp_die( -1 );
}

Expand Down Expand Up @@ -1879,7 +1879,7 @@ function wp_ajax_update_welcome_panel() {
* @since 3.1.0
*/
function wp_ajax_menu_get_metabox() {
if ( ! current_user_can( 'edit_theme_options' ) ) {
if ( ! current_user_can( 'manage_nav_menus' ) ) {
wp_die( -1 );
}

Expand Down Expand Up @@ -1966,7 +1966,7 @@ function wp_ajax_wp_link_ajax() {
* @since 3.1.0
*/
function wp_ajax_menu_locations_save() {
if ( ! current_user_can( 'edit_theme_options' ) ) {
if ( ! current_user_can( 'manage_nav_menus' ) ) {
wp_die( -1 );
}

Expand Down Expand Up @@ -2022,7 +2022,7 @@ function wp_ajax_meta_box_order() {
* @since 3.1.0
*/
function wp_ajax_menu_quick_search() {
if ( ! current_user_can( 'edit_theme_options' ) ) {
if ( ! current_user_can( 'manage_nav_menus' ) ) {
wp_die( -1 );
}

Expand Down
21 changes: 15 additions & 6 deletions src/wp-admin/menu.php
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,16 @@

$menu[59] = array( '', 'read', 'separator2', '', 'wp-menu-separator' );

$appearance_capability = current_user_can( 'switch_themes' ) ? 'switch_themes' : 'edit_theme_options';
$themes_capability = current_user_can( 'switch_themes' ) ? 'switch_themes' : 'edit_theme_options';
$appearance_capability = $themes_capability;

if (
! current_user_can( $appearance_capability ) &&
current_user_can( 'manage_nav_menus' ) &&
( current_theme_supports( 'menus' ) || current_theme_supports( 'widgets' ) )
) {
$appearance_capability = 'manage_nav_menus';
}

$menu[60] = array( __( 'Appearance' ), $appearance_capability, 'themes.php', '', 'menu-top menu-icon-appearance', 'menu-appearance', 'dashicons-admin-appearance' );

Expand All @@ -222,7 +231,7 @@
}

/* translators: %s: Number of available theme updates. */
$submenu['themes.php'][5] = array( sprintf( __( 'Themes %s' ), $count ), $appearance_capability, 'themes.php' );
$submenu['themes.php'][5] = array( sprintf( __( 'Themes %s' ), $count ), $themes_capability, 'themes.php' );

if ( wp_is_block_theme() ) {
$submenu['themes.php'][6] = array( _x( 'Editor', 'site editor menu item' ), 'edit_theme_options', 'site-editor.php' );
Expand All @@ -248,20 +257,20 @@
}

if ( current_theme_supports( 'menus' ) || current_theme_supports( 'widgets' ) ) {
$submenu['themes.php'][10] = array( __( 'Menus' ), 'edit_theme_options', 'nav-menus.php' );
$submenu['themes.php'][10] = array( __( 'Menus' ), 'manage_nav_menus', 'nav-menus.php' );
}

if ( current_theme_supports( 'custom-header' ) && current_user_can( 'customize' ) ) {
$customize_header_url = add_query_arg( array( 'autofocus' => array( 'control' => 'header_image' ) ), $customize_url );
$submenu['themes.php'][15] = array( _x( 'Header', 'custom image header' ), $appearance_capability, esc_url( $customize_header_url ), '', 'hide-if-no-customize' );
$submenu['themes.php'][15] = array( _x( 'Header', 'custom image header' ), $themes_capability, esc_url( $customize_header_url ), '', 'hide-if-no-customize' );
}

if ( current_theme_supports( 'custom-background' ) && current_user_can( 'customize' ) ) {
$customize_background_url = add_query_arg( array( 'autofocus' => array( 'control' => 'background_image' ) ), $customize_url );
$submenu['themes.php'][20] = array( _x( 'Background', 'custom background' ), $appearance_capability, esc_url( $customize_background_url ), '', 'hide-if-no-customize' );
$submenu['themes.php'][20] = array( _x( 'Background', 'custom background' ), $themes_capability, esc_url( $customize_background_url ), '', 'hide-if-no-customize' );
}

unset( $customize_url, $appearance_capability );
unset( $customize_url, $appearance_capability, $themes_capability );

// Add 'Theme File Editor' to the bottom of the Appearance (non-block themes) or Tools (block themes) menu.
if ( ! is_multisite() ) {
Expand Down
4 changes: 2 additions & 2 deletions src/wp-admin/nav-menus.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,10 @@
}

// Permissions check.
if ( ! current_user_can( 'edit_theme_options' ) ) {
if ( ! current_user_can( 'manage_nav_menus' ) ) {
wp_die(
'<h1>' . __( 'You need a higher level of permission.' ) . '</h1>' .
'<p>' . __( 'Sorry, you are not allowed to edit theme options on this site.' ) . '</p>',
'<p>' . __( 'Sorry, you are not allowed to manage navigation menus on this site.' ) . '</p>',
403
);
}
Expand Down
12 changes: 4 additions & 8 deletions src/wp-includes/admin-bar.php
Original file line number Diff line number Diff line change
Expand Up @@ -1151,11 +1151,7 @@ function wp_admin_bar_appearance_menu( $wp_admin_bar ) {
);
}

if ( ! current_user_can( 'edit_theme_options' ) ) {
return;
}

if ( current_theme_supports( 'widgets' ) ) {
if ( current_user_can( 'edit_theme_options' ) && current_theme_supports( 'widgets' ) ) {
$wp_admin_bar->add_node(
array(
'parent' => 'appearance',
Expand All @@ -1166,7 +1162,7 @@ function wp_admin_bar_appearance_menu( $wp_admin_bar ) {
);
}

if ( current_theme_supports( 'menus' ) || current_theme_supports( 'widgets' ) ) {
if ( current_user_can( 'manage_nav_menus' ) && ( current_theme_supports( 'menus' ) || current_theme_supports( 'widgets' ) ) ) {
$wp_admin_bar->add_node(
array(
'parent' => 'appearance',
Expand All @@ -1177,7 +1173,7 @@ function wp_admin_bar_appearance_menu( $wp_admin_bar ) {
);
}

if ( current_theme_supports( 'custom-background' ) ) {
if ( current_user_can( 'edit_theme_options' ) && current_theme_supports( 'custom-background' ) ) {
$wp_admin_bar->add_node(
array(
'parent' => 'appearance',
Expand All @@ -1191,7 +1187,7 @@ function wp_admin_bar_appearance_menu( $wp_admin_bar ) {
);
}

if ( current_theme_supports( 'custom-header' ) ) {
if ( current_user_can( 'edit_theme_options' ) && current_theme_supports( 'custom-header' ) ) {
$wp_admin_bar->add_node(
array(
'parent' => 'appearance',
Expand Down
18 changes: 18 additions & 0 deletions src/wp-includes/capabilities.php
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
* `edit_app_password`, `delete_app_passwords`, `delete_app_password`,
* and `update_https` capabilities.
* @since 6.7.0 Added the `edit_block_binding` capability.
* @since 7.1.0 Added the `manage_nav_menus` capability.
*
* @global array $post_type_meta_caps Used to get post type meta capabilities.
*
Expand Down Expand Up @@ -136,6 +137,13 @@ function map_meta_cap( $cap, $user_id, ...$args ) {
break;
}

// Route nav_menu_item edit/delete through manage_nav_menus
// instead of the post type's primitive edit_theme_options caps.
if ( 'nav_menu_item' === $post->post_type ) {
$caps = map_meta_cap( 'manage_nav_menus', $user_id );
break;
}

if ( ! $post_type->map_meta_cap ) {
$caps[] = $post_type->cap->$cap;
// Prior to 3.1 we would re-call map_meta_cap here.
Expand Down Expand Up @@ -239,6 +247,13 @@ function map_meta_cap( $cap, $user_id, ...$args ) {
break;
}

// Route nav_menu_item edit/delete through manage_nav_menus
// instead of the post type's primitive edit_theme_options caps.
if ( 'nav_menu_item' === $post->post_type ) {
$caps = map_meta_cap( 'manage_nav_menus', $user_id );
break;
}

if ( ! $post_type->map_meta_cap ) {
$caps[] = $post_type->cap->$cap;
// Prior to 3.1 we would re-call map_meta_cap here.
Expand Down Expand Up @@ -698,6 +713,9 @@ function map_meta_cap( $cap, $user_id, ...$args ) {
case 'customize':
$caps[] = 'edit_theme_options';
break;
case 'manage_nav_menus':
$caps[] = 'edit_theme_options';
break;
case 'delete_site':
if ( is_multisite() ) {
$caps[] = 'manage_options';
Expand Down
2 changes: 1 addition & 1 deletion src/wp-includes/class-wp-customize-control.php
Original file line number Diff line number Diff line change
Expand Up @@ -636,7 +636,7 @@ protected function render_content() {

echo $dropdown;
?>
<?php if ( $this->allow_addition && current_user_can( 'publish_pages' ) && current_user_can( 'edit_theme_options' ) ) : // Currently tied to menus functionality. ?>
<?php if ( $this->allow_addition && current_user_can( 'publish_pages' ) && current_user_can( 'manage_nav_menus' ) ) : // Currently tied to menus functionality. ?>
<button type="button" class="button-link add-new-toggle">
<?php
/* translators: %s: Add Page label. */
Expand Down
53 changes: 34 additions & 19 deletions src/wp-includes/class-wp-customize-nav-menus.php
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ public function __construct( $manager ) {
add_action( 'customize_save_nav_menus_created_posts', array( $this, 'save_nav_menus_created_posts' ) );

// Skip remaining hooks when the user can't manage nav menus anyway.
if ( ! current_user_can( 'edit_theme_options' ) ) {
if ( ! current_user_can( 'manage_nav_menus' ) ) {
return;
}

Expand Down Expand Up @@ -92,7 +92,7 @@ public function filter_nonces( $nonces ) {
public function ajax_load_available_items() {
check_ajax_referer( 'customize-menus', 'customize-menus-nonce' );

if ( ! current_user_can( 'edit_theme_options' ) ) {
if ( ! current_user_can( 'manage_nav_menus' ) ) {
wp_die( -1 );
}

Expand Down Expand Up @@ -317,7 +317,7 @@ public function load_available_items_query( $object_type = 'post_type', $object_
public function ajax_search_available_items() {
check_ajax_referer( 'customize-menus', 'customize-menus-nonce' );

if ( ! current_user_can( 'edit_theme_options' ) ) {
if ( ! current_user_can( 'manage_nav_menus' ) ) {
wp_die( -1 );
}

Expand Down Expand Up @@ -594,13 +594,15 @@ public function enqueue_scripts() {
public function filter_dynamic_setting_args( $setting_args, $setting_id ) {
if ( preg_match( WP_Customize_Nav_Menu_Setting::ID_PATTERN, $setting_id ) ) {
$setting_args = array(
'type' => WP_Customize_Nav_Menu_Setting::TYPE,
'transport' => 'postMessage',
'type' => WP_Customize_Nav_Menu_Setting::TYPE,
'transport' => 'postMessage',
'capability' => 'manage_nav_menus',
);
} elseif ( preg_match( WP_Customize_Nav_Menu_Item_Setting::ID_PATTERN, $setting_id ) ) {
$setting_args = array(
'type' => WP_Customize_Nav_Menu_Item_Setting::TYPE,
'transport' => 'postMessage',
'type' => WP_Customize_Nav_Menu_Item_Setting::TYPE,
'transport' => 'postMessage',
'capability' => 'manage_nav_menus',
);
}
return $setting_args;
Expand Down Expand Up @@ -681,6 +683,7 @@ public function customize_register() {
'title' => __( 'Menus' ),
'description' => $description,
'priority' => 100,
'capability' => 'manage_nav_menus',
)
)
);
Expand Down Expand Up @@ -709,6 +712,7 @@ public function customize_register() {
'panel' => 'nav_menus',
'priority' => 30,
'description' => $description,
'capability' => 'manage_nav_menus',
)
);

Expand All @@ -735,7 +739,8 @@ public function customize_register() {

$setting = $this->manager->get_setting( $setting_id );
if ( $setting ) {
$setting->transport = 'postMessage';
$setting->transport = 'postMessage';
$setting->capability = 'manage_nav_menus';
remove_filter( "customize_sanitize_{$setting_id}", 'absint' );
add_filter( "customize_sanitize_{$setting_id}", array( $this, 'intval_base10' ) );
} else {
Expand All @@ -747,6 +752,7 @@ public function customize_register() {
'type' => 'theme_mod',
'transport' => 'postMessage',
'default' => 0,
'capability' => 'manage_nav_menus',
)
);
}
Expand Down Expand Up @@ -786,9 +792,10 @@ public function customize_register() {
$this->manager,
$section_id,
array(
'title' => html_entity_decode( $menu->name, ENT_QUOTES, get_bloginfo( 'charset' ) ),
'priority' => 10,
'panel' => 'nav_menus',
'title' => html_entity_decode( $menu->name, ENT_QUOTES, get_bloginfo( 'charset' ) ),
'priority' => 10,
'panel' => 'nav_menus',
'capability' => 'manage_nav_menus',
)
)
);
Expand All @@ -799,7 +806,8 @@ public function customize_register() {
$this->manager,
$nav_menu_setting_id,
array(
'transport' => 'postMessage',
'transport' => 'postMessage',
'capability' => 'manage_nav_menus',
)
)
);
Expand All @@ -823,8 +831,9 @@ public function customize_register() {
$this->manager,
$menu_item_setting_id,
array(
'value' => $value,
'transport' => 'postMessage',
'value' => $value,
'transport' => 'postMessage',
'capability' => 'manage_nav_menus',
)
)
);
Expand All @@ -850,10 +859,11 @@ public function customize_register() {
$this->manager->add_section(
'add_menu',
array(
'type' => 'new_menu',
'title' => __( 'New Menu' ),
'panel' => 'nav_menus',
'priority' => 20,
'type' => 'new_menu',
'title' => __( 'New Menu' ),
'panel' => 'nav_menus',
'priority' => 20,
'capability' => 'manage_nav_menus',
)
);

Expand All @@ -866,6 +876,7 @@ public function customize_register() {
'type' => 'option', // To prevent theme prefix in changeset.
'default' => array(),
'sanitize_callback' => array( $this, 'sanitize_nav_menus_created_posts' ),
'capability' => 'manage_nav_menus',
)
)
);
Expand Down Expand Up @@ -1005,6 +1016,10 @@ public function ajax_insert_auto_draft_post() {
wp_send_json_error( 'customize_not_allowed', 403 );
}

if ( ! current_user_can( 'manage_nav_menus' ) ) {
wp_send_json_error( 'cannot_manage_nav_menus', 403 );
}

if ( empty( $_POST['params'] ) || ! is_array( $_POST['params'] ) ) {
wp_send_json_error( 'missing_params', 400 );
}
Expand Down Expand Up @@ -1328,7 +1343,7 @@ public function customize_dynamic_partial_args( $partial_args, $partial_id ) {
'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',
'capability' => 'manage_nav_menus',
)
);
}
Expand Down
Loading
Loading