Support » Fixing WordPress » Advanced (multiple) Tag Filters

  • Resolved thepeel

    (@thepeel)


    I have a clients that has all of their posts tagged and wants to call posts based on very specific tag relationships.

    For example, they want to pull all posts who have the following

    (tag1 AND tag2) OR (tag1 AND tag3) OR (tag1 AND tag4)

    I realize that could also be written as

    tag1 AND (tag2 OR tag3 OR tag4)

    I’ve tried all manner of options and have so far been unsuccessful at getting this to work. It appears as though wordpress can only do ANDs or ORs but not both like the above.

    I feel like this should be doable but I’m just missing something. Once I get this done I can move onto trying to figure out how to get it to exclude certain tags as well which is their next request.

    tag1 AND (tag2 OR tag3 OR tag4) NOT (tag5 AND/OR tag6)

    Thanks in advance, this has been driving me nuts for days.

Viewing 5 replies - 1 through 5 (of 5 total)
  • Moderator stephencottontail

    (@stephencottontail)

    The best way to do this is by calling a second instance of WP_Query and using the taxonomy parameters: https://codex.wordpress.org/Class_Reference/WP_Query#Taxonomy_Parameters The syntax is a bit clumsy at first, but it makes sense as you work with it some more.

    To do something like your first example:

    $args = array(
      'post_type' => 'post',
      'tax_query' => array(
        'relation' => 'AND',
        array(
          'taxonomy' => 'post_tag',
          'field' => 'slug',
          'terms' => 'tag-1'
        ),
        array(
          'taxonomy' => 'post_tag',
          'field' => 'slug',
          'terms' => array( 'tag-2', 'tag-3', 'tag-4' )
        )
    );
    $query = new WP_Query( $args );

    You would then use the query methods with the new $query to run the loop:

    if ( $query->have_posts() ) :
      while ( $query->have_posts() ) : $query->the_post();
        .. display posts ..
      endwhile;
    endif;

    Thanks for the reply. I tried this earlier and my code looked almost identical, but your code works 🙂 I think the only difference might have been that I am not sure if I was using slugs or not.

    So in your example, which has the relation outside, would I just add a third array to the tax_query to handle a not like so:

    $args = array(
      'post_type' => 'post',
      'tax_query' => array(
        'relation' => 'AND',
        array(
          'taxonomy' => 'post_tag',
          'field' => 'slug',
          'terms' => 'tag-1'
        ),
        array(
          'taxonomy' => 'post_tag',
          'field' => 'slug',
          'terms' => array( 'tag-2', 'tag-3', 'tag-4' )
        ),
        array(
          'taxonomy' => 'post_tag',
          'field' => 'slug',
          'terms' => array( 'tag-5', 'tag-6'),
          'operator' => 'NOT IN'
        ),
    );
    $query = new WP_Query( $args );

    So frustrating that I was so close all day and just mucked it up by something small. I eventually assumed that I couldn’t use post_tag twice.

    Also, in thinking about it, I’m trying to make it somewhat dynamic, any ideas on how to do it the first way with the ANDs grouped? This would allow me to setup repeater fields that could be pulled in dynamically, counted and turned into the query.

    Either way, thanks again! Very helpful and surprising it’s not out there somewhere already.

    Trying this, but it keeps breaking the site. It’s also big and ugly.

    $args = array(
         'post_type' => 'posts',
         'tax_query' => array(
              'relation' => 'OR',
              array(
                   'relation' => 'AND',
                   array(
                        'taxonomy' => 'post_tag',
                        'field' => 'slug',
                        'terms' => 'tag-1'
                   ),
                   array(
                        'taxonomy' => 'post_tag',
                        'field' => 'slug',
                        'terms' => 'tag-2',
                   ),
              ),
              array(
                   'relation' => 'AND',
                   array(
                        'taxonomy' => 'post_tag',
                        'field' => 'slug',
                        'terms' => 'tag-1'
                   ),
                   array(
                        'taxonomy' => 'post_tag',
                        'field' => 'slug',
                        'terms' => 'tag-3',
                   ),
              ),
              array(
                   'relation' => 'AND',
                   array(
                        'taxonomy' => 'post_tag',
                        'field' => 'slug',
                        'terms' => 'tag-1'
                   ),
                   array(
                        'taxonomy' => 'post_tag',
                        'field' => 'slug',
                        'terms' => 'tag-4',
                   ),
              ),
         ),
    );

    I’ve now gone through all of the clients requested options and there are many different combinations. This is going to take awhile to figure out. Just for fun here they are.

    (tag-1 OR tag-2)
    (tag-1 AND tag-2)
    (tag-1 AND tag-2) OR (tag-3)
    (tag-1 AND tag-2) OR (tag-3 AND tag-4)
    (tag-1 OR tag-2) AND (tag-3 OR tag-4)
    (tag-1 OR tag-2) NOT (tag-3 OR tag-4)
    (tag-1 AND tag-2) NOT (tag-3 OR tag-4)
    (tag-1 AND tag-2) OR (tag-3) NOT (tag-4 OR tag-5)

    I’ll likely mark this resolved in the morning.

    This certainly worked great and and solved many issues. Other issues jumped up in its place but overall this is very handy.

    Moderator stephencottontail

    (@stephencottontail)

    I’m a bit late on this, but in your most recent code, you’ve got

    'post_type' => 'posts'

    and it should be

    'post_type' => 'post'.

    Also, I’m not 100% sure why this happens, but when I use your code, the CPU usage for mysqld jumps up to around 380-390%, whereas with my code that I posted a day ago, the usage remains less than 1%.

Viewing 5 replies - 1 through 5 (of 5 total)
  • The topic ‘Advanced (multiple) Tag Filters’ is closed to new replies.