Ensuring custom post types show up on Wordpress categories & tags archive pages

Topics: 

wordpress-logo-stacked-rgb.pngThe default behaviors built into Wordpress drive me batty sometimes, because they've made certain assumptions that aren't always right. One of these are that the built-in Categories and Tags taxonomies are somehow special. In particular if you create a custom post type, then associate that post type with either Categories and Tags, the category or tag archive pages won't show posts for your custom post type.

Let me explain to make this clearer. On http://longtailpipe.com I have a bunch of custom post types. I'm a long-time Drupaler, and custom post types are what we do, and therefore I was happy to find a Wordpress plugin (PODS) to help with making custom post types. But I digress. For several of the post types I associated them with Categories and Tags because I wanted those posts to appear on the same category pages alongside the regular blog posts.

Imagine my surprise - I wanted to add a textual description to the archive pages, so I went to one Tag and entered a description and then went to the corresponding archive page (http://longtailpipe.com/tags/bicycling/) expecting to see the all the postings with that tag. Instead it only showed the regular blog posts with that tag, and not the video posts.

There is no configuration option anywhere in the back-end area to configure this behavior. And, it turns out this is the intended behavior.

After some yahoogling I learned that "the developers at WordPress maintain that sorting archives is for normal post types for which WordPress was created, and adding in that functionality for custom post types requires some custom code. And indeed it does." I maintain that this behavior is a bug.

Fortunately it's easy to work around this bug, but that doesn't make it any less of a bug.

Simply add this to the functions.php of your theme:

function nirvana_ltp_add_custom_types_to_tax( $query ) {
    if (is_category() || is_tag() && empty($query->query_vars['suppress_filters'])) {

        // Get all your post types
        $post_types = get_post_types();

        $query->set('post_type', $post_types);
        return $query;
    }
}
add_filter('pre_get_posts', 'nirvana_ltp_add_custom_types_to_tax');

What does this piece of magic do?

The pre_get_posts filter is called (according to the Codex) "after the query variable object is created, but before the actual query is run."

Remember that the Archive page template (archives.php, category.php, etc) is called with a pre-configured pre-executed query (WP_Query) ready to be looped. What Wordpress does out of the box is ensure the WP_Query parameters only look for Post items, and not the other post types. What this code does is to a) detect it's being executed for an archive page, then to b) modify the WP_Query parameters to include all post types.

Voila, Category and Tags archive pages suddenly query against all post types, and all your postings show up on the archive pages, and everyone is all happy again.