Encodera

Thanks for reading!

Donate to the site — we work hard for you.

Contents

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

ParameterWhat it selects
statusThe status: publish, draft
typeThe type: simple, variable
categoryAn array of category slugs: ['mugs']
tagAn array of tag slugs
skuThe SKU, a partial match
stock_statusinstock, outofstock, onbackorder
featuredtrue — featured products only
include, excludeArrays of IDs
limitHow many to return, -1 for all
orderby, orderSorting: date, title, ID, rand
returnobjects 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.

Thanks for reading!

Donate to the site — we work hard for you.