Question

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(
                                      '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?

Was it helpful?

Solution

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');

OTHER TIPS

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] );
            break;
        }
    }

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

    return $menu_order;
}
Licensed under: CC-BY-SA with attribution
Not affiliated with wordpress.stackexchange
scroll top