Order Admin sub-menu items?

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),

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

       return array( 

         'edit.php?post_type=page' =>array(
                                      'edit.php?post_type=note',
                                      'edit_pages',
                                      'notes',
                                      )   
                    );
}

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?

Related posts

Leave a Reply

3 comments

  1. 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]);
                        ksort($submenu[$find_page]);
                    endif;
                endforeach;
            endif;
        endforeach;
    }
    add_action('_admin_menu', 'custom_menu_order');
    
  2. 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!

  3. 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] );
                break;
            }
        }
    
        if ( ! empty( $custom ) ) {
            // If we want it at the beginning, use array_unshift() instead
            array_push( $submenu['woocommerce'], $custom );
        }
    
        return $menu_order;
    }