phpwordpresswoocommercecartdiscount

WooCommerce Progressive discount based on cart subtotal if there are no discounted items


I am using the following code that applies progressive discounts based on order amount.

add_action('woocommerce_cart_calculate_fees', 'woo_discount_total');
function woo_discount_total(WC_Cart $cart) {

    if( is_admin() && !defined('DOING_AJAX') ) {
        return;
    }
    $woo_current_price = $cart->subtotal;

    if($woo_current_price >= 3000 && $woo_current_price <= 9990) {
        $discount = $cart->subtotal * 0.02; // 0.02 = 2%
        $cart->add_fee('Sale 2% ', -$discount);
    }
    elseif($woo_current_price >= 10000) {
        $discount = $cart->subtotal * 0.05; // 0.05 = 5%
        $cart->add_fee('Sale 5% ', -$discount);
    }
}

But there is a problem. If there is a product on sale with a 15% discount in the cart, then all discounts are summed.

As far as I understand, I need to spell out the conditions?

What I would like is:

How can this be implemented?


Solution

  • A discounted item could be:

    In the code below I have implemented both, so if a coupon is applied or if there is an "on sale" item, Your custom progressive discount based on cart subtotal will not be applied.

    Try:

    // Conditional function that check if there are cart items "on sale"
    function has_items_on_sale( $cart ) {
        // Loop through cart items
        foreach ( $cart->get_cart() as $item ) {
            if ( $item['data']->is_on_sale() ) {
                return true;
            }
        }
        return false;
    }
    
    // Progressive discount based on cart subtotal
    add_action( 'woocommerce_cart_calculate_fees', 'subtotal_based_progressive_discount' );
    function subtotal_based_progressive_discount( $cart ) {
        if( is_admin() && !defined('DOING_AJAX') ) {
            return;
        }
        // Exit if a cart item is on sale
        if( has_items_on_sale( $cart ) ) {
            return;
        }
        // Exit if a coupon has been applied to cart
        if( $cart->get_applied_coupons() ) {
            return;
        }
    
        $subtotal = $cart->subtotal;
        $percent  = 0;
    
        if( $subtotal >= 3000 && $subtotal < 10000 ) {
            $percent = 2; // 2 %
        } elseif( $subtotal >= 10000 ) {
            $percent = 5; // 5 %
        }
    
        if( $percent > 0 ) {
            $cart->add_fee( __('Sale') . " {$percent}%", -($subtotal * $percent / 100) );
        }
    }
    

    It should work.


    Addition:

    Progressive discount based on cart item subtotal excluding "on sale" items.

    Alternatively, you can use the following to apply a progressive discount on the subtotal excluding "on sale" items (if there is no applied coupons):

    // Utility function: Get cart subtotal excluding on sale items
    function get_subtotal_excluding_on_sale_items( $cart, $subtotal = 0 ) {
        // Loop through cart items
        foreach ( $cart->get_cart() as $item ) {
            if ( ! $item['data']->is_on_sale() ) {
                $subtotal = $item['line_subtotal'] + $item['line_subtotal_tax'];
            }
        }
        return $subtotal;
    }
    
    // Progressive discount based on cart subtotal
    add_action( 'woocommerce_cart_calculate_fees', 'subtotal_based_progressive_discount' );
    function subtotal_based_progressive_discount( $cart ) {
        if( is_admin() && !defined('DOING_AJAX') ) {
            return;
        }
        
        // Exit if a coupon has been applied to cart (optional)
        if( $cart->get_applied_coupons() ) {
            return;
        }
    
        $subtotal = get_subtotal_excluding_on_sale_items( $cart );
        $percent  = 0;
    
        if( $subtotal >= 3000 && $subtotal < 10000 ) {
            $percent = 2; // 2 %
        } elseif( $subtotal >= 10000 ) {
            $percent = 5; // 5 %
        }
    
        if( $percent > 0 ) {
            $cart->add_fee( __('Sale') . " {$percent}%", -($subtotal * $percent / 100) );
        }
    }
    

    It should work.