0

I'm hoping someone can help as I have searched and cannot find an answer...

I am using a loop in a shortcode to display a list of related items and I'm having trouble working out the logic of selecting multiple categories in an AND parameter.

For example, I have a category structure like this:

Products (id: 1)
   Prod A (id: 2)
   Prod B (id: 3)
Services (id: 4)
   Service A (id: 5)
   Service B (id: 6)
Overview (id: 7)

What I would like to do is show all posts that are categorised as id 7 AND specific other IDs.

For example:

'category__and' => array(7,2),
AND 
'category__and' => array(7,5),

Which would show 2 results - posts categorised as (Overview AND Prod A) AND (Overview AND Service A).

Everything works if I only want to show one selection (eg. Overview AND Prod A) but I can't work out how to show multiples.

Changing it to category__in does not work because that shows all posts categorised as Overview including Prod B and Service B, in the above example. It's also not practical to use category__not_in to exclude categories because the list is quite long and will change (unless there's a way of programmatically working out which categories to exclude?).

Is there a way of using multiple pairs of category__and values, or a way of coding multiple loops for WP_Query to achieve this?

I hope that gives you enough to go on. Thanks in advance!

4
  • you could do 2 queries and then merge the results
    – locomo
    Commented Dec 22, 2017 at 1:24
  • Thanks @locomo. I don't suppose you have an example of how to do that by any chance?
    – washoc
    Commented Dec 22, 2017 at 1:45
  • I should possibly also add that the second IDs (ie. 2 and 5) are coming from a custom field and there might be lots of them. The example above just shows 2 for ease of explaining.
    – washoc
    Commented Dec 22, 2017 at 1:46
  • i'd suggest clarifying your original question so that people can offer good solutions .. i'm a little confused. So is the query really for Posts with category==7 and customfield1==2 AND Posts with category==7 and customfield2==5? How is that different from Posts with category==7 and customfield1==2 and customfield2==5? If the later is correct then you can do it with a meta query. I'll try posting and answer for this.
    – locomo
    Commented Dec 23, 2017 at 15:17

2 Answers 2

0

I'm little unclear from your question if the criteria has to match the Product AND the Service .. or the Product OR the Service. You can change the 'relation' parameter to achieve this (AND or OR)

$args = array(
    'posts_per_page'  => -1,
    'cat' => 7,
    'meta_query' => array(
        'relation' => 'AND',
        array(
            'key'     => 'product_customfield',
            'value'   => 2,
            'compare' => '=',
        ),
        array(
            'key'     => 'service_customfield',
            'value'   => 5,
            'compare' => '=',
        ),
    ),
);
$query = new WP_Query( $args );
1
  • Thanks @locomo, your original suggestion led me to find solution (see below) but this method you have just suggested might be better...
    – washoc
    Commented Dec 24, 2017 at 12:44
0

Thanks for the suggestions and to @locomo for suggesting merging results. The logic of my solution was to:

  • Create an empty array to hold page IDs: $buildlist = array();
  • Get the associated categories from the custom field: $items = get_field('related_overview');
  • Run a foreach loop on $items and within that run WP_Query to get the IDs of pages matching those categories, adding them to the $buildlist array
  • Remove duplicates from the $buildlist array
  • Use the $buildlist array in a final WP_Query as the 'post__in' value
  • The values in related_overview come from an advanced custom field using Taxonomy values

I don't know if this is the most efficient way of doing it but it has the results I was looking for. Code shared here for completeness of the answer and in case it helps anyone else. Any suggestions for improvement are welcome!

add_shortcode( 'related_overview', 'fn_related_overview' );
function fn_related_overview( $atts ) {

    ob_start();

      //set up array to hold page IDs which is built from looping queries of related items from custom field
      $buildlist = array();

      //get related items from custom field and add them to the array
      $items = get_field('related_overview');

  // define attributes and their defaults
    extract( shortcode_atts( array (
        'posts' => -1,
        'columns' => 4, //1-6
    ), $atts ) );

      //loop through values in custom field and add page ids to merged array to use in final query
      foreach($items as $post) {
          $relatedcatid = $post->term_id;

    //use category__and to specify overview category (ID 64) AND others in a loop
    $options1 = array(
        'post_type' => 'page',
        'orderby' => 'date',
        'posts_per_page' => $posts,
        'category__and' => array(64,$relatedcatid),
    );

            $query1 = new WP_Query( $options1 );
            while ( $query1->have_posts() ) : $query1->the_post();
              //add page ID to the buildlist                    
              $buildlist[] = get_the_ID();
            endwhile;

    }//end foreach

      //remove duplicates from array of page ids in case they are tagged to multiple categories
      $buildlist = array_unique($buildlist);

//Set up main query using page IDs from buildlist
    $options = array(
        'post_type' => 'page',
        'orderby' => 'date',
        'posts_per_page' => $posts,
        'post__in' => $buildlist,
    );


        //run main query and loop through results
  $query = new WP_Query( $options );

    if ( $query->have_posts() ) { 
    ?>

HTML BEFORE LOOP HERE

            <?php while ( $query->have_posts() ) : $query->the_post();          ?> 

HTML INSIDE LOOP HERE
<?php echo the_title(); ?>

            <?php endwhile;
            wp_reset_postdata(); ?>

HTML AFTER LOOP HERE

        <?php $myvariable = ob_get_clean();
    return $myvariable;
    }//end if has posts
} //end function

I hope that helps. Thanks.

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.