By default, WordPress creates archives which list all of your posts in reverse order. If users are looking for posts in a certain category or with a given taxonomy term, they'll have to visit the archive page for that category or term.
But what if you want to make your main archive for a post type more user-friendly? In this tutorial, I'll show you how to create an archive page for a custom post type which displays posts of that post type categorized according to a taxonomy, so that instead of one long list visitors will see a list for each taxonomy term.
What You'll Need
To follow this tutorial you'll need a development installation of WordPress and a code editor. You'll be creating a theme which is a child theme of twentyfourteen, so you'll need that installed (which it should be by default).
I'm not going to show you how to create a child theme, but if you're stuck, just have a look at the stylesheet in the code bundle for this tutorial.
1. Getting Started: Registering the Post Type and Taxonomy
In my experience this technique is most commonly needed for custom post types and taxonomies rather than for normal posts and categories or tags, so I'll start by registering a post type and taxonomy.
Note: I'm using the same 'animal' post type that I registered in an earlier tutorial on creating an image-based archive. If you want to push things a bit further, you could combine the technique in that tutorial with the one I'm showing you here and display your taxonomy term lists with featured images.
In your theme's functions file, add the following code to register the post type:
// register a custom post type called 'animals' function wptp_create_post_type() { $labels = array( 'name' => __( 'Animals' ), 'singular_name' => __( 'animal' ), 'add_new' => __( 'New animal' ), 'add_new_item' => __( 'Add New animal' ), 'edit_item' => __( 'Edit animal' ), 'new_item' => __( 'New animal' ), 'view_item' => __( 'View animal' ), 'search_items' => __( 'Search animals' ), 'not_found' => __( 'No animals Found' ), 'not_found_in_trash' => __( 'No animals found in Trash' ), ); $args = array( 'labels' => $labels, 'has_archive' => true, 'public' => true, 'hierarchical' => false, 'supports' => array( 'title', 'editor', 'excerpt', 'custom-fields', 'thumbnail', 'page-attributes' ), 'taxonomies' => array( 'post_tag', 'category'), ); register_post_type( 'animal', $args ); } add_action( 'init', 'wptp_create_post_type' );
Next, add the code to register the taxonomy:
// register a taxonomy called 'Animal Family' function wptp_register_taxonomy() { register_taxonomy( 'animal_cat', 'animal', array( 'labels' => array( 'name' => 'Animal Families', 'singular_name' => 'Animal Family', 'search_items' => 'Search Animal Families', 'all_items' => 'All Animal Families', 'edit_item' => 'Edit Animal Families', 'update_item' => 'Update Animal Family', 'add_new_item' => 'Add New Animal Family', 'new_item_name' => 'New Animal Family Name', 'menu_name' => 'Animal Family', ), 'hierarchical' => true, 'sort' => true, 'args' => array( 'orderby' => 'term_order' ), 'rewrite' => array( 'slug' => 'animal-family' ), 'show_admin_column' => true ) ); } add_action( 'init', 'wptp_register_taxonomy' );
Once you've done this, add some data. Below you can see the data I've added with some taxonomy terms applied. I don't make any claim for the accuracy of my terminology with regard to animal families, so please don't comment if I've got that wrong!
2. Setting Up the Archive Template
The next step is to create an archive template for the new post type. In your theme, create a new file called archive-animal.php
.
As this theme is a child theme of twentyfourteen, the archive template will need code copied from that theme as a wrapper for the custom loop you're going to create. So add the following to your archive template:
<?php /* WpTutsPlus tutorial for creating archive to display posts by taxonomy term Archive template for animal custom post type */ ?> <?php get_header(); ?> <div id="main-content" class="main-content"> <div id="primary" class="content-area"> <div id="content" class="site-content" role="main"> <header class="archive-header"> <h1 class="archive-title"> <?php post_type_archive_title(); ?> </h1> </header><!-- .archive-header --> </div><!-- #content --> </div><!-- #primary --> <?php get_sidebar( 'content' ); ?> </div><!-- #main-content --> <?php get_sidebar(); get_footer();
Note: If you're working with your own theme, copy the wrapping code from your own theme's index or archive file.
3. Populating the Archive Template: Fetching Taxonomy Terms
So that your archive can display animals by taxonomy term, the next step is to fetch those terms.
In your new template file, below the closing </header>
tag (or below the opening part of your wrapping code if you're using your own theme), fetch the terms using get_terms()
:
<?php //start by fetching the terms for the animal_cat taxonomy $terms = get_terms( 'animal_cat', array( 'orderby' => 'count', 'hide_empty' => 0 ) ); ?>
Note that I've used two parameters here:
-
orderby
- this allows you to specify the order of the terms displayed. I've usedcount
as the value so that the term with the most posts assigned to it will be displayed first, but you could order by name or ID - if you leave this blank, WordPress will order by name. See the Codex page onget_terms()
for more details. -
hide_empty
- this tells WordPress not to fetch any terms without posts assigned to them. It saves you having to check if your query has any posts later on.
4. Populating the Archive Template: Defining the Query
Having done this, you use foreach()
to tell WordPress to pass through each of these terms and run a query which you need to define. Below the code you just added, insert the following:
<?php // now run a query for each animal family foreach( $terms as $term ) { // Define the query $args = array( 'post_type' => 'animal', 'animal_cat' => $term->slug ); $query = new WP_Query( $args ); }
This tells WordPress to run through each term, and then defines the query it has to run each time. The arguments for the query include the post type and the term in the 'animal_cat'
taxonomy, which is the value of the $term
variable.
5. Populating the Archive Template: Adding a Loop
Having defined your query, you need to add a loop. First, output the name of the term being queried as a heading. Below the line beginning $query
but inside the braces of the foreach
statement, add this line:
echo'<h2>' . $term->name . '</h2>';
Next, add the code to contain your posts in a list:
// output the post titles in a list echo '<ul>'; echo '</ul>';
Inside the list, now add your loop:
// Start the Loop while ( $query->have_posts() ) : $query->the_post(); ?> <li class="animal-listing" id="post-<?php the_ID(); ?>"> <a href="<?php the_permalink(); ?>"><?php the_title(); ?></a> </li> <?php endwhile;
As you can see , this is a straightforward loop which outputs the title of each post inside a link to the post, and doesn't output any content. If you wanted you could add an excerpt or featured image here.
Finally, reset the query using wp_reset_postdata()
below the line reading echo '</ul>';
The Whole Loop
This is what your query and loop will now look like:
<?php // now run a query for each animal family foreach( $terms as $term ) { // Define the query $args = array( 'post_type' => 'animal', 'animal_cat' => $term->slug ); $query = new WP_Query( $args ); // output the term name in a heading tag echo'<h2>' . $term->name . '</h2>'; // output the post titles in a list echo '<ul>'; // Start the Loop while ( $query->have_posts() ) : $query->the_post(); ?> <li class="animal-listing" id="post-<?php the_ID(); ?>"> <a href="<?php the_permalink(); ?>"><?php the_title(); ?></a> </li> <?php endwhile; echo '</ul>'; // use reset postdata to restore orginal query wp_reset_postdata(); } ?>
Finally, save your template file and view your post type archive. You'll see that it lists your posts by taxonomy term rather than in one long list.
Summary
This technique is useful when you want visitors to be able to quickly see categorised data without having to look at a range of archive pages - it brings it all together in one place but sorted for convenience. Here are some ideas for how you could adapt the technique and take it further:
- Call categories or tags instead of terms. To do this, you would use
get_categories()
orget_tags()
. - Instead of creating a custom archive for a post type, use this technique in your
index.php
file to display posts by category, tag or taxonomy terms. - Instead of running one loop for each term, run two: the first one can display the most recent post with that term in full and the second one can display a list of all the rest of the posts. Use
posts_per_page
andoffset
in your query arguments to do this - see details of how this work on the WP_Query Codex page. - Use
posts_per_page
to limit the number of posts displayed so that each list is the same length. You could combine this with styling to display lists side by side.
- For each term, add a link to the term archive page after the list of posts - this is particularly useful if you're not displaying all of the posts in your list. Use
get_term_link()
to do this.
Comments