Conditionally hide shipping methods in WooCommerce - php

I am trying to hide a shipping method on the checkout page of WooCommerce when shipping country selected is United States - 'US' and cart_total is more than 100. But the script is still hiding both the Normal Shipping and Express shipping, when it should only hide the normal shipping(flat_rate:4). Any help will be greatly appreciated!
function nd_hide_shipping_when_free_is_available( $rates ) {
$shipping_counrtry = WC()->customer->get_shipping_country();
$total = WC()->cart->get_displayed_subtotal();
if ($shipping_country == "US" && $total >= 100){
unset($rates['flat_rate:4']);
return $rates;
}else{
$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', 'nd_hide_shipping_when_free_is_available', 100 );

You can try the following, that will hide 'flat_rate:4' shipping method rate id for US and when cart subtotal reaches 100 or more, otherwise when free shipping is available, it will hide other shipping methods:
add_filter( 'woocommerce_package_rates', 'shipping_based_on_country_subtotal_and_free_available', 100, 2 );
function shipping_based_on_country_subtotal_and_free_available( $rates, $package ) {
$country = WC()->customer->get_shipping_country();
$subtotal = WC()->cart->subtotal; // subtotal incl taxes
$condition = $country == "US" && $subtotal >= 100; // <== HERE Set your condition (country and minimal subtotal amount)
$free = array(); // Initializing
// Loop through shipping rates for current shipping package
foreach ( $rates as $rate_key => $rate ) {
if ( $condition ){
$targeted_rate_id = 'flat_rate:4';
if( $targeted_rate_id === $rate_key ) {
unset($rates[$targeted_rate_id]);
}
}
elseif ( 'free_shipping' === $rate->method_id ) {
$free[$rate_key] = $rate;
}
}
return ! empty( $free ) && ! $condition ? $free : $rates;
}
Code goes in functions.php file of the active child theme (or active theme). Tested and works.
Important: Once code is saved, empty the cart to refresh shipping rates...

Related

Remove all taxes in WooCommerce for a min cart total and specific countries

we need to charge 0 VAT for UK orders that are greater than 150 euro including shipping and payment gateway fees but excluding the 20% normal VAT.
So if a British residential address orders something at 130 and shipping and payment gateway fees are 9 then we charge VAT so the customer pays 139+9+20% VAT, but, if the order is 130 and shipping and payment gateway fees are 23 so a total of 153 without VAT we charge no tax.
I created this but still, it's taxing shipping fees and PayPal added fees also are getting taxed, my head is minced really thought I'd reach out for suggestions.
add_action( 'woocommerce_before_calculate_totals','auto_add_tax_for_room', 10, 1 );
function auto_add_tax_for_room( $cart ) {
if ( is_admin() && ! defined('DOING_AJAX') ) return;
$shipping_country = WC()->customer->get_shipping_country();
$subtotal = 0;
foreach ( WC()->cart->get_cart() as $cart_item ) {
$subtotal += $cart_item['data']->get_price('edit') * $cart_item['quantity'];
}
$subtotal = intval($subtotal);
if($shipping_country!='GB' || $subtotal < 125) return;
$percent = 0;
// Calculation
$surcharge = ( $cart->cart_contents_total + $cart->shipping_total ) * $percent / 100;
// Add the fee (tax third argument disabled: false)
foreach ( $cart->get_cart() as $cart_item ) {
// get product price
$price = $cart_item['data']->get_price();
$cart_item['data']->set_tax_class( 'Zero rate' ); // Above 2500
}
return;
}
The hook woocommerce_before_calculate_totals is just for cart items and the tax class here only apply to products as $cart_item['data'] is the WC_Product Object.
If your product prices are set without taxes, there is another alternative much more simpler that will remove all taxes when your conditions are met.
Try the following instead:
add_action( 'woocommerce_calculate_totals', 'set_customer_tax_exempt' );
function set_customer_tax_exempt( $cart ) {
if ( is_admin() && ! defined('DOING_AJAX') )
return;
$min_amount = 150; // Minimal cart amount
$countries = array('GB'); // Defined countries array
$subtotal = floatval( $cart->cart_contents_total );
$shipping = floatval( $cart->shipping_total );
$fees = floatval( $cart->fee_total );
$total = $subtotal + $shipping + $fees; // cart total (without taxes including shipping and fees)
$country = WC()->customer->get_shipping_country();
$country = empty($country) ? WC()->customer->get_billing_country() : $country;
$vat_exempt = WC()->customer->is_vat_exempt();
$condition = in_array( $country, $countries ) && $total >= $min_amount;
if ( $condition && ! $vat_exempt ) {
WC()->customer->set_is_vat_exempt( true ); // Set customer tax exempt
} elseif ( ! $condition && $vat_exempt ) {
WC()->customer->set_is_vat_exempt( false ); // Remove customer tax exempt
}
}
add_action( 'woocommerce_thankyou', 'remove_customer_tax_exempt' );
function remove_customer_tax_exempt( $order_id ) {
if ( WC()->customer->is_vat_exempt() ) {
WC()->customer->set_is_vat_exempt( false );
}
}
Code goes in functions.php file of the active child theme (or active theme). Tested and works.
Thanks to LoicTheAztec help I made some changes ended up using the following and it worked to fix the UK taxes issues
add_action( 'woocommerce_before_calculate_totals','auto_add_tax_for_room', 10, 1 );
function auto_add_tax_for_room( $cart ) {
if ( is_admin() && ! defined('DOING_AJAX') ) return;
$shipping_country = WC()->customer->get_shipping_country();
$subtotal = 0;
foreach ( WC()->cart->get_cart() as $cart_item ) {
$subtotal += $cart_item['data']->get_price('edit') * $cart_item['quantity'];
}
$subtotal = intval($subtotal);
if($shipping_country!='GB' || $subtotal < 125) return;
$percent = 0;
// Calculation
$surcharge = ( $cart->cart_contents_total + $cart->shipping_total ) * $percent / 100;
// Add the fee (tax third argument disabled: false)
foreach ( $cart->get_cart() as $cart_item ) {
// get product price
$price = $cart_item['data']->get_price();
$cart_item['data']->set_tax_class( 'Zero rate' );
}
return;
}
function flat_rates_cost( $rates, $package ) {
$shipping_country = WC()->customer->get_shipping_country();
$subtotal = 0;
foreach ( WC()->cart->get_cart() as $cart_item ) {
$subtotal += $cart_item['data']->get_price('edit') * $cart_item['quantity'];
}
$subtotal = intval($subtotal);
if($shipping_country!='GB' || $subtotal < 125) return $rates;
foreach ( $rates as $rate_key => $rate ){
if ( 'free_shipping' !== $rate->method_id ) {
$has_taxes = false;
$taxes = [];
// Taxes rate cost (if enabled)
foreach ($rates[$rate_key]->taxes as $key => $tax){
if( $tax > 0 ){
$has_taxes = true;
$taxes[$key] = 0; // Set to 0 (zero)
}
}
if( $has_taxes )
$rates[$rate_key]->taxes = 0;
}
}
return $rates;
}
add_filter( 'woocommerce_package_rates', 'flat_rates_cost', 10, 2 );

Hide Free shipping for specific applied coupon when discounted subtotal is below 75

I am trying to create a very specific type of coupon code.
If a customer enters "allthings30" they get 30% off.
However if the order is over £75, They get free shipping as well.
Now the website, already has free shipping in place, but I want those disabled if the order is below £75, only when this code is applied.
Using other questions on stackoverflow, I have managed to create the code, but it is being applied to every singe couple.
How do I apply this code to only the "allthings30" coupon. Any help is greatly appropriated.
add_filter( 'woocommerce_package_rates', 'coupons_removes_free_shipping', 33, 38 );
function coupons_removes_free_shipping( $rates, $package ){
if ( is_admin() && ! defined( 'DOING_AJAX' ) )
return $rates;
$min_subtotal = 75; // Minimal subtotal allowing free shipping
$coupon_code = 'allthings30'; // The required coupon code
// Get needed cart subtotals
$subtotal_excl_tax = WC()->cart->get_subtotal();
$subtotal_incl_tax = $subtotal_excl_tax + WC()->cart->get_subtotal_tax();
$discount_excl_tax = WC()->cart->get_discount_total();
$discount_incl_tax = $discount_total + WC()->cart->get_discount_tax();
// Calculating the discounted subtotal including taxes
$discounted_subtotal_incl_taxes = $subtotal_incl_tax - $discount_incl_tax;
$applied_coupons = in_array( strtolower($coupon_code), WC()->cart->get_applied_coupons() );
if( sizeof($applied_coupons) > 0 && $discounted_subtotal_incl_taxes < $min_subtotal ){
foreach ( $rates as $rate_key => $rate ){
// Targeting "Free shipping"
if( 'free_shipping' === $rate->method_id ){
unset($rates[$rate_key]);
}
}
}
return $rates;
}
You are very near… The following will do the job:
add_filter( 'woocommerce_package_rates', 'coupons_removes_free_shipping', 33, 38 );
function coupons_removes_free_shipping( $rates, $package ){
if ( is_admin() && ! defined( 'DOING_AJAX' ) )
return $rates;
$min_subtotal = 75; // Minimal subtotal allowing free shipping
$coupon_code = 'summer'; // The required coupon code
// Get cart subtotals and applied coupons
$cart = WC()->cart;
$subtotal_excl_tax = $cart->get_subtotal();
$subtotal_incl_tax = $subtotal_excl_tax + $cart->get_subtotal_tax();
$discount_excl_tax = $cart->get_discount_total();
$discount_incl_tax = $discount_excl_tax + $cart->get_discount_tax();
$applied_coupons = $cart->get_applied_coupons(); // Get applied coupons array
// Calculating the discounted subtotal including taxes
$disc_subtotal_incl_tax = $subtotal_incl_tax - $discount_incl_tax;
if( in_array( strtolower($coupon_code), $applied_coupons ) && $disc_subtotal_incl_tax < $min_subtotal ){
foreach ( $rates as $rate_key => $rate ){
// Targeting "Free shipping"
if( 'free_shipping' === $rate->method_id ){
unset($rates[$rate_key]);
}
}
}
return $rates;
}
Don't forget after saving that code to your theme's functions.php file to refresh your shipping rates in Admin shipping rates settings, disabling and save any shipping method and re-enable and save it back…

Enable only free shipping method for a specific custom field value in Woocommerce

I'm trying to add code like the one below into functions.php file. The overall function is to check products in cart and their custom fields (post_meta) called auto_delivery_default.
If its certain text in the custom field then display free shipping only, if all other text then show all other shipping methods.
Here's what I've gotten so far but I'm overlooking something making it not function right;
function show_free_ship_to_autodelivery ( $autodelivery_rate ) {
$autodelivery_free = array();
foreach( WC()->cart->get_cart() as $cart_item ){
$product = $cart_item['data'];
$product_id = $product->get_id(); // get the product ID
$autodelivery = get_post_meta( $product->get_id(), 'auto_delivery_default', true );
if( $autodelivery == "90 Days" ) {
$autodeliveryfree = array();
foreach ( $rates as $rate_id => $rate ) {
if ( 'free_shipping' === $rate->method_id ) {
$autodelivery_free[ $rate_id ] = $rate;
break;
}
}
return ! empty( $autodelivery_free ) ? $autodelivery_free : $autodelivery_rate;
}
}
}
add_filter( 'woocommerce_package_rates', 'show_free_ship_to_autodelivery', 10);
There is some errors and mistakes in your code… Instead, try the following that will hide other shipping methods when free shipping is available and when a cart item with a custom field auto_delivery_default has a value of 90 Days:
add_filter( 'woocommerce_package_rates', 'show_only_free_shipping_for_autodelivery', 100, 2 );
function show_only_free_shipping_for_autodelivery ( $rates, $package ) {
// Loop through cart items
foreach( $package['contents'] as $cart_item ){
if( $cart_item['data']->get_meta('auto_delivery_default') == '90 Days' ) {
$found = true;
break; // Stop the loop
}
}
if( ! ( isset($found) && $found ) )
return $rates; // Exit
$free = array();
foreach ( $rates as $rate_id => $rate ) {
if ( 'free_shipping' === $rate->method_id ) {
$free[ $rate_id ] = $rate;
break;
}
}
return ! empty( $free ) ? $free : $rates;
}
Code goes in function.php file of your active child theme (or active theme). Tested and works.

Change displayed Free shipping label when Free shipping is enabled in Woocommerce

I am using this official woocommerce hook and snippet to Hide other shipping methods when “Free Shipping” is triggered by a coupon. Which works fine.
Currnently, it just displays FREE SHIPPING. I am trying to add in a text line where it displays FREE SHIPPING to say "-£3.95" in order to let the user know that they have saved money off their shipping.
I have tried adding a dummy "fee" inline to the IF statement, but it wont display.
$cart->add_fee( 'You saved -£3.95');
Code is as follows:
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 );
e.g. like the following example:
There is 2 ways:
1) In your existing code (best way) - It will append your formatted saved price on free shipping:
add_filter( 'woocommerce_package_rates', 'hide_other_shipping_when_free_is_available', 100, 1 );
function hide_other_shipping_when_free_is_available( $rates ) {
// Here set your saved amount
$labeleld_price = -3.95;
$free = array();
foreach ( $rates as $rate_id => $rate ) {
if ( 'free_shipping' === $rate->method_id ) {
$free[ $rate_id ] = $rate;
// Here we append the labbelled saved price formated display
$free[ $rate_id ]->label .= ' (' . strip_tags( wc_price( $labeleld_price ) ) . ')';
break; // stop the loop
}
}
return ! empty( $free ) ? $free : $rates;
}
Code goes in function.php file of your active child theme (or active theme). tested and works.
2) Using settings - Renaming the "Free shipping" label method:

Hide other shipping options when Free shipping is available for one zone only in Woocommerce

I need a way to achieve the following: If Free Shipping is available, AND the order is being shipped to a specific zone, hide all other shipping methods.
I found this snippet:
function 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', 'hide_shipping_when_free_is_available', 100 );
How would I add a conditional into it to only apply it to orders going to one zone?
The following code will hide all other shipping methods when free shipping is available for a specific Zone (you will define in the function the targeted zone ID or Zone name):
add_filter( 'woocommerce_package_rates', 'free_shipping_hide_others_by_zone', 100, 2 );
function free_shipping_hide_others_by_zone( $rates, $package ) {
// HERE define your shipping zone ID OR the shipping zone name
$defined_zone_id = '';
$defined_zone_name = 'Europe';
// Get The current WC_Shipping_Zone Object
$zone = WC_Shipping_Zones::get_zone_matching_package( $package );
$zone_id = $zone->get_id(); // The zone ID
$zone_name = $zone->get_zone_name(); // The zone name
$free = array(); // Initializing
// Loop through shipping rates
foreach ( $rates as $rate_id => $rate ) {
if ( 'free_shipping' === $rate->method_id && ( $zone_id == $defined_zone_id || $zone_name == $defined_zone_name ) ) {
$free[ $rate_id ] = $rate;
break;
}
}
return ! empty( $free ) ? $free : $rates;
}
Code goes in function.php file of the active child theme (or active theme). Tested and work.
/**
* 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 );

Categories