Instantly share code, notes, and snippets.

Embed
What would you like to do?
WooCommerce - Hide shipping rates when free shipping is available.
<?php
/**
* Hide shipping rates when free shipping is available.
* Updated to support WooCommerce 2.6 Shipping Zones.
*
* @param array $rates Array of rates found for the package.
* @return array
*/
function my_hide_shipping_when_free_is_available( $rates ) {
$free = array();
foreach ( $rates as $rate_id => $rate ) {
if ( 'free_shipping' === $rate->method_id ) {
$free[ $rate_id ] = $rate;
break;
}
}
return ! empty( $free ) ? $free : $rates;
}
add_filter( 'woocommerce_package_rates', 'my_hide_shipping_when_free_is_available', 100 );
@jamiet

This comment has been minimized.

jamiet commented Jun 29, 2016

Is it possible to remove one of the shipping options and not all of them if free shipping is available?

@pasztig

This comment has been minimized.

pasztig commented Jun 30, 2016

I have the same questions, I want to keep the Local Pickup option if only free shipping is available. "Local Pickup" (Instance ID: 5)

@Sjouw

This comment has been minimized.

Sjouw commented Jul 5, 2016

@jamiet @pasztig: I've expanded on the provided function to hide all shipping options, except a custom shipping option I've added through a plugin.
function v161_woocommerce_hide_shipping_method( $rates ) {
$free = array();
$free_shipping = false;

    foreach ( $rates as $rate_id => $rate ) {

        if ( 'free_shipping' === $rate->method_id ) {

            $free[ $rate_id ] = $rate;
            $free_shipping = true;

        }

        if ( $free_shipping == true && 'my_custom_shipping_method' === $rate->method_id ) {
            $free[ $rate_id ] = $rate;
        }

    }

    return ! empty( $free ) ? $free : $rates;
}

Ofcourse you should be able replace the part
'my_custom_shipping_method' === $rate->method_id
with
'flat_rate:5' === $rate->id
or
'My custom shipping option name' === $rate->label

I've not tested the last 2 suggestions, but it should at least set you on the right track

@drazeni

This comment has been minimized.

drazeni commented Sep 20, 2016

@Sjouw You are an absolute king! Really saved me a headache as I had to still show "Local Pickup" with free shipping. Also to confirm, I used the label instead 'My custom shipping option name' === $rate->label and it worked perfectly. Thank you very much.

@drgdesign

This comment has been minimized.

drgdesign commented Oct 23, 2016

Thank you Sjouw, yours is the 1st version I've found that allows me to hide only one specific shipping method in Woocommerce when free shipping is implemented instead of all other shipping methods. Thank you for sharing!

@EBonar

This comment has been minimized.

EBonar commented Nov 4, 2016

@Sjouw
I have Local Pickup, Free Shipping and USPS as options for Local Shipping Zone.
To get Free Shipping, the customer has to spend at least $50.

I added the following code but it still doesn't show an option for Local Pickup, what am I doing wrong?

/**
 * Hide shipping rates when free shipping is available.
 * Updated to support WooCommerce 2.6 Shipping Zones.
 *
 * @param array $rates Array of rates found for the package.
 * @return array
 */
function my_hide_shipping_when_free_is_available( $rates ) {
	$free = array();
	
	foreach ( $rates as $rate_id => $rate ) {

        if ( 'free_shipping' === $rate->method_id ) {

            $free[ $rate_id ] = $rate;
            $free_shipping = true;

        }

        if ( $free_shipping == true && 'My custom shipping option name' === $rate->label ) {
            $free[ $rate_id ] = $rate;
        }

    }

    return ! empty( $free ) ? $free : $rates;
}

add_filter( 'woocommerce_package_rates', 'my_hide_shipping_when_free_is_available', 100 );
@masjo

This comment has been minimized.

masjo commented Dec 6, 2016

@EBonar try this

add_filter('woocommerce_package_rates', 'hide_shipping_when_free_is_available', 10, 2);
function hide_shipping_when_free_is_available($rates, $package) {
$free_yn = 0;
$pickup_yn = 0;
foreach($rates as $key => $value) {
$key_part = explode(":", $key);
$method_title = $key_part[0];
if ('free_shipping' == $method_title) {
// check if free shipping rate exists
$free_yn = 1;
$free_shipping = $rates[$key];
$free_key = $key;
}
if ('local_pickup' == $method_title) {
// check if local pickup rate exists
$pickup_yn = 1;
$local_pickup = $rates[$key];
$pickup_key = $key;
}
}
if ($free_yn == 1) {
// Unset all rates.
$rates = array();
// Restore free shipping rate.
$rates[$free_key] = $free_shipping;
if ($pickup_yn == 1) {
// Restore local pickup rate.
$rates[$pickup_key] = $local_pickup;
}
return $rates;
}
return $rates;
}

@mattiasghodsian

This comment has been minimized.

mattiasghodsian commented Feb 2, 2017

@masjo this dose not work.

@haiflosse

This comment has been minimized.

haiflosse commented May 14, 2017

I use two shipping Zone with different Minimum amount to get free shipping.
the Name of one shipping Zone is national and the other germany.
When a customer will order 49 euro in shipping Zone national it will be free shipping but when a customer in Germany must order 100 euro to get free shipping.
How can I solve this Problem.
kindly regards

I noticed that it will work automaticle. I forgot to add a free shipping in the Germany Zone.

@itsnidhu

This comment has been minimized.

itsnidhu commented Jun 19, 2017

Hi I have a situation below:

  1. Customers get "Free Shipping" on orders above $100 but No 'Free Shipping' if 10% cart discount coupon code is used.
  2. "Flat Shipping" is $9.95 and "Express Shipping" is $13.95 but
    a) if Free Shipping applies Express Shipping should show $4.00 ($13.95 - $9.95)
    b) if coupon code of 10% cart discount is used no free shipping or no discount on Express shipping applies. i.e (Flat Shipping $9.95 and Express Shipping $13.95 applies if coupon code is used)

How can I do this.

I tried setting up the Shipping Zone
a) Free Shipping "A Minimum order amount or a coupon" - Minimum order $100
b) Flat Shipping - $9.95
c) Local Pickup - I customized this to "Express Shipping" with cost $13.95

Using the function

function my_hide_shipping_when_free_is_available( $rates ) {
$free = array();

foreach ( $rates as $rate_id => $rate ) {

	if ( 'free_shipping' === $rate->method_id ) {
		$free[ $rate_id ] = $rate;
		 $free_shipping = true;
	}
	
	if ( $free_shipping == true && 'my_custom_shipping_method' === $rate->method_id ) {
        $free[ $rate_id ] = $rate;
    }
}
return ! empty( $free ) ? $free : $rates;

}
add_filter( 'woocommerce_package_rates', 'my_hide_shipping_when_free_is_available', 100 );

following things doesn't happen.

  1. If coupon code is not used
    a) For orders above $100 the express shipping is not showing along with 'Free Shipping'.
    Also the express shipping value should be (Flat Shipping $9.95 - Express Shipping $13.95) = $4

  2. If coupon code is used
    a) On using '10% cart discount - Coupon Code' on order $100 or more - Customers should only get 10% cart discount (coupon) and not get Free shipping or discount on express shipping. Therefore the shipping option should show Flat Shipping $9.95 and Express Shipping $13.95

    b) On using '10% cart discount - Coupon Code' on order under $100 - Customers should only get 10% cart discount (coupon). Therefore the shipping option should show Flat Shipping $9.95 and Express Shipping $13.95

How can I achieve this.

Please suggest.
Nidhi

@oblaum

This comment has been minimized.

oblaum commented Oct 2, 2017

@masjo works very great!!!! thanks a thousand time. what i now need that the free shipping the first option is selected by default (at the moment none of the shipping mehthods are seleced.
screen checkout 1

@dambouvier

This comment has been minimized.

dambouvier commented Feb 9, 2018

@masjo

Don't work for me :/
Is for 1 local pickup, but how to change this function for keep 2 local pickup ?

@desupero

This comment has been minimized.

desupero commented Mar 11, 2018

How would I hide other non-relevant shipping methods please? So if shipping for 1-3 items is $7 and 4-8 is $10, how would I hide the shipping option for $7, if the buyer has chosen 4-8 products please?

@ToddNewent

This comment has been minimized.

ToddNewent commented Mar 14, 2018

Hey, so if you want to hide everything but free shipping and local pickup then modify @mikejolley code and change the foreach loop as follows:

foreach ( $rates as $rate_id => $rate ) {
  if ( 'free_shipping' === $rate->method_id ) {
    $free[ $rate_id ] = $rate;
  }

  if ( 'local_pickup' === $rate->method_id ) {
    $free[ $rate_id ] = $rate;
  }
}
@neoseeyou

This comment has been minimized.

neoseeyou commented Mar 16, 2018

Hello

I want to display free shipping only when cart price is above 100 euros or if current user has a specific active membership and hide others shipping methods if possible

wc_memberships_is_user_active_member( $user_id, 'premium' )

If you could help me that would be really nice of you

Thanks

Cheers

@CarlosJGonzalez

This comment has been minimized.

CarlosJGonzalez commented Jun 19, 2018

I added a field to categories to store a date. Using this same code, I exclude Flat_Rate option when the date in the custom field is greater than the current date.

@ngothoai

This comment has been minimized.

ngothoai commented Jun 25, 2018

i used this code

add_filter( 'woocommerce_package_rates', 'businessbloomer_hide_free_shipping_for_shipping_class', 10, 2 );

function businessbloomer_hide_free_shipping_for_shipping_class( $rates, $package ) {
$in_cart = false;
foreach( WC()->cart->cart_contents as $key => $values ) {
if( $values[ 'data' ]->get_shipping_class_id() ) {
$in_cart = true;
break;
}
}
if( $in_cart ) {
unset( $rates['ba_table_rate:7'] ); // shipping method with ID (to find it, see screenshot below)
}
return $rates;
}

But after i need remove Clear customer sessions after that, then it work.,

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment