19

I'm using WP_Query for Woocommerce products in attempt to query products in a particular category. This is the syntax that worked for me -

$args = array(
    'posts_per_page' => -1,
    'product_cat' => 'category-slug-here',
    'post_type' => 'product',
    'orderby' => 'title',
);
$the_query = new WP_Query( $args );
// The Loop
while ( $the_query->have_posts() ) {
    $the_query->the_post();
    echo '' . get_the_title() . '<br /><br />';
}
wp_reset_postdata();

This returns data, but I want to pass an ID, not a category slug, to filter and I want to find products that exist in multiple categories only.

The argument product_cat is not native to WP_Query (at least that I can find), so I'm assuming this is something custom to Woocommerce. Through their documentation, I haven't been able to find anything that will allow me to filter by category ID, nor use an AND condition for this filtering.

Using cat, the array of tax_query, and category__and have not yielded any results. Essentially, I would like to query all products that exist in both category ID 102, and 115. If I have to use slugs, I'm sure there is a way around getting that info based on the ID I have, but I'd like to avoid 2 queries to filter by multiple categories.

Does anyone know how to accomplish this?

UPDATE: I have learned that separating category slugs by commas in the product_cat argument will produce an "OR" effect, so it will combine distinct products from both, but this is not what I am looking for. So, for example:

 'product_cat' => 'category-slug1, category-slug2'

will return products from both categories in total, but I am still searching for a way to find distinct products that ONLY belong to both, or multiple, categories.

RCNeil
  • 8,581
  • 12
  • 43
  • 61

4 Answers4

46

Wow, so after hours of banging my head, this is how I was able to solve this -

$args = array(
    'posts_per_page' => -1,
    'tax_query' => array(
        'relation' => 'AND',
        array(
            'taxonomy' => 'product_cat',
            'field' => 'slug',
            'terms' => 'category-slug1'
        ),
        array(
            'taxonomy' => 'product_cat',
            'field' => 'slug',
            'terms' => 'category-slug2'
        )
    ),
    'post_type' => 'product',
    'orderby' => 'title',
);
$the_query = new WP_Query( $args );

This takes advantage of the tax_query argument, including the relation => 'AND' to make sure the product falls under BOTH categories.

Hope this helps someone in the future.

I was also not able to figure out how to pass an ID, rather than a slug (although I'm sure there's a way), but here's the function to retrieve the slug based on an ID:

$terms = get_term($YOURID, 'product_cat'); 
$theslug = $terms->slug; 
RCNeil
  • 8,581
  • 12
  • 43
  • 61
  • RCNeil is this when you have the same product in 2 categories? I noticed that when I have a product which is in 2 categories, WooCommerce only shows the product details for 1 category in both categories. Trying to figure out how to have eg `smarties` show in `sweets` and `chocolate` and have the url path `sweets/smarties` and `chocolate/smarties` as my WooCommerce only shows one url for both – ngplayground Jan 22 '14 at 16:55
  • Yes, this query was meant for products that fall under 2 (or more) categories. I'm not sure how Woocommerce determines the URL for which category takes precedence. I used it for an auto parts store, and most of the time it made the URL based of the Make/Model/Car/Part, not Brand/Part, but it varied. – RCNeil Jan 22 '14 at 18:49
  • So this would change the URL for the product in each category? Where do I place it? – ngplayground Jan 22 '14 at 19:25
  • I'm saying if you put a product in 2 categories, then 2 URLs will be created like `sweets/smarties` and `chocolates/smarties` and that both would be correct. Both will resolve to that single product. When you query them, I do not know which permalink it returns, I am not sure how that priority is determined, but it will work either way. I don't know what else you are asking me. – RCNeil Jan 22 '14 at 22:40
  • Where did you place your script in WooCommerce? I can try figure things out along the way – ngplayground Jan 23 '14 at 00:01
  • You don't put it in WooCommerce, you place this in your theme. Typically in a custom page template. If you wanted it to be the home page, you'd either make a custom page template for that, or edit your index.php file, depending on your theme. – RCNeil Jan 23 '14 at 04:16
  • Just tried placing it in by changing `'terms' => 'category-slug1'` to `'terms' => 'chocolate'` its not outputting anything even though the category slug is correct – ngplayground Jan 23 '14 at 08:46
  • Thanks that's very helpful! for some reason `cat` => CAT_ID wasn't getting any products in $args and i was getting "AND 1 = 0" in the query, also it returned all products without that condition, using relation fixed it. – 0xAli Mar 02 '14 at 17:37
  • You can also add `['product_cat' => 'category-slug1,category-slug2']` a comma list will also work – tristanbailey Aug 10 '21 at 12:12
17

From the WordPress codex on WP_Query for Category Parameters:

equivalent of OR

$args = array( 'product_cat' => 'category-slug1,category-slug2' );

equivalent of AND

$args = array( 'product_cat' => 'category-slug1+category-slug2' );

e.g.

$query = new WP_Query( $args );
Jon
  • 6,437
  • 8
  • 43
  • 63
Daniel Twork
  • 179
  • 1
  • 2
11

To query by category_ID this is what worked for me.

// First obtain term id:
//...
$all_categories = get_categories( $args );
$cat_ids = array();

foreach ($all_categories as $cat) 
{
     array_push($cat_ids, $cat->term_id);
}

//Now use ids from array:
$args = array(
    'posts_per_page' => -1,
    'post_type' => 'product',
    'tax_query'     => array(
        array(
            'taxonomy'  => 'product_cat',
            'field'     => 'id', 
            'terms'     => $cat_ids
        )
    )
);
user2718602
  • 129
  • 1
  • 5
1

Inside a 'tax_query' array's array you can specify an 'operator' to be performed on the query. You can achieve what you want using the 'AND' operator.

$args = array(
'posts_per_page' => -1,
'tax_query' => array(
    'relation' => 'AND',
    array(
        'taxonomy' => 'product_cat',
        'field' => 'slug',
        'terms' => array( 'category-slug1', 'category-slug2' )
        'operator => 'AND',
    ),
),
'post_type' => 'product',
'orderby' => 'title',
);
$the_query = new WP_Query( $args );

All of the products selected by this query will match the provided 'terms'. See this link for more info: https://codex.wordpress.org/Class_Reference/WP_Query#Taxonomy_Parameters

In case the link ever breaks, here's the relevant info:

operator (string) - Operator to test. Possible values are 'IN', 'NOT IN', 'AND', 'EXISTS' and 'NOT EXISTS'. Default value is 'IN'.

asdf
  • 53
  • 6