Placing a Custom Post Type Menu Above the Posts Menu Using menu_position?

I just figured out the menu_position parameter it seems like you can place the menu of your custom post type almost everywhere. Except above the Posts menu!

How can I accomplish that?

Related posts

Leave a Reply

10 comments

  1. Positions for Core Menu Items

    • 2 Dashboard
    • 4 Separator
    • 5 Posts
    • 10 Media
    • 15 Links
    • 20 Pages
    • 25 Comments
    • 59 Separator
    • 60 Appearance
    • 65 Plugins
    • 70 Users
    • 75 Tools
    • 80 Settings
    • 99 Separator

    Parameter description for “menu position”

    $position (integer) (optional) The position in the menu order
    this menu should appear. By default, if this parameter is omitted, the
    menu will appear at the bottom of the menu structure. The higher the
    number, the lower its position in the menu.

    WARNING: if two menu items
    use the same position attribute, one of the items may be overwritten
    so that only one item displays! Risk of conflict can be reduced by
    using decimal instead of integer values, e.g. 63.3 instead of 63.

    Default: bottom of menu structure

  2. The new JetPack Plugin places its menu link immediately below the Dashboard link. It does so by setting its menu order to 0, by filtering the $menu_order array:

    function jetpack_menu_order( $menu_order ) {
            $jp_menu_order = array();
    
            foreach ( $menu_order as $index => $item ) {
                if ( $item != 'jetpack' )
                    $jp_menu_order[] = $item;
    
                if ( $index == 0 )
                    $jp_menu_order[] = 'jetpack';
            }
    
            return $jp_menu_order;
        }
    

    Out of curiosity, what would happen if you tried 0 as menu_position?

  3. Looking for a solution on the web but didn’t found. Simply does this trick (for example). Here you have the native list of positions:

    • 2 Dashboard
    • 4 Separator
    • 5 Posts
    • 10 Media
    • 15 Links
    • 20 Pages
    • 25 Comments
    • 59 Separator
    • 60 Appearance
    • 65 Plugins
    • 70 Users
    • 75 Tools
    • 80 Settings
    • 99 Separator

    If you have more items, you can read the current position for each items by printing the global $menu :

    global $menu; 
    print_r($menu); 
    

    So if I well understand, nothing can prevent us too re-order the menu like we want :

    function re_order_menu () {
        // ------- Put away items 
        $dashboard = $menu[2]
        $separator1 = $menu[4]
        $posts = $menu[5]
        $media = $menu[10]
        $links = $menu[15]
        $pages = $menu[20]
        $comments = $menu[25]
        $separator2 = $menu[59]
        $appearance = $menu[60]
        $plugins = $menu[65]
        $users = $menu[70]
        $tools = $menu[75]
        $settings = $menu[80]
        $separator3 = $menu[99]
    
        // -------- Reset menu  
        unset($menu[2]);
        unset($menu[4]);
        unset($menu[5]);
        unset($menu[10]);
        unset($menu[15]);
        unset($menu[20]);
        unset($menu[25]);
        unset($menu[59]);
        unset($menu[60]);
        unset($menu[65]);
        unset($menu[70]);
        unset($menu[75]);
        unset($menu[80]);
        unset($menu[99]);
    
        // -------- Re-order menu as you want
        $dashboard = $menu[2];
        $separator1 = $menu[4]
        $posts = $menu[5];
        $books = $menu[6];
        /* my tons of custom items */
        $authors  = $menu[7];
        $requests = $menu[8];
        $clients = $menu[9];
        $sellers  = $menu[10];
        $services = $menu[11];
        $schedules = $menu[12];
        /* let some space after */ 
        $media = $menu[30];
        $links = $menu[31];
        $pages = $menu[32];
        $comments = $menu[33];
        $separator2 = $menu[59];
        $appearance = $menu[60];
        $plugins = $menu[65];
        $users = $menu[70];
        $tools = $menu[75];
        $settings = $menu[80]
        $separator3 = $menu[99];
    
    } 
    add_action('admin_menu', 're_order_menu');
    

    It works fine for me so, I think this is legit, I’m wrong ?

  4. I’ve used ‘menu_postion’ => 0, 1,2,3,4.

    Doesn’t matter really. If you play around with it you can easily figure it out.

    Using ‘menu_position’ => 1 should place it below the Dashboard menu item above the separator thing. 0 Should place it above the Dashboard

  5. You can use this:

    function my_move_post () {
        global $menu;
        $menu[6] = $menu[5]; //move post from post 5 to 6
        unset($menu[5]); //free the position 5 so you can use it!
    }
    add_action('admin_menu', 'my_move_post');
    

    Now you can use position 5 to add you menu above Post menu.

  6. here is the caveat to the whole issue…

    WordPress 4.9.2

    wp-admin/menu.php:

    // If we're to use $_wp_last_object_menu, increment it first.
    $ptype_menu_position = is_int( $ptype_obj->menu_position ) ? $ptype_obj->menu_position : ++$_wp_last_object_menu; 
    

    NOTICE: must be an integer and NOT set already, otherwise it goes to the bottom of the list.

  7. For a working solution in WordPress 5 and below, reposition it with the following code:

    add_filter('custom_menu_order', '__return_true');
    add_filter('menu_order', function($menu_order) {
        if (
            false !== ($k1 = array_search($v1 = 'edit.php', $menu_order))
            && false !== ($k2 = array_search($v2 = 'edit.php?post_type=foo', $menu_order))
        ) {
            array_splice($menu_order, $k1, 0, $v2);
            array_splice($menu_order, $k2 + 1, 1);
        }
        return $menu_order;
    });
    

    This assumes you don’t have more than one menu item vying for pole position.

  8. On the same link you linked, it reads:

    menu_position
    (integer) (optional) The position in the menu order the post type should appear.
    Default: null - defaults to below Comments
    5 - below Posts
    10 - below Media
    20 - below Pages
    60 - below first separator
    100 - below second separator
    

    So, if you set menu_position to something like 4, then it should put it above posts.

    A position of -1 puts it above the Dashboard link.

  9. You can use decimal values (as strings). For example, I have some custom post types that I placed at the last position in menu (100001, 100002, 100003).

    Then, just put this code to move them above Posts and below Dashboard menu items.

    function reorder_admin_menu() {
    
      global $menu;
    
      // Add one separator
    
      $menu["3.1"] = array(
        0 =>  '',
        1 =>  'read',
        2 =>  'separator_' . "anything_unique",
        3 =>  '',
        4 =>  'wp-menu-separator'
        );
    
      // I have put my menu items waay at the end (exactly these values), so move them up
    
      $menu["3.2"] = $menu[100001];
      $menu["3.3"] = $menu[100002];
      $menu["3.4"] = $menu[100003];
    
      unset($menu[100001]);
      unset($menu[100002]);
      unset($menu[100003]);
    
      // move Media menu (position 10) item to front, in the same group
      $menu["3.5"] = $menu[10];
      unset($menu[10]);
    
      // Debug: ksort($menu); error_log( var_export( $menu, true ) );
    }
    
    add_action( 'admin_menu', 'reorder_admin_menu', 999 );