I searched in the different messages but I can't find exactly what I am looking for ... Could you help me?
I found this code which almost matches what I need.
It prevents the addition of new products if a product is already present in the cart.
I would also like to add the additional condition which is that if I have products in my cart, it is not possible to add the product. And show an alert message.
// Add custom Theme Functions here
// Custom conditional function that checks for parent product categories
function has_parent_term( $product_id ) {
// HERE set your targeted product category SLUG
$category_slug = 'box-dejeuner'; // <==== <==== <==== <==== <==== <==== <====
// Convert category term slug to term id
$category_id = get_term_by('slug', $category_slug, 'product_cat')->term_id;
$parent_term_ids = array(); // Initializing
// Loop through the current product category terms to get only parent main category term
foreach( get_the_terms( $product_id, 'product_cat' ) as $term ){
if( $term->parent > 0 ){
$parent_term_ids[] = $term->parent; // Set the parent product category
} else {
$parent_term_ids[] = $term->term_id;
}
}
return in_array( $category_id, $parent_term_ids );
}
// Avoid add to cart others product categories when "box-dejeuner" is in cart
add_filter( 'woocommerce_add_to_cart_validation', 'specific_category_avoid_add_to_cart_others', 20, 3 );
function specific_category_avoid_add_to_cart_others( $passed, $product_id, $quantity) {
if( WC()->cart->is_empty() || has_parent_term( $product_id ) ) {
return $passed;
}
foreach( WC()->cart->get_cart() as $cart_item ){
if( has_parent_term( $cart_item['product_id'] ) ) {
wc_add_notice( __('Si une box déjeuner est présente dans votre panier, vous ne pouvez pas commander un autre produit. Veuillez finaliser votre commande de la box et repasser une nouvelles commandes pour vos autres produits. ', 'woocommerce' ), 'error' ); // Display a custom error notice
return false; // Avoid add to cart
}
}
return $passed;
}
Related
I'm looking for a way to check out my shopping cart, so that I don't allow customers to pick up both purchase and rental items at the same time (basically forcing them to make two orders of each type). To do this I have created two categories of items (rental and purchase).
When someone tries to add an item from a category other than the one already chosen, a message appears saying that they cannot choose that item.
But... I can't get it to work properly. Either the item doesn't show the message, or it gets added to the cart anyway. We can't even increment items of the same kind already in the cart...
I pass you my code:
* Check products in the cart (don't allow rent products to be with buy products)
* #author Nicolas BOUTINAUD
* #return WooCommerce Cart Validation
*/
function checkProductsInCart() {
// If the cart is empty, it's valid.
if(WC()->cart->cart_contents_count == 0){
return true;
}
$productsNotMixed = false;
$rentInCart = false;
$buyInCart = false;
while ($productsNotMixed != true)
{
// Loop through all products in the cart
foreach (WC()->cart->get_cart() as $cart_item_key => $cart_item)
{
$product = $cart_item['data'];
// If Cart has category "Location", set $rentInCart to true
if ( has_term( 'location', 'product_cat', $product->get_id() ) )
{
$rentInCart = true;
if ( has_term( $term != 'Location', 'product_cat', $product->get_id() ) )
{
$buyInCart = true;
$productsNotMixed = true;
wc_add_notice( 'Les produits à l\'achat ne peuvent pas être commandés en même temps que les produits proposés à la location.', 'error' );
return false;
break;
}
else
{
$productsNotMixed = true;
return $valid;
}
}
else
{
$productsNotMixed = true;
return $valid;
}
}
}
}
add_filter( 'woocommerce_add_to_cart_validation', 'checkProductsInCart',10,3);´´´
I try to set a purchase limit before check out, namely:
A minimum weight requirement for the category 'formaggi'
The shop has 8 categories of products, however, the intention is to only check on 1 category.
I'm using this snippet but it doesn't work with the category,
neither for the minimum weight requirement.
/*PESO MINIMO CATEGORIA FORMAGGI 750GR - RAFFO 14mar2020*/
add_action( 'woocommerce_check_cart_items', 'cldws_set_weight_requirements' );
function cldws_set_weight_requirements() {
// Only run in the Cart or Checkout pages
if( is_cart() || is_checkout() || is_product () && has_term( ‘formaggi’, ‘product_cart’ )) {
global $woocommerce;
// Set the minimum weight before checking out
$minimum_weight = 0.750;
// Get the Cart's content total weight per categoria
$cart_contents_weight = WC()->cart->cart_contents_weight;
// Compare values and add an error is Cart's total weight
if( $cart_contents_weight < $minimum_weight ) {
// Display our error message
wc_add_notice( sprintf('<strong>Per i Formaggi è richiesto un acquisto minimo di %s gr.</strong>'
. '<br />Peso dei Formaggi nel carrello: %s gr',
$minimum_weight*1000,
$cart_contents_weight*1000,
get_option( 'woocommerce_weight_unit' ),
get_permalink( wc_get_page_id( 'shop' ) )
), 'error' );
}
}
}
Someone who knows what I am doing wrong or where it is going wrong?
There are some mistakes in your code.
The following code checks for A minimum weight requirement for the category 'formaggi', comment with explanation added between the code lines
function cldws_set_weight_requirements() {
// Only on cart and check out pages
if( ! ( is_cart() || is_checkout() ) ) return;
/* SETTINGS */
// The minimum weight
$minimum_weight = 20; // 20 kg
// Set term (category)
$term = 'formaggi';
/* END SETTINGS */
// Set variable
$found = false;
// Total weight
$total_weight = 0;
// Loop through cart items
foreach ( WC()->cart->get_cart() as $cart_item_key => $cart_item ) {
// Product id
$product_id = $cart_item['product_id'];
// Quantity
$product_quantity = $cart_item['quantity'];
// Get weight
$product_weight = $cart_item['data']->get_weight();
// NOT empty & has certain category
if ( ! empty( $product_weight ) && has_term( $term, 'product_cat', $product_id ) ) {
// The shopping cart contains a product of the specific category
$found = true;
// Calculate
$total_weight += $product_quantity * $product_weight;
}
}
// If the total weight is less than the minimum and there is a item in the cart from a specific category
if( $total_weight < $minimum_weight && $found ) {
// Displays a dynamic error warning
wc_add_notice( sprintf(
'The minimum weight for the "%s" category is %s, you currently have %s',
$term,
wc_format_weight($minimum_weight),
wc_format_weight($total_weight)
), 'error' );
// Removing the proceed button, until the condition is met
remove_action( 'woocommerce_proceed_to_checkout','woocommerce_button_proceed_to_checkout', 20);
}
}
add_action( 'woocommerce_check_cart_items', 'cldws_set_weight_requirements' );
In WooCommerce, I need to set up a minimum quantity for each item of a product category. I searched the forum and found some code that works fine except it only counts the Quantity for a product category in total:
add_action( 'woocommerce_checkout_process', 'wc_minimum_order_amount' );
add_action( 'woocommerce_before_cart' , 'wc_minimum_order_amount' );
function wc_minimum_order_amount() {
$minimum = 5; //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("Noten", $draught_links)){
$on_draught = true;
}else{
$on_draught = false;
}
if( is_cart() ) {
if($on_draught){
wc_print_notice(
sprintf( 'Bitte beachte die Mindestbestellmenge. Du brauchst mindestens %s Notenexemplare pro Arrangement. Aktuell hast du %s Stück in deinem Warenkorb.' ,
$minimum ,
WC()->cart->cart_contents_count
), 'error'
);
}
} else {
if($on_draught){
wc_add_notice(
sprintf( 'Bitte beachte die Mindestbestellmenge. Du brauchst mindestens %s Notenexemplare pro Arrangement. Aktuell hast du %s Stück in deinem Warenkorb.' ,
$minimum ,
WC()->cart->cart_contents_count
), 'error'
);
}
}
}
}
For example if I have two products (A and B) of belonging to the same product category and set up minimum quantity for this category to 5, the error message for the customer won't appear in this case:
Product A: 3
Product B: 2
I need a min quantity of 5 for every single product of that category.
Do you have an idea how to change and optimize the following code?
Since WooCommerce 3, your actual code is outdated and not convenient… There is multiple ways:
1). The best way: Set up the minimum quantity at product level (for a product category):
// On single product pages
add_filter( 'woocommerce_quantity_input_args', 'min_qty_filter_callback', 20, 2 );
function min_qty_filter_callback( $args, $product ) {
$categories = array('Noten'); // The targeted product category(ies)
$min_qty = 5; // The minimum product quantity
$product_id = $product->is_type('variation') ? $product->get_parent_id() : $product->get_id();
if( has_term( $categories, 'product_cat', $product_id ) ){
$args['min_value'] = $min_qty;
}
return $args;
}
// On shop and archives pages
add_filter( 'woocommerce_loop_add_to_cart_args', 'min_qty_loop_add_to_cart_args', 10, 2 );
function min_qty_loop_add_to_cart_args( $args, $product ) {
$categories = array('Noten'); // The targeted product category
$min_qty = 5; // The minimum product quantity
$product_id = $product->get_id();
if( has_term( $categories, 'product_cat', $product_id ) ){
$args['quantity'] = $min_qty;
}
return $args;
}
Code goes in functions.php file of your active child theme (or active theme). Tested and work.
2). Alternative way: Checking cart items and displaying an error message (similar to your code):
add_action( 'woocommerce_check_cart_items', 'wc_min_item_required_qty' );
function wc_min_item_required_qty() {
$categories = array('Noten'); // The targeted product category
$min_item_qty = 5; // Minimum Qty required (for each item)
$display_error = false; // Initializing
// Loop through cart items
foreach(WC()->cart->get_cart() as $cart_item ) {
$item_quantity = $cart_item['quantity']; // Cart item quantity
$product_id = $cart_item['product_id']; // The product ID
// For cart items remaining to "Noten" producct category
if( has_term( $categories, 'product_cat', $product_id ) && $item_quantity < $min_item_qty ) {
wc_clear_notices(); // Clear all other notices
// Add an error notice (and avoid checkout).
wc_add_notice( sprintf( 'Bitte beachte die Mindestbestellmenge. Du brauchst mindestens %s Notenexemplare pro Arrangement. Aktuell hast du %s Stück in deinem Warenkorb.', $min_item_qty , $item_quantity ), 'error' );
break; // Stop the loop
}
}
}
Code goes in functions.php file of your active child theme (or active theme). Tested and work.
To make it work for parent product category too, you will also add this custom function:
// Custom conditional function that handle parent product categories too
function has_product_categories( $categories, $product_id = 0 ) {
$parent_term_ids = $categories_ids = array(); // Initializing
$taxonomy = 'product_cat';
$product_id = $product_id == 0 ? get_the_id() : $product_id;
if( is_string( $categories ) ) {
$categories = (array) $categories; // Convert string to array
}
// Convert categories term names and slugs to categories term ids
foreach ( $categories as $category ){
$result = (array) term_exists( $category, $taxonomy );
if ( ! empty( $result ) ) {
$categories_ids[] = reset($result);
}
}
// Loop through the current product category terms to get only parent main category term
foreach( get_the_terms( $product_id, $taxonomy ) as $term ){
if( $term->parent > 0 ){
$parent_term_ids[] = $term->parent; // Set the parent product category
$parent_term_ids[] = $term->term_id; // (and the child)
} else {
$parent_term_ids[] = $term->term_id; // It is the Main category term and we set it.
}
}
return array_intersect( $categories_ids, array_unique($parent_term_ids) ) ? true : false;
}
Code goes in functions.php file of your active child theme (or active theme). Tested and work.
Then in the existing code, you will replace:
has_term( $category, 'product_cat', $product_id )
by
has_product_categories( $category, $product_id )
That will allow you to handle parent product categories too.
To make it work for a certain product category item counts in total use this code instead:
add_action( 'woocommerce_check_cart_items', 'wc_min_item_required_qty' );
function wc_min_item_required_qty() {
$categories = '30'; // The targeted product category slug or ID
$max_item_qty = 10; // Minimum Qty required (for each item)
$display_error = false; // Initializing
// Loop through cart items
foreach(WC()->cart->get_cart() as $cart_item ) {
$product_id = $cart_item['product_id']; // The product ID
if( has_term( $categories, 'product_cat', $product_id )) {
$item_quantity += $cart_item['quantity']; // Cart item quantity
}
// For cart items remaining to "Pizza" product category
if( has_term( $categories, 'product_cat', $product_id ) && $item_quantity > $max_item_qty ) {
wc_clear_notices(); // Clear all other notices
// Add an error notice (and avoid checkout).
wc_add_notice( sprintf( 'We can only take orders of up to 10 burgers per customer', $max_item_qty , $item_quantity ), 'error' );
break; // Stop the loop
}
}
}
In Woocommerce, I found a bit of code that restricts a users purchase to one per category for category a or b. So currently the user could purchase 2 items 1 from cat a and 1 from cat b. I would like to limit the user to only one product from category a or b. The code I am working with is below, thanks in advance.
add_filter( 'woocommerce_add_to_cart_validation', 'allowed_quantity_per_category_in_the_cart', 10, 2 );function allowed_quantity_per_category_in_the_cart( $passed, $product_id) {
$max_num_products = 1;// change the maximum allowed in the cart
$running_qty = 0;
$restricted_product_cats = array();
//Restrict particular category/categories by category slug
$restricted_product_cats[] = 'cat-a, cat-b';
// Getting the current product category slugs in an array
$product_cats_object = get_the_terms( $product_id, 'product_cat' );
foreach($product_cats_object as $obj_prod_cat) $current_product_cats[]=$obj_prod_cat->slug;
// Iterating through each cart item
foreach (WC()->cart->get_cart() as $cart_item_key=>$cart_item ){
// Restrict $max_num_products from each category
if( has_term( $current_product_cats, 'product_cat', $cart_item['product_id'] )) {
// Restrict $max_num_products from restricted product categories
//if( array_intersect($restricted_product_cats, $current_product_cats) && has_term( $restricted_product_cats, 'product_cat', $cart_item['product_id'] )) {
// count(selected category) quantity
$running_qty += (int) $cart_item['quantity'];
// More than allowed products in the cart is not allowed
if( $running_qty >= $max_num_products ) {
wc_add_notice( sprintf( 'Only %s '.($max_num_products>1?'products from this category are':'product from this category is').' allowed in the cart.', $max_num_products ), 'error' );
$passed = false; // don't add the new product to the cart
// We stop the loop
break;
}
}
}
return $passed;}
Try this (but it doesn't handle quantities as is not clear and much more complicated, because in cart page they can be altered):
add_filter( 'woocommerce_add_to_cart_validation', 'limit_cart_items_from_category', 10, 3 );
function limit_cart_items_from_category ( $passed, $product_id, $quantity )
{
// Accept when cart is empty
if( WC()->cart->is_empty() ) return $passed;
// HERE your product categories in this array (can be names, slugs or Ids)
$categories = array('T-shirts', 'Hoodies');
$found = $current = false;
// Check the current product
if( has_term( $categories, 'product_cat', $product_id ) ){
$current = true;
}
// Loop through cart items checking for product categories
foreach ( WC()->cart->get_cart() as $cart_item ){
if( has_term( $categories, 'product_cat', $cart_item['product_id'] ) ) {
$found = true;
break; // stop the loop.
}
}
// Current product and a cart item match with defined product categories
if( $found && $current ){
$passed = false;
$cats_str = implode('" and "', $categories );
wc_add_notice( sprintf( __('Only one item is allowed from "%s" categories…', 'woocommerce' ), $cats_str ), 'error' );
}
return $passed;
}
Code goes in function.php file of your active child theme (or active theme). Tested and work.
Thank You For your Code I modified this code and make my customized code. when customer add to cart the product from defined category, after that they didnt allow to cart other category product.
you can set the maximum number of product easily by just changing the number.
Thank You once again.
add_filter( 'woocommerce_add_to_cart_validation', 'limit_cart_items_from_category', 10, 3 );
function limit_cart_items_from_category ( $passed, $product_id, $quantity )
{
// change the number for maximum product allowed in the cart
$max_num_products = 5; // Here change the number for maximum allowed product in the cart
// Accept when cart is empty
if( WC()->cart->is_empty() ) return $passed;
// HERE your product categories in this array (can be names, slugs or Ids)
$categories = array('Sea-Food-Chaasum');
$found = $current = false;
// Check the current product
if( has_term( $categories, 'product_cat', $product_id ) ){
$current = true;
}
// Loop through cart items checking for product categories
foreach ( WC()->cart->get_cart() as $cart_item ){
if( has_term( $categories, 'product_cat', $cart_item['product_id'] ) ) {
$found = true;
$current = true;
break; // stop the loop.
}
}
// count(selected category) quantity
$running_qty += (int) $cart_item['quantity'];
// More than allowed products in the cart is not allowed
if( $running_qty >= $max_num_products )
// Current product and a cart item match with defined product categories
if( $found && $current ){
$passed = false;
$cats_str = implode('" and "', $categories );
wc_add_notice( sprintf( __('Only one item is allowed from "%s" categories…', 'woocommerce' ), $cats_str ), 'error' );
}
return $passed;
}
I have to check if one of my two mandatory products categories is in cart.
I have customized the code from this answer: Allow checkout only when a product of a mandatory category is in cart
But with my custom code, it always checks for only one of them and I get some errors. My code is not working.
How can I make it work for 2 product categories instead of one?
Here is the code:
// Function that define the mandatory product category
function your_mandatory_category_slug(){
// DEFINE HERE the SLUG of the needed product category
$category = 'cxsuite-download-option';
return $category;
}
function your_mandatory_category_slug_h(){
// DEFINE HERE the SLUG of the needed product category
$category_h = 'cxsuite-hosted-option';
return $category_h;
}
// Conditional function that returns true if the mandatory product category is in cart
function has_mandatory_category(){
$category_needed = your_mandatory_category_slug();
$category_needed_h = your_mandatory_category_slug_h();
$has_cat = false;
// Iterrating each item in cart and detecting…
foreach ( WC()->cart->get_cart() as $item ) {
// Detects if the needed product category is in cart items
if ( has_term($category_needed, 'product_cat', $item['product_id'] ) ) {
$has_cat = true;
break;
}
elseif ( has_term($category_needed_h, 'product_cat', $item['product_id'] ) ) {
$has_cat = true;
break;
}
}
return $has_cat;
}
// Function that display a message if there is not in cart a mandatory product category
function mandatory_category_display_message() {
$category_needed = your_mandatory_category_slug();
$category_needed_h = your_mandatory_category_slug_h();
// check that cart is not empty (for cart and product category archives)
if( !WC()->cart->is_empty() && ( is_cart() || is_product_category( $category_needed ) || is_product_category( $category_needed_h ) ) ){
$category_needed_single=null;
if( $category_needed=='cxsuite-download-option' ){
$category_needed_single='cxsuite-download-option';
}{
$category_needed_single=$category_needed_h;
}
$category_obj = get_term_by( 'slug', $category_needed_single, 'product_cat' );
if ( is_wp_error( $category_obj ) ) return;
// Display message when product category is not in cart items
if ( !has_mandatory_category() ) {
$category_name = $category_obj->name;
$category_url = get_term_link( $category_needed_single, 'product_cat' );
// render a notice to explain why checkout is blocked
wc_add_notice( sprintf( __( '<strong>Reminder:</strong> You have chosen Addon that can only be purchased together with a %1$s. Please add a %1$s (full or trial) before checking out. Please return here to "%1$s" product page', 'your_theme_domain'), $category_name, $category_url ), 'error' );
}
}
}
add_action( 'woocommerce_before_main_content', 'mandatory_category_display_message', 30 ); // for product mandatory category archives pages
add_action( 'woocommerce_check_cart_items', 'mandatory_category_display_message' ); // for cat page
// Function that redirect from checkout to mandatory product category archives pages
function mandatory_category_checkout_redirect() {
// If cart is not empty on checkout page
if( !WC()->cart->is_empty() && is_checkout() ){
$category_needed = your_mandatory_category_slug();
$category_needed_h = your_mandatory_category_slug_h();
$category_needed_single=null;
if(is_product_category( $category_needed )){
$category_needed_single=$category_needed;
}else{
$category_needed_single=$category_needed_h;
}
// If missing product category => redirect to the products category page
if ( !has_mandatory_category() )
wp_redirect( get_term_link( $category_needed_single, 'product_cat' ) );
}
}
add_action('template_redirect', 'mandatory_category_checkout_redirect');
Updated (on April 2018)
You can only use partially the code you have picked up from my answer, for 2 or more categories, using an array of product categories this way:
// Function that define the mandatory product category
function your_mandatory_category_slug(){
// DEFINE HERE the 2 SLUGs of the needed product categories
$categories = array('cxsuite-download-option','cxsuite-hosted-option');
return $categories;
}
// Conditional function that returns true if the mandatory products categories are in cart
function has_mandatory_category(){
$categories_needed = your_mandatory_category_slug();
$has_cat = false;
// Iterrating each item in cart and detecting…
foreach ( WC()->cart->get_cart() as $item ) {
// iterating both categories
foreach ( $categories_needed as $category_needed ) {
// Detects if one of the needed product categories is in cart items
if ( has_term($category_needed, 'product_cat', $item['product_id'] ) )
$has_cat = true;
}
if($has_cat)
break;
}
return $has_cat;
}
// Function that display a message if there is not in cart a mandatory product category
function mandatory_category_display_message() {
$categories_needed = your_mandatory_category_slug();
// check that cart is not empty (for cart and product category archives)
if( !WC()->cart->is_empty() && ( is_cart() || is_product_category( $categories_needed[0] ) || is_product_category( $categories_needed[1] ) ) ){
$category_name = array();
$category_url = array();
// iterating both categories
foreach($categories_needed as $key => $category_needed){
$category_obj = get_term_by( 'slug', $category_needed, 'product_cat' );
if ( is_wp_error( $category_obj ) )
return;
$category_name[$key] = $category_obj->name;
$category_url[$key] = get_term_link( $category_needed, 'product_cat' );
}
// Display message when one of the product categories is not in cart items
if ( !has_mandatory_category() ) {
// render a notice to explain why checkout is blocked
wc_add_notice( sprintf( __( '<strong>Reminder:</strong> You have to add in your cart, a product from "%1$s" or from "%3$s" category, to be allowed to check out. Please return here to "%1$s" or here to "%3$s" product pages', 'your_theme_domain'), $category_name[0], $category_url[0], $category_name[1], $category_url[1] ), 'error' );
}
}
}
add_action( 'woocommerce_before_main_content', 'mandatory_category_display_message', 30 ); // for product mandatory category archives pages
add_action( 'woocommerce_check_cart_items', 'mandatory_category_display_message' ); // for cart page
But you will have to choose for the last function, between one of the 2 product categories for the redirection…
// Function that redirect from checkout to mandatory product category archives pages
function mandatory_category_checkout_redirect() {
// If cart is not empty on checkout page
if( !WC()->cart->is_empty() && is_checkout() ){
$categories_needed = your_mandatory_category_slug();
// If missing product category => redirect to the products category page
if ( !has_mandatory_category() )
wp_redirect( get_term_link( $categories_needed[0], 'product_cat' ) ); // or $categories_needed[1]
}
}
add_action('template_redirect', 'mandatory_category_checkout_redirect');
This goes in function.php file of your active child theme (or theme) or also in any plugin file.
This code is based on this functional answer:
Allow checkout only when a product of a mandatory category is in cart
It is untested, but it should work…