Search code examples
phpwordpresswoocommercecart

Tiered Shipping based on cart subtotal in Woocommerce


In Woocommerce, I need to set up shipping costs based on cart subtotal as following:

  • if price is below 20€ the shipping cost is 5,90€,
  • if price start from 20€ and below 30€ the shipping cost 4,90€
  • if price start from 30€ and up the shipping cost 3,90€.

I have very basic PHP knowledge and have modified a code snippet that I have found.

This is my code:

add_filter('woocommerce_package_rates','bbloomer_woocommerce_tiered_shipping', 10, 2 );
function bbloomer_woocommerce_tiered_shipping( $rates, $package){
    $threshold1 = 20;
    $threshold2 = 30;
    if ( WC()->cart->subtotal < $threshold1 ){
        unset( $rates['flat_rate:5'] );
        unset($rates['flat_rate:6']);
    } elseif((WC()->cart->subtotal>$threshold1)and(WC()->cart->subtotal<$threshold2) ) {
        unset( $rates['flat_rate:1'] );
        unset( $rates['flat_rate:6'] ); 
    } elseif((WC()->cart->subtotal > $threshold2) and (WC()->cart->subtotal > $threshold1) ) {
        unset( $rates['flat_rate:1'] );
        unset( $rates['flat_rate:5'] );  
    }
    return $rates;
}

This seems to be working, but sometimes (and I have not figured out the trigger!) it doesn't and all three shipping methods show up in the cart. I think I noticed that it only happens when a user is logged in, but I am not 100% sure on this.

Is my function is correct? Do need to change or improve anything?


Solution

  • I have revisited your code a bit. You should try the following:

    add_filter('woocommerce_package_rates','subtotal_based_tiered_shipping', 10, 2 );
    function subtotal_based_tiered_shipping( $rates, $package ){
        $threshold1 = 20;
        $threshold2 = 30;
        $subtotal = WC()->cart->subtotal;
        
        if ( $subtotal < $threshold1 ) 
        { // Below 20 ('flat_rate:1' is enabled)
            unset( $rates['flat_rate:5'] );
            unset( $rates['flat_rate:6'] );
        } 
        elseif ( $subtotal >= $threshold1 && $subtotal < $threshold2 ) 
        { // Starting from 20 and below 30 ('flat_rate:5' is enabled)
            unset( $rates['flat_rate:1'] );
            unset( $rates['flat_rate:6'] ); 
        } 
        elseif ( $subtotal >= $threshold2 ) 
        { // Starting from 30 and up ('flat_rate:6' is enabled)
            unset( $rates['flat_rate:1'] );
            unset( $rates['flat_rate:5'] );  
        }
        return $rates;
    }
    

    Code goes in function.php file of your active child theme (or active theme).

    It should works now as intended.

    To make it work with "Free shipping" methods too, you will have to disable "Free shipping requires..." option (set to "N/A").


    Sometimes you should need to refresh shipping caches:

    Once saved this code and emptied cart, go to your shipping settings. In your shipping zone, disable save and re-enable save your shipping methods.