Changing the Order of Admin Menu Sections?

I am getting a bit frustrated over here after having spent a few hours trying to accomplish this fairly simple task without any luck.

Essentially I have 5 custom post types which I created and all I want to do is show each of them in a specific order directly under the “dashboard”.

Read More

From the WordPress documentation it seems that you can’t really do this because the highest menu order seems to be “5”. And above
L

I am guessing some expert reading this can show me the simple way that I can order the admin menu exactly the way I want to by utilizing the functions file and without utilizing a plugin (which I know exists).

Please go ahead and try to create 5 separate post types and include them in a specific order directly under the dashboard… it seems this is not possible.??… is there some type of jquery hack to make this work that someone could share with me or preferably without utilizing jQuery?

Related posts

Leave a Reply

6 comments

  1. Hi @BinaryBit:

    It’s no wonder you are a bit frustrated; the admin menu is one of the most obtuse and frustrating implementations through WordPress core. Honestly, I don’t know what they were thinking when they designed it that way.

    @EAMann did an excellent job of explaining how the admin menus work in WordPress (I wish I had been able to read that about 4 months ago… 🙂

    Still, after I figured it out how it worked I was still at a loss to work with it without devoting enough time to keep my head straight while I tried to do simple things. So that’s why I built a Menu API that simplifies and streamlines working with the WordPress admin menu.

    They are 100% compatible with WordPress’ existing structures and still very much in alpha since I’ve been the only one using it. I’m sure there are use-cases they do not yet handle. But I’ll post the code here for you and others to try out.

    You can download the file to drop in your theme’s directory here: wp-admin-menu-classes.php and what follows shows how you might call the functions in your theme’s functions.php file:

    <?php
    require_once('wp-admin-menu-classes.php');
    add_action('admin_menu','my_admin_menu');
    function my_admin_menu() {
      swap_admin_menu_sections('Pages','Posts');              // Swap location of Posts Section with Pages Section
      rename_admin_menu_section('Media','Photos & Video');    // Rename Media Section to "Photos & Video"
      delete_admin_menu_section('Links');                     // Get rid of Links Section
      $movie_tags_item_array = get_admin_menu_item_array('Movies','Movie Tags');  // Save off the Movie Tags Menu
      update_admin_menu_section('Movies',array(               // Rename two Movie Menu Items and Delete the Movie Tags Item
        array('rename-item','item'=>'Movies','new_title'=>'List Movies'),
        array('rename-item','item'=>'Add New','new_title'=>'Add Movie'),
        array('delete-item','item'=>'Movie Tags'),
      ));
      copy_admin_menu_item('Movies',array('Actors','Add New')); // Copy the 'Add New' over from Actors
      renamed_admin_menu_item('Movies','Add New','Add Actor');  // Rename copied Actor 'Add New' to 'Add Actor
      add_admin_menu_item('Movies',array(                       // (Another way to get a 'Add Actor' Link to a section.)
        'title' => 'Alt Add Actor ',
        'slug' => 'post-new.php?post_type=actor',
      ), array(// Add Back the Movie Tags at the end.
        'where'=>'end'
      ));
      add_admin_menu_item('Movies',$movie_tags_item_array,array(// Add Back the Movie Tags at the end.
        'where'=>'end'
      ));
      delete_admin_menu_section('Actors');                      // Finally just get rid of the actors section
    }
    

    What’s more, these functions are even under consideration (as a base) for inclusion in WordPress 3.1 so if we’re lucky these might even become standard!

  2. Here’s a quick walkthrough of how the WordPress admin menu is built – I’m not talking the add_menu_page API, I mean the actual default WordPress menu.

    Calling the Menu File

    The menu is, obviously, loaded by wp-admin/admin.php. But it’s not loaded through the standard API we’re used to using based on the WordPress documentation. Rather, the entire menu (all possible options, submenus, etc) are loaded via a simple array that’s defined in wp-admin/menu.php.

    So to load the menu system, admin.php just requires menu.php … around line 99 in WordPress 3.0.

    Loading the Menu

    The menu itself is stored in the global array $menu. According to the in-line documentation, the menu array has these elements:

    The elements in the array are:
        *     0: Menu item name
        *     1: Minimum level or capability required.
        *     2: The URL of the item's file
        *     3: Class
        *     4: ID
        *     5: Icon for top level menu
    

    The dashboard, for example, is:

    $menu[2] = array( __('Dashboard'), 'read', 'index.php', '', 'menu-top menu-top-first menu-icon-dashboard', 'menu-dashboard', 'div' );
    

    The file goes through and loads each menu item into the array and loads all of their sub-menu items into an array called $submenu that indexes based on the parent menu’s url. So the Dashboard’s submenu item called “Dashboard” is:

     $submenu[ 'index.php' ][0] = array( __('Dashboard'), 'read', 'index.php' );
    

    After the system is done loading all the menus (there aren’t that many, but the system steps through the index at time by 5 or 10 … notice that the Dashboard, even though it’s the first menu item, is still indexed as item “2” (PHP arrays start at index 0 … so this gives you some maneuvering room).

    At this point, the system calls wp-admin/includes/menu.php.

    Stepping through the Menu

    This third file walks through each menu item and, based on the privileges assigned to the current user, either uses the menu or removes it. First it loops through all the sub-menus and removes pages the user can’t access. Then it loops through parent pages and does the same thing. Then it removes any duplicate separators that remain from having eliminated menus.

    Finally, it sorts the menus based on their assigned menu order.

    Ordering custom menus

    The hook admin_menu is called after menus are set up but before anything is ordered. So it’s possible to order the entire WordPress menu system without “hacking” the API.

    After the action admin_menu is fired, your custom pages are loaded into the system. The next thing that happens, is WordPress checks a filter called custom_menu_order … this filter is always returned false and tells WordPress whether or not you want to use a custom order.

    Add the following to your theme to set the flag to true instead and define your explicit menu order:

    function custom_menu_order($menu_ord) {
           if (!$menu_ord) return true;
           return array('index.php', 'edit.php', 'edit-comments.php');
    }
    
    add_filter('custom_menu_order', 'custom_menu_order');
    add_filter('menu_order', 'custom_menu_order');
    

    Specify the order you want for all of the menus (I supplied references to the menu-loading file so you can get a list of filenames) and this should take care of it.


    EDIT (9/2/2010):

    To specify the order of a custom post type’s edit screen using this method, you need to know the URL of the edit screen. I most cases, it will be http://blog.url/wp-admin/edit.php?post_type=POST_TYPE. This depends on how WordPress is set up on your site (if it’s installed in the root or in a subfolder) and the slug of the custom post type you’re using.

    For example…

    Let’s say you have a custom post type for ‘Stack Exchange Questions’ and you want the editor to appear in the same section as the dashboard directly below the dashboard icon. You’d use the following code in your theme’s functions.php file:

    function custom_menu_order($menu_ord) {
           if (!$menu_ord) return true;
           return array('index.php', 'edit.php?post_type=stack_exchange_questions');
    }
    
    add_filter('custom_menu_order', 'custom_menu_order');
    add_filter('menu_order', 'custom_menu_order');
    

    The rest of the menu will be unaffected, but your custom edit page will be moved to the same section as the dashboard and will appear immediately below it. You can use this to move your custom post types to any section of the admin menu and place them in any order. You can also move standard menu items around the same way.

    Just make sure you specify the order of all menu items in the given section, otherwise your menu might be subject to some unexpected weirdness.

  3. I realize this is an old thread, but I think it’s worth updating with a MUCH easier solution. Please note that this works with 3.5 and has not been tested with any other version. The following code can be placed in a plugin or the functions.php file.

    See: http://codex.wordpress.org/Plugin_API/Filter_Reference/menu_order. Modified slightly to suit the original poster’s needs (though, I hope he found a solution by now…).

      // Rearrange the admin menu
      function custom_menu_order($menu_ord) {
        if (!$menu_ord) return true;
        return array(
          'index.php', // Dashboard
          'edit.php?post_type=custom_type_one', // Custom type one
          'edit.php?post_type=custom_type_two', // Custom type two
          'edit.php?post_type=custom_type_three', // Custom type three
          'edit.php?post_type=custom_type_four', // Custom type four
          'edit.php?post_type=custom_type_five', // Custom type five
          'separator1', // First separator
          'edit.php?post_type=page', // Pages
          'edit.php', // Posts
          'upload.php', // Media
          'link-manager.php', // Links
          'edit-comments.php', // Comments
          'separator2', // Second separator
          'themes.php', // Appearance
          'plugins.php', // Plugins
          'users.php', // Users
          'tools.php', // Tools
          'options-general.php', // Settings
          'separator-last', // Last separator
        );
      }
    
      add_filter('custom_menu_order', 'custom_menu_order'); // Activate custom_menu_order
      add_filter('menu_order', 'custom_menu_order');
    

    Any items in the admin menu that are not listed here won’t be removed. They will be appended to the bottom of the menu.

  4. I understand you don’t want to use a plugin, but for pure simplicity, try the Admin Menu Editor plugin by Janis Elsts. Rearrange your admin menus any way you like; can also hide menu items.

  5. To move menu items around, I like using the Global $menu variable.

    For example, if I wanted to move the “Pages” menu to the bottom of the menus, I would use this in functions.php or a plugin:

    function admin_menu_items() {
        global $menu;
        $menu[102]=$menu[20];//make menu 102 be the same as menu 20 (pages)
        $menu[20]=array();//make original pages menu disappear
    
    }
    add_action('admin_menu', 'admin_menu_items');
    

    and if I wanted to swap the Posts and Links menus:

    function admin_menu_items() {
        global $menu;
        $storemenu = $menu[15];//save links menu into $storemenu
        $menu[15] = $menu[5];//make links menu = posts menu
        $menu[5] = $storemenu; //make menu 5/posts = $storemenu/links   
    }
    add_action('admin_menu', 'admin_menu_items');
    

    Been using this trick a little while, just tested with WP 3.4.1

  6. Awesome. Thank you so much.
    I just put some lines of code into my functions.php

    require_once('/extras/wp-admin-menu-classes.php');
    add_action('admin_menu','my_admin_menu');
    function my_admin_menu() {
      swap_admin_menu_sections('Pages','Posts'); // Swop location of Posts Section with Pages Section
    }
    

    Plus placing the wp-admin-menu-classes.php in my theme folder and now the ‘posts’ button is swopped with the ‘pages’ button.

    I hope this will become part of the core soon and in a way so that we don’t need to write the whole menu within a function to just reorder two buttons.

    In fact it was a bit tricky to get a more specified order for 4 buttons.
    In order to change the of 4 buttons to: Pages, Post, Media, Links
    I needed to use the folowing code:

      swap_admin_menu_sections('Pages','Posts');                
      swap_admin_menu_sections('Media','Links');                 
      swap_admin_menu_sections('Posts','Links');