Get a list of WooCommerce sale products

You can get lists of all simple products, variable products, or featured products easily with WooCommerce. It’s also easy to get things like “in-stock” products or “out of stock” products. However, getting a list of WooCommerce sale products can be a bit tougher because sale products use different meta keys to determine sale status depending on the product type.

Let’s take a look at a couple of ways you can get sale products.

Check sale status

First of all, this post will tell you how to get all sale products. If you’re only interested in checking for sale status with one product, there’s a very simple way to do that:

global $product;
if ( $product->is_on_sale() ) {

We’re talking about querying all sale products instead.

Display all sale products

First of all, many developers want to query sale products so they can display them in a custom template or archive page.

If you want to display all sale products in a “deals” page or something and you want to use the WooCommerce loop to display them, you can easily do so via the sale products shortcode. No complex queries or additional code necessary 🙂 :

[sale_products columns="3" per_page="12"]

This lets WooCommerce do the heavy lifting for you, so use this if you’re just looking to output an archive of sale products:

WooCommerce sale products

On Sale page

Querying WooCommerce sale products

You can use WP_Query to get your sale products, but how you do this matters. The default recommendation is typically to use the _sale_price meta to key to determine which products are on sale.

The issue with this is that variable products don’t use this key, so it would only return simple products. No problem, right? Let’s just add the meta key that variable products use as well: _min_variation_sale_price. We can then query both of these keys with an OR relationship to get products with either meta key.

$args = array(
    'post_type'      => 'product',
    'posts_per_page' => 8,
    'meta_query'     => array(
        'relation' => 'OR',
        array( // Simple products type
            'key'           => '_sale_price',
            'value'         => 0,
            'compare'       => '>',
            'type'          => 'numeric'
        array( // Variable products type
            'key'           => '_min_variation_sale_price',
            'value'         => 0,
            'compare'       => '>',
            'type'          => 'numeric'

$loop = new WP_Query( $args );

This totally works. You can now do whatever you’re trying to do with sale products that’s not simply outputting them onto the page. That doesn’t mean it’s the best way to get your sale products.

Let’s return to that shortcode we mentioned before to see how WooCommerce gets sale products.

Whoa, they’re doing something different. This uses the wc_get_product_ids_on_sale() function, which returns an array containing the IDs of the products that are on sale. This lets them use a simple query to get the sale products:

$query_args = array(
    'posts_per_page'    => 8,
    'no_found_rows'     => 1,
    'post_status'       => 'publish',
    'post_type'         => 'product',
    'meta_query'        => WC()->query->get_meta_query(),
    'post__in'          => array_merge( array( 0 ), wc_get_product_ids_on_sale() )
$products = new WP_Query( $query_args );

This is a more efficient way to query WooCommerce sale products.

So why is this better?

  • it’s easier for SQL to run the single post__in query compared to the more complicated query for meta keys
  • this method uses a separate query to get the product IDs on sale, and that can be parsed and optimized (related to next point)
  • querying for post__in when we already have the IDs is much, much faster because the wc_get_product_ids_on_sale function uses a transient, meaning this query is skipped if the transient exists

The moral of the story is that WooCommerce (and WordPress) optimize a lot for you, so before building your own query, take a look at how WooCommerce core handles this to see if there are similar use cases, or if there’s a function that can do part of the query for you.


  • Niloy Sarker 2 years ago Reply

    Thank you very much for this article. it’s really help me to create my new woocommerce plugin.

  • Aaron 1 year ago Reply


    I am using the mystile theme and trying to have a category called “Sale Items” which automatically gets populated with all the items that are currently on sale.

    Is it possible to do this?


    • Andrew Halloway 5 months ago Reply

      HI Aaron

      I am trying to do this as well, did you ever work out how?


  • Sean 1 year ago Reply


    I used your Dynamic Pricing plugin to discount a whole category by 20%, the products show that they are on sale, but when I use the shortcode to display all my sale items, none of the products discounted through Dynamic Pricing show up.

    Is there a fix for this one at all? Cheers!

    • Beka Rice 1 year ago Reply

      Hey Sean, I’m afraid we don’t have a Dynamic Pricing plugin, I’d recommend getting in touch with the author for support 🙂

  • prashant 1 year ago Reply

    thanks a lot it’s a really working nice once.

  • Bradley Lancaster 9 months ago Reply

    Thanks so much. Do you guys have say building a woocommerce theme from scratch course? I did the Treehouse one its good but not complete and not from scratch. Do you know where you can get a book or video training like this?


  • mike woythaler 8 months ago Reply

    Hello Max and Beka Rice: Thanks so much for the information you unselfishly shared in this article. I’m new to WC, learning it for the last 4 days. I’m interested in querying all products that have sales percentage > 70%. Could you give some pointers as how to go about doing that (what the $query_arg looks like, etc.) Thanks so much. Please keep up the great work:)

  • Musyafak 7 months ago Reply

    How to create spesific promotion page for example weekend sale page, promo page with prizes etc

  • Rick van Modem 6 months ago Reply

    Your article doesn’t really make clear that the function wc_get_product_ids_on_sale() does not return variation products on sale. So even though it might be a faster function, it’s also an incomplete one.

    • Rick van Modem 6 months ago Reply

      Whooops… It does actually. I guess I just messed up myself.

  • Dan Atrill 5 months ago Reply

    Very useful, thanks!

  • Titos Antypas 5 months ago Reply

    Very good article! I would like to ask how i can display all the on sale products of a SPECIFIC category on a sales page…

    • Beka Rice 5 months ago Reply

      Hey Titos, a custom query would probably be needed in that case, I’d recommend having a look at the taxonomy query parameters to get a specific category instead of all sale products.

Submit a Comment