I am trying to get it so that if a customer were to add a coupon code (Any of them) the Free Shipping option would go away and the flat rate fee would be implemented. - You would think this would be an easy thing to implement, there would be 100's of plugins and ways described to do this, but I have not found any. I do not want to pay $89 for the plugin to do this one thing
A side bonus would be if they are using a coupon but are spending over $249 they can still qualify for Free shipping. I read some where how to do this, but it requires me to get the POST ID, which with the latest WooCommerce is not possible like it was before, I do not know the shipping ID so I am at a lost Here is the code
add_filter( 'woocommerce_shipping_packages', function( $packages ) {
$applied_coupons = WC()->session->get( 'applied_coupons', array() );
if ( ! empty( $applied_coupons ) ) {
$free_shipping_id = 'free_shipping:2';
unset($packages[0]['rates'][ $free_shipping_id ]);
}
return $packages;
} );
Thanks
Edited
add_filter( 'woocommerce_package_rates', 'coupons_removes_free_shipping',
10, 2 );
function coupons_removes_free_shipping( $rates, $package ){
if ( is_admin() && ! defined( 'DOING_AJAX' ) )
return $rates;
$min_total = 250; // Minimal subtotal allowing free shipping
// Get needed cart totals
$total_excl_tax = WC()->cart->get_total();
$discount_excl_tax = WC()->cart->get_discount_total();
// Calculating the discounted subtotal including taxes
$discounted_subtotal_incl_taxes = $total_excl_tax - $discount_excl_tax;
$applied_coupons = WC()->cart->get_applied_coupons();
if( sizeof($applied_coupons) > 0 && $discounted_subtotal_incl_taxes < $min_total ) {
foreach ( $rates as $rate_key => $rate ){
// Targeting "Free shipping"
if( 'free_shipping' === $rate->method_id ){
unset($rates[$rate_key]);
}
}
}
return $rates;
}
The below code will enable "Free shipping" for applied coupons only if cart subtotal reaches a minimal amount (discounted including taxes):
add_filter( 'woocommerce_package_rates', 'coupons_removes_free_shipping', 10, 2 );
function coupons_removes_free_shipping( $rates, $package ){
if ( is_admin() && ! defined( 'DOING_AJAX' ) )
return $rates;
$min_subtotal = 250; // Minimal subtotal allowing free shipping
// 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 = 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;
}
Code goes in function.php file of your active child theme (or active theme). Tested and work.
Original answer:
The below code will remove "Free shipping" shipping methods when any coupon is applied without any settings need. There is some mistakes in your actual code. Try the following:
add_filter( 'woocommerce_package_rates', 'coupons_removes_free_shipping', 10, 2 );
function coupons_removes_free_shipping( $rates, $package ){
if ( is_admin() && ! defined( 'DOING_AJAX' ) )
return $rates;
$applied_coupons = WC()->cart->get_applied_coupons();
if( sizeof($applied_coupons) > 0 ){
// Loop through shipping rates
foreach ( $rates as $rate_key => $rate ){
// Targeting "Free shipping" only
if( 'free_shipping' === $rate->method_id ){
unset($rates[$rate_key]); // Removing current method
}
}
}
return $rates;
}
Code goes in function.php file of your active child theme (or active theme). Tested and works.
By default WooCommerce will still allow a free shipping method to be selected if the coupon code is filled in and active in the shopping cart. The following code can be added to your child’s functions.php page to hook in and hide any free shipping option if a coupon code is used.
add_filter( 'woocommerce_shipping_packages', function( $packages ) {
$applied_coupons = WC()->session->get( 'applied_coupons', array() );
if ( ! empty( $applied_coupons ) ) {
$free_shipping_id = 'free_shipping:2';
unset($packages[0]['rates'][ $free_shipping_id ]);
}
return $packages;
} );
Simply change the $free_shipping_id in the above code to the ID of your free shipping option. You may find your ID by going to WooCommerce > Settings > Shipping Options and then click on your Free Shipping option. The post ID will be in the URL of the page that displays the Free Shipping details/settings.
i.e www.yourdomain.com/wp-admin/post.php?post=40107&action=edit
Where 40107 is the shipping ID in this example. Your shipping ID will be different.
Related
In WooCommerce we have set flat_rate shipping amount to 4.95€ and free_shipping shows up for a minimal total amount of 45€.
Now, if a customer has a cart with - let`s say 48€ - he does not have to pay shipping costs, as he has reached the order total amount to apply free_shipping.
If he does apply now a 10% coupon, he ends up having 43.20€ order total amount and therefore has to pay shipping fees again.
We would like to still offer free shipping to that customer, after he applied the coupon and "landed" below the free_shipping amount. Otherwise its not very attractive using a 10% coupon (4.80€ in our case) but must pay 4.95€ shipping again.
Based on Applied coupons disable Free shipping conditionally in Woocommerce answer code, here is my code attempt:
add_filter( 'woocommerce_package_rates', 'coupons_removes_free_shipping', 10, 2 );
function coupons_removes_free_shipping( $rates, $package ){
if ( is_admin() && ! defined( 'DOING_AJAX' ) )
return $rates;
$shipping_counrtry = WC()->customer->get_shipping_country();
if ($shipping_counrtry == 'DE') : $min_subtotal = 45;
endif;
$shipping_counrtry = WC()->customer->get_shipping_country();
if ($shipping_counrtry == 'AT') : $min_subtotal = 75;
endif;
// 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 = 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 ){
// SET THE RATE HERE; but how
}
}
}
return $rates;
}
Updated
First in your shipping settings for Free shipping, you will need to set the minimal amount to 0 (zero). Then the following code will handle cart item non discounted subtotal for a "Free shipping" minimal amount (that will solve your issue):
add_filter( 'woocommerce_package_rates', 'conditional_free_shipping', 10, 2 );
function conditional_free_shipping( $rates, $package ){
$shipping_country = WC()->customer->get_shipping_country(); // Get shipping country
$free_shipping = $other_rates = array(); // Initializing
if ($shipping_country === 'DE') {
$min_subtotal = 45;
} elseif ($shipping_country === 'AT') {
$min_subtotal = 75;
}
// Get subtotal incl tax (non discounted) for the current shipping package
$items_subtotal = array_sum( wp_list_pluck( $package['contents'], 'line_subtotal' ) );
$items_subtotal += array_sum( wp_list_pluck( $package['contents'], 'line_subtotal_tax' ) );
// Loop through shipping rates for current shipping package
foreach ( $rates as $rate_key => $rate ){
if( 'free_shipping' === $rate->method_id ){
$free_shipping[$rate_key] = $rate;
} else
$other_rates[$rate_key] = $rate;
}
}
return isset($min_subtotal) && $items_subtotal >= $min_subtotal ? $free_shipping : $other_rates;
}
Code goes in functions.php file of the active child theme (or active theme). It should work.
Don't forget to empty your cart to refresh shipping cached data.
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…
In woocommerce regarding Shipping methods, I am trying to have the following:
Products A only in cart: set with "Free shipping"
Products B only in cart: set with:
Flat rate amount of 15 if Products B purchased amount is less than 200
Free shipping if Products B purchased amount reaches 200 or more..
Products A + Products B are in cart at the same time: "Free Shipping" without any amount restriction.
I have tried by using flat rate and shipping classes I am getting like if product A and product B is there then if the cart doesn't reach 200 it is taking 15 shipping charge.
Any help is appreciated.
Updated: To make it work first you will need:
To add a "Free" shipping class (first),
To enable 2 shipping methods: "Free shipping" and "Flat rate",
In your products with Free shipping will need to be set with the shipping class "Free",
In your other product will not have any defined shipping class.
For the "free shipping" method, you will not add any restrictions amount to it.
For the "Flat rate" shipping method, you will set it as in this screen shot:
The magic will be done by the following code that will make the rest:
add_filter('woocommerce_package_rates', 'conditional_free_shipping', 10, 2);
function conditional_free_shipping( $rates, $package ){
if ( is_admin() && ! defined( 'DOING_AJAX' ) )
return $rates;
## -- Your settings below -- ##
$shipping_class = 'free'; // "Free" shipping class products
$min_free_amount = 200; // Minimal Free shipping amount for normal products
## -- -- -- -- -- -- -- -- -- ##
$has_free = false; // Initializing
$products_total = 0; // Initializing
// Loop through cart items
foreach( $package['contents'] as $cart_item ) {
if( $cart_item['data']->get_shipping_class() == $shipping_class ) {
$has_free = true;
} else {
// Get the total purchased amount for normal product
$products_total += $cart_item['line_total'] + $cart_item['line_tax'];
}
}
foreach ( $rates as $rate_key => $rate ){
// 1. Only Free shipping products in cart OR both products kind in cart
if( $has_free ) {
if( 'flat_rate' === $rate->method_id )
unset( $rates[$rate_key] ); // Remove flat rate
}
// 2. Only normal products in cart
else {
// A. If it's under the min amount
if( 'free_shipping' === $rate->method_id && $products_total < $min_free_amount )
unset( $rates[$rate_key] ); // Remove Free shipping
// B. When min amount is reached
elseif( 'flat_rate' === $rate->method_id && $products_total >= $min_free_amount )
unset( $rates[$rate_key] ); // Remove flat rate
}
}
return $rates;
}
Code goes in function.php file of your active child theme (active theme). Tested and works.
You might need to refresh shipping cached data: disable, save and enable, save related shipping methods for the current shipping zone, in Woocommerce shipping settings.
I did some improvement in the code now it is working fine..
add_filter('woocommerce_package_rates', 'conditional_free_shipping', 10, 2);
function conditional_free_shipping( $rates, $package ){
if ( is_admin() && ! defined( 'DOING_AJAX' ) )
return $rates;
## -- Your settings bellow -- ##
$shipping_class = 'free'; // "Free" shipping class products
$min_free_amount = 200; // Minimal Free shipping amount for normal products
## -- -- -- -- -- -- -- -- -- ##
$has_normal = $has_free = false; // Initializing
$products_total = 0; // Initializing
// Loop through cart items
foreach( $package['contents'] as $cart_item ) {
if( $cart_item['data']->get_shipping_class() == $shipping_class ) {
$has_free = true;
} else {
$has_normal = true;
// Get the total purchased amount for normal product
$products_total += $cart_item['line_total'] + $cart_item['line_tax'];
}
}
foreach ( $rates as $rate_key => $rate ){
// 1. Only Free shipping products in cart
if( $has_free && ! $has_normal ) {
if( 'flat_rate' === $rate->method_id )
unset( $rates[$rate_key] ); // Remove flat rate
}
elseif(( $has_free && $has_normal )){
if( 'flat_rate' === $rate->method_id && $products_total <= $min_free_amount )
unset( $rates[$rate_key] );
}
// 2. Only normal products in cart OR Both products kind in cart
elseif( ( ! $has_free && $has_normal ) ) {
// A. If it's under the min amount
if( 'free_shipping' === $rate->method_id && $products_total < $min_free_amount )
unset( $rates[$rate_key] ); // Remove Free shipping
// B. When min amount is reached
elseif( 'flat_rate' === $rate->method_id && $products_total >= $min_free_amount )
unset( $rates[$rate_key] ); // Remove flat rate
}
}
return $rates;
}
I have a specific coupon which is special50. When someone applied this coupon on the store then a new shipping method need to add. When current shipping method price is $50 (flat rate) and after applying coupon new shipping method, pricing will be $25. In a word, if you apply this coupon you will receive 50% OFF on products(which WooCommerce has already provided to us) and 50% OFF on shipping(which really I need).
add_action( 'woocommerce_flat_rate_shipping_add_rate', 'add_another_custom_flat_rate', 10, 2 );
function add_another_custom_flat_rate( $method, $rate ) {
$new_rate = $rate;
$new_rate['id'] .= ':' . 'custom_rate_name';
$new_rate['label'] = 'Shipping and handling';
global $woocommerce, $wpdb;
$coupon = "SELECT post_title FROM {$wpdb->posts} WHERE post_title='special50' AND post_type ='shop_coupon' AND post_status ='publish'";
if(in_array($coupon_id, $woocommerce->cart->applied_coupons)){
$cost = 25;
}
$new_rate['cost'] = $cost;
$method->add_rate( $new_rate );
}
This can be done using the following custom function hooked in woocommerce_package_rates filter hook, without any need of creating an additional discounted flat rate. The following code will change the "flat rate" shipping method cost when 'special50' coupon is applied.
You should first "Enable debug mode" in Woocommerce settings > shipping > Shipping options.
The code:
add_filter('woocommerce_package_rates', 'coupon_discount_on_flat_rate', 10, 2);
function coupon_discount_on_flat_rate( $rates, $package ){
if ( is_admin() && ! defined( 'DOING_AJAX' ) )
return $rates;
// Checking for 'special50' in applied coupons
if( in_array( 'special50', WC()->cart->get_applied_coupons() ) ){
foreach ( $rates as $rate_key => $rate ){
$has_taxes = false;
// Targeting "flat rate" shipping method
if( $rate->method_id === 'flat_rate' ){
// Set 50% of the cost
$rates[$rate_key]->cost = $rates[$rate_key]->cost / 2;
// Taxes rate cost (if enabled)
foreach ($rates[$rate_key]->taxes as $key => $tax){
if( $rates[$rate_key]->taxes[$key] > 0 ){
$has_taxes = true;
// set 50% of the cost
$taxes[$key] = $rates[$rate_key]->taxes[$key] / 2;
}
}
if( $has_taxes )
$rates[$rate_key]->taxes = $taxes;
}
}
}
return $rates;
}
Code goes in function.php file of your active child theme (or active theme). Tested and works.
Dont forget to disable "Enable debug mode" once this has been tested and works.
In WooCommerce, I am using the code below to add a $12 surcharge to sales for Canadian Customers in the functions.php file of the child theme for one of my client.
But I need to remove the charge for all pdf downloads.
Is this possible altering the code I used?
Here is my code:
add_action( 'woocommerce_cart_calculate_fees','xa_add_surcharge' );
function xa_add_surcharge() {
global $woocommerce;
if ( is_admin() && ! defined( 'DOING_AJAX' ) )
return;
$county = array('CA');
$fee = 12.00;
if ( in_array( $woocommerce->customer->get_shipping_country(), $county ) ) :
$surcharge = + $fee;
$woocommerce->cart->add_fee( 'Surcharge for International Orders', $surcharge, true, '' );
endif;
}
It's possible checking in cart items for non downloadable product (or depending ion your PDF products settings for non virtual products).
Additionally I have revisited your code a bit:
add_action( 'woocommerce_cart_calculate_fees','add_custom_surcharge', 10, 1 );
function add_custom_surcharge( $wc_cart ) {
if ( is_admin() && ! defined( 'DOING_AJAX' ) ) return;
$countries = array('CA'); // Defined countries
// Continue only for defined countries
if( ! in_array( WC()->customer->get_shipping_country(), $countries ) ) return;
$fee_cost = 12; // The Defined fee cost
$downloadable_only = true;
// Checking cart items for NON downloadable products
foreach ( $wc_cart->get_cart() as $cart_item_key => $cart_item ) {
// Checks if a product is not downloadable.
if( ! $cart_item['data']->is_downloadable( ) ){ // or cart_item['data']->is_virtual()
$downloadable_only = false;
break;
}
}
// If one product is not downloadable and if customer shipping country is Canada we add the fee
if ( ! $downloadable_only )
$wc_cart->add_fee( "Surcharge for International Orders", number_format( $fee_cost, 2 ), true );
}
Code goes in function.php file of your active child theme (or theme) or also in any plugin file.
All code is tested on Woocommerce 3+ and works.