This seems like it should be simple but I can't quite get there.
Goal: I need to display a notice to users when they change their shipping method if the cart total is less than the required limit.
I wrote a function in functions.php file
function min_delivery(){
//Get Chosen Shipping Method//
$chosen_methods = WC()->session->get( 'chosen_shipping_methods' );
$chosen_shipping = $chosen_methods[0];
//end method
//check if they've chosen delivery
if ($chosen_shipping == 'flat_rate:2') {
//set cart minimum
$minimum = 15.00;
//get cart total - 2.00 is the delivery fee
$total = WC()->cart->total-2.00;
// check if the total of the cart is less than the minium
if ( $total < $minimum ) {
//check if it's in the cart
if( is_cart() ) {
wc_print_notice(
sprintf( 'Minimum £15.00 for Delivery' ,
wc_price( $minimum ),
wc_price( $total )
), 'error'
);
//else at checkout
} else {
wc_add_notice(
sprintf( 'Min 15.00 for Delivery' ,
wc_price( $minimum ),
wc_price( $total )
), 'error'
);
}
}//end of total less than min
//else they have pick up
} else {
//set cart minimum
$minimum = 4.50;
//get cart total - 2.00 is the delivery fee
$total = WC()->cart->total-2.00;
if ( $total < $minimum ) {
//check if it's in the cart
if( is_cart() ) {
wc_print_notice(
sprintf( 'Minimum £15.00 for Delivery' ,
wc_price( $minimum ),
wc_price( $total )
), 'error'
);
//else at checkout
} else {
wc_add_notice(
sprintf( 'Min 15.00 for Delivery' ,
wc_price( $minimum ),
wc_price( $total )
), 'error'
);
}
}//end of total less than min
}//end pickup/delivery else
}//end function
Now calling this function with the before checkout form works great
add_action( 'woocommerce_before_checkout_form' , 'min_delivery' );
However my issue is when people update the shipping on the fly, i.e choose between them. I figured there would be a hook I could use such as one of these
//add_action( 'woocommerce_checkout_process', 'min_delivery' );
//add_action( 'update_order_review' , 'min_delivery' );
//add_action( 'woocommerce_review_order_after_shipping' , 'min_delivery' );
add_action( 'woocommerce_before_checkout_form' , 'min_delivery' );
//add_action( 'woocommerce_after_checkout_shipping_form', 'min_delivery' );
//add_action('woocommerce_cart_totals_after_shipping', 'min_delivery');
However none of them do the job. When i look into the console, when updating there is an AJAX Call to ?wc-ajax=update_order_review but I couldn't seem to hook into that
I'm wandering if i'm barking up the wrong tree here and you can even amend the page through hooks and functions as PHP has already rendered?
As per the goal the whole point is to restrict order/payment for delivery where cart total is less than £15 and notify the customer of the reason.
I have revisited and tried to simplify your code. The following will add conditionally a custom information message (refreshed dynamically) in cart and checkout totals table after shipping rows:
add_action( 'woocommerce_cart_totals_after_shipping', 'shipping_notice_displayed', 20 );
add_action( 'woocommerce_review_order_after_shipping', 'shipping_notice_displayed', 20 );
function shipping_notice_displayed() {
if ( did_action( 'woocommerce_cart_totals_after_shipping' ) >= 2 ||
did_action( 'woocommerce_review_order_after_shipping' ) >= 2 ) {
return;
}
// Chosen Shipping Method
$chosen_shipping_method_id = WC()->session->get( 'chosen_shipping_methods' )[0];
$chosen_shipping_method = explode(':', $chosen_shipping_method_id)[0];
$cart_subtotal = WC()->cart->subtotal; // No need to remove the fee
// Settings
$cart_minimum1 = 4.5;
$cart_minimum2 = 15;
// HERE define the cart mininimum (When delivery is chosen)
if ( $cart_subtotal < $cart_minimum2 && $chosen_shipping_method != 'flat_rate' ) {
$cart_minimum = $cart_minimum1;
} elseif ( $cart_subtotal < $cart_minimum2 && $chosen_shipping_method == 'flat_rate' ) {
$cart_minimum = $cart_minimum2;
}
// Display a message
if( isset($cart_minimum) ){
// The message
$message = sprintf( '%s %s for Delivery' ,
is_cart() ? 'Minimum' : 'Min',
strip_tags( wc_price( $cart_minimum, array('decimals' => 2 ) ) )
);
// Display
echo '</tr><tr class="shipping info"><th> </th><td data-title="Delivery info">'.$message.'</td>';
}
}
Code goes in function.php file of your active child theme (or active theme). Tested and works.
Related
The following code based on an official code snippet from WooCommerce set a minimal required total amount, to be able to checkout:
add_action( 'woocommerce_checkout_process', 'wc_minimum_order_amount' );
add_action( 'woocommerce_before_cart' , 'wc_minimum_order_amount' );
function wc_minimum_order_amount() {
// Set this variable to specify a minimum order value
$minimum = 50;
if ( WC()->cart->total < $minimum ) {
if( is_cart() ) {
wc_print_notice(
sprintf( 'Your current order total is %s — you must have an order with a minimum of %s to place your order ' ,
wc_price( WC()->cart->total ),
wc_price( $minimum )
), 'error'
);
} else {
wc_add_notice(
sprintf( 'Your current order total is %s — you must have an order with a minimum of %s to place your order' ,
wc_price( WC()->cart->total ),
wc_price( $minimum )
), 'error'
);
}
}
}
How can I set a certain minimum order amount in WooCommerce but only for specific postal codes?
Any help is appreciated.
To set a minimum order amount for specific postcodes in WooCommerce, try the following:
add_action( 'woocommerce_checkout_process', 'wc_minimum_order_amount' );
add_action( 'woocommerce_before_cart' , 'wc_minimum_order_amount' );
function wc_minimum_order_amount() {
$minimum = 50; // Set the minimum order value
$postcodes = array('99152', '99154'); // Define your targeted postcodes in the array
$postcode = ''; // Initializing
if ( isset($_POST['shipping_postcode']) && ! empty($_POST['shipping_postcode']) ) {
$postcode = $_POST['shipping_postcode'];
if ( empty($postcode) && isset($_POST['billing_postcode']) && ! empty($_POST['billing_postcode']) ) {
$postcode = $_POST['billing_postcode'];
}
} elseif ( $postcode = WC()->customer->get_shipping_postcode() ) {
if ( empty($postcode) ) {
$postcode = WC()->customer->get_billing_postcode();
}
}
if ( WC()->cart->total < $minimum && ! empty($postcode) && in_array( $postcode, $postcodes ) ) {
$error_notice = sprintf( 'Your current order total is %s — you must have an order with a minimum of %s to place your order ' ,
wc_price( WC()->cart->total ),
wc_price( $minimum )
);
if( is_cart() ) {
wc_print_notice( $error_notice, 'error' );
} else {
wc_add_notice( $error_notice, 'error' );
}
}
}
Code goes in functions.php file of the active child theme (or active theme). Tested and works.
I need to force a minimum order amount for just some categories in WooCommerce, and therefore set an alert in the cart and checkout pages.
So far I managed to set an alert if the total amount in the cart is lower than the minimum amount set, but I can't manage to create a category based filter. Actually any other product is added in the cart the alert is overtaken and the user is allowed to buy the product of that category I want to limit.
Here is the code:
/**
* Set a minimum order amount for checkout
*/
add_action( 'woocommerce_checkout_process', 'wc_minimum_order_amount' );
add_action( 'woocommerce_before_cart' , 'wc_minimum_order_amount' );
add_action( 'woocommerce_before_checkout' , 'wc_minimum_order_amount' );
function wc_minimum_order_amount() {
// Set this variable to specify a minimum order value
$minimum = 30;
// set array with cat IDs
$category_ids = array( 336, 427, 433 );
// set bool that checks is minimum amount has been reached
$needs_minimum_amount = false; // Initializing
$subTotal_amount = WC()->cart->subtotal; // Items subtotal including taxes
$total_amount = WC()->cart->total; // Items subtotal excluding taxes
if ( $total_amount < $minimum ) {
// Loop through cart items
foreach ( WC()->cart->get_cart() as $cart_item ) {
$product_id = $cart_item['product_id'];
$variation_id = $cart_item['variation_id'];
// Check for matching product categories
if( sizeof($category_ids) > 0 ) {
$taxonomy = 'product_cat';
if ( has_term( $category_ids, $taxonomy, $product_id ) ) {
$needs_minimum_amount = true;
break; // Stop the loop
}
}
}
if( $needs_minimum_amount ) {
if( is_cart()) {
wc_print_notice(
sprintf( 'Your current order total is %s — you must have an order with a minimum of %s to place your order ' ,
wc_price( WC()->cart->total ),
wc_price( $minimum )
), 'error'
);
} else {
wc_add_notice(
sprintf( 'Your current order total is %s — you must have an order with a minimum of %s to place your order' ,
wc_price( WC()->cart->total ),
wc_price( $minimum )
), 'error'
);
}
}
}
}
References:
Set minimum Order amount for specific Products or Categories in WooCommerce
https://docs.woocommerce.com/document/minimum-order-amount/
Any help?
There are some mistakes in your code… Use the following instead:
add_action( 'woocommerce_checkout_process', 'wc_minimum_order_amount' );
add_action( 'woocommerce_before_cart', 'wc_minimum_order_amount' );
add_action( 'woocommerce_before_checkout_form', 'wc_minimum_order_amount' );
function wc_minimum_order_amount() {
$min_amount = 30; // Min subtotal required
$taxonomy = 'product_cat'; // Product category taxonomy | For product tags use 'product_tag'
$terms = array( 336, 427, 433 ); // Category terms (can be Ids, slugs, or names)
$found = false; // Initializing
$subtotal = WC()->cart->subtotal; // Incl. taxes
$total = WC()->cart->total; // Incl. taxes
if ( $total < $min_amount ) {
// Loop through cart items
foreach ( WC()->cart->get_cart() as $cart_item ) {
if ( has_term( $terms, $taxonomy, $cart_item['product_id'] ) ) {
$found = true;
break; // Stop the loop
}
if( $found ) {
$message = sprintf( 'Your current order total is %s — you must have an order with a minimum of %s to place your order ' ,
wc_price( $total ),
wc_price( $min_amount )
);
if( is_cart()) {
wc_print_notice( $message, 'error' );
} else {
wc_add_notice( $message, 'error' );
}
}
}
}
}
Code goes in functions.php file of the active child theme (or active theme). It should work.
Addition: Based on specific subtotal incl. taxes
This code version is based on items subtotal belonging to specific defined categories:
add_action( 'woocommerce_checkout_process', 'wc_minimum_order_amount' );
add_action( 'woocommerce_before_cart', 'wc_minimum_order_amount' );
add_action( 'woocommerce_before_checkout_form', 'wc_minimum_order_amount' );
function wc_minimum_order_amount() {
$min_amount = 30; // Min subtotal required
$taxonomy = 'product_cat'; // Product category taxonomy | For product tags use 'product_tag'
$terms = array( 336, 427, 433 ); // Category terms (can be Ids, slugs, or names)
$subtotal = 0; // Initializing
// Loop through cart items
foreach ( WC()->cart->get_cart() as $cart_item ) {
if ( has_term( $terms, $taxonomy, $cart_item['product_id'] ) ) {
$subtotal += $cart_item['line_subtotal'] + $cart_item['line_subtotal_tax'];
}
}
if ( $subtotal < $min_amount ) {
if( $found ) {
$message = sprintf( 'Your current order total is %s — you must have an order with a minimum of %s to place your order ' ,
wc_price( $total ),
wc_price( $min_amount )
);
if( is_cart()) {
wc_print_notice( $message, 'error' );
} else {
wc_add_notice( $message, 'error' );
}
}
}
}
It should works.
Finally I found the solution working a little on the code provided by #LoicTheAztec.
Below the final code. Tested and working.
// Set a minimum order amount for checkout
add_action( 'woocommerce_checkout_process', 'wc_minimum_order_amount' );
add_action( 'woocommerce_before_cart' , 'wc_minimum_order_amount' );
// add_action( 'woocommerce_before_checkout' , 'wc_minimum_order_amount' );
function wc_minimum_order_amount() {
$min_amount = 30; // Set this variable to specify a minimum order value
$taxonomies = array('product_cat'); // Product category taxonomy | For product tags use 'product_tag'
$term_ids = array( 336, 427, 433 ); // Category terms (can be Ids, slugs, or names)
$found = false; // Initializing // set bool that checks if minimum amount has been reached
$subtotal = 0; // Initializing // set subtotal formed by specific category total (incl. taxes)
$subTotal_amount = WC()->cart->subtotal; // Items subtotal including taxes
$total_amount = WC()->cart->total; // Items subtotal including taxes
// 1 - Loop through cart items targeting those having that specific category
foreach ( WC()->cart->get_cart() as $cart_item ) {
if ( has_term( $term_ids, $taxonomies[0], $cart_item['product_id'] ) ) {
$subtotal += $cart_item['line_subtotal'] + $cart_item['line_subtotal_tax'];
}
}
// 2 - Check if at least one product of that category is in the cart
if($subtotal > 0){
$found = true;
}
// 2 - check if subtotal is below the min amount set
if ( $subtotal < $min_amount ) {
if( $found ) {
$message = sprintf( 'Your current order total is %s — you must have an order with a minimum of %s to place your order ' ,
wc_price( $subtotal ),
wc_price( $min_amount )
);
if( is_cart()) {
wc_print_notice( $message, 'error' );
} else {
wc_add_notice( $message, 'error' );
}
}
}
}
In WooCommerce, I use the following code to set a minimum order amount:
add_action( 'woocommerce_checkout_process', 'wc_minimum_order_amount' );
add_action( 'woocommerce_before_cart' , 'wc_minimum_order_amount' );
function wc_minimum_order_amount() {
$minimum = 50; // Hier gibst du den Mindestbestellwert ein
if ( WC()->cart->total < $minimum ) {
if( is_cart() ) {
wc_print_notice( sprintf( 'Der Mindestbestellwert beträgt %s pro Bestellung. Der aktuelle Bestellwert beträgt %s.' , // Text fuer Warenkorb
wc_price( $minimum ),
wc_price( WC()->cart->total )
), 'error' );
} else {
wc_add_notice( sprintf( 'Der Mindestbestellwert beträgt %s pro Bestellung. Der aktuelle Bestellwert beträgt %s.' , // Text fuer Kasse
wc_price( $minimum ),
wc_price( WC()->cart->total )
), 'error' );
}
}
}
Now if the customer chooses "self pickup" ("Local pickup shipping method), I don't want any minimum required order amount.
How can I set Minimum order amount except for "Local pickup" shipping method in WooCommerce?
Based on Getting minimum order amount for 'Free Shipping' method in checkout page answer code and also Set a minimum order amount in WooCommerce answer code, here is the correct way to set a 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 = 50; // 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 is %s (your current order amount is %s).", "woocommerce"), // Text message
wc_price( $minimum_amount ),
wc_price( $cart_total )
), 'error' );
}
}
Code goes in functions.php file of your active child theme (or active theme). Tested and works.
or also you can use:
add_action( 'woocommerce_checkout_process', 'wc_minimum_required_order_amount' );
add_action( 'woocommerce_before_cart' , 'wc_minimum_required_order_amount' );
function wc_minimum_required_order_amount() {
// HERE Your settings
$minimum_amount = 100; // 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 ) {
$text_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 )
);
if ( is_cart() ) {
wc_print_notice( $text_notice, 'error' );
} else {
wc_add_notice( $text_notice, 'error' );
}
}
}
Code goes in functions.php file of your active child theme (or active theme). Tested and works.
In woocommerce I am currently seeking to add a function in my theme's functions.php file, if two conditions are met. Then, using elseif(), deploy the function if only one condition is met.
The code is as follows:
add_action( 'woocommerce_widget_shopping_cart_before_buttons' , 'wc_minimum_order_amount' );
function wc_minimum_order_amount() {
$minimum = 150;
$minimum2 = 100;
if ( is_page([232]) && WC()->cart->subtotal < $minimum2 ) {
if( 'woocommerce_widget_shopping_cart' ) {
wc_print_notice(
sprintf( 'Your current order total does not meet the %s minimum' ,
wc_price( $minimum2 )
), 'error'
);
remove_action( 'woocommerce_widget_shopping_cart_buttons', 'woocommerce_widget_shopping_cart_proceed_to_checkout', 20 );
}
else {
wc_add_notice(
sprintf( 'Your current order total does not meet the %s minimum' ,
wc_price( $minimum2 )
), 'error'
);
}
}
elseif ( WC()->cart->subtotal < $minimum ) {
if( 'woocommerce_widget_shopping_cart' ) {
wc_print_notice(
sprintf( 'Your current order total does not meet the %s minimum',
wc_price( $minimum )
), 'error'
);
remove_action( 'woocommerce_widget_shopping_cart_buttons', 'woocommerce_widget_shopping_cart_proceed_to_checkout', 20 );
}
else {
wc_add_notice(
sprintf( 'Your current order total does not meet the %s minimum' ,
wc_price( $minimum )
), 'error'
);
}
}
}
What I am trying to do is hide the checkout button for the woocommerce widget if the minimum order amount is not met. However, different pages have different minimums.
I'm trying to hide the checkout button if the cart isn't equal to $150. But for one page in particular, I only want the cart to have a minimum of $100.
Note that the hook that you are using is only made for minicart widget, so you don't need to test that in an IF statement.
You are making that much more complicated that it should be. Try the following revisited code instead:
add_action( 'woocommerce_widget_shopping_cart_before_buttons' , 'wc_minimum_order_amount' );
function wc_minimum_order_amount() {
$min_amount = is_page([232]) ? 100 : 150;
if( WC()->cart->subtotal < $min_amount ) {
remove_action( 'woocommerce_widget_shopping_cart_buttons', 'woocommerce_widget_shopping_cart_proceed_to_checkout', 20 );
wc_add_notice(
sprintf( 'Your current order total does not meet the %s minimum' ,
wc_price( $min_amount )
), 'error'
);
}
}
Code goes in function.php file of your active child theme (or active theme). It should better work now.
I need to set a minimum order fee in the shopping cart so if products in the cart don't total more than £10 then an extra fee is applied to bring the price up to £10.
Here is the code I have at the moment which works well in the cart phase however when you reach the checkout the pricing section doesn't stop loading for some reason and you can't checkout, can anyone help?
Code from functions.php:
function woocommerce_custom_surcharge() {
global $woocommerce;
if ( is_admin() && ! defined( 'DOING_AJAX' ) )
return;
$minimumprice = 10;
$currentprice = $woocommerce->cart->cart_contents_total;
$additionalfee = $minimumprice - $currentprice;
if ( $additionalfee >= 0 ) {
wc_print_notice(
sprintf( 'We have a minimum %s per order. As your current order is only %s, an additional fee will be applied at checkout.' ,
wc_price( $minimumprice ),
wc_price( $currentprice )
), 'error'
);
$woocommerce->cart->add_fee( 'Minimum Order Adjustment', $additionalfee, true, '' );
}
}
add_action( 'woocommerce_cart_calculate_fees','woocommerce_custom_surcharge' );
Enhanced and updated on May 2019.
The infinite loading spin issue that you are facing is due to wc_print_notice() when it's used in woocommerce_cart_calculate_fees hook. It's seems like a bug.
If you use instead wc_add_notice(), the problem is gone but the notice is displayed 2 times.
Additionally I have revisited your code.The only solution is to split it in 2 separated functions (and a third one for the message):
// Add a custom fee (displaying a notice in cart page)
add_action( 'woocommerce_cart_calculate_fees', 'add_custom_surcharge', 10, 1 );
function add_custom_surcharge( $cart ) {
if ( is_admin() && ! defined( 'DOING_AJAX' ) )
return;
if ( did_action( 'woocommerce_cart_calculate_fees' ) >= 2 )
return;
$min_price = 100; // The minimal cart amount
$current_price = $cart->cart_contents_total;
$custom_fee = $min_price - $current_price;
if ( $custom_fee > 0 ) {
$cart->add_fee( __('Minimum Order Adjustment'), $custom_fee, true );
// NOTICE ONLY IN CART PAGE
if( is_cart() ){
wc_print_notice( get_custom_fee_message( $min_price, $current_price ), 'error' );
}
}
}
// Displaying the notice on checkout page
add_action( 'woocommerce_before_checkout_form', 'custom_surcharge_message', 10 );
function custom_surcharge_message( ) {
$min_price = 100; // The minimal cart amount
$cart = WC()->cart;
$current_price = $cart->cart_contents_total;
$custom_fee = $min_price - $current_price;
// NOTICE ONLY IN CHECKOUT PAGE
if ( $custom_fee > 0 ) {
wc_print_notice( get_custom_fee_message( $min_price, $current_price ), 'error' );
}
}
// The fee notice message
function get_custom_fee_message( $min_price, $current_price ) {
return sprintf(
__('We have a minimum %s per order. As your current order is only %s, an additional fee will be applied.', 'woocommerce'),
wc_price( $min_price ),
wc_price( $current_price )
);
}
Code goes in functions.php file of your active child theme (or active theme). Tested and works.