I came across the need to have a site Editor to edit menus. I found some answers that suggest the add_cap() approach, to add the edit_theme_options capability to Editor role.

This should be done once and then removed from functions.php:

// Do this only once. Can go anywhere inside your functions.php file
$role_object = get_role( 'editor' );
$role_object->add_cap( 'edit_theme_options' );

The same answer shows a way to hide unwanted Appearance sub-menus. But it also hides those sub-menus to Administrator role.

My question is: is this a right way to solve that problem and show the sub-menus to Admin but hide them to Editor role?

// Show Appearance sub-menus only to users with 'manage_options' capability

function hide_menu() {
    if ( ! current_user_can( 'manage_options' ) ) {
        remove_submenu_page( 'themes.php', 'themes.php' ); // hide the theme selection submenu
        remove_submenu_page( 'themes.php', 'widgets.php' ); // hide the widgets submenu
        remove_submenu_page( 'themes.php', 'customize.php?return=%2Fwp-admin%2Ftools.php' ); // hide the customizer submenu
        remove_submenu_page( 'themes.php', 'customize.php?return=%2Fwp-admin%2Ftools.php&autofocus%5Bcontrol%5D=background_image' ); // hide the background submenu

        // these are theme-specific. Can have other names or simply not exist in your current theme.
        remove_submenu_page( 'themes.php', 'custom-header' );
        remove_submenu_page( 'themes.php', 'custom-background' );

add_action('admin_head', 'hide_menu');

1 Answer 1


Recently I had to tackle the same issue. Instead of setting the capability permanently for editors, I used user_has_cap filter to allow access dynamically.

add_filter('user_has_cap', 'editor_allow_edit_menu', 10, 4);
function editor_allow_edit_menu($allcaps, $caps, $args, $user) {

  if ( ! isset( $allcaps['editor'] ) || true !== $allcaps['editor'] ) {
    return $allcaps;

  global $pagenow;
  // new items are added to the menu with ajax
  // you could perhaps also check here that the ajax action is 'add-menu_item' from $_POST
  if ( wp_doing_ajax() || 'nav-menus.php' === $pagenow ) {
    $allcaps['edit_theme_options'] = true;

  return $allcaps;

The above code allows the user to access the menu editing page and add new items to menu, which happens by admin-ajax action. This however doesn't display a link to the editing page. For that I added a custom link to the admin menu.

add_action( 'admin_menu', 'add_nav_menus_link_for_editor' );
function add_nav_menus_link_for_editor() {
  if ( ! current_user_can('editor') ) {
  // Custom link to the nav menus page
    '?options=nav-menus.php', // I didn't get 'nav-menus.php' working directly here and didn't bother figuring out why
  // remove themes menu page, would be visible otherwise when user is on menu editing page and has the edit_theme_options capability

As I didn't get nav-menus.php working when used directly on add_menu_page() as the page slug, I added quick and dirty redirect switcheroo to direct the user to the menu editing page when one clicks the custom menu link.

add_action('admin_init', 'redirect_to_nav_menu_page');
function redirect_to_nav_menu_page() {
  if ( current_user_can('editor') && isset($_GET['options']) && 'nav-menus.php' === $_GET['options'] ) {
    wp_redirect( admin_url( 'nav-menus.php' ) );

I think this way access is more limited as the capability is only set when using one specific admin page. Trying to directly access any other settings page will result in capabilities error notification.

This is simplified version of the code I used. Originally I had a fancy loop that allowed similar access for editors to few other settings pages, too, based on one config array.

  • I like the this approach. Have to test it. Thanks! (Sorry for the delay commenting here.)
    – alvarogois
    Sep 7, 2020 at 10:32

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.