Getting the Intersection of Two Custom Taxonomy Terms for a Custom Post Type?

(Moderators note: Was originally titled “How to get_posts of a custom post type that is in two custom taxonomies?”)

I have a custom post type that has two taxonomies which are separate, one called “Project Type” and one called “Package”. I need to get a list of projects which are of “Project Type” A and “Package” A. I tried using following code:

Read More
$args = array(
  'post_type' => 'portfolio', 
  'numberposts' => -1, 
  'project_type' => 'A', 
  'package' => 'A'
); 
$my_posts = get_posts($args);  

But this gets all the posts that are EITHER in Project Type A OR Package A.

Is there any way to say in get_posts() that I want to return only those posts that are in BOTH taxonomies?

Related posts

Leave a Reply

3 comments

  1. As of v1.3, the Query Multiple Taxonomies plugin works great with WP_Query. Your original args work as is.

    $args = array(
    'post_type' => 'portfolio',
    'numberposts' => -1,
    'project_type' => 'A',
    'package' => 'A'
    );
    

    Then make a new query and check it:

    $foo = new WP_Query($args);
    var_dump($foo->posts);
    

    I tested this on my own custom taxonomy setup, and it only returned posts which matched both terms in the query.

    Another convenient method of grabbing multiple taxonomy terms with QMT is building simple URL queries:

    site.com/?post_type=portfolio&package=foo&project=bar
    

    I’ve used this method with the add_query_args() function to create links on a page that modify the current query, refining it by adding additional terms and taxonomies. The syntax also works great with a search input, as multiple words in the input field are posted as foo+bar, which works great with QMT:

    site.com/?post_type=portfolio&project=alpha&colors=red+blue+green
    

    Which returns only posts that meet all these criteria – Type: Portfolio / Project: Alpha / Colors: red + blue + green

  2. Hi @shaun:

    @Rarst is right in that they are adding this functionality to WordPress v3.1, but it won’t be here for a while and I’m sure you need it now. You could try to grab the code they are working on and try to make it work, you could use the plugin both @Rarst and @somatic mention, or you could just include the code you need into your theme, below.

    The following code is a posts_where hook to add a tax_terms query variable with a value of the format (i.e. colon-commas) where the values are term slugs:

    "{$varname1}:{$value1},{$varname2}:{$value2},...{$varnameN}:{$valueN}"
    

    This is a self-contained .php you can drop into the root of your website to test it out before pulling the add_action call and the tax_terms_where() function into your theme’s functions.php file (or into the .php file of one of your own plugins.)

    <?php
    /*
    * Adds "tax_terms" to WP_Query()
    *
    * See: http://lists.automattic.com/pipermail/wp-hackers/2010-October/035258.html
    * See: http://wordpress.stackexchange.com/questions/2255/
    *
    */
    
      header('Content-Type:text/plain');
      include "wp-load.php";
      add_action('posts_where','tax_terms_where',10,2);
    
      $result = new WP_Query('post_type=portfolio&tax_terms=project_type:A,package:A');
      foreach($result->posts as $post) {
        echo "{$post->post_title}n";
      }
    
    function tax_terms_where($where,$wp_query) {
      if (isset($wp_query->query)) {
        $query = $wp_query->query;
        if (is_string($query))
          parse_str($query,$query);
        if (is_array($query) && isset($query['tax_terms'])) {
          global $wpdb;
          $tax_terms = explode(',',$query['tax_terms']);
          foreach($tax_terms as $tax_term) {
            list($taxonomy,$term) = explode(':',$tax_term);
            $sql = <<<SQL
    AND $wpdb->posts.ID IN (
      SELECT tr.object_id
      FROM $wpdb->term_relationships AS tr
      INNER JOIN $wpdb->term_taxonomy AS tt ON tr.term_taxonomy_id = tt.term_taxonomy_id
      INNER JOIN $wpdb->terms AS t ON tt.term_id = t.term_id
      WHERE tt.taxonomy='%s' AND t.slug='%s'
    )
    SQL;
            $where .= $wpdb->prepare($sql,$taxonomy,$term);
          }
        }
      }
      return $where;
    }
    

    If this isn’t exactly what you need because, for example, you’d rather match the $term->term_id instead of matching the $term->slug then the code shouldn’t be too hard to modify for your needs, assuming you are comfortable with SQL and .php.

  3. Old Q, but apparently comes up so here is current state — taxonomy queries got much improved in 3.1 and further since.

    These days it will easily be handled with tax query using AND relationship, example from Codex:

    'tax_query' => array(
        'relation' => 'AND',
        array(
            'taxonomy' => 'movie_genre',
            'field'    => 'slug',
            'terms'    => array( 'action', 'comedy' ),
        ),
        array(
            'taxonomy' => 'actor',
            'field'    => 'term_id',
            'terms'    => array( 103, 115, 206 ),
            'operator' => 'NOT IN',
        ),
    ),
    

    See Taxonomy Parameters for full documentation.


    Usual disclaimer – I hadn’t messed with custom stuff myself so far.

    I think complex taxonomy queries are not implemented in WP core (yet). Try Query Multiple Taxonomies plugin.