Search code examples
phpwordpresswoocommercehook-woocommerceshipping-method

Disable only specific flat rate shipping method when free shipping is available in WooCommerce


I have two flat rates on my WooCommerce site and I want to disable one of them, when free shipping is enabled. I have a function which is working for all flat rates only.

How do I check for an instance id on a shipping rate? Can anyone help me understand how to check for the instance id?

I Was trying to echo shipping data out to make sense of what values were available but no echo was showing on the front end either so a tip on why would be great.

Here is my code attempt:

function hide_shipping_when_free_is_available( $rates, $package ) {
    $new_rates = array();

    foreach ( $rates as $rate_id => $rate ) {
        // Only modify rates if free_shipping is present.
        if ( 'free_shipping' === $rate->method_id ) {
            $new_rates[ $rate_id ] = $rate;
            break;
        }
    }

    if ( ! empty( $new_rates ) ) {
        //Save local pickup if it's present.
        foreach ( $rates as $rate_id => $rate ) {
            if ('local_pickup' === $rate->method_id ) {
                $new_rates[ $rate_id ] = $rate;
            }
            if ( 'flat_rate:20' === $rate->instance_id )
                $new_rates[ $rate_id ] = $rate; 
            }
        return $new_rates;
    }

    return $rates;
}
add_filter( 'woocommerce_package_rates', 'hide_shipping_when_free_is_available', 10, 2 );

Solution

  • If you inspect the shipping methods radio buttons on cart or in checkout you will see something like:

    <input type="radio" name="shipping_method[0]" data-index="0" id="shipping_method_0_flat_rate20" value="flat_rate:20" class="shipping_method" checked="checked">
    

    So in value="flat_rate:20" (which is the rate Id):

    • the method Id is flat_rate,
    • and instance ID is 20.

    Note: The code could be really simplified…

    But as you don't provide the free shipping and other flat rate rates IDs (or instances Ids), I Keep your code making some changes to it, this way:

    function hide_shipping_when_free_is_available( $rates, $package ) {
        $new_rates = array();
    
        foreach ( $rates as $rate_id => $rate ) {
            // Only modify rates if free_shipping is present.
            if ( 'free_shipping' === $rate->method_id ) {
                $new_rates[ $rate_id ] = $rate;
                break;
            }
        }
    
        if ( ! empty( $new_rates ) ) {
            foreach ( $rates as $rate_id => $rate ) {
                //Save local pickup if it's present.
                if ('local_pickup' === $rate->method_id ) {
                    $new_rates[ $rate_id ] = $rate;
                }
                if ( 20 == $rate->instance_id )
                    $new_rates[ $rate_id ] = $rate;
                }
            }
            return $new_rates;
        }
        return $rates;
    }
    add_filter( 'woocommerce_package_rates', 'hide_shipping_when_free_is_available', 10, 2 );
    

    It should work.