up vote 5 down vote favorite
5
share [g+] share [fb]

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".

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?

link|improve this question
feedback

4 Answers

up vote 13 down vote accepted

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!

link|improve this answer
Fantastic addition to the API! It took me months to add my first custom menu section with the existing framework (which is why I studied the code do much) ... but your API seems much more intuitive to use! – EAMann Sep 2 '10 at 4:10
@EAMann - Thanks! If you want to offer any suggestions or even collaborate on improving it I'd love to get something established that could make it easier for everyone except for just the few who happen to see this Q&A. – MikeSchinkel Sep 3 '10 at 8:19
feedback

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.

link|improve this answer
There's a small error in your example code under the "Ordering custom menus" heading, the if conditional statement is missing the $ on the variable name... (Great answer though).. – t31os Nov 17 '10 at 15:24
Thanks for the catch! – EAMann Nov 17 '10 at 20:27
How would you add the custom post type for "Stack Exchange Questions" to a section below the Dashboard section? – epaps May 31 '11 at 4:32
Hi EAMann - quick question. Since the newest version of wordpress has this process changed at all or become simpler? – NetConstructor.com Sep 14 '11 at 19:26
feedback

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.

link|improve this answer
I tried this plugin in multisite installation .It works best.But we need to manually configure the options for every sub-site if we have multisite Installation. – user391 Oct 13 '10 at 15:07
feedback

After making my self sick over this through the entire afternoon, I really cannot recommend the "Admin Menu Editor" plugin at this point. I was first trying to use the built in API, which itself has a number of problems. Basically it's only fit for adding entirely new things, and removing the pre-existing menus. The (AME) plugin just made things worse. It was only after I dropped it for good, then tried to force things myself for a while, and then went looking for other solutions, that I found the hooks mentioned somewhere.

But the hooks are not enough for submenus. So I will probably try the API above next (which I actually read about at the offset but thought maybe it was too much overhead ... I will see) however what I really wanted was to be able to pluck submenu items out and turn them into main menus or move them into other main menus, and rename/reorder things if I wanted. Basically what the plugin promised, but really could not functionally deliver for 3.1. The plugin also seemed to make localization not work at all, but there is so much interplay there it's hard to tell, and the fact that it always deferred to WP made things really impossible.

Something definitely needs to change. What was worst probably was getting the menus right, but the menu effects would not play nice. So the main/sub menu(s!) may or may not be hilighted or whatever etc because the classes are applied improperly. WordPress is the best thing going but it needs to be better able to take a back seat, since it is a tool after all.

link|improve this answer
1  
Why effort is appreciated, this doesn't quite address original question and should not be an answer. You will be able to leave comments when you gain some reputation on site. – Rarst Aug 23 '11 at 16:57
feedback

Your Answer

 
or
required, but never shown

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