Complex WordPress IA 2: Custom Taxonomy Navigation

Part 1.

Before we dive in,  I forgot to include the code that actually shows the pages.  I won’t go in to it, because it’s covered here: in detail, but after we end our custom query loop, we want to insert another if statement to see if it’s paged or not.  If it’s paged, it will display our pagination.

What is a Custom Taxonomy?

A Custom Taxonomy is simply a grouping (taxonomy) that we, the developer, create, based on the needs of the project.  WP only comes with two default taxonomies, Categories and Tags.  While useful for illustrating the concept of what a taxonomy is, they can be very limiting and increase confusion on a site because a category or tag archive will pull every post and page that is tagged with that category or tag. Most of the time if you want an archive, you want to make it easier to find a specific type of post, and it gives us a lot more flexibility in organizing content.

In this lesson we’re going to:

  1. Create taxonomy-genre.php
  2. Create an in-page navigation element that lists all the genres and
  3. insert that element in to both templates.

First, creating templates is easy in WordPress.  We do the exact same thing we did last time. In our text-editor, open a new file, save as taxonomy-genre.php and we’re on our way.  We can do this because of the WordPress Template Hierarchy, which I’ve mentioned before.

The template hierarchy describes how the software finds the appropriate files to serve. If it can’t find the most specific file, it finds the next most specific, then the next, until it gets back to index.php.  Sidenote – when making your own WP theme or reviewing someone else’s work, templates should always be named according to the WP theme standards and coded to their spec. It’s not simply good practice, it’s manners, and those conventions exist for a reason.

Off of my soapbox.

Step 1: Custom Taxonomy Archive

In the case of custom post types the hierarchy is this:

  1. archive-customposttype-slug.php (where slug is the name of a specific item in that post)
  2. archive-customposttype.php
  3. archive.php

and the same logic applies to taxonomies. When in doubt, get more specific!  It helps for debugging.

We’ll make sure we include the header ( get_header() ) and the footer ( get_footer() ) and then copy in our code from archive-songs.php, because the same basic format will be used, just with slightly different logic.

Step 2: The Loop

For the loop, we’re going to add the $tax_query parameter.  Tax Query takes an array of arrays, and is in an array itself!  So our new custom query looks like:
// Define custom query parameters
$custom_query_args = array(
'post_type' => 'songs',
'tax_query' => array(
'taxonomy' => 'genre',
'field' => 'slug',
'terms' => $term->slug,


The query is getting posts of the post type songs, with a genre assigned to them, matching the slug of the term.

The logical question is, what is $term?

$term is a variable we need to set.  this should look a little familiar, but basically we’re setting $term to equal the slug of the page we’re on. Here’s that code, and we need to include this inside a php tag before our query.

$term = get_term_by( 'slug', get_query_var( 'term' ), get_query_var( 'taxonomy' ) );

This modifies our query to output only the Songs matching the Genre in the slug of the page that we’re looking at. Pretty cool huh?

Step 3: The tiny nav

Let’s take this one step further.  We can now add a navigation element to both templates using the same code to get all of the Genres so we can navigate between genres easily!  This is a win because primary site navigation has to reflect priorities and even important content like this may not be the most important 2-6 links.

Pro tip: the easiest way to make sense of navigation is to avoid overstuffing it in the first place.

I’m using a design pattern which you can find here. There is a tiny javascript dependency,  but the logic on it is pretty simple – basically, replace the full list with a select menu when the browser window is small enough.

But how to dynamically (that is, tell WordPress to automatically insert) our Genres in to the list?

We’re going to start by creating variables.  Inside of a php tag, paste in:

$taxonomy = 'genre';
$orderby = 'name';
$show_count = false;
$title = '';
$args = array(
'taxonomy' => $taxonomy,
'orderby' => $orderby,
'show_count' => $show_count,
'title_li' => $title,
'use_desc_for_title' => 0,
'current_category' => 0,

Then, we’re going to pass those arguments to a WordPress function called get_categories, and store that result in one final variable, $categories, like so:

$categories = get_categories($args)

Last, inside of of the nav element we’ve just made, we’ll make a foreach loop. For PHP newbs, the syntax can be a little challenging, but basically we’re telling WordPress that, for each Genre, output this specific chunk of html.  And, we’re also taking advantage of WordPress get_categories, because if it’s the current category, it will now append the class “current-cat” to the list item. This allows us to style the list to show a user what genre they are on.

foreach ( $categories as $category ) {

$term_id = $category->term_id;
$term_slug = $category->slug;
$term_name = $category->name;
$term_URL = get_category_link( $category->term_id );
$class = 'current-cat';
if ($term_slug == $term->slug) {
echo '<li class="cat-item cat-item-'. $term_id .' '. $class .'">'.'<a href="'.$term_URL .'">'. $term_name .'</a>'.'</li>';
} else {
echo '<li class="cat-item cat-item-'. $term_id .'">'.'<a href="'.$term_URL .'">'. $term_name .'</a>'.'</li>';

We’re wrapping each term name in the link to the term’s unique page.

This won’t include a link back to the songs archive, but that’s easy enough to include manually, like so:
<li><a href="/songs">ALL</a></li>

There you go!  To recap,  we now have the templates we need to show all of the songs, and all of the songs by a specific genre. Our custom taxonomy of genre is all set up to work automagically.

Next time, we’ll cover how to set up parent and child pages, and how to show sibling pages when you’re on a child for our discogrpahy and album pages.