I'm planning to use a couple of custom post types for a plugin of mine. The whole plugin should reside under 1 toplevel menu item. Thus I would prefer a menu structure like so:

  • Dashboard
  • Posts
  • [...]
  • My Plugin

    • Custom Post Type #1
    • Custom Post Type #2
    • [...]

This is possible by including 'show_in_menu' => 'my_plugin_toplevel_menu_item_slug' in register_post_type when registering my custom post types. Howerer, there are a few issues I've come across using this method.

  • I have no say in how the title should be outputted. I would prefer to use <h2 class="nav-tab-wrapper"> ... </h2>, but now post.php prints the h2 output for me, and I don't know an easy way of overriding this. It is possible to do this with javascript as soon as the page is loaded, but this is a bit ugly in my opinion.
  • When using 'show_in_menu', the submenu page order cannot be altered. The custom post types are placed at the top automatically, because I guess Wordpress just gets to it quicker than I do.
  • The h2 icon disappears for some reason (I haven't really looked into this yet though, it might be very easy to solve).

Does anybody have an idea how to tackle these issues elegantly?


See temporary solution in my answer below.

  • 1
    AFAIK, manipulating the global $submenu is the only way to do this. You should add your solution as an Answer.
    – brasofilo
    Commented Feb 28, 2013 at 5:56
  • I might come back and write an answer later, but I wonder if this would work: 1) set show_in_menu to true (for compatibility with other CPT-related plugins), use remove_menu_page() to remove menu item, use add_submenu_page() to add back to the correct location and with a custom page title.
    – mrwweb
    Commented Aug 18, 2014 at 23:45

1 Answer 1


The (temporary?) solution I've settled for, is the following:

  1. Use the show_in_menu parameter of register_post_type
  2. Use javascript to display custom title after page load
  3. Solve the submenu page order (which automatically puts the custom post types at the top, which is not my intention), with the following helper function:


// Sort the children of a given toplevel menu item
// Keep original order intact as much as possible, while
//  enforcing the [before => after] rules given by $force_order
function help_sort_submenu_items($toplevel_slug, $force_order) {
  global $submenu;

  $done = array();
  $hold = array();
  $newmenu = array();

  foreach ($submenu[$toplevel_slug] as $i => $item) {
    $force_after = array_search($item[2], $force_order);
    if ($force_after !== false && empty($done[$force_after])) {
      $hold[$item[2]] = $item;
    } else {
      $newmenu []= $item;
      $done[$item[2]] = true;

      $just_added_id = $item[2];
      while ($just_added_id = $force_order[$just_added_id]) {
        $next = $hold[$just_added_id];
        $newmenu []= $next;
        $done[$just_added_id] = true;

  $submenu[$toplevel_slug] = $newmenu;

Usage like so:

help_sort_submenu_items('my_plugin_toplevel_menu_item_slug', array(
  'submenu_page_with_this_slug_comes_before' => 'submenu_page_with_this_slug',
  'another' => 'rule'

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.