Im developing a theme for article directory and i would like to link some way taxonomies to taxonomies. I had a custom post type called "company" with 2 taxnomies

Taxonomy #1 is category with terms(shops,workshops,churchs,shoppings,etc)

Taxonomy #2 is location with terms(New York, New jersey,Miami, etc)

With taxonomy #1 i can do

local.dev/category/shops/ to list all shops

With taxonomy #2 i can do

local.dev/location/miami/ to list all companies in miami

Currently i got working by this answer of MikeSchinkel the following:


Which i can use also like these to retrieve my desired results:


BUT i would like to do

local.dev/shops/miami or 
local.dev/shops/new-york to list shops in different locations 

Making all the urls looks nicer. Is this possible? My terms will be all unique so im sure they will not collide with posts tags or slugs or anything

Probably the best thing is to create a rewrite rule right? Please give me some light on this, im a bit lost.

  • Note: I'm not sure, if I understood your needs completely, therefore I assume, that you've got the "Taxonomy 2" as terms on "Taxonomy 1".
    – kaiser
    Aug 9, 2012 at 18:27
  • @kaiser i think you not, let me edit my question to see if i can make it clear as english is not my native language
    – chifliiiii
    Aug 9, 2012 at 18:28
  • Sounds like your not looking for a way to do the query in the backend, you want a restful approach to this - something via the URI correct? If so, what URI structure is it that you want?
    – eddiemoya
    Aug 14, 2012 at 19:46
  • @eddiemoya what i what is a way to make my urls looks nice. I updated question with more examples
    – chifliiiii
    Aug 16, 2012 at 12:10

3 Answers 3


With reservations, sure, you can do what you want with this code:

add_action('init', 'wpse_61376_rewrites');
function wpse_61376_rewrites() {

Then go to Settings → Permalinks in wp-admin and click "Save Changes" to flush your rewrites and activate this rule.


The problem about not having a prefix is that any permalink with two "sections" (site.com/section-1/section-2/) will be caught by this permalink and you will end up with undesirable behavior at times. For instance, an entry with two pages, site.com/about/2 or a comments feed for a page, site.com/page/feed/. Long story short, this is ill-advised.

Suggested Solution

If it were me, I would add a static base for safety. You said this was for a directory, so that seems a good base:

add_action('init', 'wpse_61376_rewrites');
function wpse_61376_rewrites() {

Your URLs would then be, site.com/directory/shops/miami/, which is as intuitive as it is safe.


Since WordPress 3.1 you can query by multiple taxonomy in the URL out of the box, without any development. This only works with query strings be default, and custom rewrite rules will need to be added to make this work in a pretty permalink fashion.

Out of the box


This works great, and will grab any post of type 'company' that has the shops category and the new-york location. Obviously though, it looks like you want this to function with pretty permalinks, so we'll need to create some custom rewrite rules.

Pretty Permalinks

First thing we need to do is make clear what the pattern we want for this multiple taxonomy permalink structure. In your question you used /shop/new-york. This could work, but there are many problems with it.

Taxonomy Base

It is important to understand that all urls to the WordPress front end get "rewritten" and end up as requests to index.php. Not the index.php in your theme, rather the one in the core application. Things like post slugs, category names, tags, etc - they all get sent that GET query vars. The rewrite rules are regex patterns that turn /foo/bar into index.php?foo=bar or whatever the query string is that needs to be built.

Because your examples have no "taxonomy base", /shops will collide with any post of any post type that shares the slug. Additionally, since we are not using any category base at all, it would be complicated to for the rewrite rules to know when a certain URL is /<cat-term>/<location-term> or supposed to be /<cat-term>/<post-slug>. Think of taxonomy bases as name spacing - if we instead used /category/shops/location/new-york, then the regex could be written to look for a pattern of /category/<cat-term>/location/<location-term>, and do so unambiguously.

With that said, even though you asked for /<cat-term>/<location-term>, I am going to go through this explanation using /category/<cat-term>/location/<location-term>.

Post Type Base

As with the taxonomy base my examples assume you have company set as the slug for your "company" custom post type - and is certainly optional, you can chose not to use one. Simply be aware that if that post type base is not present then the query will not filter by post type company, and the resulting archive will show any posts of any post type that meet the taxonomy criteria.

Rewrite Rules

There are a few options as to how this can work, to varying degrees of flexibility depending on what you want. I'm going to create two extremes, one where everything is rigid, and one that is completely flexible. You'll have to comment one out otherwise they overwrite each other if you just run it as is. Pick the one you like best, or modify them to meet somewhere in the middle.

function multiple_taxonomy_rewrite_rules( $rules ){

     * This is very strict. Only allows category first, 
     * and location must be second. 
     * This is also an example of how to make this rule 
     * only work for the "company" post type. 
     * Notice the hard-coded "post_type=company" string
     * at the end.
     * This will only work with the following structure...
     * * /company/category/<term>/location/<term>
    $newrules['company/category/(.+)/location/(.+)/?$'] = 'index.php?=category=$matches[1]&location=$matches[2]&post_type=company';

     * This is a very flexible version. Allowing for 
     * almost any permutation of the structure. 
     * This will work with...
     * * /<any-post-type>/category/<term>/location/<term>
     * * /<any-post-type>/location/<term>/category/<term>
     * * /category/<term>/location/<term> (no post type base - meaning query doesnt filter by post type)
     * * /location/<term>/category/<term> (no post type base - meaning query doesnt filter by post type)
    $newrules['(.+)?/?(category|location)/(.+)/(category|location)/(.+)/?$'] = 'index.php?=post_type=$matches[1]&$matches[2]=$matches[3]&$matches[4]=$matches[5]';

    return $newrules + $rules;
add_action('rewrite_rules_array', 'multiple_taxonomy_rewrite_rules');

Hopefully this is helpful.


To clarify, the issues regarding taxonomy or post type bases are not hard technical limitations, they are words of caution. Less unique patterns are ok to varying degrees, but the less unique, the more chance there is of a collision. You should simply be aware of the consequences of any particular pattern are.

I explained in the comments that it would also be possible to use a unique slug as a prefix for this particular pattern. You could use...

'company/(.+)/(.+)/?$' = 'index.php?category=$matches[1]&location=$matches[2]&post_type=company';

Keep in mind, that in this scenario I am only using example taxonomies so those could just as easily be replaced with category and region, or any pair of taxonomies you like. - also, I am using the prefix company, but it doesn't matter what it is, as long as its a unique string.

  • Thaks for the info, im using @MikeSchinkel answer posted in wordpress.stackexchange.com/questions/9419/… to remove base slug because im sure it will not conflict with others. What i really want to accomplish is convert local.dev/shops/?region=miami which is currently working into local.dev/shops/miami/ .There is no way to add the region taxonomy rewrite rule to work when shops rewrite rule is being applied?
    – chifliiiii
    Aug 16, 2012 at 12:09
  • Let me clarify, you dont need to use a tax base. However, it will lead to more collisions if there are dynamic capture regions that aren't 'namespaced'. To mitigate you could place everything after a unique slug that would identify the URI as intending to be for this multi-taxonomy query. an example would be 'company/(.+)/(.+)/?$' = 'index.php?category=$matches[1]&location=$matches[2]$post_type=company; This will work because it means you've decided that /company/ is reserved for the company/<cat>/<loc>/ pattern - thats fine, but anything else that starts with 'company'.
    – eddiemoya
    Aug 16, 2012 at 16:29
  • You could of course decide you wanted to use '(.+)/(.+)/?$' = 'index.php?category=$matches[1]&location=$matches[2]$post_type=company' but that would capture everything that has two slugs, meaning /page/page-slug, /category/term-slug, everyting would instead get rewritten to a have the first slug be a categroty term, and the second to be a location. Thats usually a problem for most websites.
    – eddiemoya
    Aug 16, 2012 at 16:32
  • Lastly, you are asking if you can rewrite for multiple taxonomies - category and region is what you said in your comment. The answer is yes, my entire answer explains that, I was using category and location as the two taxonomies, but region can be used just as easily.
    – eddiemoya
    Aug 16, 2012 at 16:33
  • I read again your explanation and basically its the same as Matthew said. I saw it crearly when he explained it so i gave the correct answer to him. Thanks to both of you
    – chifliiiii
    Aug 16, 2012 at 23:23


Just use get_terms() in combination with get_site_url().


To add MU support, just drop in the get_current_blog_id() to retrieve the ID of the current blog. This gives you the $blog_id, which is the only blog in a single site setup and therefore works too for non-MU installations.


Now, let's build a list.

echo '<ul>';
foreach ( get_terms( "shops" ) ) as $shop )
    $site_url = get_site_url( get_current_blog_id() );
    echo "<li><a href='{$site_url}shops/{$shop->slug}' title='{$shop->description}'>{$shop->name}</a></li>";
echo '</ul>';

This example assumes, that you've just your site url and your taxonomy terms slug appended.

  • i just edited my question. Thanks for the help anyway
    – chifliiiii
    Aug 9, 2012 at 18:32

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.