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 base-name/parent-tax/child-tax/custom-post-type-name
  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. */
  • You are flushing the rewrite rules twice?
    – fuxia
    Commented Oct 9, 2012 at 19:11
  • Good catch. For now, flushing is there once and will be fired on init every time. In the long run, flushing would be moved to activation/deactivation of the plugin. Commented Oct 9, 2012 at 19:17
  • What are you currently getting when you are on the '123 hot rod lane' post? The problem with this is that posts are not necessarily going to be accessed through that taxonomy term of 'honda', so you are most likely going to get /cars/123-hot-rod-lane/' on a single post, where you would correctly get /cars/dealers/honda/ if you were looking at the tax term 'honda'. Commented Oct 9, 2012 at 19:22
  • 1
    you may not need a rewrite rule if you structure the rewrite arguments of your post/tax registration properly. see this answer for something you might be able to use as a starting point. you will need to filter post_type_link to generate the permalinks. i'll take a shot at it later if i've got time.
    – Milo
    Commented Oct 9, 2012 at 20:19
  • 2
    BuddyPress accomplishes deep urls (some/thing/some/thing/else/) using another method of just slicing up the url. I believe they do this before WP tries to identify which template to use... And then they pass those additional values in as a query string. I was looking at it today, but didn't really figure it out entirely. If you want to download BuddyPress, a free plugin, you can look at bp-core-catchuri.php to see what I'm talking about. Commented Oct 11, 2012 at 23:13

2 Answers 2


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 domain.com/post-type-name/taxonomy-name/term-name/, 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 domain.com/cars/93-saturn-ion than it would to remember (or understand) domain.com/cars/dealers/wonderland-auto/93-saturn-ion.

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

  • Thanks @guiniveretoo I didn't catch the formatting issue. Commented Oct 17, 2012 at 13:02
  • 2
    lol nice post but you didn't answer his question. I would like to know a solution too. According to seo recommendations, having a url reflecting a "directory" is more friendly for both human and seo bots.
    – yeahman
    Commented May 10, 2014 at 19:01

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;


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.