How to modify URL structures in custom post types and taxonomies or terms

I am well aware that there are several posts covering the topic of customizing the permalink URL structure of custom post types, custom taxonomies, and taxonomy terms. However, none of them are real clear, don’t work correctly, or cause problems elsewhere.

Here are a few links, which already “kind of” cover URL rewriting.

  1. How to create a permalink structure with custom taxonomies and
    custom post types like
  2. Custom post types, taxonomies, and permalinks
  3. Mixing custom post type and taxonomy rewrite structures?

I am looking to create a permalink URL structure along the lines of:

  • Post Type Name: cars
  • Taxonomy Name: dealers
  • Term Name: honda
  • Post Title: 123 Hot Rod Lane

Example setup of the ideal permalink URL structure:

Generic permalink structure:

More specific permalink structure:

  • /cars/ needs to be accessible as an archive listing of every post
    made in the post type.
  • /cars/dealers/ needs to be accessible as an archive listing of
    every post made in the taxonomy.
  • /cars/dealers/honda/ needs to be accessible as an archive listing
    of every post made in that taxonomy term.
  • /cars/dealers/honda/123-hot-rod-lane/ needs to be accessible as a
    singular view of the post made in the cars custom post type.

Just to be clear, so no one does any unnecessary work while replying to this question. I do NOT need anything other than just adding the correct rewrite rules for my post type, taxonomy, and terms. This questions is directly in regards to permalink URL rewriting, and NOT in relation to listing of posts or archives. I just need to be sure WordPress recognizes them properly, while using conditional calls like is_post_type_archive() or is_tax() or is_singular(), etc.

I’ve attempted numerous times, from numerous questions/answers on this site. Nothing seems to work.

Here is my registered custom post type, and registered custom taxonomy:

    public function register_custom_data(){
        /* Register a post type for Cars. */
        $labels = array(
            'name' => _x('Cars', 'post type general name'),
            'singular_name' => _x('Car', 'post type singular name'),
            'add_new' => _x('Add New Car', 'Car'),
            'add_new_item' => __('Add New Car'),
            'edit_item' => __('Edit Car'),
            'new_item' => __('New Car'),
            'all_items' => __('All Cars'),
            'view_item' => __('View Car'),
            'search_items' => __('Search Cars'),
            'not_found' =>  __('No Cars found'),
            'not_found_in_trash' => __('No Cars found in Trash'), 
            'parent_item_colon' => '',
            'menu_name' => __('Cars')
        $args = array(
            'labels' => $labels,
            'public' => true,
            'publicly_queryable' => true,
            'show_ui' => true, 
            'show_in_menu' => false, 
            'show_in_nav_menus' => false,
            'can_export' => true,
            'query_var' => true,
            'rewrite' => true,
            'menu_icon' => NULL,
            'capability_type' => 'post',
            'has_archive' => true, 
            'hierarchical' => false,
            'menu_position' => NULL,
            'supports' => array(
            'rewrite' => array(
                'slug' => 'cars', 
                'with_front' => true
        register_post_type('mbe_cars', $args);

        /* Car Dealers */
        $labels = array(
            'name' => _x('Dealers', 'taxonomy general name'),
            'singular_name' => _x('Dealer', 'taxonomy singular name'),
            'search_items' =>  __('Search Dealers'),
            'all_items' => __('All Dealers'),
            'parent_item' => __('Parent Dealer'),
            'parent_item_colon' => __('Parent Dealer:'),
            'edit_item' => __('Edit Dealer'), 
            'update_item' => __('Update Dealer'),
            'add_new_item' => __('Add New Dealer'),
            'new_item_name' => __('New Dealer Name'),
            'menu_name' => __('Dealers')

        $args = array(
            'hierarchical' => true,
            'labels' => $labels,
            'show_ui' => true,
            'query_var' => true,
            'rewrite' => array(
                'slug' => 'dealers',
                'hierarchical' => true

        register_taxonomy('mbe_car_dealers', 'mbe_cars', $args);

        /* Update urls. */

Solutions Collecting From Web of "How to modify URL structures in custom post types and taxonomies or terms"

I’m not sure it’s possible, or perhaps it just may not be the best approach. Here is my reasoning:

Posts can be attached to multiple terms, so in essence there could be multiple links to the same post:

Depending on how you got there.

You will definitely be able to have, but I think that it may not completely make sense within WordPress to have such a long URI.

I think this for 2 reasons:

  1. The possibility of multiple taxonomy terms (let alone multiple taxonomies attached to a custom post type, or any post) would create a lot of overlapping links, as well as more possibilities to break bookmarks – lets say I bookmark /cars/dealers/honda/123-hot-rod, but then you realize that it wasn’t actually Honda, it was Toyota – you changing the tax term related to the post would break that link. Not a likely occurance, but it’s possible.

  2. Frankly, it’s less user friendly. Not that the average user pays attention to the web paths they are on, but it is easier to remember than it would to remember (or understand)

When you are on that single post’s page, the default ‘above_nav’ in most themes includes the taxonomy terms with the date underneath of the Page title anyways, so that information is still there, in a more legible, and usable way.


123 Hot Rod

posted November 2, 2012 in Wonderland Used Cars

I wouldn’t like to submit this as an answer however, it’s an amazing little snippet that links up your taxonomies and terms.

add_filter('request', 'add_tags_and_categories');  
  function add_tags_and_categories($q) {
    if (isset($q['your_term_or_tax']) || isset($q['category_name'])) {
    $q['post_type'] = 'your_custom_post';   
      return $q;
return $q;

I hope this can help on your journey to an answer. I commonly use it to link up my Custom Post Types to the /tags/ & /category/ built-in’s like so:

add_filter('request', 'add_tags_and_categories');  
 function add_tags_and_categories($q) {
   if (isset($q['tag']) || isset($q['category_name'])) {
     $q['post_type'] = get_post_types();

            return $q;

 return $q;