I have gleaned code on stack overflow that allows me to display notices with minimum cart totals based on Zip code. I include the code below.
My PROBLEM is that the message automatically defaults to Zone 1.
Which means that if a new visitor (who actually lives in Zone 2) comes to the site, places items in cart, visits cart -> the error message for Zone 1 is already showing up. The new visitor has not input their postcode yet. The cart shipping calculator is where the new visitor will enter their postcode (zip code).
I don't know what will be a workaround for this problem, but I was wondering if one can add an IF statement before the Cart Notice code, that basically checks: if customer postcode is not set yet, then display message: "Please enter your postcode".
Then, if customer_postcode is set, then display the minimum cart value messages based on zones as in the existing code already.
I hope I am making sense - and hope someone can help me.
//MINIMUM CART AMOUNT FOR CHECKOUT
add_action( 'woocommerce_check_cart_items', 'required_min_cart_subtotal_amount' );
function required_min_cart_subtotal_amount() {
$zone = WC_Shipping_Zones::get_zone_by ( 'zone_name', "1" . 'zone_name', "2" . 'zone_name' , "3" );
// Only run it in Cart or Checkout pages
if( is_cart() || ( is_checkout() && ! is_wc_endpoint_url() ) ) {
// Get cart shipping packages
$shipping_packages = WC()->cart->get_shipping_packages();
//Get the WC_Shipping_Zone instance object for the first package
$shipping_zone = wc_get_shipping_zone( reset( $shipping_packages ) );
$zone_id = $shipping_zone->get_id(); //Get the zone ID
$zone_name = $shipping_zone->get_zone_name(); // Get the zone name
// Total (before taxes and shipping charges)
$total = WC()->cart->subtotal;
// HERE set minimum cart total amount (for Zone 1,2,3 and for other zones)
// $min_total = $zone_id == 200.0 : 99.99 ? "1";
$min_total = 180;
if ($zone_id == "2") $min_total = 100;
if ($zone_id == "3") $min_total = 220;
// Add an error notice if cart total is less than the minimum required
if( $total <= $min_total ) {
// Display an error message
wc_add_notice( sprintf(
__("A minimum order of - %s is required. Please enter your Postal Code in the Shipping section below. Minimum orders differ from area to area."),
wc_price( $min_total)
), 'error' );
remove_action( 'woocommerce_proceed_to_checkout','woocommerce_button_proceed_to_checkout', 20);
}
add_action( 'woocommerce_proceed_to_checkout', 'disable_checkout_button', 1);
}
}
Related
I need to hide or only let the customers choose shipping option delivery if the order amount is above 15. If the order amount is under 15 they should not order for delivery only for local pickup.
I tried some code i found here, but it doesnt work. it only works on cart page, if you change the delivery option on checkout page you can still order with delivery shipment method.
This is the code I found.
add_action( 'woocommerce_check_cart_items', 'wc_minimum_required_order_amount' );
function wc_minimum_required_order_amount() {
// HERE Your settings
$minimum_amount = 15; // The minimum cart total amount
$shipping_method_id = 'local_pickup'; // The targeted shipping method Id (exception)
// Get some variables
$total = (float) WC()->cart->total; // Total cart amount
$chosen_methods = (array) WC()->session->get( 'chosen_shipping_methods' ); // Chosen shipping method rate Ids (array)
// Only when a shipping method has been chosen
if ( ! empty($chosen_methods) ) {
$chosen_method = explode(':', reset($chosen_methods)); // Get the chosen shipping method Id (array)
$chosen_method_id = reset($chosen_method); // Get the chosen shipping method Id
}
// If "Local pickup" shipping method is chosen, exit (no minimun is required)
if ( isset($chosen_method_id) && $chosen_method_id === $shipping_method_id ) {
return; // exit
}
// Add an error notice is cart total is less than the minimum required
if ( $cart_total < $minimum_amount ) {
wc_add_notice( sprintf(
__("The minimum required order amount is %s (your current order amount is %s).", "woocommerce"), // Text message
wc_price( $minimum_amount ),
wc_price( $cart_total )
), 'error' );
}
}
This question already exists:
How to set minimum total order amount for different currencies in order to disallow shipping options?
Closed 12 months ago.
I've disallowed shipping options for customers when they are in the cart page of Woocommerce and the total amount of cart is less than $20 but I'd like to apply that as well for the equivalence of the same amount in another currency "Bs."
I'm using the following as my current code which I've learnt from existing source "Minimum order amount except for specific shipping method in WooCommerce" :
add_action( 'woocommerce_check_cart_items', 'wc_minimum_required_order_amount' );
function wc_minimum_required_order_amount() {
// HERE Your settings
$minimum_amount = 20; // The minimum cart total amount
$shipping_method_id = 'local_pickup'; // The targeted shipping method Id (exception)
// Get some variables
$cart_total = (float) WC()->cart->total; // Total cart amount
$chosen_methods = (array) WC()->session->get( 'chosen_shipping_methods' ); // Chosen shipping method rate Ids (array)
// Only when a shipping method has been chosen
if ( ! empty($chosen_methods) ) {
$chosen_method = explode(':', reset($chosen_methods)); // Get the chosen shipping method Id (array)
$chosen_method_id = reset($chosen_method); // Get the chosen shipping method Id
}
// If "Local pickup" shipping method is chosen, exit (no minimun is required)
if ( isset($chosen_method_id) && $chosen_method_id === $shipping_method_id ) {
return; // exit
}
// Add an error notice is cart total is less than the minimum required
if ( $cart_total < $minimum_amount ) {
wc_add_notice( sprintf(
__("The minimum required order amount for shipping is %s (your current order amount is %s).", "woocommerce"), // Text message
wc_price( $minimum_amount ),
wc_price( $cart_total )
), 'error' );
}
}
I am using Woocommerce set minimum order for a specific user role answer code and it works like a charm!
Though I would like to only have a minimum order amount if the product(s) placed in the shopping cart are not in stock (backorder). If the product(s) in the shopping cart are in stock, there should be no minimum order amount. Could someone help me out?
To make the code work only when there is backordered items, you need to include in the code a check for backordered items as follows:
add_action( 'woocommerce_check_cart_items', 'set_min_total_per_user_role' );
function set_min_total_per_user_role() {
// Only run in the Cart or Checkout pages
if( is_cart() || is_checkout() ) {
// Set minimum cart total (by user role)
$minimum_cart_total = current_user_can('company') ? 250 : 100;
// Total (before taxes and shipping charges)
$total = WC()->cart->subtotal;
$has_backordered_items = false;
// Check for backordered cart items
foreach ( WC()->cart->get_cart() as $cart_item ) {
if ( $cart_item['data']->is_on_backorder( $cart_item['quantity'] ) ) {
$has_backordered_items = true;
break; // stop the loop
}
}
// Add an error notice is cart total is less than the minimum required
if( $has_backordered_items && $total <= $minimum_cart_total ) {
// Display our error message
wc_add_notice( sprintf( '<strong>Dear customer, minimum order of %s is required to make a purchase on your site.</strong> <br>
Your actual cart amount is: %s',
wc_price($minimum_cart_total),
wc_price($total)
), 'error' );
}
}
}
Code goes in functions.php file of the active child theme (or active theme). It should works.
Based on: Woocommerce set minimum order for a specific user role
I have a php code that sets a 100 minimum order site wide, that works good.
I want to set a different minimum order of 250 for a specific role 'company' using the same code or by cloning it and wrapping it in an if() statement, only I have no idea how to write it. Would appreciate any kind of help.
This it the currant code (don't mind the Hebrew text, its just the error messages, when the condition is not met):
// Set a minimum dollar amount per order
add_action( 'woocommerce_check_cart_items', 'spyr_set_min_total' );
function spyr_set_min_total() {
// Only run in the Cart or Checkout pages
if( is_cart() || is_checkout() ) {
global $woocommerce;
// Set minimum cart total
$minimum_cart_total = 100;
// Total we are going to be using for the Math
// This is before taxes and shipping charges
$total = WC()->cart->subtotal;
// Compare values and add an error is Cart's total
// happens to be less than the minimum required before checking out.
// Will display a message along the lines of
// A Minimum of 10 USD is required before checking out. (Cont. below)
// Current cart total: 6 USD
if( $total <= $minimum_cart_total ) {
// Display our error message
wc_add_notice( sprintf( '<strong>לקוח יקר, יש צורך במינימום הזמנה
של %s %s₪ על מנת לבצע רכישה באתר.</strong>'
.'<br />סכום הביניים בעגלה הינו: %s %s₪',
$minimum_cart_total,
get_option( 'woocommerce_currency_symbol'),
$total,
get_option( 'woocommerce_currency_symbol') ),
'error' );
}
}
}
Thanks!
Try the following using current_user_can(), so in your code:
// Set a minimum amount per order (and user role)
add_action( 'woocommerce_check_cart_items', 'set_min_total_per_user_role' );
function set_min_total_per_user_role() {
// Only run in the Cart or Checkout pages
if( is_cart() || is_checkout() ) {
// Set minimum cart total
$minimum_cart_total = current_user_can('company') ? 250 : 100;
// Total (before taxes and shipping charges)
$total = WC()->cart->subtotal;
// Add an error notice is cart total is less than the minimum required
if( $total <= $minimum_cart_total ) {
// Display our error message
wc_add_notice( sprintf( '<strong>Dear customer, minimum order of %s is required to make a purchase on your site.</strong> <br>
Your actual cart amount is: %s',
wc_price($minimum_cart_total),
wc_price($total)
), 'error' );
}
}
}
Code goes on function.php file of your active child theme (or active theme). It should works.
To format prices for display you can use the dedicated wc_price() formatting function.
Related: Apply a discount for a specific user role in Woocommerce
First you have to retrieve the roles of the current user.
$roles = is_user_logged_in() ? (array) wp_get_current_user()->roles : [];
Now you want to check if the role company is in the user's roles to determine the minimum.
$minimum_cart_total = in_array('company', $roles) ? 250 : 100;
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