53

I've got the following code, which cleans up a lot of stuff that is not going to be used within the admin area:

add_action( 'admin_menu', 'my_remove_menu_pages' );

function my_remove_menu_pages() {
  remove_menu_page( 'edit.php' );                   //Posts
  remove_menu_page( 'upload.php' );                 //Media
  remove_menu_page( 'edit-comments.php' );          //Comments
  remove_menu_page( 'themes.php' );                 //Appearance
  remove_menu_page( 'users.php' );                  //Users
  remove_menu_page( 'tools.php' );                  //Tools
  remove_menu_page( 'options-general.php' );        //Settings

};

However, there are two menu items that have been inserted from plugins.

When I hover over each menu item, it says the links are:

/wp-admin/edit.php?post_type=acf
/wp-admin/admin.php?page=wpcf7

Is there a way to hide these menu pages, too?

3
  • May be Stupid to ask, but why hack the admin menu, when you could deactivate the plugins in question?
    – eyoung100
    Commented May 23, 2014 at 21:27
  • 6
    @eyoung100 There are several reasons. The most apparent one would be to hide certain functionality from specific user( role)s. Also one might want to restructure the admin menu, and thus need to remove (and add back again) certain menu entries.
    – tfrommen
    Commented Oct 23, 2014 at 17:16
  • If you would use a solution via coding, a plugin is a helper in context, like the plugin 'Adminimize'. The plugin list also the slugs there are necessary to remove via custom code if the settings of the plugin is not your requirement.
    – bueltge
    Commented May 22, 2019 at 7:22

7 Answers 7

90

You need to use the right hooks (which are not always the same as the URLs/slugs), and it doesn't hurt to use a hook that runs later (e.g., admin_init):

add_action( 'admin_init', 'wpse_136058_remove_menu_pages' );

function wpse_136058_remove_menu_pages() {

    remove_menu_page( 'edit.php?post_type=acf' );
    remove_menu_page( 'wpcf7' );
}

You can use the following to debug:

add_action( 'admin_init', 'wpse_136058_debug_admin_menu' );

function wpse_136058_debug_admin_menu() {

    echo '<pre>' . print_r( $GLOBALS[ 'menu' ], TRUE) . '</pre>';
}

This gives (for my setup) the following for the Contact Form 7 plugin menu page:

[27] => Array
        (
            [0] => Formular
            [1] => wpcf7_read_contact_forms
            [2] => wpcf7
            [3] => Contact Form 7
            [4] => menu-top menu-icon-generic toplevel_page_wpcf7 menu-top-last
            [5] => toplevel_page_wpcf7
            [6] => none
        )

The array element with key 2 is what you are looking for: wpcf7.

3
  • 7
    Showing how to dump the menu and find what to use for remove_menu_page() was a huge help -- taught me how to fish instead of just handing me the fish! Commented Jun 20, 2016 at 19:34
  • For acf there is a better approach see the docs Commented Feb 12, 2017 at 10:55
  • The debug code is of great help. Thanks a ton for sharing!
    – Devner
    Commented Jul 14, 2019 at 17:14
26
    // PLUGINS THAT ADD AS DASHBOARD SUBMENU
    // IF THIS IS THE URL BELOW - THE PAGE VARIABLE IS WHAT I NEED ( SO WHATEVER COMES AFTER PAGE= )
    // http://example.com/wp-admin/index.php?page=iconize-plugin-update-notifier
    remove_submenu_page( 'index.php', 'iconize-plugin-update-notifier' );

    // OR FOR EXAMPLE WOOCOMMERCE DASHBOARD SUBMENU
    remove_submenu_page( 'index.php', 'wc-about' ); //WOO
    remove_submenu_page( 'index.php', 'wc-credits' ); //WOO
    remove_submenu_page( 'index.php', 'wc-translators' ); //WOO

    // CUSTOM POST TYPE TOP LEVELS
    remove_menu_page( 'edit.php?post_type={$POST_TYPE}' ); //LOOK FOR WHAT COMES AFTER POST TYPE IN THE URL
    remove_menu_page( 'edit.php?post_type=testimonials-widget' ); //TESTIMONIALS WIDGET
    remove_menu_page( 'edit.php?post_type=product' ); //WOOCOMMERCE

    // CUSTOM POST TYPE SUBMENU
     remove_submenu_page( 'edit.php?post_type={$POST_TYPE}', '{$SUBMENU_URL_VARIABLE}' ); //EXAMPLE FORMAT
     // SO IF BELOW IS THE URL
     // http://example.com/wp-admin/edit.php?post_type=testimonials-widget&page=testimonialswidget_settings
     // YOU NEED TO SEE WHATS AFTER PAGE
     remove_submenu_page( 'edit.php?post_type=testimonials-widget', 'testimonialswidget_settings' ); //TESTIMONIALS WIDGET

    // OTHER EXAMPLES
    remove_menu_page( 'revslider' ); // REVSLIDER
    remove_menu_page( 'woocommerce' ); // WOOCOMMERCE
    remove_menu_page( 'order-post-types-shop_order' ); // WOOCOMMERCE
    remove_menu_page( 'order-post-types-shop_coupons' ); // WOOCOMMERCE
    remove_menu_page( 'shortcodes-ultimate' ); // SHORTCODES ULTIMATE
    remove_menu_page( 'wp-admin-microblog/wp-admin-microblog.php' ); // ADMIN MICROBLOG
    remove_menu_page( 'snippets' ); //CODE SNIPPETS
    remove_menu_page( 'gf_edit_forms' ); // GRAVITY FORMS
        remove_submenu_page( 'gf_edit_forms', 'gf_settings' ); // GRAVITY FORMS
        remove_submenu_page( 'gf_edit_forms', 'gf_export' ); // GRAVITY FORMS
        remove_submenu_page( 'gf_edit_forms', 'gf_update' ); // GRAVITY FORMS
        remove_submenu_page( 'gf_edit_forms', 'gf_addons' ); // GRAVITY FORMS
        remove_submenu_page( 'gf_edit_forms', 'gf_help' ); // GRAVITY FORMS

        remove_submenu_page( 'cleverness-to-do-list', 'cleverness-to-do-list-settings' ); //Cleverness TODO

YOU CAN DEBUG ALL THIS WITH THE FOLLOWING TO GET ALL THE INFO YOU NEED:

if (!function_exists('debug_admin_menus')):
function debug_admin_menus() {
if ( !is_admin())
        return;
    global $submenu, $menu, $pagenow;
    if ( current_user_can('manage_options') ) { // ONLY DO THIS FOR ADMIN
        if( $pagenow == 'index.php' ) {  // PRINTS ON DASHBOARD
            echo '<pre>'; print_r( $menu ); echo '</pre>'; // TOP LEVEL MENUS
            echo '<pre>'; print_r( $submenu ); echo '</pre>'; // SUBMENUS
        }
    }
}
add_action( 'admin_notices', 'debug_admin_menus' );
endif;

The keys will give you the array values that allow you do all of this with wordpress globals (although not recommended)

function remove_submenus_all_please() {
if ( !is_admin())
        return;
  global $submenu;
    unset($submenu['index.php'][10]); // Removes Updates
  //Posts menu
 // unset($submenu['edit.php'][5]); // Leads to listing of available posts to edit
 // unset($submenu['edit.php'][10]); // Add new post
 // unset($submenu['edit.php'][15]); // Remove categories
 // unset($submenu['edit.php'][16]); // Removes Post Tags
}
add_action('admin_menu', 'remove_submenus_all_please', 999);

And to remove for certain users just do the same thing except with capabilities added:

function remove_by_caps_admin_menu() {
if ( !is_admin())
        return;
    if ( !current_user_can('manage_options') ) {
        remove_menu_page( 'revslider' ); // REVSLIDER
    } elseif ( !current_user_can('edit_posts') ) {
        remove_menu_page( 'woocommerce' ); // WOO
    } else {
    }
}
add_action('admin_menu', 'remove_by_caps_admin_menu', 999);

AND TO TIE IT ALL TOGETHER WHY NOT SHORTEN OUR CODE? YOU CAN USE ARRAYS TO AVOID WRITING remove_submenu_page 50 times. This also works with the toolbar nodes:

if ( !function_exists( 'remove_admin_menupages_in_array' ) ) {
function remove_admin_menupages_in_array() {
    if ( !is_admin())
        return;
          $admin_menus = array(
                                'revslider',
                                'woocommerce',
                                'shortcodes-ultimate',
          );

    foreach ( $admin_menus as $menu_page ) {
        if ( !current_user_can('manage_options') ) {
            remove_menu_page( $menu_page );
        }
    } // foreach
 } // function
add_action('admin_menu', 'remove_admin_menupages_in_array', 9999);
} // exists
20

You probably need to set the add_action priority to a higher number and target those two new links specifically like so:

add_action( 'admin_menu', 'my_remove_menu_pages', 999 );

function my_remove_menu_pages() {
  remove_menu_page( 'edit.php' );                   //Posts
  remove_menu_page( 'upload.php' );                 //Media
  remove_menu_page( 'edit-comments.php' );          //Comments
  remove_menu_page( 'themes.php' );                 //Appearance
  remove_menu_page( 'users.php' );                  //Users
  remove_menu_page( 'tools.php' );                  //Tools
  remove_menu_page( 'options-general.php' );        //Settings
  remove_menu_page( 'edit.php?post_type=acf' );
  remove_menu_page( 'wpcf7' );
};

Advanced Custom Fields also provides a help document on how to do this for their menu here:

http://www.advancedcustomfields.com/resources/how-to/how-to-hide-acf-menu-from-clients/

Contact Form 7 also has it's own way of restricting the visibility of the menu:

http://contactform7.com/restricting-access-to-the-administration-panel/

1
  • hiding contactform7 worked for me by using remove_menu_page( 'wpcf7' ); Commented Jun 8, 2016 at 8:29
10

Update

I created a code snippet with a more robust function that deals with both main menus and sub-menu items.

Original answer

Instead of specifying the menus you want to remove, specify the menues you want to keep :)

add_action('admin_init', 'nwcm_admin_init');

function nwcm_admin_init()
{   
    // Remove unnecessary menus 
    $menus_to_stay = array(
        // Client manager
        'nwcm',

        // Dashboard
        'index.php',

        // Users
        'users.php'
    );      
    foreach ($GLOBALS['menu'] as $key => $value) {          
        if (!in_array($value[2], $menus_to_stay)) remove_menu_page($value[2]);
    }   

} 

This way you don't have to search for plugin names and modify the code when you add new plugins..

1
  • 1
    Exactly what I was looking for! Also your Code snippet seems like a great one! Thanks a ton for adding your solution. Appreciate it!
    – Devner
    Commented Jul 14, 2019 at 16:45
5

Of course you can specify only the items you want to remove. Have a look in the code below:

/wordpress/wp-content/plugins/your_plugin/your_plugin.php :


add_action('admin_init', 'nwcm_admin_init');

function nwcm_admin_init()
{   
// Remove unnecessary menus 
$menus_to_remove = array(
    // menu items you want to remove
    'menu_item_1',
    'menu_item_2',
    .
    .
    'menu_item_n'
);     

// To avoid warning message, check whether 'menu' is set AND is an array
if(isset($GLOBALS['menu']) && is_array($GLOBALS['menu'])) {
   foreach ($GLOBALS['menu'] as $key => $value) {  
     //Remove the '!' in the 'if' condition.        
     if (in_array($value[2], $menus_to_remove)) remove_menu_page($value[2]);
   }
}   

} 

This is just the negative of numediaweb's method. Thanks @numediaweb. It works fine.

P.S.: 'menu_item_1/n' -> point mouse over the menu item and fetch the exact page of that menu item shown in the link.

5

You need to find the right $menu_slug. The following code worked for me:

add_action( 'admin_init', 'remove_menus' );
function remove_menus(){
  remove_menu_page( 'wpcf7' );
}
0

use this code snippet

function your_custom_name() {    
    remove_menu_page('vc-general'); //the slug as seen wp-admin.php?page=vc-general  
}    
add_action( 'admin_init', 'your_custom_name' );
1
  • Please edit your answer, and add an explanation: why could that solve the problem?
    – fuxia
    Commented Feb 14, 2018 at 17:10

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