skip to Main Content

We are planning to start a campaign. We want to give a temporary 10% discount on every product we sell on our site for the next 30 days. Ideally, we’d like to display both the regular price and the discounted price.

  • Our shop is built on WooCommerce.
  • Our products don’t have variations.
  • We have approximately 200,000 products.
  • Most tools struggle to handle that many products.

How to do this?

2

Answers


  1. Chosen as BEST ANSWER

    How I have done it:

    • Putting all products on sale by updating their _sale_price and _price with the data from _regular_price multiplied by 0.9 (10%).
    • When the promotion ends, manually removing _sale_price and updating _price with _regular_price by executing SQL queries.

    Warning: This solutions don't work with variations!

    Add the discount to all products

    If the products aren't on sale, they don't have _sale_price meta_key in the database table wp_postmeta. To add these, we can loop trough all products and use update_post_meta. When working with bigger databases, I suggest splitting the update into smaller batches. I used 1000 per batch in the code below. If you want the query for all your products at once, replace 'posts_per_page' => 1000 with 'posts_per_page' => -1.

    Warning: This code will not work properly if any of your products already have a _sale_price!

    // Get the products that don't have '_sale_price'
    $args = array(
        'post_type'      => 'product',
        'posts_per_page' => 1000,
        'meta_query'     => array(
            'relation' => 'AND',
            array(
                'key'     => '_sale_price',
                'compare' => 'NOT EXISTS',
            ),
            array(
                'key'     => '_regular_price',
                'value'   => '',
                'compare' => '!='
            ),
        ),
    );
    $products = query_posts( $args );
    
    // Loop through queried products
    foreach ($products as $post) {
        $product = wc_get_product( $post->ID );
    
        // Discount by 10% and round to 2 decimal places
        $discount = 10;
        $newprice = round($product->get_regular_price() * ((100-$discount) / 100), 2);
    
        // Update product's prices
        update_post_meta( $product->get_id(), '_sale_price', $newprice );
        update_post_meta( $product->get_id(), '_price', $newprice );
    }
    

    Remove the discount

    I am using SQL queries, because it's fast and easy. If you are looking for an alternative way to do it, check this post: Remove Sale Price from all products in WooCommerce admin

    Warning: These SQL queries will delete all your existing sale prices!

    Delete all products' _sale_price:

    DELETE FROM `wp_postmeta1` WHERE meta_key = '_sale_price';
    

    Update products' _price with the values of _regular_price:

    UPDATE wp_postmeta as price 
        INNER JOIN wp_postmeta as regular_price ON 
            price.post_id = regular_price.post_id AND 
            regular_price.meta_key = "_regular_price" AND
            price.meta_key = "_price"
        SET price.meta_value = regular_price.meta_value;
    

    References:


  2. Updated (allowing products with zero price and resetting existing sale prices)

    Instead of overwriting products prices as you suggest in your comment, you could use the following to add a temporary global discount, that keeps the original product price with a general sale price with a 10% discount:

    // Below define the discount rate
    function discount_rate(){
        return 0.9; // 10% discount
    }
    
    add_filter('woocommerce_product_get_price', 'custom_price_discount', 20, 2);
    add_filter('woocommerce_product_variation_get_price', 'custom_price_discount', 20, 2);
    function custom_price_discount( $price, $product ) {
        if ( $price > 0 ) {
            return floatval($product->get_regular_price()) * discount_rate();
        }
        return $price;
    }
    
    add_filter('woocommerce_product_get_sale_price', 'custom_sale_price_discount', 20, 2);
    add_filter('woocommerce_product_variation_get_sale_price', 'custom_sale_price_discount', 20, 2); 
    function custom_sale_price_discount( $price, $product ) {
        return $product->get_price();
    }
      
    add_filter('woocommerce_product_is_on_sale', 'custom_product_is_on_sale', 20, 2);
    function custom_product_is_on_sale( $is_on_sale, $product ) {
        return $product->get_price() > 0 ? true : false;
    }
    
    function remove_zero_prices( $prices ) {
        foreach( $prices as $key => $price ) {
            if ( $price > 0 ) {
                continue;
            }
            unset($prices[$key]);
        }
        return $prices;
    }
    
    add_filter( 'woocommerce_get_price_html', 'custom_dynamic_sale_price_html', 20, 2 );
    function custom_dynamic_sale_price_html( $price_html, $product ) {
        if( $product->is_type('variable') ) {
            $prices     = $product->get_variation_prices( true );
            $reg_prices = remove_zero_prices( $prices['regular_price'] );
    
            if ( count($reg_prices) > 0 ) {
                return wc_format_sale_price( wc_price( end($reg_prices) ), wc_price( reset($reg_prices) * discount_rate() ) ) . $product->get_price_suffix();
            } 
        }
        return $price_html;
    }
    

    Code goes in functions.php file of your child theme (or in a plugin). Tested and works. It could work with your very large catalog.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search