I have a function which sets a maximum order quantity of items in cart to 16. So user cannot checkout with more than 16 items.
I am also running a plugin which adds a free_gift key to the $cart_item array when a coupon is added.
The problem is that when a user adds 16 items + free_gift = the total is 17 items which prevents checkout.
How can I remove the free_gift from being added to the cart item count?
Example:
Make Woocommerce cart think that 16 items + 1 free_gift = 16 items
Make Woocommerce cart think that 12 items + 1 free_gift = 12 items
My code so far, which allows free_gifts to be added over the max 16 limit, but does not apply the max rule of 16 items:
// Set a maximum number of products requirement before checking out
add_action( 'woocommerce_check_cart_items', 'spyr_set_max_num_products' );
function spyr_set_max_num_products() {
// Only run in the Cart or Checkout pages
if( is_cart() || is_checkout() ) {
$cart_num_products = 0;
foreach ( WC()->cart->cart_contents as $cart_item_key => $cart_item ) {
// HERE I AM TRYING TO SKIP AND PREVENT CART ITEMS OF FREE_GIFTS BEING COUNTED
if ( isset( $cart_item['free_gift'] ) ) {
continue;
}
// Count for regular products.
$cart_num_products++;
}
// Set the maximum number of products before checking out
$maximum_num_products = 16;
// Compare values and add an error is Cart's total number of products
// happens to be less than the minimum required before checking out.
// Will display a message along the lines of
// A Maximum of 16 products is allowed before checking out. (Cont. below)
if( $cart_num_products > $maximum_num_products ) {
// Display our error message
wc_add_notice( sprintf( '<strong>A Maximum of %s snacks are allowed per order.</strong>'
. '<br />Current number of snacks: %s.',
$maximum_num_products,
$cart_num_products ),
'error' );
}
}
}
Try the following, that will remove your custom free item from cart items count:
add_action( 'woocommerce_check_cart_items', 'max_allowed_cart_items' );
function max_allowed_cart_items() {
// Only run in the Cart or Checkout pages
if( is_cart() || is_checkout() ) {
// Set the maximum number of products before checking out
$max_items_count = 16;
$cart_items_count = WC()->cart->get_cart_contents_count( );
foreach ( WC()->cart->get_cart() as $cart_item ) {
if ( isset( $cart_item['free_gift'] ) ) {
$cart_items_count -= $cart_item['quantity'];
}
}
if( $cart_items_count > $max_items_count ) {
// Display our error message
wc_add_notice( sprintf( '<strong>A Maximum of %s snacks are allowed per order.</strong>'
. '<br />Current number of snacks: %s.',
$max_items_count,
$cart_items_count ),
'error' );
}
}
}
Code goes in function.php file of your active child theme (or active theme). It should works.
First check if the free item is in the cart. When it is you count the items "-1" in your function before the checkout is accessable.
function free_product_in_cart($free_product_id) {
$free_product_cart_id = WC()->cart->generate_cart_id( $free_product_id );
return WC()->cart->find_product_in_cart( $free_product_cart_id ); //Return true when the free product is in the cart
}
So then you update your logic to check:
if(free_product_in_cart(your product id) {
$free_item_space = 1;
} else {
$free_item_space = 0;
}
if( $cart_num_products > $maximum_num_products + $free_item_space) {
// Display our error message
wc_add_notice( sprintf( '<strong>A Maximum of %s snacks are allowed per order.</strong>'
. '<br />Current number of snacks: %s.',
$maximum_num_products,
$cart_num_products ),
'error' );
}
Related
I have some cart logic which checks for a minimum of 3 items if 1 item from the chilled category is in the cart. - This is tested and working.
However, if I add another item to the cart from a different category (ambient), and there are now both chilled and ambient items in the cart, the rule is no longer applied.
How can I make sure the 3 chilled minimum rule is applied if an ambient item is also in the cart?
// Set minimum quantity per product before checking out
add_action( 'woocommerce_check_cart_items', 'protein_set_min_total' );
function protein_set_min_total() {
// Only run in the Cart or Checkout pages
if( is_cart() || is_checkout() ) {
global $woocommerce, $product;
$i=0;
// Set minimum product cart total
//And initialise product catergory counters
$minimum_protein = 3;
$total_protein = 0;
$cat_in_cart = false;
foreach ( $woocommerce->cart->cart_contents as $product ) :
if ( has_term( 'chilled', 'product_cat', $product['product_id'] ) ) {
$total_protein += $product['quantity'];
}
endforeach;
if (has_term( 'chilled', 'product_cat', $product['product_id'] ) && $total_protein < $minimum_protein) {
wc_add_notice( sprintf( '<strong>A Minimum of %s products are required from The CHILLED category before checking out.</strong>'
. '<br />Current number of Chilled items in the cart: %s.',
$minimum_protein,
$total_protein ),
'error' );
}
//}
}
}
The code below will count all items belonging to the chilled category. Only if this is equal to 3 or more, will it be possible to continue the order process.
So you get:
function action_woocommerce_check_cart_items() {
// Only run on the cart or checkout pages
if ( is_cart() || is_checkout() ) {
// Minimum
$minimum = 3;
// Category
$category = 'chilled';
// Initialize
$total = 0;
// Loop through cart items
foreach ( WC()->cart->get_cart() as $cart_item_key => $cart_item ) {
// Product id
$product_id = $cart_item['product_id'];
// Has certain category
if ( has_term( $category, 'product_cat', $product_id ) ) {
// Add to total
$total += $cart_item['quantity'];
}
}
// When total is greater than 0 but less than the minimum
if ( $total > 0 && $total < $minimum ) {
// Notice
wc_add_notice( sprintf( __( 'A minimum of %s products are required from the %s category before checking out.', 'woocommerce' ), $minimum, $category ), 'error' );
// Optional: remove proceed to checkout button
remove_action( 'woocommerce_proceed_to_checkout', 'woocommerce_button_proceed_to_checkout', 20 );
}
}
}
add_action( 'woocommerce_check_cart_items' , 'action_woocommerce_check_cart_items', 10, 0 );
I currently have a wordpress site with a minimum order value set for my WooCommerce store, set up in my functions.php and it works perfectly. I now want to set one product tag as an exception to this rule, and have no minimum order value for this... is this possible?
I am actually using Set a minimum order amount in WooCommerce answer code.
Not sure whether changing to a plug-in such as ‘wc minimum order amount’ is the answer or can this be added in the existing code?
Any advice greatly appreciated!
To make this code non active for specific product tags, use the following:
add_action( 'woocommerce_check_cart_items', 'required_min_cart_subtotal_amount' );
function required_min_cart_subtotal_amount() {
$minimum_amount = 35; // HERE Set minimum cart total amount
$product_tags = array('Lewis'); // HERE set the product tags (term names, slugs or Ids)
$cart_subtotal = WC()->cart->subtotal; // Total (before taxes and shipping charges)
$tag_found = false;
// Loop through cart items
foreach ( WC()->cart->get_cart() as $cart_item ) {
// Check for product tag
if( has_term( $product_tags, 'product_tag', $cart_item['product_id'] ) ) {
$tag_found = true;
break;
}
}
// Add an error notice is cart total is less than the minimum required
if( $cart_subtotal < $minimum_amount && ! $tag_found ) {
// Display an error message
wc_add_notice( '<strong>' . sprintf( __("A minimum total purchase amount of %s is required to checkout."), wc_price($minimum_amount) ) . '<strong>', 'error' );
}
}
Or if you want to exclude specific product tags from cart subtotal use instead:
add_action( 'woocommerce_check_cart_items', 'required_min_cart_subtotal_amount' );
function required_min_cart_subtotal_amount() {
$minimum_amount = 35; // HERE Set minimum cart total amount
$product_tags = array('Disc'); // HERE set the product tags (term names, slugs or Ids)
$cart_subtotal = 0; // Total (before taxes and shipping charges)
// Loop through cart items
foreach ( WC()->cart->get_cart() as $cart_item ) {
// Check for product tag
if( ! has_term( $product_tags, 'product_tag', $cart_item['product_id'] ) ) {
$cart_subtotal += $cart_item['line_subtotal'] + $cart_item['line_subtotal_tax'];
}
}
// Add an error notice is cart total is less than the minimum required
if( $cart_subtotal < $minimum_amount ) {
// Display an error message
wc_add_notice( '<strong>' . sprintf( __("A minimum total purchase amount of %s is required to checkout."), wc_price($minimum_amount) ) . '<strong>', 'error' );
}
}
Code goes in functions.php file of the active child theme (or active theme). Tested and works.
I have a minimum order amount of 4 items OR 8 items. e.g. So 1,2,3,5,6,7 items are invalid quantity.
I am trying to EXCLUDE products which are from category: christmas from this rule.
e.g. So customer is able to purchase 1 item from christmas category, but must buy a minimum of 4 OR 8 items from all other categories.
Below Code works on its own to check to see if the items in the cart are from Christmas category:
add_action('woocommerce_before_cart', 'bbloomer_check_category_in_cart');
function bbloomer_check_category_in_cart() {
// Set $cat_in_cart to false
$cat_in_cart = false;
// Loop through all products in the Cart
foreach ( WC()->cart->get_cart() as $cart_item_key => $cart_item ) {
// If Cart has category "christmas", set $cat_in_cart to true
if ( has_term( 'christmas', 'product_cat', $cart_item['product_id'] ) ) {
$cat_in_cart = true;
break;
}
}
Second part of my code does not work based on the above conditional. It does however work on its own.
// If no christmas category in cart, run minimum order code:
if ( !$cat_in_cart ) {
add_action( 'woocommerce_check_cart_items', 'spyr_set_min_num_products' );
function spyr_set_min_num_products() {
// Only run in the Cart or Checkout pages
if( is_cart() || is_checkout() ) {
global $woocommerce;
// Set the minimum number of products before checking out
$minimum_num_products = 8;
$minimum_taster_products = 4;
// Get the Cart's total number of products
$cart_num_products = WC()->cart->cart_contents_count;
// Compare values and add an error is Cart's total number of products
// happens to be less than the minimum required before checking out.
// A Minimum of 4 OR 8 products is required before checking out. (Cont. below)
if( ($cart_num_products < $minimum_num_products) && ($cart_num_products > $minimum_taster_products) ) {
// Display our error message
wc_add_notice( sprintf( '<strong>Our Smallest Plan requires at least %s snacks per order.</strong>'
. '<br />Current number of snacks: %s.',
$minimum_num_products,
$cart_num_products ),
'error' );
} else if ($cart_num_products < $minimum_taster_products) {
// Display our error message
wc_add_notice( sprintf( '<strong>A Minimum of %s snacks is required for a TASTER BOX.</strong>'
. '<br />Current number of snacks: %s.',
$minimum_taster_products,
$cart_num_products ),
'error' );
}
}
}
}
}
Solved myself. Instead of two separate functions, needed to move into a single function and check for categories using woocommerce_check_cart_items
add_action( 'woocommerce_check_cart_items', 'spyr_set_min_num_products' );
function spyr_set_min_num_products() {
// Set $cat_in_cart to false
$cat_in_cart = false;
// Loop through all products in the Cart
foreach ( WC()->cart->get_cart() as $cart_item_key => $cart_item ) {
// If Cart has category "download", set $cat_in_cart to true
if ( has_term( 'christmas', 'product_cat', $cart_item['product_id'] ) ) {
$cat_in_cart = true;
break;
}
}
// Only run in the Cart or Checkout pages
if( is_cart() || is_checkout() ) {
global $woocommerce;
// Set the minimum number of products before checking out
$minimum_num_products = 8;
$minimum_taster_products = 4;
// Get the Cart's total number of products
$cart_num_products = WC()->cart->cart_contents_count;
// Compare values and add an error is Cart's total number of products
// happens to be less than the minimum required before checking out.
// A Minimum of 4 OR 8 products is required before checking out. (Cont. below)
if( ( !$cat_in_cart ) && ($cart_num_products < $minimum_num_products) && ($cart_num_products > $minimum_taster_products) ) {
// Display our error message
wc_add_notice( sprintf( '<strong>Our Smallest Plan requires at least %s snacks per order.</strong>'
. '<br />Current number of snacks: %s.',
$minimum_num_products,
$cart_num_products ),
'error' );
} else if ( ( !$cat_in_cart ) && ($cart_num_products < $minimum_taster_products) ) {
// Display our error message
wc_add_notice( sprintf( '<strong>A Minimum of %s snacks is required for a TASTER BOX.</strong>'
. '<br />Current number of snacks: %s.',
$minimum_taster_products,
$cart_num_products ),
'error' );
}
}
}
I've searched extensively to see if other folks had this situation and received an answer with no luck.
Essentially, I have two items customers can add to their cart. I want to make it so they cannot checkout with either of those items if their subtotal is not $15 or more.
Having the ability to just drop their IDs into the code would be fine. Or, I can assign them to the same category and set this minimum by category.
So far all I have is the basic PHP that sets a universal minimum. I just need some help figuring out how to limit this to meet my needs.
I'm a designer not a dev, so any help is much appreciated.
// 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 = 10;
// 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>A Minimum of %s %s is required before checking out.</strong>'
.'<br />Current cart\'s total: %s %s',
$minimum_cart_total,
get_option( 'woocommerce_currency'),
$total,
get_option( 'woocommerce_currency') ),
'error' );
}
}
}
2020 Update
Setting minimum value for some products categories or products ID's in cart for Cart and Checkout pages only.
This untested snippet made of this and this from wooThemes, and this too:
add_action( 'woocommerce_checkout_process', 'wc_minimum_order_amount' );
add_action( 'woocommerce_before_cart' , 'wc_minimum_order_amount' );
function wc_minimum_order_amount() {
## SETTINGS ##
$minimum_amount = 50; // Define a minimum order amount
$category_ids = array( 17, 18 ); // Define your category ids in the array (or an empty array to disable)
$product_ids = array( 64, 67, 78 ); // Define your product ids in the array (or an empty array to disable)
// Only on cart or checkout pages
if( WC()->cart->is_empty() || ! ( is_cart() || is_checkout() ) )
return; // Exit
$total_amount = WC()->cart->subtotal; // Items subtotal including taxes
if ( $total_amount < $minimum_amount ) {
$needs_minimum_amount = false; // Initializing
// Loop through cart items
foreach ( WC()->cart->get_cart() as $cart_item ) {
$product_id = $cart_item['product_id'];
$variation_id = $cart_item['variation_id'];
// 1. 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
}
}
// 2. Check for matching product Ids
if( sizeof($product_ids) > 0 ) {
if ( array_intersect( $product_ids, array($product_id, $variation_id) ) ) {
$needs_minimum_amount = true;
break; // Stop the loop
}
}
}
if( $needs_minimum_amount ) {
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_amount ),
wc_price( $total_amount )
), 'error' );
}
}
}
Code goes in functions.php file of your active child theme (active theme). Tested and works.
You can set your categories ID's, your products ID's and the minimum order value amount.
— — … I m p o r t a n t … N o t e … — —
This hooks are working for messages. But to avoid users from clicking you need to add Javascript/jQuery and maybe with ajax too (client side detection).
I have a snipped below that restricts woocommerce orders to 5 items. When they try go through checkout with more than 5 items it pops up a message telling them that and they then have to remove items. What I am wondering is if there is a way so that they can't add more than 5 items to the basket?
add_action( 'woocommerce_check_cart_items', 'set_max_num_products' );
function set_max_num_products() {
// Only run in the Cart or Checkout pages
if( is_cart() || is_checkout() ) {
global $woocommerce;
// Set the max number of products before checking out
$max_num_products = 5;
// Get the Cart's total number of products
$cart_num_products = WC()->cart->cart_contents_count;
// A max of 5 products is required before checking out.
if( $cart_num_products > $max_num_products ) {
// Display our error message
wc_add_notice( sprintf( '<strong>A maxiumum of %s samples are allowed per order. Your cart currently contains %s.</strong>',
$max_num_products,
$cart_num_products ),
'error' );
}
}
}
Every product must be validated before it can be added to the cart. You can modify the validation status via the woocommerce_add_to_cart_validation filter and thus control whether it is or is not added to the cart.
function so_33134668_product_validation( $valid, $product_id, $quantity ){
// Set the max number of products before checking out
$max_num_products = 5;
// Get the Cart's total number of products
$cart_num_products = WC()->cart->cart_contents_count;
$future_quantity_in_cart = $cart_num_products + $quantity;
// More than 5 products in the cart is not allowed
if( $future_quantity_in_cart > $max_num_products ) {
// Display our error message
wc_add_notice( sprintf( '<strong>A maxiumum of %s samples are allowed per order. Your cart currently contains %s.</strong>',
$max_num_products,
$cart_num_products ),
'error' );
$valid = false; // don't add the new product to the cart
}
return $valid;
}
add_filter( 'woocommerce_add_to_cart_validation', 'so_33134668_product_validation', 10, 3 );