Spotlight: Wordpress Admin Menu - Remove "Add New" pages or posts link

Back in June I posted about tidying up the WordPress admin dashboard. Recently I got a comment on that article asking if the admin menu could be altered for different users in a similar way.

Here's the question:

Can I lose the “add new” under Pages drop down for editors? I don’t want them to have the ability to create new pages.

I've played with the Wordpress admin menu a bit before now. There are two global variables which allow you to add (although there are much better ways to do this) and more importantly remove items from the WordPress menu. These variables are $menu for top-level menu groups like "Posts", "Media" and $submenu for managing the sub-level items like "Add New" or "Library".

WordPress Pages MenusIn this case, we only want to remove the "Add New" sub-menu item from the pages menu, so we only need to use $submenu. If you use var_dump or print_r to display the contents of $submenu you'll see the part of the array for the "Pages" menu looks like the snippet below. It contains two entries: one for the "Pages" listing which allows you to edit pages, and one for the "Add New" link that we want to remove. Also note: for each sub-menu item there are three pieces of information: The text to show, the capability the user must have to see this link, and the relative URL for the menu item.

*Please note: all of the following will also work for posts. You will need to substitute the word "page(s)" for "post(s)" and follow the additional instructions. For other parts of the WordPress admin you'll need to find the right URLs, sub menu items and capabilities. All code should be placed in your theme's functions.php file. Full code example is here: functions.php [ZIP File]

// $submenu array...
 'edit.php?post_type=page' => 
    array
      5 => 
        array
          0 => string 'Pages' (length=5)
          1 => string 'edit_pages' (length=10)
          2 => string 'edit.php?post_type=page' (length=23)
      10 => 
        array
          0 => string 'Add New' (length=7)
          1 => string 'publish_pages' (length=13)
          2 => string 'post-new.php?post_type=page' (length=27)

With all this in mind, the simplest way to remove the "Add New" link from the pages menu, is to unset this part of the array before the menu is drawn. We can create a function to do this in the functions.php file, first declaring the $submenu global variable and then unsetting the bit that we don't want. Finally we need to add our function to the admin_menu action hook so that it is called at the right time.

// functions.php
function modify_menu()
{
  global $submenu;
  unset($submenu['edit.php?post_type=page'][10]);

  // for posts it should be: 
  // unset($submenu['edit.php'][10]);
}
// call the function to modify the menu when the admin menu is drawn
add_action('admin_menu','modify_menu');

At first glance we've now achieved what we set out to do - the "Add New" link is removed from the menu, however this doesn't really solve the underlying problem. The url for adding a new page is post-new.php?post_type=page and because we haven't changed the permissions of an editor they can still access the page. Furthermore, there is also an "Add New" link at the top of "Pages" list page - so they can also still find the page easily.

So what we really need to do, is change the capabilities of the "editor" role. In WordPress each role has a set of "capabilities" or permissions - things they are allowed to do. The capability that allows someone with the "editor" role to access the Add New Page screen is "edit_page", however if we remove this capability we will lose the whole "Pages" menu and also stop them being able to edit pages.

There is no way to use capabilities to restrict access to the Add New Page screen without also restricting access to the Pages list & Edit page screen. However, we can stop people from being able to publish pages using the "publish_pages" capability - this means they can create pages but they won't appear on the website. Although this isn't a perfect solution, it seems like a good start.

// functions.php
function modify_capabilities()
{
  // get the role you want to change: editor, author, contributor, subscriber
  $editor_role = get_role('editor');
  $editor_role->remove_cap('publish_pages');
  
  // for posts it should be:
  // $editor_role->remove_cap('publish_posts');
  
  // to add capabilities use add_cap()
}

add_action('admin_init','modify_capabilities');

The above snippet shows a function which gets the "editor" role and removes the "publish_pages" capability. This is hooked into "admin_init" so that it is run on each admin page. Now when editors go to the Add New Page screen they will only be able to "Submit for review" not publish the page. So now we know how to both actually stop users from creating pages AND remove the sub-menu item.

Now that we're working with capabilities, we can change our modify_menu function to do the same. Instead of completely unsetting the menu item, we can set the capability so that it only works if the user has the capability "publish_pages". This is just a slightly nicer way to hide the menu item - you could grant one specific editor user the "publish_pages" capability and they would still be able to access the menu item.

// functions.php
function modify_menu()
{
  global $submenu;
  $submenu['edit.php?post_type=page'][10][1] = 'publish_pages';

  // for posts it should be:
  // $submenu['edit.php'][10][1] = 'publish_posts';
}
add_action('admin_menu','modify_menu');

Next let's get rid of that pesky "Add New" button on the Pages list screen. There doesn't seem to be a hook we can use to do this, so instead I've used good ol' fashioned CSS. We check if we are on the "edit-page" screen using the $current_screen global variable and if the user has the "publish_pages" capability using the current_user_can method. Then we spit out some CSS to hide the button and hook this into admin_head to the CSS is output in a sensible place.

// functions.php
function hide_buttons()
{
  global $current_screen;
  
  if($current_screen->id == 'edit-page' && !current_user_can('publish_pages'))
  {
    echo '<style>.add-new-h2{display: none;}</style>';  
  }
  
  // for posts the if statement would be:
  // if($current_screen->id == 'edit-post' && !current_user_can('publish_posts'))
}
add_action('admin_head','hide_buttons');

Now we have editors which cannot see the "Add New" link in the Pages menu, or the button on the Pages screen, so there's no easy way for them to get there. Even if they are clever enough to figure out the URL they won't actually be able to publish their pages. However if we want to go the whole hog, we can add a bit more code to redirect them from the Add New Page screen and show them an error message.

// functions.php
function permissions_admin_redirect() {
  $result = stripos($_SERVER['REQUEST_URI'], 'post-new.php?post_type=page');
  
  // for posts result should be:  
  // $result = stripos($_SERVER['REQUEST_URI'], 'post-new.php');
  
  if ($result!==false && !current_user_can('publish_pages')) {
    wp_redirect(get_option('siteurl') . '/wp-admin/index.php?permissions_error=true');
  }
  
  // for posts the if statement should be:
  // if ($result!==false && !current_user_can('publish_posts')) {
}

add_action('admin_menu','permissions_admin_redirect');

The above is an additional function to test the current request URI. If it matches the Add New Page screen AND the user doesn't have the "publish_page" capability we redirect them to the admin dashboard. The dashboard URL is /wp-admin/index.php, but I've added permissions_error=true so that WordPress will know to show an error message.

// functions.php
function permissions_admin_notice()
{
  // use the class "error" for red notices, and "update" for yellow notices
  echo "<div id='permissions-warning' class='error fade'><p><strong>".__('You do not have permission to access that page.')."</strong></p></div>";
}

function permissions_show_notice()
{
  if($_GET['permissions_error'])
  {
    add_action('admin_notices', 'permissions_admin_notice');  
  }
}
add_action('admin_init','permissions_show_notice');

Finally, two more functions and one more action hook. The first to draw an error message / warning to the user, and the second which checks the "permissions_error" parameter and shows the error message if it is set. Now there is absolutely no way for an editor to get to the Add New Page screen, instead they will be redirected to the dashboard and shown an error.

So this all turned out to be ever-so-slightly more complicated that I expected because there is no way to distinguish between the permission to edit and the permission to add a page or post. However, like most things in WordPress with a bit of graft it's usually possible! I hope this has been useful, if you got lost or something doesn't make sense or you know of a better way to do this please let me know via the comments.

Code Example: All code should go into your theme's functions.php file. You can download the complete code sample with comments right here: functions.php [ZIP File]

Resources