A Guide to WordPress Custom Post Types: Taxonomies, Admin Columns, Filters and Archives


Before diving into this tutorial please go through my first tutorial on Custom Post Types, where I have explained some of the important aspects of CPTs (Custom Post Types). In this tutorial we shall explore more about this wonderful feature in WordPress.

This tutorial covers how to create custom taxonomies, admin columns, taxonomy filters and an archive page for your CPT. So let's begin.

Custom Taxonomy for Custom Post Types

Taxonomies are a great way to group things together and help us to search posts belonging to a specific group. In WordPress we generally use Categories and Tags as taxonomies. The steps given below explain how to create custom taxonomies for your CPT.

Step 1 : Register Custom Function

Open your plugin file, in our case Movie-Reviews.php and add the following code to register the custom function.

add_action( 'init', 'create_my_taxonomies', 0 );

Step 2 : Implementation of Custom Function and Registering Custom Taxonomy

function create_my_taxonomies() {
			'labels' => array(
				'name' => 'Movie Genre',
				'add_new_item' => 'Add New Movie Genre',
				'new_item_name' => "New Movie Type Genre"
			'show_ui' => true,
			'show_tagcloud' => false,
			'hierarchical' => true

Here the register_taxonomy function does all the hard work of creating a custom taxonomy (in our case a category) with the name 'movie_reviews_movie_genre' for the custom post type 'movie_reviews'. The labels define the different strings used in the admin section of the taxonomy.

  • 'show_ui' => true is used to make the taxonomy editor visible in the dashboard.
  • 'show_tagcloud' => false decode whether the tag cloud should be visible. In our case it's disabled.
  • 'hierarchical' => true decodes the format of the custom taxonomy.

Note: 'hierarchical' => false converts the categories into tags.

Step 3 : Displaying Custom Taxonomies

After saving the Movie-Reviews.php file, open your custom template file, in our case single-movie_reviews.php and add the following highlighted code to make the categories visible in our posts.

 /*Template Name: New Template
get_header(); ?>
<div id="primary">
    <div id="content" role="main">
     <?php $mypost = array( 'post_type' => 'movie_reviews', );
      $loop = new WP_Query( $mypost ); ?>
	  <!-- Cycle through all posts -->
      <?php while ( $loop->have_posts() ) : $loop->the_post();?>
          <article id="post-<?php the_ID(); ?>" <?php post_class(); ?>>
	          <header class="entry-header">
                <!-- Display featured image in top-aligned floating div -->
                 <div style="float: top; margin: 10px">
                    <?php the_post_thumbnail( array( 100, 100 ) ); ?>
				 <!-- Display Title and Author Name -->
				 <strong>Title: </strong><?php the_title(); ?><br />
                 <strong>Director: </strong>
                 <?php echo esc_html( get_post_meta( get_the_ID(), 'movie_director', true ) ); ?>
                 <br />
				<strong>Genre: </strong>
				the_terms( $post->ID, 'movie_reviews_movie_genre' ,  ' ' );
<br />
                 <!-- Display yellow stars based on rating -->
                <strong>Rating: </strong>
                $nb_stars = intval( get_post_meta( get_the_ID(), 'movie_rating', true ) );
                for ( $star_counter = 1; $star_counter <= 5; $star_counter++ ) {
                    if ( $star_counter <= $nb_stars ) {
                        echo '<img src="' . plugins_url( 'Movie-Reviews/images/icon.png' ) . '" />';
                    } else {
                        echo '<img src="' . plugins_url( 'Movie-Reviews/images/grey.png' ). '" />';
			  <!-- Display movie review contents -->
	          <div class="entry-content">
	               <?php the_content(); ?>
   <?php endwhile;  ?>
<?php wp_reset_query(); ?>
<?php get_footer(); ?>

Step 4 : The Result

Here we have added a custom taxonomy 'Movie Genre' in our movie reviews CPT. Now we will be able to add new categories from the admin panel and assign each of them to our CPT.

Displaying Additional Columns

In the WordPress admin CPT listing page, by default two columns exist - Date and Comments - through which we can sort those CPT items. In order to add extra columns and sorting please follow the steps given below.

Step 1 : Register Function

Open the plugin file Movie-Reviews.php and add the following line of code to register a function to be called when the Movie Reviews listing page is being prepared.

add_filter( 'manage_edit-movie_reviews_columns', 'my_columns' );

Here we have used the variable filter manage_edit-(Custom_Post_Type)_columns, which passes the column list of the CPT as an argument to the function.

Step 2 : Implementation of the Function

function my_columns( $columns ) {
	$columns['movie_reviews_director'] = 'Director';
	$columns['movie_reviews_rating'] = 'Rating';
	unset( $columns['comments'] );
	return $columns;

Here we have added two columns: Director and Rating in the admin panel of the CPT and also deleted the Comments column from the listing.

Step 3 : Populating the Columns

Register a function to populate the columns.

add_action( 'manage_posts_custom_column', 'populate_columns' );

Step 4 : Implementation

function populate_columns( $column ) {
	if ( 'movie_reviews_director' == $column ) {
		$movie_director = esc_html( get_post_meta( get_the_ID(), 'movie_director', true ) );
		echo $movie_director;
	elseif ( 'movie_reviews_rating' == $column ) {
		$movie_rating = get_post_meta( get_the_ID(), 'movie_rating', true );
		echo $movie_rating . ' stars';

Here since the function gets executed when any of the CPT columns is rendered, it checks for the currently requested columns before echoing them. We have used the get_the_ID() function to retrieve the index of the current row and then in turn have used the get_post_meta to retrieve the data in the column.

Step 5 : Register Columns as Sortable

Now let us register a function to be called when WordPress identifies sortable columns in CPT.

add_filter( 'manage_edit-movie_reviews_sortable_columns', 'sort_me' );

Step 6 : Implementation

function sort_me( $columns ) {
	$columns['movie_reviews_director'] = 'movie_reviews_director';
	$columns['movie_reviews_rating'] = 'movie_reviews_rating';

	return $columns;

This function identifies two columns to make them sortable and then returns the array. But our work hasn't finished yet.

Step 7 : Order by Custom Field

add_filter( 'request', 'column_ordering' );

add_filter( 'request', 'column_orderby' );

function column_orderby ( $vars ) {
	if ( !is_admin() )
		return $vars;
	if ( isset( $vars['orderby'] ) && 'movie_reviews_director' == $vars['orderby'] ) {
		$vars = array_merge( $vars, array( 'meta_key' => 'movie_director', 'orderby' => 'meta_value' ) );
	elseif ( isset( $vars['orderby'] ) && 'movie_reviews_rating' == $vars['orderby'] ) {
		$vars = array_merge( $vars, array( 'meta_key' => 'movie_rating', 'orderby' => 'meta_value_num' ) );
	return $vars;

The above function is associated with the request filter and adds elements to the query array, based on the variables in the query URL. Actually WordPress doesn't know how to order by the fields 'Movie Director' or 'Movie Rating', so we need to teach WordPress how to do that through this function.

We have successfully added two sortable columns in the admin section.

Creating Filters With Custom Taxonomy

Here we shall see how custom taxonomies (in this case, categories) can be used as an additional filter in the CPT listing page in the WordPress admin, so that administrators can display CPT elements belonging to a specific category.

Step 1 : Register the Function

Open your plugin file and add the following code to register a function to be called when WordPress is preparing to display the filter drop down list.

add_action( 'restrict_manage_posts', 'my_filter_list' );

Step 2 : Implementation of the Function

function my_filter_list() {
	$screen = get_current_screen();
	global $wp_query;
	if ( $screen->post_type == 'movie_reviews' ) {
		wp_dropdown_categories( array(
			'show_option_all' => 'Show All Movie Genres',
			'taxonomy' => 'movie_reviews_movie_genre',
			'name' => 'movie_reviews_movie_genre',
			'orderby' => 'name',
			'selected' => ( isset( $wp_query->query['movie_reviews_movie_genre'] ) ? $wp_query->query['movie_reviews_movie_genre'] : '' ),
			'hierarchical' => false,
			'depth' => 3,
			'show_count' => false,
			'hide_empty' => true,
		) );

Here we have used a global variable to know the type of post that is being displayed and also used a post query variable to check if there is already an existing filter and accordingly set the filter. The wp_dropdown_categories function is used to display all the taxonomies registered with Movie Genres. The 'orderby', 'show_count', 'hide_empty', 'depth' etc. are different arguments specifying sorting, show items count on each category, hide non associated categories, determine the maximum depth to be shown for the hierarchical categories respectively.

Step 3 : Display Filtered Results

Now after the filter drop down list has been prepared, we shall write some code to display the filtered results. Register a function to be called when the post display query is prepared.

add_filter( 'parse_query','perform_filtering' );

Step 4 : Implementation of the Display Function

function perform_filtering( $query ) {
	$qv = &$query->query_vars;
	if ( ( $qv['movie_reviews_movie_genre'] ) && is_numeric( $qv['movie_reviews_movie_genre'] ) ) {
		$term = get_term_by( 'id', $qv['movie_reviews_movie_genre'], 'movie_reviews_movie_genre' );
		$qv['movie_reviews_movie_genre'] = $term->slug;

The perform_filtering function receives the current WordPress post query object and then commences by getting a pointer to the query variables stored inside the query object. Then it verifies if a Movie Genre is a part of the query variables and then executes the query.

Now you will be able to use the filter to display the Movies by their Genres.

Last but Not the Least: Create an Archive Page

As we have created a custom template for our CPT, we can also create a custom archive page overriding the default archive template.

Step 1 : Adding a Fallback to the Archive Template

Open the plugin file Movie-Reviews.php and the add the highlighted code in the include_template_function function.

function include_template_function( $template_path ) {
	if ( get_post_type() == 'movie_reviews' ) {
		if ( is_single() ) {
			// checks if the file exists in the theme first,
			// otherwise serve the file from the plugin
			if ( $theme_file = locate_template( array ( 'single-movie_reviews.php' ) ) ) {
				$template_path = $theme_file;
			} else {
				$template_path = plugin_dir_path( __FILE__ ) . '/single-movie_reviews.php';
		elseif ( is_archive() ) {
			if ( $theme_file = locate_template( array ( 'archive-movie_reviews.php' ) ) ) {
				$template_path = $theme_file;
			} else { $template_path = plugin_dir_path( __FILE__ ) . '/archive-movie_reviews.php';

	return $template_path;

WordPress searches through the theme directory for an archive template file before using the default one. This function checks if the user has provided an archive template in the theme directory else it looks for the file in the plugin's folder.

Step 2 : Create the Archive Template

Save and Close the plugin file and then create a new file called archive-movie_reviews.php and add the following code into it.

<?php get_header(); ?>
<section id="primary">
	<div id="content" role="main" style="width: 70%">
	<?php if ( have_posts() ) : ?>
		<header class="page-header">
			<h1 class="page-title">Movie Reviews</h1>
			<!-- Display table headers -->
				<th style="width: 200px"><strong>Title</strong></th>
			<!-- Start the Loop -->
			<?php while ( have_posts() ) : the_post(); ?>
				<!-- Display review title and author -->
					<td><a href="<?php the_permalink(); ?>">
					<?php the_title(); ?></a></td>
					<td><?php echo esc_html( get_post_meta( get_the_ID(), 'movie_director', true ) ); ?></td>
			<?php endwhile; ?>

			<!-- Display page navigation -->

		<?php global $wp_query;
		if ( isset( $wp_query->max_num_pages ) && $wp_query->max_num_pages > 1 ) { ?>
			<nav id="<?php echo $nav_id; ?>">
				<div class="nav-previous"><?php next_posts_link( '<span class="meta-nav">&larr;</span> Older reviews'); ?></div>
				<div class="nav-next"><?php previous_posts_link( 'Newer reviews <span class= "meta-nav">&rarr;</span>' ); ?></div>
		<?php };
	endif; ?>
<br /><br />
<?php get_footer(); ?>

Here we have used the loop to cycle through the post entries and then display them using a table layout. We have also defined a navigation menu if there are more items than the maximum number configured under WordPress Settings. Navigation menus are displayed using the next_post_links and previous_post_links functions.

We have used the global wp_query object containing the data about the currently executed query, in order to render the page contents. The get_post_meta function has been used to retrieve custom field data.

Step 3 : The Result

Save the file and check the archive page for the Movie Reviews archive list.

Here we come to the end of this tutorial. I hope you have been able to grasp the significance of Custom Post Types. There is more to explore, just play around with it.

Thanks for reading and feel free to give your feedback.

Related Posts
  • Code
    Creative Coding
    Advanced Use of Attachments in WordPress: Creating Custom Queries for AttachmentsAdvanced use of attachments in wordpress 400
    This tutorial is the second in a four part series in which you'll learn some techniques for working with images in attachments in WordPress which give you advanced options.Read More…
  • Code
    Creative Coding
    Advanced Use of Attachments in WordPress: Assigning Categories and Taxonomy Terms to AttachmentsAdvanced use of attachments in wordpress 400
    This tutorial is the first in a four part series in which you'll learn some techniques for working with images in attachments in WordPress which give you advanced options. Read More…
  • Code
    Creative Coding
    Using a Custom Post Type to Create a Home Page BannerUsing a custom post type to create a home page banner
    Sometimes it's useful to have a nice obvious banner on your site's home page—for announcements, snippets that aren't long enough to merit a blog post, or links to new content within the site. But you don't want to be editing your homepage content every time you add a new piece of content, nor do you want to be delving into the code to add content.Read More…
  • Code
    Creative Coding
    Using WordPress for Web Application Development: Features: Custom Queries with WP_QueryApplication foundation 400
    We've been looking at how WordPress can be used as a foundation for application development, but one of the things that we've yet to cover that most modern frameworks offer is how to query the database to retrieve results for any given view. Specifically, we haven't talked about how to get information out of the database and insert it into our pages.Read More…
  • Code
    Using HighCharts in WP-AdminHighcharts 400
    Charts are a great way to present data. They make data more digestible by making it visually appealing. In WordPress, there is no built-in method for getting posts and pages data in a graphical form. Although, there are certain plugins available which integrate Google Analytics with WordPress, but they are overkill if you want to get only a portion of that data. Also, nothing should keep you from learning new techniques and to dive straight into the subject is the best way to learn.Read More…
  • Code
    Theme Development
    How to Create a Homepage With Multiple Listings Using Custom QueriesFrontpage custom queries preview 400
    WordPress gives you a couple of built-in options for your website's front page: a display of your most recent blog posts or a static page of your choice. But what if you want to create something a bit more interesting than that? If your site has a lot of data using categories, taxonomies or custom post types to organize it, you might want to display data of more than one kind on your homepage. The good news is that you can do this using a custom template for the homepage. In this template you write a number of custom queries to list the data in the way you want to. In this tutorial you'll learn how to do the following: Create a custom homepage template for use by your theme Include four queries in that template to display different kinds of data, including three custom queries The queries will list standard posts plus one custom post type registered for this project, called 'animal'. You can find the template file with the four queries in the code bundle.Read More…