How to block WordPress admin menu item

Remove Admin Menu Item

Remove Admin Menu Item

Suppose you don’t wish your blog registered users see some menu items in WordPress admin back-end and it is not the user role capabilities management subject. That is no such capability exists which you can use. For example, if you need to block just user profile editor and nothing more. It can be useful if you wish to allow for the group of volunteers to use the only user budget for all of them to make some task at your blog. In this case it is important that no one from that users group can edit user password and other user profile details. So you should to block WordPress admin menu items and URLs related to the user profile editor execution.
I will show you how to make it in this post. We just add a little piece of code to your theme functions.php file. Let’s go.

Open your blog current theme functions.php file. And put into begin of it following code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
// block profile menu for users with role subscriber
if ( is_user_logged_in() ) {
  if (current_user_can('subscriber')) {
    function remove_profile_submenu() {
      global $submenu;
      //remove Your profile submenu item
      unset($submenu['profile.php'][5]);
    }
    add_action('admin_head', 'remove_profile_submenu');
 
    function remove_profile_menu() {
      global $menu;
// remove Profile top level menu
      unset($menu[70]);
    }
    add_action('admin_head', 'remove_profile_menu');
 
 
    function profile_redirect() {
      $result = stripos($_SERVER['REQUEST_URI'], 'profile.php');
      if ($result!==false) {
        wp_redirect(get_option('siteurl') . '/wp-admin/index.php');
      }
    }
 
    add_action('admin_menu', 'profile_redirect');
  }
}
// end of block profile menu for users with role

That’s it. This code snippet blocks user profile editor for all users with subscriber role. I use subscriber role just for example. It can be any another role including your own custom made one. To create your own user role and fill it with capabilities as you and only you wish, use User Role Editor plugin.
Let’s look inside the code.
1st, at line 3 we check what role current logged-in user has:

3
if (current_user_can('subscriber')) {

To check another role than subscriber one, change role name to that you wish inside the single quotes at line 3.
Then lines 4-8 removes ‘Your profile’ submenu item. Pay attention on line 7:

7
 unset($submenu['profile.php'][5]);

How to discover what element of $submenu array to unset? Open wp-admin/menu.php file. Search menu title you wish to block. Search around for $submenu array element declaration. I miss Fortune love you :), you will find needed data. If you can not find it ask your question here, I will try to help.
Lines 11-15 removes ‘Profile’ top level menu. Look at the line 14:

14
  unset($menu[70]);

In case you wish to block top level menu item you should unset correspondent element of $menu array. Use the same wp-admin/menu.php file for your reference at the 1st step.

Is it enough and can we finish here? No. We just hide menu items from user. But he/she still can call wp-admin/profile.php directly from the browser. At lines 22-29 we redirect user to admin back-end dashboard if he/she tries to call profile.php script.

To block another menu item than “Profile” look into wp-admin/menu.php file from WordPress core and select one you like more :).
“WordPress admin menu permissions” post describes WordPress administrator menu structure including user capability, $menu/$submenu arrays indexes and names of calling PHP scripts for every menu item. Use it for your reference if you are not comfortable with PHP source code reading.
The code I wrote above is tested against WordPress 2.9.2.

Thanks to Clay for general idea and useful post Remove WordPress Admin Menu Without Affecting WordPress Core System which was written directly on discussed subject.

Tags: , ,

  • roland

    tried it got: Fatal error: Call to undefined function is_user_logged_in()

  • Check your WordPress version. It is possible that this function did not exist in the earlier versions of WordPress. This code definitely work with WordPress 2.9.2. I test it with that version only.
    It could depend of the place where you put the code you test also.
    is_user_logged_in() is the small function and lives at wp-include/pluggable.php


    if ( !function_exists('is_user_logged_in') ) :
    /**
    * Checks if the current visitor is a logged in user.
    *
    * @since 2.0.0
    *
    * @return bool True if user is logged in, false if not logged in.
    */
    function is_user_logged_in() {
    $user = wp_get_current_user();

    if ( $user->id == 0 )
    return false;

    return true;
    }
    endif;

    It is available from theme functions.php file. I checked it again just now :). If you tries to call it from the plugin and it is not available just include pluggable.php file into your code with require_once directive or place the code above there in order to get it.

  • Matt

    Hi,

    Thanks for the code, very useful. I already had the menus removed from views but I took this part to block access:

    function profile_redirect() {
    $result = stripos($_SERVER['REQUEST_URI'], 'profile.php');
    if ($result!==false) {
    wp_redirect(get_option('siteurl') . '/wp-admin/index.php');
    }
    }

    add_action('admin_menu', 'profile_redirect');

    My question is, is it possible to redirect multiple items e.g. my-sites.php, upload.php, themes.php? If so what is the easiest way to do this?

    Thanks again!

  • Hi,
    try this modified version:

    function profile_redirect() {
    $result = false;
    $linksToBlock = array('profile.php', 'my-sites.php', 'upload.php','themes.php');
    foreach ($linksToBlock as $key=>$value) {
    $result = stripos($_SERVER['REQUEST_URI'], $value);
    if ($result!==false) {
    break;
    }

    }
    if ($result!==false) {
    wp_redirect(get_option('siteurl') . '/wp-admin/index.php');
    }
    }
    I did not test this modification, please let me know the result.

  • Matt

    Hi Vladimir,

    Thanks very much. I used the following code:

    function profile_redirect() {
    $result = false;
    $linksToBlock = array('profile.php', 'my-sites.php', 'upload.php', 'themes.php');
    foreach ($linksToBlock as $key=>$value) {
    $result = stripos($_SERVER['REQUEST_URI'], $value);
    if ($result!==false) {
    break;
    }

    }
    if ($result!==false) {
    wp_redirect(get_option('siteurl') . '/wp-admin/index.php');
    }
    }

    add_action('admin_menu', 'profile_redirect');

    Strangely, it seems to block all of the php files succesfully apart from upload.php. Any ideas?

    Many thanks.

  • You are right, Matt. It is really strange. I checked how code works with PHP debugger for 'upload.php' and see that code goes through wp_redirect(), but redirection doesn't occur for unknown reason. The subject needs additional investigation. I will return with an idea if I have something…

  • There's an easier way to block top level menus without requesting URI. This is what I'm using:
    <?php
    function remove_menus () {
    global $menu;
    global $current_user;
    get_currentuserinfo();
    if ($current_user->user_level < 3){
    $restricted = array(__('Tools'),__('Contact'),__('Comments'));
    end ($menu);
    while (prev($menu)){
    $value = explode(' ',$menu[key($menu)][0]);
    if(in_array($value[0] != NULL?$value[0]:”” , $restricted)){unset($menu[key($menu)]);}
    }
    }
    }
    add_action('admin_menu', 'remove_menus');?>

  • Gunu

    The above code “// block profile menu for users with role subscriber” works perfect in WP 3

    Many Thanks, also for the “Use Role Editor” plugin!

  • Gunu

    This is nice and easier for more menu-items but…… The Profile’ top level menu still working and we still can call wp-admin/tools.php (etc.) directly from the browser.

  • Chris

    This worked great for me. I was using the Hide Dashboard plugin to keep users out of the backend but it was still allowing the profile editor to be visible. So, I put your function together with the Hide Dashboard plugin. Then I changed line 6 to
    if ($role != ‘administrator’) {
    Now, only admins can see the backend. Perfect solution for what I was trying to accomplish. Thanks!!

  • Pingback: Custom User Roles and WordPress Core Code Compatibility Issues | ShinePHP.com()

  • Richard

    @ Vladimir Garagulya

    Nice code, but for the custom post type ‘review’, blocking post_new (for standard posts) will also block
    post_new.php?post_type=review

  • Richard

    This works for everything except edit.php

    function menu_redirect() { // Redirect links. Thanks to Vladimir Garagulya at http://www.shinephp.com/how-to-block-wordpress-admin-menu-item/

    $result = false;
    $linksToAllow = array(‘edit.php?post_type=review’, ‘post-new.php?post_type=review’); // Links to allow
    foreach ($linksToAllow as $key=>$value) {
    $result = stripos($_SERVER[‘REQUEST_URI’], $value);
    if ($result!==false) {
    $result = ‘blah’;
    break;
    }
    }

    if ($result!==blah) {
    $linksToBlock = array(‘edit.php’, ‘post-new.php’, ‘tools.php’, ‘profile.php’, ‘edit-comments.php’); // Links to block
    foreach ($linksToBlock as $key=>$value) {
    $result = stripos($_SERVER[‘REQUEST_URI’], $value);
    if ($result!==false) {
    $result = ‘something’;
    break;
    }
    }
    }

    if ($result==something) {
    wp_redirect(get_option(‘siteurl’) . ‘/wp-admin/index.php’);
    }

    }

    add_action(‘admin_menu’, ‘menu_redirect’);

  • Thanks, Richard, for the enhanced code. I just added missed single quotes to the

    if ($result!==’blah’) {

    line.
    I have knew about problem with some URL parameters processing if we block the whole script as ‘edit.php’. You showed the very simple and effective way to resolve that. Thanks again.

  • At wp-content/themes/ open your blog theme folder, find ‘functions.php’ file. You need to add code there.

  • If you look at a line #204 of wp-admin/menu.php file you will see

    $submenu['profile.php'][5] = array(__('Your Profile'), 'read', 'profile.php');

    So try to list array $submenu[‘profile.php’], see its content.
    In your code you can check $submenu[‘profile.php’][i][0] for the menu ‘title’ and then decide to block this menu item or not.

  • Pingback: wp-popular.com » Blog Archive » How to block WordPress admin menu item | ShinePHP.com()

  • i ned to block a submenu of a menu like
    i need the users to view invoice>new
    but not invoice>settings
    how would i do this
    please help me out here
    thanks

  • Please give me more details. About what menu do you write? Is it menu of the WordPress plugins or something else?

  • Pingback: richarduk on "Custom post type only works when role has edit_posts capability" | w3 experts()

  • Kostas R

    I used this code to disable the Profile for Contributors!!! THANKS A MILLION!

  • Ninguno_19

    is a good hook but the user continius enter if he knows the specific url like, http://www.mywordpresspage.com/wp-admin/options-general.php
    🙁

  • Please read this thread http://www.shinephp.com/how-to-block-wordpress-admin-menu-item/#comment-60642073

    I think if you add your link (http://www.mywordpresspage.com/wp-admin/options-general.php) to the blocked links list it will work as expected.

  • Ruggero Rossi

    In wp 3.1.3 you have to change these lines:
    $userRole = ($current_user->data->wp_capabilities);
    $role = key($userRole);
    unset($userRole);
    if ($role==’subscriber’) {

    with:

    if(user_can($current_user, ‘subscriber’)) {

  • Agree. Thanks, Ruggero for the code enhancement.

  • Eric

    What is if you want to only block a submenu and not the whole section?  Say the “Themes” sub menu from “Appearance”?

  • You should unset
    $submenu['themes.php'][5] and
    block access to the themes.php file.

  • Eric

    Thanks, I’ll give that a try!

  • Great I was looking for the way to redirect non admins back to home page and I have found it now.

  • Joseph Lee

    Works great! Many thanks.