WordPress Archive Pages Based on Custom Taxonomy

Please Note: This article has since been extended. Please read more up-to-date information in Revisiting Custom Post Types, Custom Taxonomies, and Permalinks

Note: This article is an extension of Custom Post Types, Custom Taxonomies, and Permalinks in WordPress 3.0 which discusses the Custom Post Type and Custom Taxonomy implementation we’ve setup thus far. While a summary is offered here, please know that some details discussed herein reflect the implementation discussed previously.

In order to set up front end visible archive pages for Custom Taxonomies, everything begins with the rewrite slug attached to your Custom Taxonomy. This can be edited using the Custom Rewrite Slug field provided by Custom Post Type UI. Some planning is required on your part, but the plan must take into consideration the Page structure currently implemented.

So far, we’ve based our Cameras Custom Post Type on the slug of /cameras/. This works out well as our Custom Post Type houses information based on DSLR Cameras. We’ve set up an index-style page that sits at /cameras/, and our single pages are stored under /cameras/%postname%/. We’ve just now included a Custom Taxonomy, and we’d like to include that in the mix as well.

Out of the box taxonomy permalinks

By default, a Custom Taxonomy rewrite slug is based on the Taxonomy Name. Considering our Brands Custom Taxonomy, we might expect the Taxonomy listing would be made available at /cameras/brands/%taxonomyname%/; unfortunately that’s not the case. Given the Taxonomy being a default implementation, we’d actually find the listing at /brands/%taxonomyname%/. You’ll also note that any Cameras we’ve marked under a particular brand will show up in the listing. For example, if we navigated to http://wordpress/cpt/brands/canon/, we’d be faced with a page resembling:

Default post listing based on taxonomy

This listing behaves just like a regular Posts archive page would, and that’s because it’s literally based on the archive.php template file of your theme. While it works, it’s not ideal. Thinking ahead, if you have multiple Custom Post Types along with WordPress posts, there isn’t much segmentation when it comes to actually viewing archive pages on the front end.

Take into consideration the possibility of us expanding our content by also including a Custom Post Type for Flashes. If we were to use a Custom Taxonomy for Flash Brands (as opposed to Camera Brands) with that Custom Post Type as well, we’d have overlapping entries and it would quickly become unorganized as results for both flashes and cameras would turn up when viewing http://wordpress/cpt/brands/canon/ which isn’t always desirable.

At this point it’s important to note the specificity of a Custom Post Type/Custom Taxonomy implementation. There is a strong possibility that you very well may want to merge Canon flashes and cameras in your archive pages, but you may not. For the purpose of example, we’re going to deem it necessary to segment the two. To accomplish that, you’ll need to beef up the rewrite slug for your Custom Taxonomies.

Customizing your Custom Taxonomy template

When dealing with taxonomies, WordPress looks for specific theme files. As with other theme files, templates for Custom Taxonomies can be based on the taxonomy name, in this case brands. Create a file called taxonomy-brands.php in your theme directory, WordPress checks for this file before hitting archive.php which can allow you to make the front end more custom. As an example, we’ll use the following for our taxonomy-brands.php:

<?php get_header(); ?>
<?php $term = get_term_by( 'slug', get_query_var( 'term' ), get_query_var( 'taxonomy' ) ); ?>
<div id="container">
<div id="content" role="main">
<h1 class="page-title"><?php echo $term->name; ?> Archives</h1>
<?php if (have_posts()) : ?>
<?php while (have_posts()) : the_post(); ?>
<div class="post type-post hentry">
<h2 class="entry-title">
<a href="<?php echo get_permalink(); ?>" title="<?php the_title(); ?>" rel="bookmark">
<?php the_title(); ?>
<div class="entry-meta">
<span class="meta-prep meta-prep-author">Posted on</span>
<a href="<?php echo get_permalink(); ?>" title="<?php the_time( 'g:i a' ); ?>" rel="bookmark">
<span class="entry-date"><?php the_time( 'F j, Y' ); ?></span></a>
</div><!-- .entry-meta -->
<div class="entry-summary">
<?php the_excerpt(); ?>
</div><!-- .entry-summary -->
<?php endwhile; ?>
<?php endif; ?>
</div><!-- #content -->
</div><!-- #container -->
<?php get_sidebar(); ?>
<?php get_footer(); ?>
view raw functions.php hosted with ❤ by GitHub

This file is based on category.php with a few modifications. First is the call to get_term_by() which uses get_query_var() to determine what Custom Taxonomy term we’re working with. From there, we carry on through The Loop as normal, outputting the information we’d like to use and where.

The only lasting problem here, is the fact that we’re still sitting at http://wordpress/cpt/brands/canon/. I’d much rather have this page available at http://wordpress/cpt/cameras/brands/canon/ as to differentiate it from other Custom Post Types and their Custom Taxonomies.

Correctly identifying your rewrite slug

Custom Post Type UI makes it really easy to modify our Custom Rewrite Slug, which controls this change entirely. As mentioned earlier, a rewrite slug, unless otherwise defined, is based on the Custom Taxonomy name itself, hence our current /brands/%taxonomyname%/ result. We simply need to change our Custom Rewrite Slug to include the URL structure we’re looking for, in this case cameras/brands:

Refining the slug used for a taxonomy archive page

Saving the change to our Custom Taxonomy rewrite slug will push the permalink change and we’ll finally be able to hit our more appropriate http://wordpress/cpt/cameras/brands/canon/ URL, right? Not quite. It turns out that if we hit http://wordpress/cpt/cameras/brands/canon/ WordPress thinks we’re trying to hit a single post from our Cameras Custom Post Type and redirects us to the closest match.

In order to get our final archives-style pages to load properly, we’re going to have to modify our Custom Post Type Custom Rewrite Slug to differentiate a request for a single post entry versus our archive-style pages. To do that, we’ll need to change the slug from cameras to something more appropriate like cameras/body which could signify that we’re viewing a camera body.

With that change in place, we’re in business! We’re now able to hit http://wordpress/cpt/cameras/brands/canon/ and view the Posts that have been marked as Canon Posts, using our custom permalink as well as our custom template file. You can repeat this process with additional taxonomies by creating appropriate rewrite slugs in conjunction with new taxonomy-%taxonomyname%.php template files.

Adding links to Taxonomy archives in the sidebar

Many of the WordPress-native functions can be adapted for use with Custom Post Types and Custom Taxonomies. To add links to your newly created Custom Taxonomy archive pages, you could add something like this snippet to your sidebar.php:

<li id="camera-brands" class="widget-container">
<h3 class="widget-title">Camera Brands</h3>
<?php $cam_brands = get_terms('brands', 'hide_empty=1'); ?>
<?php foreach( $cam_brands as $brand ) : ?>
<a href="<?php echo get_term_link( $brand->slug, 'brands' ); ?>">
<?php echo $brand->name; ?>
$wpq = array( 'post_type' => 'cameras', 'taxonomy' => 'brands', 'term' => $brand->slug );
$brand_posts = new WP_Query ($wpq);
<?php foreach( $brand_posts->posts as $post ) : ?>
<a href="<?php echo get_permalink( $post->ID ); ?>">
<?php echo $post->post_title; ?>
<?php endforeach ?>
<?php endforeach ?>
view raw functions.php hosted with ❤ by GitHub

While a bit of the markup is specific to Twenty Ten’s sidebar.php we can dissect what’s going on here:

  1. Pull our brands
  2. Create a list item for our brand
  3. Pull all posts that have been marked as being that brand (via the taxonomy and term arguments)
  4. Loop through each post within that defined Custom Taxonomy entry and dump out what we’d like to use
  5. Repeat until finished with all Custom Taxonomy entries

When incorporated into the sidebar, we’ll get something like this:

Customized sidebar based on Custom Post Types and Custom Taxonomies

As you can imagine, that sidebar listing would quickly grow to an unmanageable size, but the example illustrates just what’s possible using a few WordPress native functions and your Custom Post Types/Custom Taxonomies.

Custom Post Types and Custom Taxonomies are powerful

These changes in WordPress 3.0 are more than welcome, as they’re going to set the stage for much more traditional CMS-like behavior. The implementation discussed in this short series of articles is quite specific but hopefully outlines one of the many ways to work with Custom Post Types and Custom Taxonomies, all the while keeping a prettier permalink structure throughout your sites.