How to Add WordPress CPT Admin Menu as Sub Menu

cpt-menu-as-submenu
f(x) Photo Tag Admin Page

When I write f(x) Photo Tag plugin, I think it’s best to put the menu under “Media” because it’s simpler, and also make sense.

Sometimes we want to add custom post type admin menu as sub-menu item on other post type or under settings page, because it make sense (not all post type need to be parent menu), and I like this approach because it make WordPress Admin cleaner.

And Here’s how I do that:

#1. Disable CPT Menu

When registering your custom post type, simply change the show_in_menu args as false.

register_post_type( 'your-cpt', array(
    'description'           => '',
    'public'                => true,
    'show_ui'               => true,
    'show_in_menu'          => false, /* Do not show admin menu */
    [...]
) );

Now, your CPT will have no link in admin menu.

Note:
before you remove the menu, copy the link of your edit post type menu item, we will add that link in second step.

Your menu link should be something like:

http://your-site/wp-admin/edit.php?post_type=your-cpt

The part we are using is edit.php?post_type=your-cpt as menu slug in add_submenu_page() function.

#2. Add Sub Menu in Preferred Parent Menu Item

It’s very simple, we simply need to use add_submenu_page() function via admin_menu hook.

/* Register Admin Sub Menu */
add_action( 'admin_menu', 'my_cpt_admin_submenu' );

/**
 * Add admin menu
 * @link https://developer.wordpress.org/reference/functions/add_submenu_page/
 */
function my_cpt_admin_submenu(){

    add_submenu_page(
        'upload.php',                 // parent slug
        'Your CPT Title',             // page title
        'Sub Menu Title',             // sub-menu title
        'edit_posts',                 // capability
        'edit.php?post_type=your-cpt' // your menu menu slug
    );
}

The args for page title, menu title, caps, etc above need to match your register CPT args.

Or you can make it pull data from your registered CPT object to make it easier:

/* Register Admin Sub Menu */
add_action( 'admin_menu', 'my_cpt_admin_submenu' );

/**
 * Add admin menu.
 */
function my_cpt_admin_submenu(){

    /* Your CPT */
    $cpt = 'your-cpt';

    /* Get CPT Object */
    $cpt_obj = get_post_type_object( $cpt );

    add_submenu_page(
        'upload.php',                      // parent slug
        $cpt_obj->labels->name,            // page title
        $cpt_obj->labels->menu_name,       // menu title
        $cpt_obj->cap->edit_posts,         // capability
        'edit.php?post_type=' . $cpt       // menu slug
    );
}

Note:
The code above will add CPT link under “Media” menu. If you want to add it to other parent page, change the “parent slug” args in add_submenu_page() function.

e.g: If you want to add sub menu under the “Page” parent menu, you can change the “parent slug” args to edit.php?post_type=page and not upload.php.

Now you should see your CPT link under “Media” menu. But we are not done yet.

When you edit your CPT item, you will notice that the menu is not active. We are going to fix that in next step.

cpt-sub-menu-not-active

#3. Fix Parent Active Menu

This problem occurs because WordPress did not recognize “Media” as parent menu for “Edit Screen” for your CPT.

So we need to add “Media” as parent for that page using parent_file filter:

/* Parent Menu Fix */
add_filter( 'parent_file', 'my_cpt_parent_file' );

/**
 * Fix Parent Admin Menu Item
 */
function my_cpt_parent_file( $parent_file ){

    /* Get current screen */
    global $current_screen, $self;

    /**
     * Add upload.php as parent file/menu if
     * it's Post Type list Screen or Edit screen of our post type.
     */
    if ( in_array( $current_screen->base, array( 'post', 'edit' ) ) && 'your-cpt' == $current_screen->post_type ) {
        $parent_file = 'upload.php';
    }

    return $parent_file;
}

UPDATE: 23 July 2016

For “add new” page if you want to highlight the sub menu, you need to also filter “submenu_file”, here’s an example code:

/* Parent Menu Fix */
add_filter( 'submenu_file', 'my_cpt_submenu_file' );

/**
 * Fix Sub Menu Item Highlights
 */
function my_cpt_submenu_file( $submenu_file ){

    /* Get current screen */
    global $current_screen, $self;

    if ( in_array( $current_screen->base, array( 'post', 'edit' ) ) && 'your-cpt' == $current_screen->post_type ) {
        $submenu_file = 'edit.php?post_type=your-cpt';
    }

    return $submenu_file;
}

Now all done and working perfectly 🙂

cpt-sub-menu-final-result

Note:
you can use this method for other purposes, not only for post type, etc.

UPDATE (20 June 2016):

Matt Pramschufer ask in the comment about sub-menu in sub-menu. I think I found a simple solution, just add dash when adding sub menu to “fake” the level. Here’s an example:

wpadmin-submenu-in-submenu

5 Comments

  1. Matt Pramschufer

    Okay this is great, but the real tricky part is adding a Child of a Sub Menu. So if you wanted to add an “Add New” to your Photo Tag menu item, how would you go about doing that? Also, I am still running into issues with embedding sub menus and the “Active” state of the WP Admin navigation bar not realizing I am in that “sub menu” area.

    Reply
    • David

      if you need submenu for your menu item I suggest to not set the parent as submenu. WP only support one level of admin sub menu.
      the “Add New” is available in CPT screen, also in admin bar (if you set it).

      about the active state of the menu, I don’t know about that. I didn’t experience that in my CPT (as above). can you share your code?

      Reply
  2. Yossely

    Hi David! This is an excellent tutorial, very specific and just what I’ve been looking for.

    Thank you for sharing it!

    Reply
  3. iLen

    There is no other solution on any other side. It is my pleasure to meet you with this solution.
    Thank you very much for sharing it.

    Reply

Leave a Reply

Your email address will not be published. Required fields are marked *