Search code examples
phpwordpresswoocommercediscount

How to change Woocommerce variable product min and max prices to reflect discounts


I have implemented this custom code to programmatically discount prices for logged-in users. The discount correctly applies to variation prices, after I choose a variation.

I slightly changed the code to not take into account already discounted products, so my code looks like this

Edit: I also added condition to exclude gift card products from the discount.

add_filter( 'woocommerce_product_get_price', 'custom_discount_price', 10, 2 );
add_filter( 'woocommerce_product_variation_get_price', 'custom_discount_price', 10, 2 );
function custom_discount_price( $price, $product ) {
    // For logged in users
    if ( is_user_logged_in() ) {
        $discount_rate = 0.95; // 5% of discount
        
        // Product is on sale or is a gift card
        if ( $product->is_on_sale() || $product->get_id() == 5770 || $product->get_id() == 5766 || $product->get_id() == 5764 ) {
            return $price;
        }
        // Product is not on sale
        else {
            // Returns the custom discounted price
            return $price * $discount_rate;
        }
    }
    return $price;
}
} 

But on the category page and even on the single variable product page there is this range telling the customers what the product's min variation price to max variation price is and this price range doesn't show discounted prices, but the original ones.

So for example:

I programatically discounted all the products by 90%.

A product has three variations -> X, Y, Z.

For variation X I set a price $10.

For variation Y I set a price $20.

For variation Z I set a price $30.

On category page I can see the product with it's image and the title -> Product: $10 - 30$.

But it should actually display prices $1 - $3, because I programatically discounted all the prices.

I'm looking everywhere and trying anythig, but to no results. Is there a way to achieve this? Thank you.

Edit: I changed the discount rate in the code snippet to 0.95 to match my provided answer.


Solution

  • Ok so this is what I got now.

    My previous answer was severely flawed and didn't account for all possibilities, but I think I got most cases covered.

    After the code in my question I added this code:

    add_filter( 'woocommerce_variable_price_html', 'custom_discount_variable_price', 10, 2 );
    function custom_discount_variable_price( $price, $product ) {
        if ( is_user_logged_in() && ! is_admin() ) {
            $discount_rate = 0.95; // 5% of discount
            $min_var_reg_price = $product->get_variation_regular_price( 'min', true );
            $min_var_sale_price = $product->get_variation_sale_price( 'min', true );
            $max_var_reg_price = $product->get_variation_regular_price( 'max', true );
            $max_var_sale_price = $product->get_variation_sale_price( 'max', true );
            if ( ! ( $min_var_reg_price == $max_var_reg_price && $min_var_sale_price == $max_var_sale_price ) ) {
                // regular price or sale price are not the same
                if ( $min_var_sale_price < $min_var_reg_price * $discount_rate ) {
                    if ($max_var_sale_price < $max_var_reg_price * $discount_rate) {
                        // min_var_sale_price - max_var_sale_price
                        $price = sprintf( __( '%s - %s', 'woocommerce' ), wc_price( $min_var_sale_price ), wc_price( $max_var_sale_price ), $product->get_price_suffix() );
                    } else {
                        // min_var_sale_price - max_var_reg_price
                        $price = sprintf( __( '%s - %s', 'woocommerce' ), wc_price( $min_var_sale_price ), wc_price( $max_var_reg_price * $discount_rate ), $product->get_price_suffix() );
                    }
                } else {
                    if ($max_var_sale_price < $max_var_reg_price * $discount_rate) {
                        // min_var_reg_price - max_var_sale_price
                        $price = sprintf( __( '%s - %s', 'woocommerce' ), wc_price( $min_var_reg_price * $discount_rate ), wc_price( $max_var_sale_price ), $product->get_price_suffix() );
                    } else {
                        // min_var_reg_price - max_var_reg_price
                        $price = sprintf( __( '%s - %s', 'woocommerce' ), wc_price( $min_var_reg_price * $discount_rate ), wc_price( $max_var_reg_price * $discount_rate ), $product->get_price_suffix() );
                    }
                }
            } 
            // regular price or sale price are the same
            else {
                if ( $min_var_sale_price < $min_var_reg_price * $discount_rate ) {
                    $price = $min_var_sale_price;
                } else {
                    $price = $min_var_reg_price * $discount_rate;
                }
                    
            }
            return $price;
        } else {
            return $price;
        }
    }
    

    I took inspiration from the awesome Business Bloomer and edited his code snippet. Then I had to account for different min and max variation prices and their combinations. Now it doesn't matter if it's a sale price or regular price or if some of them are higher than others, the variable product price range should display correctly adjusted for the discount rate.

    I'm suspicious that sometimes it might not work correctly - when I set the discount rate too high some of the prices are not displayed as they should. But while the discount rate stays at 5% it is intended to stay at, it looks like it's working.

    I'm definitely open to suggestions on how to make it work even better.

    Edit: I added is_admin() check to not change prices in admin environment and also added last else{return $price} statement, because I didn't see price range in admin Products page.