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() { register_taxonomy( 'movie_reviews_movie_genre', 'movie_reviews', array( '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.
<?php /*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 ) ); ?> </div> <!-- 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> <?php the_terms( $post->ID, 'movie_reviews_movie_genre' , ' ' ); ?> <br /> <!-- Display yellow stars based on rating --> <strong>Rating: </strong> <?php $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' ). '" />'; } } ?> </header> <!-- Display movie review contents --> <div class="entry-content"> <?php the_content(); ?> </div> <hr/> </article> <?php endwhile; ?> </div> </div> <?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> </header> <table> <!-- Display table headers --> <tr> <th style="width: 200px"><strong>Title</strong></th> <th><strong>Director</strong></th> </tr> <!-- Start the Loop --> <?php while ( have_posts() ) : the_post(); ?> <!-- Display review title and author --> <tr> <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> </tr> <?php endwhile; ?> <!-- Display page navigation --> </table> <?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">←</span> Older reviews'); ?></div> <div class="nav-next"><?php previous_posts_link( 'Newer reviews <span class= "meta-nav">→</span>' ); ?></div> </nav> <?php }; endif; ?> </div> </section> <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.
Comments