Search code examples
phpwoocommercecartminimumshipping-method

Set Local pick up cost to zero when Free shipping is available in WooCommerce


I offer free shipping for €45. I have hidden the other shipping methods, except local pick-up, when free is available using the code below.

add_filter( 'woocommerce_package_rates', 'hide_shipping_except_local_when_free_is_available', 100 );
function hide_shipping_except_local_when_free_is_available($rates) {
    $free = $local = array();

    foreach ( $rates as $rate_id => $rate ) {
        if ( 'free_shipping' === $rate->method_id ) {
            $free[ $rate_id ] = $rate;
        } elseif ( 'local_pickup' === $rate->method_id ) {
            $local[ $rate_id ] = $rate;
        }
    }
    return ! empty( $free ) ? array_merge( $free, $local ) : $rates;
}

My problem here is that Local pick-up must be free when cart subtotal is up to €45, so the customer must be able to choose between 2 free options (free shipping or local pick-up free) when free shipping is available or choose between paid shipping options.

I can't find the way to do it. Any help will be appreciated.


Solution

  • To offer also free local pickup when free shipping is available (keeping other shipping methods hidden), try to use the following code replacement (commented):

    add_filter( 'woocommerce_package_rates', 'filter_woocommerce_package_rates', 100, 2 );
    function filter_woocommerce_package_rates( $rates, $package ) {
        $free = array(); // Initializing variable
    
        // 1st Loop (free shipping): Loop through shipping rates for the current shipping package
        foreach ( $rates as $rate_key => $rate ) {
            if ( 'free_shipping' === $rate->method_id ) {
                $free[$rate_key] = $rate;
                break;
            }
        }
    
        // 2nd Loop (local pickup): Loop through shipping rates for the current shipping package
        foreach ( $rates as $rate_key => $rate ) {
            // Set 'local_pickup' cost to zero when free shipping is available
            if ( 'local_pickup' === $rate->method_id && ! empty($free) ) {
                $taxes = array(); // Initializing variable
    
                // Loop through tax costs
                foreach ($rate->taxes as $key => $tax) {
                    $taxes[$key] = 0; // Set tax cost to zero
                }
                $rate->cost = 0; // Set cost to zero
                $rate->taxes = $taxes; // Set back taxes costs array
                $free[$rate_key] = $rate; // Set this rate into the $free array
                break; // Remove this, if there is more than 1 Local pickup option for a shipping Zone
            }
        }
        return ! empty($free) ? $free : $rates;
    }
    

    Code goes in functions.php file of your child theme (or in a plugin). It should work.

    Important: You will have to empty your cart to refresh shipping method cache.

    Other related threads: