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

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

  • Aaron 2 years ago


    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 10 months ago

      HI Aaron

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


  • Sean 2 years ago


    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 2 years ago

      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 2 years ago

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

  • Bradley Lancaster 1 year ago

    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 1 year ago

    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 12 months ago

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

  • Rick van Modem 11 months ago

    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 11 months ago

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

  • Dan Atrill 10 months ago

    Very useful, thanks!

  • Titos Antypas 10 months ago

    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 10 months ago

      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.

Hmm looks like this article is over 2 years old! Its content may be outdated, so comments are now closed.