How to Add Existing Taxonomies to WordPress Custom Post Types

This article covers how to add existing taxonomies to a custom post type, and how to make that custom post type show up in those taxonomies’ archive pages.

We’ll take an example from our own work. We recently debuted Courses, a new way for us to thoroughly teach topics in WordPress development. Courses are just regular old posts for now, but we’re transitioning them into being their own custom post type. This has a number of advantages, such as making it easier to have a “Courses-only” archive page.

However, even though they’ll be their own custom post type, we want Courses to make use of three of our existing WordPress taxonomies:

  1. category, WordPress’s default category taxonomy,
  2. post_tags, WordPress’s default tags taxonomy, and
  3. difficulty, a custom difficulty taxonomy that we’ve registered ourselves.

Moreover, we want Courses to mix with our other post types in archive pages. If, for example, you click “Intermediate” to find all of our content that’s at Intermediate difficulty, we want our Intermediate Courses to show up right alongside our regular Intermediate articles.

This turns out to have several steps to it. So this week, we’re going to cover how to add existing taxonomies to a custom post type, and how to make that custom post type show up in that taxonomy’s archive pages.

One more thing before we get started. If you’re looking to learn WordPress development, we’ve written the best guide to it out there:

The Best Way to Learn WordPress Development

Get Up and Running Today!

Up and Running is our complete “learn WordPress development” course. Now in its updated and expanded Third Edition for 2018, it’s helped hundreds of happy buyers learn WordPress development the fast, smart, and thorough way.

Here’s what they have to say:

“I think anyone interested in learning WordPress development NEEDS this course. Watching the videos was like a bunch of lights being turned on.” -Jason, WordPress developer

“Other courses I’ve tried nearly always lack clear explanations for why WordPress does things a certain way, or how things work together. Up and Running does all of this, and everything is explained clearly and in easy-to-understand language.” -Caroline, WordPress freelancer

Now, let’s dive into the code for adding an existing taxonomy to a WordPress custom post type.

The Code

Below is the complete code we’ll be looking at today. This would be best as the only file in a standalone plugin. For more on registering plugins see our article on the topic.

// 1. Register post type
add_action( 'init', 'wpshout_register_cpts' );
function wpshout_register_cpts() {
	$args = array(
		'public' => true,
		'label'  => 'Courses',
		'has_archive'  => true,
		'rewrite'  => array( 'slug' => 'courses' ),
		'supports' => array( 
			'title',
			'editor',
			'author',
			'thumbnail',
			'excerpt',
			'comments',
			'revisions'
		),
	);
	register_post_type( 'course', $args );
}

// 2. Add existing taxonomies to post type
add_action( 'init', 'wpshout_add_taxonomies_to_courses' );
function wpshout_add_taxonomies_to_courses() {
	register_taxonomy_for_object_type( 'category', 'course' );
	register_taxonomy_for_object_type( 'difficulty', 'course' );
	register_taxonomy_for_object_type( 'post_tag', 'course' );
}

// 3. Make Courses posts show up in archive pages
add_filter( 'pre_get_posts', 'wpshout_add_custom_post_types_to_query' );
function wpshout_add_custom_post_types_to_query( $query ) {
	if( 
		is_archive() &&
		$query->is_main_query() &&
		empty( $query->query_vars['suppress_filters'] )
	) {
		$query->set( 'post_type', array( 
			'post',
			'course'
		) );
	}
}

The big takeaway is that adding taxonomies to custom post types requires three distinct steps.

The code above does three things, in order:

  1. Register the “Courses” custom post type with the necessary attributes.
  2. Add three existing taxonomies—category, post_tag, and our custom taxonomy difficulty—to the Courses post type.
  3. Cause Courses to show up in archive pages, so that a search by category, difficulty, and so on will include Courses results.

None of these three pieces is exceptionally difficult—it’s knowing that you need to do all three of them that was the big takeaway for me, and hopefully for you. Let’s look at each piece in more detail.

1. Registering Courses with register_post_type()

This section uses WordPress’s init hook to run a call to register_post_type() with a number of arguments given by an $args array. If you’ve never registered a custom post type before, check out the Codex’s description of register_post_type() itself. The $args-and-a-function-within-a-WordPress-hook setup is absolutely core to WordPress, and register_post_type() isn’t too hard to understand if you’re familiar with that pattern.

The one thing I want to mention is that manually including a 'supports' parameter within $args was necessary for us. If you leave it out of $args entirely, your custom post type has some properties by default, but doesn’t have some (like excerpts) that we wanted. And if you include just 'supports' => 'excerpts', then it’ll turn off everything else—like post titles, authors, or content. So we felt it necessary to list every standard feature we want our Courses to have:

'supports' => array( 
	'title',
	'editor',
	'author',
	'thumbnail',
	'excerpt',
	'comments',
	'revisions'
)

2. Adding Existing Taxonomies to the Courses Custom Post Type

This simple section uses three calls to register_taxonomy_for_object_type() to register the category, post_tag, and difficulty taxonomies for Courses. These three lowercase strings are the “slugs” for the Category, Tag, and Difficulty taxonomies. We had to look them up for Category and Tag (since those are WordPress default taxonomies), and we knew that we’d given Difficulty the difficulty slug when we’d registered it.

The end result looks like this:

wordpress taxonomies on custom post type

Click to enlarge

Credit to Pippin Williamson for this section’s basic code. As a note, Pippin recommends that you use the plugins_loaded hook rather than the init hook if you’re doing this in a plugin; however, we tried this, and only init worked for us.

3. Using pre_get_posts() to Add Courses to Archive Pages

This last piece is essential if you want users to be able to actually click, for example, “Intermediate” and see a list of all Intermediate posts and Courses. It uses a function that hooks into WordPress’s important pre_get_posts hook (which we’ll be explaining in detail soon!) to modify the query on every archive page such that both posts and courses are included.

Here is the function’s code again, with logic written in more detail as comments:

function wpshout_add_custom_post_types_to_query( $query ) {	
	if( 
		// If we're trying to generate an archive page, and
		is_archive() &&

		// If the current query is the page's main query, and
		$query->is_main_query() &&

		// If the query hasn't already been modified to ignore
		// filters like the one we're writing
		empty( $query->query_vars['suppress_filters'] )
	) {

		// Then set the query to fetch posts of type
		// both "post" and "course"
		$query->set( 'post_type', array( 
			'post',
			'course'
		) );
	}
}

The final result (on a staging site I keep locally) looks like:

Archive page with mixed post types

Click to enlarge

(Credit for this basic code pattern to CSS-Tricks. Note that we changed their is_category() || is_tag() check to just is_archive(), which covers all types of archives pages, including, for example, author pages.)

Now You Know How to Add Taxonomies to Custom Post Types

Thanks for reading. Again, each step in this process is somewhat simple, but knowing you have to do all three was a bit of an “Aha” moment as I did this myself.

As always, we’d love to read questions or comments below!

Image credit: evelynishere


6 Responses

Comments

  • Redrambles says:

    Excellent article!! Thank you.

  • Riccardo says:

    Thanks for this very clear and easy article, I was just looking for such information because I wanna add Tags feature to my portfolio custom type post and then allowing those custom type posts to be visible in the query result inside an archive page.
    Next day I will try hope to be successful.
    Many thanks, your articles are always clear and easy to understand even for a newbie as me.

    Riccardo

Pingbacks