Manually Creating Custom Taxonomies In WordPress

In our previous post we were talking about how to create a custom post types and now let’s create taxonomies for them. What mean taxonomy here? For WordPress taxonomy is a mechanism for posts grouping in a different ways.

Two of the most popular taxonomies in wordpress that people use more regularly are Categories and Tags.

So let’s add a Category for our new Custom Post Type.

For this we’ll take function

register_taxonomy($taxonomy, $object_type, $args) -

And take it to our material_init; function

$taxonomy_material_category_labels = array(
'name' => esc_html__('Material Categories', 'themedomain' ),
'singular_name' => esc_html__('Material Category', 'themedomain' ),
'menu_name' => esc_html__('Material Categories', 'themedomain' ),
'search_items' => esc_html__('Search Material Categories', 'themedomain' ),
'popular_items' => esc_html__('Popular Material Categories', 'themedomain' ),
'all_items' => esc_html__('All Material Categories', 'themedomain' ),
'parent_item' => esc_html__('Parent Material Category', 'themedomain' ),
'parent_item_colon' => esc_html__('Parent Material Category:', 'themedomain' ),
'edit_item' => esc_html__('Edit Material Category', 'themedomain' ),
'update_item' => esc_html__('Update Material Category', 'themedomain' ),
'add_new_item' => esc_html__('Add New Material Category', 'themedomain' ),
'new_item_name' => esc_html__('New Material Category Name', 'themedomain' ),
'separate_items_with_commas' => esc_html__('Separate material categories with commas', 'themedomain' ),
'add_or_remove_items' => esc_html__('Add or remove material categories', 'themedomain' ),
'choose_from_most_used' => esc_html__('Choose from the most used material categories', 'themedomain' )
$taxonomy_material_category_args = array(
'labels' => $taxonomy_material_category_labels,
'public' => true,
'show_in_nav_menus' => true,
'show_ui' => true,
'show_admin_column' => true,
'show_tagcloud' => true,
'hierarchical' => true,
'rewrite' => array( 'slug' => 'material-category', 'with_front' => false ),
'query_var' => true
register_taxonomy( 'material-category', array( 'material' ),
$taxonomy_material_category_args );


For the Taxonomy Name it necessary to choose a unique name, differ from already existing and which does not conflict with other taxonomies, post types, and reserved WordPress public and private query variables.

$taxonomy (string)

The name of the taxonomy. Name should only contain lowercase letters and the underscore character, and not be more than 32 characters long (database structure restriction).

$object_type (array/string)

Name of the object type for the taxonomy object. Object-types can be built-in Post Type or any Custom Post Type that may be registered.

$args (array)

An array of Arguments.


labels (array)

An array of labels for this taxonomy, is displayed in the admin panel.

  • name
    general name for the taxonomy, usually plural;
  • singular_name
    name for one object of this taxonomy;
  • menu_name
    the menu name text. This string is the name to give menu items.;
  • search_items
    the search items text;
  • popular_items
    the popular items text block;
  • all_items
    the all items text;
  • parent_item
    the parent item text. This string is not used on non-hierarchical taxonomies such as post tags.;
  • parent_item_colon
    The same as parent_item, but with colon : in the end null;
  • edit_item
    the edit item text;
  • update_item
    the update item text;
  • add_new_item
    the text for adding new taxonomy element;
  • new_item_name
    the text for creating new taxonomy element;
  • separate_items_with_commas
    the separate item with commas text used in the taxonomy meta box. This string is not used on hierarchical taxonomies.;
  • add_or_remove_items
    the add or remove items text and used in the meta box when JavaScript is disabled. This string is not used on hierarchical taxonomies.;
  • choose_from_most_used
    the choose from most used text used in the taxonomy meta box. This string is not used on hierarchical taxonomies.;

public (boolean)

Whether a taxonomy is intended for use publicly either via the admin interface or by front-end users.

show_in_nav_menus (boolean)

True makes this taxonomy available for selection in navigation menus.

show_ui (boolean)

Whether to generate a default UI for managing this taxonomy.

show_admin_column (boolean)

Whether to allow automatic creation of taxonomy columns on associated post-types table.

show_tagcloud (boolean)

Whether to allow the Tag Cloud widget to use this taxonomy. Whether to allow the Tag Cloud widget to use this taxonomy.

hierarchical (boolean)

true – the taxonomy is hierarchical (have descendants) like categories.
false - the taxonomy is not hierarchical like tags.

rewrite (boolean/array)

Set to false to prevent automatic URL rewriting. If set an array then it possible to set an arbitrary query parameter (query var).

Possible array arguments:

  • slug - Used as pretty permalink text (i.e. /tag/) - defaults to $taxonomy (taxonomy's name slug);
  • with_front - allowing permalinks to be prepended with front base - defaults to true;

query_var (boolean or string)

False to disable the query_var, set as string to use custom query_var instead of default which is $taxonomy, the taxonomy's "name".

Creating tag taxonomy

For creating tag taxonomy we use the same function as we did for category. With only a small difference.

Array parameter $args - "hierarchical" => false

Well, the name of the taxonomy should be different.

Let’s put this function in our function material_init;

$taxonomy_material_tag_labels = array(
'name' => esc_html__('Material Tags', 'themedomain' ),
'singular_name' => esc_html__('Material Tag', 'themedomain' ),
'search_items' => esc_html__('Search Material Tags', 'themedomain' ),
'popular_items' => esc_html__('Popular Material Tags', 'themedomain' ),
'all_items' => esc_html__('All Material Tags', 'themedomain' ),
'parent_item' => esc_html__('Parent Material Tag', 'themedomain' ),
'parent_item_colon' => esc_html__('Parent Material Tag:', 'themedomain' ),
'edit_item' => esc_html__('Edit Material Tag', 'themedomain' ),
'update_item' => esc_html__('Update Material Tag', 'themedomain' ),
'add_new_item' => esc_html__('Add New Material Tag', 'themedomain' ),
'new_item_name' => esc_html__('New Material Tag Name', 'themedomain' ),
'separate_items_with_commas' => esc_html__('Separate material tags with commas', 'themedomain' ),
'add_or_remove_items' => esc_html__('Add or remove material tags', 'themedomain' ),
'choose_from_most_used' => esc_html__('Choose from the most used material tags', 'themedomain' ),
'menu_name' => esc_html__('Material Tags', 'themedomain' )
$taxonomy_material_tag_args = array(
'labels' => $taxonomy_material_tag_labels,
'public' => true,
'show_in_nav_menus' => true,
'show_ui' => true,
'show_tagcloud' => true,
'hierarchical' => false,
'rewrite' => array( 'slug' => 'material-tag', 'with_front' => false ),
'show_admin_column' => true,
'query_var' => true
register_taxonomy( 'material-tag', array( 'material' ),
$taxonomy_material_tag_args );

material_init – put in functions.php

The Result is


add taxonomy

Let's add the ability to view images assigned to a post in the table of posts for more convenience.

There are several ways. They all use the same filter.


Where instead {post_type} write our post type name

1. Simplest way

function material_add_post_columns($my_columns){
$my_columns['featured_image'] = 'Featured Image';
return $my_columns;
add_filter( 'manage_edit-material_columns',
'material_add_post_columns', 10, 1 );


The disadvantage of this method is probably that the columns are added at the end of the table.

2. In this method, you can adjust the placement of columns.

Let's place our image column very first.

function material_add_post_columns($my_columns){
$keywords = array( 'featured_image' => 'Featured Image' );
$my_columns = array_slice( $my_columns, 0, 1, true ) +
$keywords + array_slice( $my_columns, 1, NULL, true );
return $my_columns;
add_filter( 'manage_edit-material_columns',
'material_add_post_columns', 10, 1 );


A completely different view, right? But there is another way, the most obvious.

3. Describe all columns

function material_add_post_columns($my_columns){
$my_columns = array(
'featured_image' => __('Featured Image'),
'title' => __('Title'),
'author' => __('Author'),
'taxonomy-material-category' => __('Categories'),
'taxonomy-material-tag' => __('Tags'),
'comments' =>'<span class="vers"><img alt="Comments" src="'.site_url().'/wp-admin/images/comment-grey-bubble.png" /></span>',
'date' => __('Date')
return $my_columns;
add_filter( 'manage_edit-material_columns',
'material_add_post_columns', 10, 1 );

Array keys $my_columns are column titles id in the end of the table. You can open the developer tools and check there how to write them correctly.


Now let’s fill in our column with the necessary information.

function material_fill_post_columns( $column ) {
global $post;
switch ( $column ) {
case 'featured_image':
echo get_the_post_thumbnail( get_the_ID(), array( 100, 100 ) );
add_action( 'manage_posts_custom_column',
'material_fill_post_columns', 10, 1 );


So, simply, we managed to make a more visual list of posts.

Finally, let's add the ability to sort our posts, let's say by author. Well, if you have a lot of authors.

function material_sortable_column($sortable_columns){
$sortable_columns['author'] = array('author', false);// false = asc. desc - default sorting
return $sortable_columns;

Now when you click on the heading of the column Author it will be sorted.


This can be stopped if you want to sort by standard entries.

And if you have a column with the display of the number of views of the post and this number is stored in the custom field views.

Then you will need to change the query when sorting the column.

function material_column_views_request( $vars ) {
if(is_admin()) {
switch ($vars['orderby']) {
case 'sort_views':
$vars['meta_key'] = 'views';
$vars['orderby'] = 'meta_value_num';
return $vars;
add_filter( 'request', 'material_column_views_request' );

To edit the column width you can do this:

function material_views_column_css(){
echo '<style type="text/css">.column-views{width:10%;}</style>';
add_action('admin_head', 'material_views_column_css');


And finally, we add the functionality of counting post views.

The following function is added to the functions.php  and function call is written in the output template of our single page in the form of

function material_set_post_views($postID) {
$count_key = ‘views’;// the name of custom field
static $count = false;
if($count) return true;
$useragent = $_SERVER['HTTP_USER_AGENT'];
$notbot = "Mozilla|Opera"; //Chrome|Safari|Firefox|Netscape
$bot = "Bot/|robot|Slurp/|yahoo";
if ( !preg_match("/$notbot/i", $useragent) ||
preg_match("!$bot!i", $useragent) ) {
return false; // check that a real user has logged in, not a robot
} else {
$count = get_post_meta($postID, $count_key, true);
$count = 0;
delete_post_meta($postID, $count_key);
add_post_meta($postID, $count_key, '0');
} else {
update_post_meta($postID, $count_key, $count);

So as you saw there are many ways to use custom taxonomies. If you use both, custome post types and custom taxonomies to build customized content management system (CMS) that will meet your needs. Hope now you have better understanding how to organize WordPress content with the help of taxonomies. Let us know how you are using custom taxonomies on your websites?