Woocommerce minimum order by category/quantity - php

I'm wondering if it would be possible to create an if statement where if a customer hasn't added enough (quantity - not price) of a specific product category to their order, a message shows up saying they need to add more to avoid a surcharge. I'm thinking something along the lines of the minimum order amount snippet documented here:
add_action( 'woocommerce_checkout_process', 'wc_minimum_order_amount' );
function wc_minimum_order_amount() {
global $woocommerce;
$minimum = 50;
if ( $woocommerce->cart->total() < $minimum ) {
$woocommerce->add_error( sprintf( 'You must have an order with a minimum of %s to place your order.' , $minimum ) );
}
}
Any help would be greatly appreciated.

This might be done by using the woocommerce_checkout_process and woocommerce_before_cart Woocommerce Hooks.
So add this code at your theme's functions.php file (change the Name Your category string):
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; //Qty product
if ( WC()->cart->cart_contents_count < $minimum ) {
$draught_links = array();
foreach(WC()->cart->get_cart() as $cart_item_key => $values ) {
$_product = $values['data'];
$terms = get_the_terms( $_product->id, 'product_cat' );
foreach ($terms as $term) {
$draught_links[] = $term->name;
}
}
if (in_array("Name Your category", $draught_links)){
$on_draught = true;
}else{
$on_draught = false;
}
if( is_cart() ) {
if($on_draught){
wc_print_notice(
sprintf( 'You must have an order with a minimum of %s to place your order, your current order total is %s.' ,
$minimum ,
WC()->cart->cart_contents_count
), 'error'
);
}
} else {
if($on_draught){
wc_add_notice(
sprintf( 'You must have an order with a minimum of %s to place your order, your current order total is %s.' ,
$minimum ,
WC()->cart->cart_contents_count
), 'error'
);
}
}
}
}

From the WooCommerce Docs
public float $cart_contents_count - The total count of the cart items.
So it stands to reason that this should do what you need:
add_action( 'woocommerce_checkout_process', 'wc_minimum_order_amount' );
function wc_minimum_order_amount() {
global $woocommerce;
$minimum = 50;
if ( $woocommerce->cart->cart_contents_count < $minimum ) {
$woocommerce->add_error( sprintf( 'You must have an order with a minimum of %s to place your order.' , $minimum ) );
}
}

Related

Set a minimum order amount for specific postcodes in WooCommerce

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.

WooCommerce: Set minimum order amount for just specific product categories

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' );
}
}
}
}

Remove conditionally "proceed to checkout" button from minicart in Woocommerce

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.

Dynamic information based on shipping method and cart total In Woocommerce

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.

Hide Proceed to Checkout in Wordpress/WooCommerce

Using Wordpress and WooCommerce and I need help adding two user roles. I got it working with one role, but need to also apply this to another role.
Below I am using user role 'wholesale', but there is also another user role that this rule needs to apply to 'us_wholesale'.
Here is my code in functions.php:
add_action( 'woocommerce_checkout_process', 'wdm_wu_minimum_order_amount' );
function wdm_wu_minimum_order_amount() {
$current_screen_user = wp_get_current_user();
if( in_array( 'wholesale', $current_screen_user->roles ) ) {
$minimum = 150;
if ( WC()->cart->subtotal < $minimum ) {
if( is_cart() ) {
wc_print_notice(
sprintf( 'You must have an order with a minimum of %s to place your order, your current order total is %s.' ,
wc_price( $minimum ),
wc_price( WC()->cart->subtotal )
), 'error'
);
} else {
wc_add_notice(
sprintf( 'You must have an order with a minimum of %s to place your order, your current order total is %s.' ,
wc_price( $minimum ),
wc_price( WC()->cart->subtotal )
), 'error'
);
} } } }
And my override in woocommerce cart-totals.php:
<?php
$current_screen_user = wp_get_current_user();
if( in_array( 'wholesale', $current_screen_user->roles ) ) {
$minimum = 150; // Set the minimum amt.
$cart_amt = WC()->cart->subtotal; // cart sub_total, this is actual total excluding discounts and shipping.
if ( $cart_amt < $minimum ) {
if( is_cart() ) {
//Added notices for cart page.
wc_print_notice(
sprintf( 'You must have an order with a minimum of %s to place your order, your current order total is %s.' ,
wc_price( $minimum ),
wc_price( $cart_amt )
), 'error'
);
} else {
//Added notice msg for checkout page.
wc_add_notice(
sprintf( 'You must have an order with a minimum of %s to place your order, your current order total is %s.' ,
wc_price( $minimum ),
wc_price( $cart_amt)
), 'error'
);
}
} else {
do_action( 'woocommerce_proceed_to_checkout' );
}
} else {
do_action( 'woocommerce_proceed_to_checkout' );
}
?>
Since you only have two roles you're checking, why not just replace the following line:
if( in_array( 'wholesale', $current_screen_user->roles ) ) {
with
if( in_array( 'wholesale', $current_screen_user->roles ) || in_array( 'us_wholesale', $current_screen_user->roles ) ){
That way your current (presumably working?) functions will run if the current user has either wholesale or us_wholesale as a user role.

Categories