Let's say you create a custom post type named Online Bible. You visit your custom post type archive page and the URL is http://example.com/onlinebible. You create a post called Introduction and your URL is:

http://example.com/onlinebible/introduction.

Great!

Now you decide you want a custom taxonomy to categorize your posts by Books of this Bible, so you create a custom taxonomy called Books. So you create this taxonomy, add a Book category called Titus, create a new post called Summary and choose the Titus category for the post. You save your draft and look above the editor and see http://example.com/onlinebible/summary.

Wait. That’s not right. What you really wanted was:

http://example.com/onlinebible/titus/summary

I mean, you chose that category right? Shouldn’t it show up before ‘summary?’

Your Custom Taxonomy Permalink Structure

The answer is no. WordPress does not know to do this……you actually have to tell it to. You have to instruct it as to your custom taxonomy permalink structure.

Let me show you now how to do it.

Our Example

So here is what we want:

Our main archive page:

http://example.com/onlinebible

Our categories when we choose them:

http://example.com/onlinebible/titus/summary

No categories when none are chosen

http://example.com/onlinebible/summary

So let’s begin.

1. Your Custom Post Type

Here is our example custom post type called Online Bible:

//Setup Custom Post Type - Online Bible
add_action( 'init', 'create_custom_post_type_online_bible' );

function create_custom_post_type_online_bible() {
   $labels = array(
    'name' => __( 'Online Bible' ),
    'singular_name' => __( 'Online Bible' ),
    'all_items' => __('All Online Bible'),
    'add_new' => _x('Add new Online Bible', 'Online Bible'),
    'add_new_item' => __('Add new Online Bible'),
    'edit_item' => __('Edit Online Bible'),
    'new_item' => __('New Online Bible'),
    'view_item' => __('View Online Bible'),
    'search_items' => __('Search in Online Bible'),
    'not_found' =>  __('No Online Bible found'),
    'not_found_in_trash' => __('No Online Bible found in trash'),
    'parent_item_colon' => ''
    );

    $args = array(
    'labels' => $labels,
    'public' => true,
    'has_archive' => 'onlinebible',
	'query_var' => true,
    'menu_icon' => 'dashicons-book',
	'rewrite' => array('slug' => 'onlinebible/%books%'),
	'taxonomies' => array( 'post_tag', 'books'),
	'supports'  => array( 'title', 'editor', 'publicize', 'author', 'thumbnail' , 'custom-fields', 'excerpt', 'comments', 'genesis-cpt-archives-settings' )
	);

  register_post_type( 'online_bible', $args);
}

In this custom post type we want to make sure that our rewrite argument has a slug of the custom post type and the dynamic category. We do this by making ‘onlinebible/%books% our slug.

2. Our Custom Taxonomy

The custom taxonomy (category) we want to create is Books, where we will add the books of our Online Bible.

function books_taxonomy() {  
    register_taxonomy('books', 'onlinebible', array(
		'labels' => array(
			'name'          => 'Books'
		,	'singular_name' => 'Book'
		,	'search_items'  => 'Search Books'
		,	'edit_item'     => 'Edit Book'
		,	'add_new_item'  => 'Add New Book'
		)
	,	'hierarchical' => true
	,	'query_var'    => true
	,	'rewrite'      => array('slug' => 'onlinebible', 'with_front' => false)
	)); // type taxonomy
}
add_action( 'init', 'books_taxonomy');

In this custom taxonomy, we want our slug not to include this dynamic category, so we just put ‘onlinebible’ as our slug.

3. Our Dynamic Category Rewrite

Now we have our custom post type archive page as http://example.com/onlinebible.

Check!

But when we go to create ANY post we get this URL:

http://example.com/onlinebible/%books%/postname

…and that will not work and will actually throw us an error (because of the %books% in the url).

We have to tell WordPress what we want it to do, and what we want it to do is find the chosen category term of the post and replace the %books% string in the URL with our chosen category term.

Here is how we do it:

function tm_books_post_link( $post_link, $id = 0 ){
    $post = get_post($id);  
        $terms = wp_get_object_terms( $post->ID, 'books' );
        if( $terms ){
            return str_replace( '%books%' , $terms[0]->slug , $post_link );
	} 
    return $post_link;  
}
add_filter( 'post_type_link', 'tm_books_post_link', 1, 3 );

We get the chosen term of the post and replace %books% with that term slug.

Great!

Well, almost.

The Problem

What happens when there is no term chosen. What if we don’t want to choose a term and have the onlinebible/postname permalink structure instead?

We get an error. Why? Because if we do NOT choose a term, we get the http://example.com/onlinebible/%books%/postname URL (which throws us an error), mainly because our rewrite only happens when there is a term chosen.

Thus we need to add in a condition that removes the %book% in the URL if a term is not chosen.

We can do it by adding an else clause to replace our %books% with a blank space:

function tm_books_post_link( $post_link, $id = 0 ){
    $post = get_post($id);  
        $terms = wp_get_object_terms( $post->ID, 'books' );
        if( $terms ){
            return str_replace( '%books%' , $terms[0]->slug , $post_link );
	} else {
	    return str_replace( '%books%/' , '' , $post_link );
}
	
    return $post_link;  
}
add_filter( 'post_type_link', 'tm_books_post_link', 1, 3 );

**And remember to put the ‘/’ after ‘%books%’ so that it will remove the extra one.

Conclusion

There are many other options to this and you can find a plethora of answers on https://wordpress.stackexchange.com and search results on Google.

But I hope this helps in regards to the use of custom taxonomies acting as categories to your custom post type and nailing down the custom taxonomy permalink structure that you desire.

How have you handled the custom taxonomy permalink structure in the past? What options have you given? Let me know below an as always, feel free to ask questions about the post.

Let's say you create a custom post type named Online Bible. You visit your custom post type archive page and the URL is http://example.com/onlinebible. You create a post called Introduction and your URL is:


Comments