Based on Allow checkout only when a product of a mandatory category is in cart I tried to make my own code sample that Renders a notice and prevents checkout if the cart only contains products in specific categories. It works on prevention and error notice however on adding other products, it still denies checkout.
/**
* Renders a notice and prevents checkout if the cart
* only contains products in a specific category
*/
//add_action( 'woocommerce_check_cart_items', 'brown_wc_prevent_checkout_for_category' );
function brown_wc_prevent_checkout_for_category() {
// set the slug of the category for which we disallow checkout
$categories = array('drinks','extra-accompaniments');
foreach ($categories as $category => $value) {
// get the product category
$product_cat = get_term_by( 'slug', $category, 'product_cat' );
// sanity check to prevent fatals if the term doesn't exist
if ( is_wp_error( $product_cat ) ) {
return;
}
// check if this category is the only thing in the cart
if ( brown_wc_is_category_alone_in_cart( $category ) ) {
// render a notice to explain why checkout is blocked
wc_add_notice( sprintf( 'Please choose atleast one bento.', $category ), 'error' );
}
}
}
/**
* Checks if a cart contains exclusively products in a given category
*
* @param string $category the slug of the product category
* @return bool - true if the cart only contains the given category
*/
function brown_wc_is_category_alone_in_cart( $category ) {
//When the cart is empty, remove warning message that I have set for when the snippet takes effect
if (!WC()->cart->is_empty()) {
// All the code
// check each cart item for our category
foreach ( WC()->cart->get_cart() as $cart_item_key => $cart_item ) {
// if a product is not in our category, bail out since we know the category is not alone
if ( ! has_term( $category, 'product_cat', $cart_item['data']->id ) ) {
return false;
}
}
// if we're here, all items in the cart are in our category
return true;
} else {
return false; // Assume you'd want false here, since the cart is empty
}
}
There is some mistakes in your code that avoid it to work successfully. Your code and requirements are quiet different, than my previous answer.
You will have to set your needed button URL and text for the notice, like the "bento" product category link and button name.
Here is the code:
// Conditional function that check if the non mandatory product categories are in all cart items
function has_not_mandatory_category(){
// DEFINE HERE the your non mandatory product categories (Ids, slugs or names)
$categories = array('drinks','extra-accompaniments');
// Iterrating each item in cart and detecting…
foreach ( WC()->cart->get_cart() as $cart_item ) {
$product_id = $cart_item['product_id']; // <== This is the right way (working for product variations too)
if ( ! has_term( $categories, 'product_cat', $product_id ) )
return false;
}
return true;
}
// Display a message and prevent checkout if the non mandatory product categories are not in all cart items
add_action( 'woocommerce_check_cart_items', 'prevent_checkout_display_notice' ); // for cart and checkout
function prevent_checkout_display_notice() {
// DEFINE HERE the return button URL and title
$button_url = '#';
$button_title = 'Go there';
// Display message if the non mandatory product categories are not in all cart items
if ( has_not_mandatory_category() )
wc_add_notice(
sprintf( __( 'Please choose at least one bento. <a class="button" href="%s">%s</a>', 'your_theme_domain'),
$button_url,
$button_title
), 'error'
);
}
Code goes in function.php file of your active child theme (or active theme).
Tested and works…
Instead of targeting non mandatory product categories you should do the contrary…