I am adding items to a CPT Admin menu using add_submenu_page which works great, but they are added to the bottom of the sub-menu after the CPT options. I want to be able to have them on top , but I suppose this question can also apply to ordering all Admin based sub-menu items.

What I tried ( not working, I tried several variations),

function custom_menu_order($menu_ord) {
       if (!$menu_ord) return true;

       return array( 

         'edit.php?post_type=page' =>array(

add_filter('custom_menu_order', 'custom_menu_order');
add_filter('menu_order', 'custom_menu_order');

Would this be because menu_order filter does not take sub-menu's into account?

3 Answers 3


The filter 'custom_menu_order' will not work on the menu order because apply_filters in wp-admin/includes/menu.php supplies false as the filtered content. You can try changing false to $menu and the filter works grand.

Since we obviously can't touch the core, here's how I got it to work:

function custom_menu_order(){
    global $submenu;

    $find_page = 'edit.php';
    $find_sub = 'Post Tags';

    foreach($submenu as $page => $items):
        if($page == $find_page):
            foreach($items as $id => $meta):
                if($meta[0] == $find_sub):
                    $submenu[$find_page][0] = $meta;
                    unset ($submenu[$find_page][$id]);
add_action('_admin_menu', 'custom_menu_order');
  • It's ugly but it will have to do.
    – Wyck
    Commented Sep 19, 2011 at 4:07
  • Actually this won't do, the array keys bounce all over the place.
    – Wyck
    Commented Sep 19, 2011 at 4:29
  • I got it to work by traversing the array. The saving grace here is zero is not used as a key for the sub items on a menu. Commented Sep 19, 2011 at 13:37
  • This will only work on pages added through the add_submenu_page() function. Core subs like Theme Editor, etc... can't be touched here. Commented Sep 19, 2011 at 13:42
  • Ya this does work, before I was just using key value, thanks. I want to add that it was not working with the _admin_menu or menu_order filter for some reason but it does work with custom_menu_order
    – Wyck
    Commented Sep 19, 2011 at 19:55

I know I'm necro-posting but I recently had the same issue. Please note that I used Rao's solution on SO to get to this answer.

Assuming your CPT is called "notes".

 * @see https://codex.wordpress.org/Plugin_API/Filter_Reference/menu_order
add_filter( 'custom_menu_order', 'change_note_submenu_order' );

 * Change the submenu order for the Note CPT in the Admin panel
 * @param  [type] $menu_ord I don't think this is actually used for anything...
 * @return [type]           $menu_ord
 * @see https://stackoverflow.com/questions/18766477/wordpress-change-admin-submenu-order
function change_note_submenu_order( $menu_ord ) {
  global $submenu;

  /* Uncomment the line below to see all menu orders */
  // echo '<pre>'.print_r($submenu,true).'</pre>';

   * NOTE: Original note submenu order should be:
   *  5 (note list),
   * 10 (Add new),
   * 15 (Categories),
   * 16 (Tags),
   * 17 (Your Custom Page added via add_submenu_page) */
  $arr = array();
  $arr[] = $submenu['edit.php?post_type=note'][17]; // Custom menu page (Omit if unused)
  $arr[] = $submenu['edit.php?post_type=note'][5];  // Note List
  $arr[] = $submenu['edit.php?post_type=note'][10]; // Add New Note
  $arr[] = $submenu['edit.php?post_type=note'][15]; // Categories
  $arr[] = $submenu['edit.php?post_type=note'][16]; // Tags
  $submenu['edit.php?post_type=note'] = $arr;

  return $menu_ord;

Definitely comment out the echo '<pre>'.print_r($submenu,true).'</pre>'; if your having trouble. Also remember you can manually set the array too in the change_note_submenu_order function.

$notes_list  = array("Notes", "edit_posts", "edit.php?post_type=notes");
$custom_page = array("Custom Menu Page Title", "Capability", "Menu Slug", "Page Title");
$new_note    = array("Add New", "edit_posts", "post-new.php?post_type=note");
$arr         = array($custom_page, $notes_list, $new_note);
$submenu['edit.php?post_type=note'] = $arr;

Hope this helps somebody!


Another necro for a simpler issue.

I just wanted to move my custom link to the bottom (added comment on how it could be used to address original question as well):

public function change_wc_submenu_order( $menu_order ) {
    global $submenu;

    foreach ( $submenu['woocommerce'] as $index => $item ) {
        if ('My Custom Submenu Title' === $item[0] ) {
            $custom = $item;
            unset( $submenu['woocommerce'][$index] );

    if ( ! empty( $custom ) ) {
        // If we want it at the beginning, use array_unshift() instead
        array_push( $submenu['woocommerce'], $custom );

    return $menu_order;

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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