I need to implement a list of a custom post_type that has to be able to filter them by two taxonomies,

I found this answer that helps out with the wp_query syntax

My question is, now, how should the url look like?

The post_type: ad and the taxonomies are area and category

Current posts url is:

/category/bikes wich works


/ads/area/area-5 wich works

But how sould I generate the slug for the page where is filtering by category==bikes and area==area-5 ?


Outside wp I would rewrite something like this (for this example):




But I don't see how to work around that in wp

Any ideas?


  • 1
    I'm not sure what your question is. There is no built in pretty permalink mechanism to do what you want, you have to add your own rewrite rules to handle them.
    – Milo
    Commented Jun 9, 2014 at 18:44
  • I see, so should I Do that and generate myself the links (without using the_permalink() function) ? Commented Jun 9, 2014 at 18:47
  • your example seems to relate to an archive of multiple posts, not a single post, so the_permalink wouldn't be relevant to that function.
    – Milo
    Commented Jun 9, 2014 at 19:01
  • True, sorry; I mixed thoughts. So yes, I should just rewrite and generate links myself (and not use wp_list_categories and things like that), right? Commented Jun 9, 2014 at 19:26
  • similar issue there- wp_list_categories will output categories, but the intersection between multiple taxonomies has nothing to do with the permalink of just one term in one taxonomy.
    – Milo
    Commented Jun 9, 2014 at 20:13

1 Answer 1


Just released today a plugin named Cortex, freely available on GitHub. You need PHP 5.4+ and Composer to install it (docs).

This plugin allows to write custom 'routes' to queries, it is based on Symfony routing component so mechanism of adding routes is similar to that.

Here you'll find full docs for Cortex.

Using Cortex all you need is a simple route:

add_action( 'brain_loaded', function() {

  Brain\Routes::add( '/ads/{cat}/{area}', 'cat_area_ad' )
  ->requirements( [ 'cat' => '[a-z]+', 'area' => 'area-[0-9]+' ] )
  ->query( function( $matches ) {
    return [
       'post_type' => 'ad',
       'tax_query' => [
          'relation' => 'AND',
            'taxonomy' => 'category',
            'terms'    => [ $matches['cat'] ],
            'field'    => 'slug'
            'taxonomy' => 'area',
            'terms'    => [ $matches['area'] ],
            'field'    => 'slug'
  } );

} );

"cat_area_ad" is an ID I assigned to route, that allows to easily build url for the route (see Cortex docs):

function get_cat_area_url( $cat = '', $area = '' ) {
  if ( did_action( 'parse_request' ) && ! empty( $cat ) && ! empty( $area ) ) {
    if ( strpos( $area, 'area-' ) !== 0 ) {
      $area = 'area-' . $area;
    return Brain\Routes::url( 'cat_area_ad',  [ 'cat' => $cat, 'area' => $area ] );
  } else {
    return home_url();

Previous function allows to get an url for the route, but both area and category must be passed as function arguments.

Once reading OP seems that "area" terms are named in the form "area-XX" (where 'XX' is a number) I made the route require that format and I also made get_cat_area_url function automatically prepend "area-" to the area string passed as argument (if not already present), so you can use it like so:

$url = get_cat_area_url( 'bikes', '5' );
echo $url; // will be: example.com/ads/bikes/area-5

get_cat_area_url function works properly only if 'parse_request' hook have been triggered (due to a limitation of Cortex url() API method), but in any template file you can use it without problems because when a template is shown that hook has always been triggered.

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.