Is it possible to set the position of an item in the admin menu? I'm trying to move the media link under my custom post types. I know that the media link is position 10. Is it possible to set it to 14?

I know that I can change the position of all the links using the custom_menu_order filter but I'm not seeing a way to set the position in that filter.

2 Answers 2


This is not an exact answer, but I think there are enough elements to build the desired output.

I sort the menu manipulating the global $menu, not really best practice, but for now it works.

The result of this example is moving Links Manager, Comments and Media Library to the end of the first block. The effect is: first all Post Types then these items.

We need a recursive array search function to locate the key of each item, [5], [10], [15], etc. This way we can be sure of being targeting the right item and don't need to inspect the menu to confirm each one's key.

The first thing is to grab the position of the second separator (separator2), as we are going to move everything just before it. Then we search for each item that we want to move, make a copy of it and unset from the $menu. Finally, we subtract the number of "movable" items from the position of the separator (say 100) and add our items in the positions 97, 98, 99 (in this example we're moving 3 items).

add_action( 'admin_menu', 'sort_cpts_wpse_99459', 9999 );

function sort_cpts_wpse_99459() 
    global $menu;
    $mod_menu = array();

    $separator = b5f_recursive_array_search( 'separator2', $menu );
    $links = b5f_recursive_array_search( 'link-manager.php', $menu );
    $upload = b5f_recursive_array_search( 'upload.php', $menu );
    $comments = b5f_recursive_array_search( 'edit-comments.php', $menu );

    if( $links )
        $mod_menu['links'] = $menu[ $links ];
        unset( $menu[ $links ] );

    if( $upload )
        $mod_menu['upload'] = $menu[ $upload ];
        unset( $menu[ $upload ] );

    if( $comments )
        $mod_menu['comments'] = $menu[ $comments ];
        unset( $menu[ $comments ] );

    $position_menu = (int)$separator - count( $mod_menu );
    foreach( $mod_menu as $m )
        $menu[ $position_menu ] = $m;

function recursive_array_search( $needle, $haystack ) 
    foreach( $haystack as $key => $value ) 
        $current_key = $key;
            $needle === $value 
            OR ( 
                is_array( $value )
                && b5f_recursive_array_search( $needle, $value ) !== false 
            return $current_key;
    return false;
  • Thanks @brasofilo. I dropped b5f_ from the functions so they would all match up to make it work and removed the links reference sine it's been removed.
    – kel
    May 14, 2013 at 23:02

I know, that's an old one here, but the following solution is actually quite a bit nicer, i think:

add_filter('custom_menu_order', 'antwortzeit_custom_menu_order');
add_filter('menu_order', 'antwortzeit_custom_menu_order');
function antwortzeit_custom_menu_order($menu_order) {
    if (!$menu_order) return true;

    $menu_order_string = implode(', ', $menu_order);
    $menu_order_string = str_replace(', upload.php', '', $menu_order_string);
    $menu_order_string = str_replace('index.php', 'index.php, upload.php', $menu_order_string);

    return explode(', ', $menu_order_string);

Do a var_dump on $menu_order_string before the replace to see the positions and choose your position for the str_replace. In this very case, we're repositioning the media library right behind the dashboard.

Hope this'll help somebody in the future.

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.