Up until this point, I’ve never worked on a project or done any type of work that required a custom post type to be added to an existing menu in the WordPress dashboard.

For the most part, I’m generally of the mindset that custom post types should:

  • Exist as top level menus
  • Should be added at the bottom of the WordPress dashboard menu

This mentality is primarily motivated by the fact that I see the core WordPress menu options as first-class citizens in the dashboard, custom post types as being second-class citizens.

That’s just a rule of thumb, though. There are always exceptions.

But there are also times where custom post types could be treated as, say, third-class citizens where they should be integrated with an existing menu be it a core menu or another custom post type menu.

Luckily, it’s trivially easy to add a custom post type as a menu item to an existing menu.

Adding The Custom Post Types

To demonstrate this, we’ll add two custom post types: Portfolios and Locations.

Portfolios

The portfolio is meant to represent a collection of galleries, so this would ideally create a ‘Portfolio’ menu where the user would be able to add a new, edit, search, and manage galleries:

// Define the 'Portfolio' post type. This is used to represent galleries
// of photos. This will be our top-level custom post type menu.
$args = array(
  'labels'	=>	array(
            'all_items'           => 'Gallery',
						'menu_name'	      		=>	'Portfolio',
						'singular_name'       =>	'Gallery',
					 	'edit_item'           =>	'Edit Gallery',
					 	'new_item'            =>	'New Gallery',
					 	'view_item'           =>	'View Gallery',
					 	'items_archive'       =>	'Gallery Archive',
					 	'search_items'        =>	'Search Portfolio',
					 	'not_found'	      		=>	'No galleries found',
					 	'not_found_in_trash'  =>	'No galleries found in trash'
					),
	'supports'			=>	array( 'title', 'editor', 'author', 'revisions' ),
	'menu_position'	=>	5,
	'public'				=>	true
);
register_post_type( 'portfolio', $args );

This will introduce the Portfolio menu into the WordPress dashboard menu. If you’ve been working with custom post types for a while, there’s nothing really new in this specific code.

Locations

Next, we’ll add the menu for the Locations. It’s roughly the same as the code above except we aren’t including a menu_postion.

Instead, we’re adding a parameter for the show_in_menu option:

// Next, we'll define a second custom post type called 'Locations' where we could
// potentially display a list of locations that are used as part of our portfolio.
// This custom post type will be added as a submenu to the 'Portfolio' menu
$args = array(
  'labels'	=>	array(
						'all_items'           => 	'Locations',
						'menu_name'	          =>	'Locations',
						'singular_name'       =>	'Location',
					 	'edit_item'           =>	'Edit Location',
					 	'new_item'            =>	'New Location',
					 	'view_item'           =>	'View Location',
					 	'items_archive'       =>	'Location Archive',
					 	'search_items'        =>	'Search Locations',
					 	'not_found'	          =>	'No locations found.',
					 	'not_found_in_trash'  => 'No locations found in trash.'
					),
	'supports'      =>	array( 'title', 'editor', 'revisions' ),
	'show_in_menu'  =>	'edit.php?post_type=portfolio',
	'public'		    =>	true
);
register_post_type( 'location', $args );

Notice that the show_in_menu parameter accepts a URL of the page to which this menu should be added.

edit.php?post_type=portfolio is obviously the URL for our Portfolio custom post type; however, you could potentially specify the URL to, say, simply edit.php to add the menu to the Posts menu.

Get The Gist

Anyway, easy enough, right?

I’ve created a gist of this entire code that can be viewed here on GitHub. Feel free to add comments or modifications as needed as this is primarily for demonstration purposes.

It obviously would need to be registered with the proper hooks and actions to be integrated into WordPress.

Category:
Notes
Tags:

Join the conversation! 32 Comments

  1. Nice! Like you, I’ve only ever needed to add CPTs as top-level, but this is a cool bit of code to know about.

    As far as dashboard citizenry goes…. Depending on the CPT and it’s prominence on the site, it may get a higher place in the menu. For instance, I did a recruiting site earlier this year with a Jobs CPT. It’s the primary menu item the client will be using/ looking for on the menu, so I positioned it pretty close to top. Not necessarily right, just my approach. :)

    Cheers,
    Carrie

    • For instance, I did a recruiting site earlier this year with a Jobs CPT. It’s the primary menu item the client will be using/ looking for on the menu, so I positioned it pretty close to top. Not necessarily right, just my approach.

      Totally! If you’re using WordPress as a CMS for jobs and positions, then Jobs are definitely higher rated than anything else.

      Great example :).

  2. I’ve used them as children of existing items when we’ve been working with post to post relationships. So with a Company as the parent CPT and Teams as the child CPT (which divided company users in to – Teams).

    That’s the only example I have though. Any other time that might have been used, we ended up building a custom UI and just hide the WordPress admin UI for them.

    • As far as hiding the WordPress admin UI is concerned, how far have you taken that?

      I ask because I’ve done some things as small as just removing menu items and dashboard widgets to writing full on custom views that don’t allow anyone except an administrator to see the actual dashboard.

      I’m always curious how other developers do it.

  3. Tom, is there a way to add custom post types to a custom menu item?

    I’m working on a e-commerce theme that sells different types of products that one post type is just not able to handle. Is it possible to add a custom menu item named something like “Products” and have two or three custom post types under that menu?

    • There is a way to do it, but you won’t necessary have the same functionality as a top-level menu.

      For example, say that you have a custom post type called Portfolio (like in the example above), and you normally have the two menu items:

      View All
      All New

      You can add another custom post type, say, Images, to the Portfolio menu by passing this as an argument to the $args array:

      'show_in_menu' => 'edit.php?post_type=portfolio'

      Where you pass the ID of the post type defined as the first argument of register_post_type. This will introduce an “Images” menu item so the list now looks like:

      View All
      All New
      Images

      Does this make sense, or did I misunderstand your question?

      • More like how the Settings menu is. Where the top level menu is not a post type but the items bellow it are different settings.

        Products (not a post type)
        -Product 1 (custom post type)
        -Product 2 (custom post type)
        -Product 3 (custom post type)

        • Oh, gotcha! Yeah – for something like that you’d want to check out add_menu_page and add_submenu_page.

          Those functions do exactly what you’re describing – it takes a little more work because you’ll need to setup options and what not, but this should take care of what you need.

          • Thanks, I’ll give those a look.

            • Your question is old but figured this might come in handy for someone else. I just spent a long time looking through the WP source code trying to do the same thing: I have a custom menu created using add_menu_page(). It has a handful of sub_menu items. I have a custom post type that is related to this menu and I wanted the add / list links for that post type to be submenu items.

              Short answer: No easy way to do it in WP. The way it generates the menus and custom post type UI means there is no simple call you can make.

              Solution:
              1. Register your post type with the following options:
              ‘show_ui’ => true,
              ‘show_in_menu’ => false
              In this example my custom post type is acct_notes

              2. In your theme’s functions.php file or your plugin file, add an action to admin_menu:
              add_action(‘admin_menu’, ‘modify_admin_menus’);

              3. Add submenu_pages for the two post UI links — list posts, create new post.
              The first param is the slug of the menu you’re adding it to. The second is the name that will show up on the page. The third is what the link will show up as. The fourth is the capability required to access it. The fifth is the slug for this menu item. And last is the function that will generate the output. In this case we’re not going to use it so we can pass NULL.

              add_submenu_page(‘members’, ‘Account Notes’, ‘Account Notes’, ‘manage-options’, ‘view_account_notes’, NULL);

              4. The last step is the function that will change those submenu links so that they go to the correct post UI pages.

              function modify_admin_menus(){
              global $submenu;
              if(array_key_exists(‘members’, $submenu)){
              foreach($submenu[‘members’] as $key => $value){
              $k = array_search(‘view_account_notes’, $value);
              if($k){
              $submenu[‘members’][$key][$k] = (current_user_can($submenu[‘members’][$key][1]))? admin_url(‘/edit.php?post_type=acct_notes’):”;
              }

              $l = array_search(‘new_account_note’, $value);
              if($l){
              $submenu[‘members’][$key][$l] = (current_user_can($submenu[‘members’][$key][1]))? admin_url(‘/post-new.php?post_type=dojo_acct_notes’) : ”;}
              }
              }
              }

              What’s going on in the function is that it’s checking the global $submenu array to see if our top level menu item (members) exists — it might not if the user doesn’t have permission to access it. If they do it then looks to see if that top level menu item has a submenu page with the slug “view_account_notes” — what we assigned in add submenu_page. Finally, it checks the permission we assigned in add_submenu_page and if the current user has that permission it outputs the new link. If they don’t it removes the link altogether.

              We do that same check twice — once for the link to list our custom post type, and once for the link to add a new custom post type.

              It would be far preferable to have this capability built in, but this will let you add custom post type user interfaces to any menu you want.

  4. Thanks. It works as expected

  5. What’s up, its pleasant paragraph regarding media print, we all understand media is a impressive source
    of facts.

  6. Tom is it possible to add a post type archive link to the menu without using plugins?

  7. Hey Tom,

    Is it possible to use this method and still retain the “add_new” link/label? When I add the custom post type to the menu of another CPT I only get the “all_items” link/label.

  8. Hi,
    I m having the problem to show the custom post type in Appearance -> Menu.
    I’ve set the three attributes
    'show_ui' => TRUE, 'show_in_menu' => TRUE, 'show_in_nav_menus' => TRUE
    and then in screen option I checked the custom post type but in vain.
    Thanx.

  9. Is anyway to show the custom post type menu inside of the ‘posts’ menu?
    Thank you.

  10. Thanks, It was really helpful, what i was looking for.

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.