Filtering Posts by Multiple Taxonomy Terms such as in an Admin Post Listing?

After reading
Adding a Taxonomy Filter to Admin List for a Custom Post Type? I tried it but I wasn’t able to get it to filter two (2) different taxonomies at same time. The system is only filtering latest taxonomy and ignoring other one.

Does anyone know how to filter two taxonomies at same time?

Related posts

Leave a Reply

2 comments

  1. I don’t have the time to actually write up a fully working example for you right now, but since you requested help in email I figured I would point you in the right direction.

    As you may or may not know, this isn’t really an issue for the admin post listing; most all of that code should work fine. The issue is that currently WordPress does not have the ability to use query_posts()/get_posts()/WP_Query to filter on more than one taxonomy term without using hooks. (There is a very good chance that will change in v3.1; we can only hope!)

    The solution is to use a 'posts_where' hook as illustrated here with the tax_terms_where() function written for that answer:

    You’ll also need to modify the 'parse_query' hook to capture your filter values, something like this (I have not tested this, so there may be small syntax errors):

    <?php
    add_filter('parse_query','yoursite_parse_query');
    function yoursite_parse_query($query) {
      global $pagenow;
      $qv = &$query->query_vars;
      if ($pagenow=='edit.php') {
        $tax_terms = array();
        if (!empty($qv['marka'])) 
          $tax_terms[] = "marka:{$qv['marka']}";
        if (!empty($qv['konu'])) 
          $tax_terms[] = "konu:{$qv['konu']}";
        if (count($tax_terms)) 
          $qv['tax_terms'] = implode(',',$tax_terms);
      }
    }
    

    The above assumes you have dropdowns with names of 'marka' and 'konu'. You’ll probably also need to tell WordPress to recognize them as query vars using an 'admin_init' hook. Again, I haven’t tested this so I’m hoping it works as written:

    add_action('init','yoursite_init');
    function yoursite_init() {
      global $wp;
      $wp->add_query_var('marka');
      $wp->add_query_var('konu');
    }
    

    That’s about it. Combine the knowledge of the three posts; this one, the one on admin lists, and the one on multiple taxonomy queries and I think you’ll get it done. You might even want to post your solution for others to learn from. Let me know if you get stuck.

  2. Late answer

    Update for WordPress 3.5+

    I wrote the following plugin to extend the WP_List_Tables for built in and custom post types with the following features:

    • Add column (if show_admin_column is set to false)
    • Add the taxons incl. links to the table cell
    • Add a dropdown that shows the amount of posts assigned to the taxon to filter the displayed posts
    • Allow for filtering by more than one taxonomy

    Here’s the plugin (best served as mu-plugin):

    add_action( 'plugins_loaded', array( 'WCM_Admin_PT_List_Tax_Filter', 'init' ) );
    class WCM_Admin_PT_List_Tax_Filter
    {
        private static $instance;
    
        public $post_type;
    
        public $taxonomies;
    
        public $new_cols = array();
    
        static function init()
        {
            null === self :: $instance AND self :: $instance = new self;
            return self :: $instance;
        }
    
        public function __construct()
        {
            add_action( 'load-edit.php', array( $this, 'setup' ) );
        }
    
        public function setup()
        {
            add_action( current_filter(), array( $this, 'setup_vars' ), 20 );
            add_action( 'restrict_manage_posts', array( $this, 'get_select' ) );
            add_filter( "manage_taxonomies_for_{$this->post_type}_columns", array( $this, 'add_columns' ) );
        }
    
        public function setup_vars()
        {
            $this->post_type  = get_current_screen()->post_type;
            $this->taxonomies = array_diff(
                 get_object_taxonomies( $this->post_type )
                ,get_taxonomies( array( 'show_admin_column' => 'false' ) )
            );
        }
    
        public function add_columns( $taxonomies )
        {
            return array_merge(
                 $taxonomies
                ,$this->taxonomies
            );
        }
    
        /**
         * Select form element to filter the post list
         * @return string HTML
         */
        public function get_select()
        {
            $html = '';
            foreach ( $this->taxonomies as $tax )
            {
                $options = sprintf(
                 '<option value="">%s %s</option>'
                ,__( 'View All' )
                    ,get_taxonomy( $tax )->label
                );
                $class = is_taxonomy_hierarchical( $tax ) ? ' class="level-0"' : '';
                foreach ( get_terms( $tax ) as $taxon )
                {
                    $options .= sprintf(
                         '<option %s%s value="%s">%s%s</option>'
                        ,isset( $_GET[ $tax ] ) ? selected( $taxon->slug, $_GET[ $tax ], false ) : ''
                        ,'0' !== $taxon->parent ? ' class="level-1"' : $class
                        ,$taxon->slug
                        ,'0' !== $taxon->parent ? str_repeat( '&nbsp;', 3 ) : ''
                        ,"{$taxon->name} ({$taxon->count})"
                    );
                }
                $html .= sprintf(
                    '<select name="%s" id="%s" class="postform">%s</select>'
                    ,$tax
                    ,$tax
                    ,$options
                );
            }
    
            return print $html;
        }
    }
    

    Explanation

    First I did an awesome, but large work-around to get the custom columns in (didn’t know about the 3.5 update for show_admin_column). Then I did a lot to parse_query to get it filter by two taxonomies. Luckily I instantly had a surprising result (with no code added). Look at the following example dump:

      public 'tax_query' => 
        object(WP_Tax_Query)[429]
          public 'queries' => 
            array (size=2)
              0 => 
                array (size=5)
                  'taxonomy' => string 'post_format' (length=11)
                  'terms' => 
                    array (size=1)
                      0 => string 'post-format-gallery' (length=19)
                  'include_children' => boolean true
                  'field' => string 'slug' (length=4)
                  'operator' => string 'IN' (length=2)
              1 => 
                array (size=5)
                  'taxonomy' => string 'category' (length=8)
                  'terms' => 
                    array (size=4)
                      0 => int 5
                      1 => int 6
                      2 => int 7
                      3 => int 8
                  'include_children' => boolean false
                  'field' => string 'term_id' (length=7)
                  'operator' => string 'IN' (length=2)
          public 'relation' => string 'AND' (length=3)
    

    WP already does this by default!