Shipping cost based on cart total weight in Woocommerce 3 - php

In my Woocommerce Webshop I do have different Products. I would like to have shipping cost calculated on total cart items weight:
from 0 to 6 Kilos the cost is 5 €,
from 6 to 12 Kilos the cost is 9 €
Actually if I have a Product which is 1 Kilo the shipping cost is 5 €, but if I have 10 items of this product in my basket, the shipping fee is still 5 € (and it should be 9 € instead).
How can I have a progressive shipping cost based on cart total weight?

Try the following function which "Flat Rate" cost will be changed based on cart total weight.
Using "Flate rate" shipping method, you will need to set a reference shipping cost with a simple initial cost instead of any formula. It can be for example 1. This cost will be replaced by my answer code, dynamically based on cart total weight.
You may have to "Enable debug mode" in general shipping settings under "Shipping options" tab, to disable temporarily shipping caches.
add_filter('woocommerce_package_rates', 'shipping_cost_based_on_weight', 12, 2);
function shipping_cost_based_on_weight( $rates, $package ){
if ( is_admin() && ! defined( 'DOING_AJAX' ) )
return $rates;
// HERE define the differents costs
$cost1 = 5; // Up to 6 Kg
$cost2 = 9; // Above 6 Kg and below 12 kg
$cost3 = 9; // Above 12 kg
// The cart total Weight
$total_weight = WC()->cart->get_cart_contents_weight();
// Loop through the shipping taxes array
foreach ( $rates as $rate_key => $rate ){
$has_taxes = false;
// Targetting "flat rate"
if( 'flat_rate' === $rate->method_id ){
// Get the initial cost
$initial_cost = $new_cost = $rates[$rate_key]->cost;
// Calculate new cost
if( $total_weight <= 6 ) { // Below 6 Kg
$new_cost = $cost1;
}
elseif( $total_weight > 6 && $total_weight <= 12 ) { // Between 6 and 12 Kg
$new_cost = $cost2;
}
else { // Above 12 Kg
$new_cost = $cost3;
}
// Set the new cost
$rates[$rate_key]->cost = $new_cost;
// Taxes rate cost (if enabled)
$taxes = [];
// Loop through the shipping taxes array (as they can be many)
foreach ($rates[$rate_key]->taxes as $key => $tax){
if( $rates[$rate_key]->taxes[$key] > 0 ){
// Get the initial tax cost
$initial_tax_cost = $new_tax_cost = $rates[$rate_key]->taxes[$key];
// Get the tax rate conversion
$tax_rate = $initial_tax_cost / $initial_cost;
// Set the new tax cost
$taxes[$key] = $new_cost * $tax_rate;
$has_taxes = true; // Enabling tax
}
}
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.
Once tested, don't forget to disable "Enable debug mode" option in shipping settings.

Related

Set a shipping cost per line item in WooCommerce

There is the built in option for woocommerce shipping to set a fee for quantity of products in cart. There is also option for fee per shipping class. But I have thousands of products and need to charge a fee for each product(each product not qty of products).
For example 2 product "apples", and 23 product "oranges" in cart. I need to charge flat fee of $10 for any amount of apples and $10 for any amount of oranges. I dont seem to find solution to this in any of the available plugins. They all do fee per quantity but not this.
To get a cost by line item in cart, it requires the following:
1) In WooCommerce Settings > Shipping: set a cost of 10 for your "Flat rate" shipping methods (and save).
2) Add to functions.php file of your active child theme (or active theme), this code:
add_filter( 'woocommerce_package_rates', 'shipping_cost_based_on_number_of_items', 10, 2 );
function shipping_cost_based_on_number_of_items( $rates, $package ) {
$numer_of_items = (int) sizeof($package['contents']);
// Loop through shipping rates
foreach ( $rates as $rate_key => $rate ){
// Targetting "Flat rate" shipping method
if( 'flat_rate' === $rate->method_id ) {
$has_taxes = false;
// Set the new cost
$rates[$rate_key]->cost = $rate->cost * $numer_of_items;
// Taxes rate cost (if enabled)
foreach ($rates[$rate_key]->taxes as $key => $tax){
if( $tax > 0 ){
// New tax calculated cost
$taxes[$key] = $tax * $numer_of_items;
$has_taxes = true;
}
}
// Set new taxes cost
if( $has_taxes )
$rates[$rate_key]->taxes = $taxes;
}
}
return $rates;
}
Refresh the shipping caches: (required)
This code is already saved on your active theme's function.php file.
The cart is empty
In a shipping zone settings, disable / save any shipping method, then enable back / save.
Tested and work.

Woocommerce custom shipping rate calculation based on weight

In Woocommerce, I would like to have a function that I can include within my theme that adds shipping rate based on price and weight.
if price is above 20USD shipping is free, below Shipping cost : 3USD
if weight is above 10kg shipping fee is 2USD extra
Based on "Shipping calculated on the items weight and cart amount" answer thread, I tried something like the beneath code:
//Adding a custom Shipping Fee to cart based conditionally on weight and cart amount
add_action('woocommerce_cart_calculate_fees', 'custom_conditional_shipping_fee', 10, 1);
function custom_conditional_shipping_fee( $cart_object ){
#### SETTINGS ####
// Your targeted "heavy" product weight
$target_weight = 1;
// Your targeted cart amount
$target_cart_amount = 20;
// Price by Kg;
$price_kg = 2;
// Amount set in 'flat rate' shipping method;
$flat_rate_price;
// Initializing variables
$fee = 0;
$calculated_weight = 0;
// For cart SUBTOTAL amount EXCLUDING TAXES
WC()->cart->subtotal_ex_tax >= $target_cart_amount ? $passed = true : $passed = false ;
// For cart SUBTOTAL amount INCLUDING TAXES (replace by this):
// WC()->cart->subtotal >= $target_cart_amount ? $passed = true : $passed = false ;
// Iterating through each cart items
foreach( $cart_object->get_cart() as $cart_item ){
// Item id ($product ID or variation ID)
if( $cart_item['variation_id'] > 0)
$item_id = $cart_item['variation_id'];
else
$item_id = $cart_item['product_id'];
// Getting the product weight
$product_weight = get_post_meta( $item_id , '_weight', true);
// Line item weight
$line_item_weight = $cart_item['quantity'] * $product_weight;
// When cart amount is up to 1kg, Adding weight of heavy items
if($passed && $product_weight < $target_weight)
$calculated_weight += $line_item_weight;
}
#### Making the fee calculation ####
// Cart is up to 250 with heavy items
if ( $passed && $calculated_weight != 0 ) {
// Fee is based on cumulated weight of heavy items
$fee = ($calculated_weight * $price_kg) - $flat_rate_price;
}
// Cart is below 250
elseif ( !$passed ) {
// Fee is based on cart total weight
$fee = ($cart_object->get_cart_contents_weight( ) * $price_kg) - $flat_rate_price;
}
#### APPLYING THE CALCULATED FEE ####
// When cart is below 250 or when there is heavy items
if ($fee > 0){
// Rounding the fee
$fee = round($fee);
// This shipping fee is taxable (You can have it not taxable changing last argument to false)
$cart_object->add_fee( __('Shipping weight fee', 'woocommerce'), $fee, true);
}
}
Edit:
And at the same time I want it to show this immediately on the cart page. Now it is showing "enter address to view shipping options". Basically just look at total of cart and show either a rate or free shipping based on the rules described for weight and price.
woocommerce_package_rates is the right filter to customize the shipping rate.
You can achieve this by following way.
Step-1: Create two shipping method, Free shipping and Flat rate with coast 3$
Step-2: Copy and paste below code snippet into functions.php
Config the flat rate and free shipping properly on the snippet.
add_filter( 'woocommerce_package_rates', 'modify_shipping_rate', 15, 2 );
function modify_shipping_rate( $available_shipping_methods, $package ){
global $woocmmerce;
$total_weight = WC()->cart->cart_contents_weight;
$total_coast = WC()->cart->get_cart_contents_total();
if( $total_coast >= 20 ){
unset($available_shipping_methods['flat_rate:1']); //Remove flat rate for coat abobe 20$
}elseif( $total_weight > 10 ){
unset($available_shipping_methods['free_shipping:1']); // remove free shipping for below 20$
$available_shipping_methods['flat_rate:1']->cost += 2; // add 2$ if weight exceeds 10KG
}else{
unset($available_shipping_methods['free_shipping:1']); // remove free shipping for below 20$
}
return $available_shipping_methods;
}
Use below snippet to change the default cart message.
add_filter( 'woocommerce_cart_no_shipping_available_html', 'change_msg_no_available_shipping_methods', 10, 1 );
add_filter( 'woocommerce_no_shipping_available_html', 'change_msg_no_available_shipping_methods', 10, 1 );
function change_msg_no_available_shipping_methods( $default_msg ) {
$custom_msg = "Enter address to view shipping options";
if( empty( $custom_msg ) ) {
return $default_msg;
}
return $custom_msg;
}
The following code isn't based on a custom fee, but on shipping methods customizations.It requires to set in shipping settings, for each shipping zone:
A "Flat Rate" with a defined cost ($3 for you)
A "Free Shipping" with no requirements (no restrictions).
The code will handle flat rate calculation cost based on the weight and also the tax calculations.
The code will work for any shipping zone without needing to define in the code the shipping method IDs.
Here is the code:
add_filter( 'woocommerce_package_rates', 'filter_package_rates_callback', 10, 2 );
function filter_package_rates_callback( $rates, $package ) {
## -------- Settings -------- ##
$targeted_total = 20; // The targeted cart amount
$weight_threshold = 10; // The cart weight threshold
$extra_for_10kg = 2; // 10 Kg addition extra cost;
$total_weight = WC()->cart->get_cart_contents_weight();
$cart_subtotal = WC()->cart->get_subtotal(); // Excluding taxes
// Set shipping costs based on weight
foreach ( $rates as $rate_key => $rate ){
$has_taxes = false;
if( $cart_subtotal < $targeted_total || $total_weight >= $weight_threshold ){
// Remove Free shipping Method
if( 'free_shipping' === $rate->method_id ) {
unset( $rates[$rate_key] );
}
// Flat rate calculation cost when 10 kg weight is reached
if( 'flat_rate' === $rate->method_id && $total_weight >= $weight_threshold ) {
// The default rate cost (set in the shipping method)
$default_cost = $rate->cost;
// The new calculated cost (up to 10 kg)
$new_cost = $default_cost + $extra_for_10kg;
// Tax rate conversion (for tax calculations)
$tax_rate_converion = $new_cost / $default_cost;
// Set the new cost
$rates[$rate_key]->cost = $new_cost;
// TAXES RATE COST (if enabled)
foreach ($rates[$rate_key]->taxes as $key => $tax){
if( $tax > 0 ){
// New tax calculated cost
$taxes[$key] = $tax * $tax_rate_converion;
$has_taxes = true;
}
}
// Set new taxes cost
if( $has_taxes )
$rates[$rate_key]->taxes = $taxes;
}
} else {
// Remove Flat Rate methods (keeping Free Shipping Method only)
if( 'flat_rate' === $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 works.
Refresh the shipping caches: (required)
1) This code is already saved on your function.php file.
2) In a shipping zone settings, disable / save any shipping method, then enable back / save.
You are done and you can test it.
Displaying shipping methods directly (Regarding your question edit)
The provided information in your question is not enough to see how this can be managed.
If you are selling in one country, and you have a unique shipping zone, you can force the country for unlogged customers to get the shipping methods displayed, using the following:
add_action( 'template_redirect', 'allow_display_shipping_methods' );
function allow_display_shipping_methods() {
// HERE define the targeted country code
$country_code = 'GB';
// Set the shipping country if it doesn't exist
if( ! WC()->customer->get_shipping_country() )
WC()->customer->set_shipping_country('GB');
}
Code goes in function.php file of your active child theme (or active theme). Tested and works.
Now this is another question, in your initial question and should be asked as a new question.
Related answers:
Set a custom shipping rate cost calculated on cart total weight in WooCommerce
Free shipping depending on weight and on minimal cart amount
Shipping cost based on cart total weight in Woocommerce 3
Hide and unhide a specific shipping methods based on shipping class in WooCommerce

Progressive cart item custom shipping cost in Woocommerce

I need to figure out a way to do woocommerce shipping rates based on items on cart.
I need to charge 120 if buying 1-2 items and 180 buying 3. I added a free shipping option for 4+ (based on $)
I tried adding this to the flat rate price: 120+60([qty]-2) it works in all instances but the 1 item, because it charges $60.
Any thoughts?
With the following code, you will be able to get this shipping rates:
- 1 or 2 items: $120
- 3 items: $180
- 4 items or more: Free shipping (hiding flat rate method)
1) Add the following code to function.php file of your active child theme (active theme):
add_filter('woocommerce_package_rates', 'custom_progressive_shipping_costs', 10, 2);
function custom_progressive_shipping_costs( $rates, $package ){
$items_count = WC()->cart->get_cart_contents_count();
if( $items_count < 3 ){
$cost_rate = 2;
} else {
$cost_rate = $items_count;
}
foreach ( $rates as $rate_key => $rate ){
$taxes = [];
$has_taxes = false;
// Targeting "flat rate"
if ( 'flat_rate' === $rate->method_id ) {
// For 1, 2 or 3 items
if ( $items_count <= 3 ) {
$rates[$rate_key]->cost = $rate->cost * $cost_rate;
// Taxes rate cost (if enabled)
foreach ($rates[$rate_key]->taxes as $key => $tax){
if( $tax > 0 ){
$has_taxes = true;
$taxes[$key] = $tax * $cost_rate;
}
}
if( $has_taxes )
$rates[$rate_key]->taxes = $taxes;
}
// For more than 3 hide Flat rate
else {
// remove flat rate method
unset($rates[$rate_key]);
}
}
}
return $rates;
}
And save…
2) In Your shipping method settings, you will need to set 60 as your "Flat rate" cost and SAVE.
You need to keep your minimal amount for "Free shipping" method.
You are done. Tested and works.

Set a percentage discount to Local pickup shipping method in Woocommerce

I have a WordPress site which uses WooCommerce plugin. I would like to offer buyer 5% reduction from cart total if they select local pickup as a shipping method.
I already tried - 5 * [qty] and it doesn't seem to be working.
I also tried -0.95 * [cost] with no luck
I am using WooCommerce 3 and achieved the above result by writing a function inside the function.php of active theme.
function prefix_add_discount_line( $cart ) {
$chosen_methods = WC()->session->get( 'chosen_shipping_methods' );
$chosen_shipping_no_ajax = $chosen_methods[0];
if ( 0 === strpos( $chosen_shipping_no_ajax, 'local_pickup' ) ) {
// Define the discount percentage
$discount = $cart->subtotal * 0.05;
// Add your discount note to cart
$cart->add_fee( __( 'Collection discount applied', 'yourtext-domain' ) , -$discount );
}
}
add_action( 'woocommerce_cart_calculate_fees', 'prefix_add_discount_line');
The problem with the fee API is that it always apply Taxes for negative fee (Discount) and don't care about existing coupons discounts.
The code below, will set a defined discount percentage In the shipping method "Local pickup" itself.
You will need to set a reference shipping cost with a simple initial cost instead of your formula. It can be for example 10, and will be replaced by the code discount.
You may have to "Enable debug mode" in general shipping settings under "Shipping options" tab, to disable temporarily shipping caches.
The code (where you will set your discount percentage):
add_filter('woocommerce_package_rates', 'local_pickup_percentage_discount', 12, 2);
function local_pickup_percentage_discount( $rates, $package ){
if ( is_admin() && ! defined( 'DOING_AJAX' ) )
return $rates;
// HERE define the discount percentage
$percentage = 5; // 5%
$subtotal = WC()->cart->get_subtotal();
// Loop through the shipping taxes array
foreach ( $rates as $rate_key => $rate ){
$has_taxes = false;
// Targetting "flat rate"
if( 'local_pickup' === $rate->method_id ){
// Add the Percentage to the label name (otional
$rates[$rate_key]->label .= ' ( - ' . $percentage . '% )';
// Get the initial cost
$initial_cost = $new_cost = $rates[$rate_key]->cost;
// Calculate new cost
$new_cost = -$subtotal * $percentage / 100;
// Set the new cost
$rates[$rate_key]->cost = $new_cost;
// Taxes rate cost (if enabled)
$taxes = [];
// Loop through the shipping taxes array (as they can be many)
foreach ($rates[$rate_key]->taxes as $key => $tax){
if( $rates[$rate_key]->taxes[$key] > 0 ){
// Get the initial tax cost
$initial_tax_cost = $new_tax_cost = $rates[$rate_key]->taxes[$key];
// Get the tax rate conversion
$tax_rate = $initial_tax_cost / $initial_cost;
// Set the new tax cost
$taxes[$key] = $new_cost * $tax_rate;
$has_taxes = true; // Enabling tax
}
}
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.
Don't forget to disable "Enable debug mode" option in shipping settings.

Woocommerce conditional shipping cost reduction based on cart amount and item count

I'm looking for a way to make a custom reduction on shipping cost, based on cart total percentage, flat rate and quantity per type of product.
For 6 product : flat shipping rate 20€
Total cart is 120€ | Shipping cost = flat rate cost - 10% total cart | 20 - 12 = 8€
Total cart is 180€ | Shipping cost = flat rate cost - 10% total cart | 20 - 18 = 2€
Total cart is 220€ | Shipping cost = flat rate cost - 10% total cart | 20 - 22 = 0€
For 12 product : flat shipping rate 30€
Total cart is 120€ | Shipping cost = flat rate cost - 10% total cart | 30 - 12 = 18€
Total cart is 180€ | Shipping cost = flat rate cost - 10% total cart | 30 - 18 = 12€
Total cart is 220€ | Shipping cost = flat rate cost - 10% total cart | 30 - 22 = 8€
How can this be done?
This can be done without a plugin…
1) You will need first in WooCommerce shipping settings for each shipping zone to set an amount of 1 for "Flat rate" method:
This amount will be changed in our function to 20€ from 1 to 11 items and 30€for 12 and more items. This amount will be decreased by the 10% cart total amount.
2) Then using a custom function hooked in woocommerce_package_rates filter hook, you will be able to make a discount on shipping cost based on cart item count and on cart total.
Here is that code:
add_filter( 'woocommerce_package_rates', 'custom_package_rates', 10, 2 );
function custom_package_rates( $rates, $packages ) {
if ( is_admin() && ! defined( 'DOING_AJAX' ) ) return;
// Get some cart data and set variable values
$cart_count = WC()->cart->get_cart_contents_count();
$cart_total = WC()->cart->cart_contents_total;
$cart_10_percent = $cart_total * 0.1;
$flat_rate_value = 20; // Default "Flat rate" value
foreach($rates as $rate_key => $rate_values ) {
$method_id = $rate_values->method_id;
$rate_id = $rate_values->id;
if( $method_id == 'flat_rate' ){
if( $cart_count < 6 )
$cart_10_percent = 0; // No percent discount
elseif( $cart_count >= 12 )
$flat_rate_value = 30; // "Flat rate" value for 12 or more items
$rate_cost = $flat_rate_value > $cart_10_percent ? $flat_rate_value - $cart_10_percent : 0;
// Set the new calculated rate cost
$rates[$rate_id]->cost = number_format( $rates[$rate_id]->cost * $rate_cost, 2 );
// Taxes rate cost (if enabled)
$taxes = array();
foreach ($rates[$rate_id]->taxes as $key => $tax){
if( $tax > 0 ){ // set the new tax cost
// set the discounted tax cost
$taxes[$key] = number_format( $tax * $rate_cost, 2 );
}
}
$rates[$rate_id]->taxes = $taxes;
}
}
return $rates;
}
Code goes in function.php file of your active child theme (or theme) or also in any plugin file.
Tested on WooCommerce 3 and works.
Refresh the shipping caches (needed sometimes):
1) First empty your cart.
2) This code is already saved on your function.php file.
3) Go in a shipping zone settings and disable one "flat rate" (for example) and "save". Then re-enable that "flat rate" and "save". You are done and you can test it.

Categories