Querying products
To get not one product but a list by a condition — new arrivals, a category's products, everything on sale — use wc_get_products(). It takes an array of conditions and returns an array of WC_Product objects.
A simple query
// wp-content/plugins/acme-shop/includes/products.php
add_action('woocommerce_after_single_product_summary', function () {
$products = wc_get_products([
'status' => 'publish',
'limit' => 4,
'orderby' => 'date',
'order' => 'DESC',
]);
echo '<h2>New arrivals</h2><ul>';
foreach ($products as $product) {
printf(
'<li><a href="%s">%s</a> — %s</li>',
esc_url($product->get_permalink()),
esc_html($product->get_name()),
$product->get_price_html()
);
}
echo '</ul>';
}, 25);The query takes the four latest published products. Open any product page: at the bottom, after the description tabs, a New arrivals list with links and prices appears.
Parameters
| Parameter | What it selects |
|---|---|
status | The status: publish, draft |
type | The type: simple, variable |
category | An array of category slugs: ['mugs'] |
tag | An array of tag slugs |
sku | The SKU, a partial match |
stock_status | instock, outofstock, onbackorder |
featured | true — featured products only |
include, exclude | Arrays of IDs |
limit | How many to return, -1 for all |
orderby, order | Sorting: date, title, ID, rand |
return | objects or ids |
A category's products in stock
$products = wc_get_products([
'category' => ['mugs'],
'stock_status' => 'instock',
'limit' => 12,
]);Conditions are combined with AND: only mugs that are in stock are returned.
IDs only
$ids = wc_get_products([
'category' => ['mugs'],
'limit' => -1,
'return' => 'ids',
]);
echo count($ids);With return => ids the function does not build objects, so it is noticeably faster. This is how products are counted or a list is prepared for another operation.
Pagination
$result = wc_get_products([
'limit' => 12,
'page' => 2,
'paginate' => true,
]);
echo $result->total; // products in total
echo $result->max_num_pages; // pages in total
foreach ($result->products as $product) {
echo $product->get_name();
}With paginate an object is returned instead of an array, with three fields: the products of the current page, the total count and the number of pages.
The query class
wc_get_products() is shorthand for the WC_Product_Query class:
$query = new WC_Product_Query(['category' => ['mugs'], 'limit' => 12]);
$products = $query->get_products();The result is the same. The class is handy when conditions are assembled piece by piece with $query->set('limit', 24).
Searching by meta data
WooCommerce does not understand your own key in the conditions array — it has to be taught with a filter:
// wp-content/plugins/acme-shop/includes/products.php
add_filter('woocommerce_product_data_store_cpt_get_products_query', function (array $query, array $vars): array {
if (isset($vars['acme_lead_time'])) {
$query['meta_query'][] = [
'key' => '_acme_lead_time',
'value' => (int) $vars['acme_lead_time'],
'type' => 'NUMERIC',
];
}
return $query;
}, 10, 2);After that wc_get_products(['acme_lead_time' => 3]) returns products with a lead time of three days.
Common mistake
A query with limit => -1 and without return => ids builds thousands of objects on a large catalog and hits the memory limit. Always set a reasonable limit, and to walk the whole catalog take IDs or read products in batches with page.