Posted on

Using multiple custom taxonomies

Usually, WordPress supports one category, one tag and one taxonomy in the search, if you use the query variables to set the taxonomies. You can enter multiple taxonomies as parameters to the query, but only the first one is used.

If you want to have multiple taxonomies involved, you need to build a tax_query. The correct format is described in the Codex.

Of course, you can’t just pass the array in a query variable, so you’ll have to build it. Here’s how you do a two-taxonomy search.

Search form

First, we need to add the inputs to the search form. For taxonomies, having a dropdown select is usually the best option. You can create dropdowns with the wp_dropdown_categories() function. It works for all taxonomies, despite the name. The important thing is to change the ‘name’ parameter for each dropdown.

So, in our case, we would have two dropdowns, like this, in the search form code:

wp_dropdown_categories( array( 'name' => 'movie_director', 'taxonomy' => 'director' ) );
wp_dropdown_categories( array( 'name' => 'movie_actor', 'taxonomy' => 'actor' ) );

Introducing the query variables

WordPress cleans out unknown query variables for data hygiene reasons. That’s a good thing, but a bit of a complication for us, because our query variables are unknown to WordPress. We need to introduce them. Add this to your site:

add_filter( 'query_vars', 'introduce_qvs' );
function introduce_qvs( $qv ) {
    $qv[] = 'movie_director';
    $qv[] = 'movie_actor';
    return $qv;
}

This lets WordPress know these query variables are cool.

Formatting the tax query

Now we just need to format the tax query from the query variables. This happens in the relevanssi_modify_wp_query filter, which is executed before Relevanssi search and which is therefore very good when you need to modify the query parameters in any way.

add_filter( 'relevanssi_modify_wp_query', 'movie_tax_query' );
function movie_tax_query( $query ) {
    $tax_query = array();
    if ( ! empty( $query->query_vars['movie_director'] ) ) {
        $tax_query[] = array(
            'taxonomy' => 'director',
            'field'    => 'term_id',
            'terms'    => explode( ',', $query->query_vars['movie_director'] ), // to support comma-separated values
            'operator' => 'IN', // or 'AND', if you require all values to match, or 'NOT IN'
        );
    }
    if ( ! empty( $query->query_vars['movie_actor'] ) ) {
        $tax_query[] = array(
            'taxonomy' => 'actor',
            'field'    => 'term_id',
            'terms'    => explode( ',', $query->query_vars['movie_actor'] ),
            'operator' => 'IN',
        );
    }
    if ( ! empty( $tax_query ) ) {
        $tax_query['relation'] = 'AND'; // you can also use 'OR' here
        $query->set( 'tax_query', $tax_query );
    }
    return $query;
}

This should do the trick.

52 comments Using multiple custom taxonomies

  1. Hello,
    First off, Nice work on the plugin, we are considering this plugin for use in a big project that’s based on wordpress.

    My Question:
    I am trying to make this work for searching multiple post_types
    My post types are places, events, and posts. I want the search to only search places and events.

    example.com/?s=&post_type=event|place <- Only returns places

    What is it that makes this usage different from the example?

    Thanks,
    -Taylor

    1. This only works with taxonomies. Post types are not taxonomies.

      Looks like post_type has the same problem as the ‘cat’ query variable: WordPress strips out anything unnecessary. I’ll have to do the same fix, I suppose, that is add a query variable ‘post_types’ that’ll take a comma-separated list of post types. That’s a simple fix, I’ll add it to the next version.

  2. Is there a demo I can see for this functionality in the premium plugin?

    What I want to do is filter a custom post type using several taxonomies and would like to use drop downs to filter each of the taxonomies. So the user would choose an option in the drop down for each taxonomy (or leave the option as “all”). And then the visitor would hit Go and the results would filter ON THE SAME PAGE.

    Is this how the plugin works? Is filtering the results on the same page possible? I would be purchasing the developer version for use on a client site.

    Thanks

    1. No demo available, but yes, it is possible to do that. It takes some PHP knowledge, as you need to combine the filters set in each dropdown box to a single query variable, but that’s simple and I have some sample code to show you how it’s done. If necessary, I can be hired to write the code for you for about $100.

      I just installed 3.4.1 on my test blog minutes ago, but at least I’ve found no issues with 3.4.

      1. Hi,

        i am having trouble getting the premium version to do this aby chance you could send me the sample code?

    1. No, that doesn’t work. This does:
      example.com?customfield_key=key&customfield_value=value

      This should work, but for some reason doesn’t:
      example.com?meta_key=key&meta_value=value

      because WP empties the values.

  3. Hi Mikko – like this plugin so far. I want to have the multiple taxonomies and terms in my search and will upgrade to Premium to do so. My question is how do I get my search form to send the query string the second way, rather than the first way (?s=query&director=Scorsese&actor=De+Niro) with taxonomy name= term name? I’m using checkboxes with the name set to taxonomy name and the value set to the term. I’d like it to be like this: ?s=query&taxonomy=director|actor&term=Scorsese|De+Niro

  4. I was asking about The Premium version because I noticed in your Release Notes for Premium 1.7.7 (March 4 2012) you mentioned this functionality:
    ==============

    The logic when using multiple taxonomies is now clearer. There’s OR logic between terms in the same taxonomy and AND logic between different taxonomies. Sounds complicated? Here’s an example from Jonathan Liuti, who refined the logic:

    http://www.example.com/?s=term&taxonomy=country|country|topic|topic&term=Finland|Belgium|crisis|war

    This search would return all posts that fulfill all these conditions

    include the word “term”

    have taxonomy country set to Finland OR Belgium OR both

    have taxonomy topic set to crisis OR war OR both

    ==============

    This is exactly what I am after. That’s why I was asking about the query string formation. Do I need Premium to enable this OR relation within the same taxonomy and AND logic between different taxonomies ?

    1. That old method was Premium-only, but you can do that better with tax_query, and that works with free and Premium. Here’s your example formatted as tax query:

      $args = array(
      ‘post_type’ => ‘post’,
      ‘tax_query’ => array(
      ‘relation’ => ‘AND’,
      array(
      ‘taxonomy’ => ‘country’,
      ‘field’ => ‘slug’,
      ‘terms’ => array( ‘finland’, ‘belgium’ ),
      ‘operator’ => ‘IN’),
      array(
      ‘taxonomy’ => ‘topic’,
      ‘field’ => ‘slug’,
      ‘terms’ => array( ‘crisis’, ‘war’ ),
      ‘operator’ => ‘IN’)
      )
      );

  5. I am using the above logic for to format my tax query. I am using checkboxes so multiple values are allowed. So if a user selects Canada and Japan under Region, it is creating the query string:

    ?s=oil&region=canada&region=japan

    which I thought was cool, but it appears to filter the results differently if I change the order to

    ?s=oil&region=japan&region=canada.

    Do you know why?

    1. Yes: Relevanssi sees only the first region parameter, WordPress doesn’t allow the second one to reach Relevanssi. You’ll have to do it some other way.

      Add a filter on `relevanssi_modify_wp_query`, read in the query variables and form a tax_query of them. That’s the best way to do it.

      1. Perhaps I am building the tax query wrong – maybe the terms are not in the proper array format? I pasted the tax query filter here http://pastebin.com/33Vwtdav would you mind having a look. I am willing to hire you to help me accomplish this if you are interested.

        1. Sure, I can take a look, if you give me admin access (and preferably FTP access as well, since this involves editing files). You can email me at mikko @ mikkosaari.fi.

  6. Hi Mikko

    I’ve been searching for ages to find some help on this at it seems your post is the nearest solution I’ve found, but I’d still stuck.

    I’ve created a search form with three dropdown selects created by wp_dropdown_categories and a word search. Each drop down selects sub/child categories from three main parent categories. If the user selects all three it works perfectly returning just the post which matches every selection. If one or two dropdowns are not selected, the search terms produced are category=0, which means it just returns every post rather than just the posts in the one category selected.
    I’m new to Relevanssi, plus I’m not sure how to inpliment your code ‘Formatting the tax query’?

    <form
    role="search" method="get" id="searchform" action="”>

    <input type="text" value="” placeholder=”Enter term or leave
    blank” name=”s”
    id=”s” />

    KInd regards
    Mike

        1. The form seems correct to me. Now it’s just a question of what kind of tax_query gets built out of them – that’s probably the problem. I’d start by investigating what’s in $wp_query->query_vars, when the user chooses different options.

          1. OK I’m presuming the tax query addfilter/function is also pasted into my functions.php? Or am I modifying the relevanssi_modify_wp_query routine search.php in relevanssi. I’m not clear from your instuctions.

            Also you’ve used ‘movie_director’ which I presume is your parent category name and that ‘director’ is the slug?

            And to attach a third dropdown I reproduce another if (!empty($query statment for the third dropdown?

            Sorry to be thick! But as you know PHP needs to be so precise!

          2. You never modify Relevanssi files. The code goes to theme functions.php.

            Movie_director is the name of the query variable, as defined in the name parameter of the dropdown. Director is the name of the taxonomy.

            Yes, you need to add third if statement.

          3. OK so all this is done and the plugin configured. My dropdown code above produces cat=26&cat=39&cat=62, but produces an OR result even tough I have AND selected?
            I’m on the latest 3.8.1 wordpress

          4. I’ve put name into the array ‘name=etc’ and pasted the code at the bottom of the functions.php, so now get country=26&colour=39&type=64, but this just lists every post, even if i choose 3 categories I know fit one single post. If I put it back to cat=26….etc, it returns the one correct post. Leave one option unselected and I get cat=0 the OR function which lists everything or if I select another 3rd category (perhaps a wider parent category) it only lists results from the widest category and doesn’t include the post which matches the first two categories.
            I’ve disabled anything in the functions.php that refers to search but nothing has had any effect?
            Many thanks for the help, this is driving me nuts!!!!

          5. Mikko
            Many thanks for your help so far. I think I need to take a large step backwards and first work out why the wp_dropdown_categories array items like selected and exclude are obviously not working. If I can do that I can at least get over the cat=0 problem
            Mike

          6. From testing this afternoon I would say some items in the wp_dropdown_categories array do interfere with each other, for instance using ‘child_of’ stops ‘selected’ working and I can’t get the dropdown to work at all with ‘taxonomy’ in the array (unless its taxonomy=’category’, but then ‘child_of’ doesn’t work). Then using’ name=’ causes the search string country=26&colour=39&type=81 not to work, but cat=26&cat=39&cat=81 does?

            In using multiple wp_dropdown_categories the AND function seems to work for all three functions if they are selected and they match categorised posts (i.e. cat=26&cat=39&cat=81), but if the last dropdown is not selected and produces cat=0 the search returns everything (cat=26&cat=39&cat=0) But then again….. Cat=0 is ignored in dropdowns one and two if you don’t select either of them, which is puzzling (cat=0&cat=39&cat=81 or cat=26&cat=0&cat=81). Even if you manage to use ‘selected’ in the third dropdown to pre-select a parent Cat id, it will still return all the contents of the parent (an OR function).

            I’m now looking else where to achieve these functions or I’ll have to get them built by someone with a better knowledge than me. I’m now not sure wp_dropdown_categories is the way forward!

            Thanks again for your help.

          7. The taxonomy parameters have different logic. If you have AND search selected, the taxonomy parameters still default to OR logic.

            Adding

            add_filter(‘relevanssi_default_tax_query_relation’, ‘return_and’);

            function return_and($operator) { return ‘AND’; }

            to your functions.php will switch the default taxonomy operator to AND.

            Also, you’re probably going to have trouble with all the dropdowns having the same parameter name.

  7. Hi

    I’m using multiple custom taxonomies on searching, so i try step by step this tutorial.

    The first and second ones works fine, i verified using (var_dump($wp_query)).

    But the last step doesn’t work.

    Where should I put the code?

    1. It’s a filtering function, so anywhere that gets run, but functions.php works. If the function doesn’t run at all, that means Relevanssi is not running.

        1. Well, if a Relevanssi filter is not triggering, that’s a pretty strong indicator. You can also deactivate Relevanssi and see if the results change.

        1. It would require a closer debugging to say why is that. Can you tell me the value that is passed to “relevanssi_where” filter hook when you run a query with a category parameter?

Leave a Reply to Mikko Saari Cancel reply

Are you a Relevanssi Premium customer looking for support? Please use the Premium support form.

Your email address will not be published. Required fields are marked *