I hope someone can help. I've set up some code (thanks to this post) that adds a product to my cart if the value of the cart is over $50.
That works. However, if the value is less than $50, I want to make sure that product is NOT in the cart. So say a user adds a product, the additional product is added, but they then remove a product so the value is under $50 (not including the new product added!) ... I want it to remove the product that was added.
I tried to implement the code as in the post mentioned above:
add_action( 'template_redirect', 'add_product_to_cart' );
function add_product_to_cart() {
// Bonus products
$product_1 = '4751';
$product_2 = '4752';
$product_3 = '24711';
// Get cart value in a clean format
$cart_total = WC()->cart->get_cart_subtotal();
$cart_total = html_entity_decode($cart_total, ENT_QUOTES, 'UTF-8');
$cart_total_format = strip_tags($cart_total);
$cart_value = preg_filter("/[^0-9]/", "", $cart_total_format);
$sum_raw = $cart_value;
// Set the sum level
$level3 = '50';
// Check sum and apply product
if ($sum_raw >= $level3) {
// Cycle through each product in the cart and check for match
$found = 'false';
foreach (WC()->cart->cart_contents as $item) {
global $product;
$product_id = $item['variation_id'];
if ($product_id == $product_3) {
$found = 'true';
}
}
// If product found we do nothing
if ($found == 'true') {}
// else we will add it
else {
//We add the product
WC()->cart->add_to_cart($product_3);
}
}
// Check if sum
if ($sum_raw < $level3) {
foreach ($woocommerce->cart->get_cart() as $cart_item_key => $cart_item) {
if ($cart_item['variation_id'] == $product_3) {
//remove single product
$woocommerce->cart->remove_cart_item($cart_item_key);
}
}
}
}
But it's not removing the product. :/ Anyone got any ideas why it wouldn't work, or if there's a better solution to check the cart: if cart > $50 add a product... if it ever changes and goes < $50, remove that same product...
And also exclude that newly added product from the checks (so < $50 NOT including that product that's just been added programmatically).
Please help! :(
Maybe You have to change this line :
$cart_value = preg_filter("/[^0-9]/", "", $cart_total_format);
to (add - minus):
$cart_value = preg_filter("/[^0-9\-]/", "", $cart_total_format);
Try this code... you are currently trying to update on "add" action while it should on "remove" action.
add_action( 'template_redirect', 'remove_product_from_cart' );
function remove_product_from_cart() {
// Run only in the Cart or Checkout Page
if( is_cart() || is_checkout() ) {
/*
GET THE CART TOTAL
*/
// Set the product ID to remove
$prod_to_remove = PRODUCT-ID-TO-BE-REMOVED;
// Cycle through each product in the cart
foreach( WC()->cart->cart_contents as $prod_in_cart ) {
// Get the Variation or Product ID
$prod_id = ( isset( $prod_in_cart['variation_id'] ) && $prod_in_cart['variation_id'] != 0 ) ? $prod_in_cart['variation_id'] : $prod_in_cart['product_id'];
// Check to see if IDs match
if( $prod_to_remove == $prod_id ) {
// Get it's unique ID within the Cart
$prod_unique_id = WC()->cart->generate_cart_id( $prod_id );
// Remove it from the cart by un-setting it
unset( WC()->cart->cart_contents[$prod_unique_id] );
}
}
}
}
Related
i'm a bit stuck for this.. i'm trying to remove a condition whenever the user adds a specific product, in this case a box of wines
So when i add a bottle of wine there's a minium amount condition so you have to add 3, but when you add a box the condition must be removed
add_action('woocommerce_after_cart_contents', 'box_special_function', 1, 1);
function box_special_function()
{
// getting cart items
$cart = WC()->cart->get_cart();
$terms = [];
// Getting categories of products in the cart
foreach ($cart as $cart_item_key => $cart_item) {
$product = $cart_item['data'];
$terms[] = get_the_terms( $product->get_id(), 'product_cat' );
}
// Cycling categories to find if there is a box inside of the cart
foreach($terms as $term => $item){
foreach($item as $key){
if($key->name == "BOX"){
// The only thing i did is to remove notices (which doesn't even work .-.)
$notices = WC()->session->get('wc_notices', array());
foreach($notices['error']){
wc_clear_notices();
}
}
}
}
}
I can't even force to checkout so i'm stuck with this.. can somebody clear my mind?
You can update your minimum product add to cart functionality, and remove validation for your specific products like this:
add_filter( 'woocommerce_quantity_input_args', 'custom_woocommerce_quantity_changes', 10, 2 );
function custom_woocommerce_quantity_changes( $args, $product ) {
$product_id = $product->get_id();
$product_title = $product->get_title();
//echo "<pre>"; print_r($product_title); echo "</pre>";
if($product_id == 1002 || $product_title == 'BOX'){
$args['input_value'] = 1;
$args['min_value'] = 1;
$args['max_value'] = 30;
$args['step'] = 1;
}else{
$args['input_value'] = 3; // Start from this value (default = 1)
$args['max_value'] = 30; // Max quantity (default = -1)
$args['min_value'] = 3; // Min quantity (default = 0)
$args['step'] = 1; // Increment/decrement by this value (default = 1)
}
return $args;
}
print your specific product id or product name and use same name or id in your if condition :
if($product_id == 1002 || $product_title == 'BOX')
For rest of product set min, max and input product validation from "else" parts.
In WooCommerce I use an OUTLET category with on sale products and I would like to set a minimum subtotal (30 €) for customers purchasing any "Outlet" product.
I tried to hook into woocommerce_after_calculate_totals to:
check cart items for a specific product category
display a notice when a specific product category is found and the order is lower than 30 €
and eventually redirect to cart page when user tries to checkout with an order lower than 30 €.
Here is my code:
add_action( 'woocommerce_after_calculate_totals', 'check_order_outlet_items', 10, 0 );
function check_order_outlet_items() {
global $woocommerce;
if (is_cart() || is_checkout()) {
// Check if cart contains items in Outlet cat.
$items = $woocommerce->cart->get_cart();
foreach($items as $item => $values) {
$product_id = $values['product_id'];
$terms = get_the_terms( $product_id, 'product_cat' );
foreach ($terms as $term) {
if ($term->name == "OUTLET") {
$outlet_found = 1;
break;
}
}
if ($outlet_found) {break;}
}
if ($outlet_found) {
// Calculate order amount including discount
$cart_subtotal = $woocommerce->cart->subtotal;
$discount_excl_tax_total = $woocommerce->cart->get_cart_discount_total();
$discount_tax_total = $woocommerce->cart->get_cart_discount_tax_total();
$discount_total = $discount_excl_tax_total + $discount_tax_total;
$order_net_amount = $cart_subtotal - $discount_total;
// Check if condition met
if ($order_net_amount < 30) {
if (is_checkout()) {
wp_redirect(WC()->cart->get_cart_url());
exit();
} else {
wc_add_notice( __( 'You must order at least 30 €', 'error' ) );
}
}
}
}
}
This code works perfectly in the cart page (displaying notice if cart's amount < 30 even if carts amount goes below 30 after adding a coupon) and redirecting to cart if users wants to go to checkout.
But If I go to checkout page with an amount >= 30 and then add a coupon (to lower cart amount below 30), then the Ajax recalculating totals loops and the page is blocked. But then if I reload the checkout page I'm correctly redirected to cart page.
The right hook to be used in this case is woocommerce_check_cart_items this way:
add_action( 'woocommerce_check_cart_items', 'check_cart_outlet_items' );
function check_cart_outlet_items() {
$categories = array('OUTLET'); // Defined targeted product categories
$threshold = 30; // Defined threshold amount
$cart = WC()->cart;
$cart_items = $cart->get_cart();
$subtotal = $cart->subtotal;
$subtotal -= $cart->get_cart_discount_total() + $cart->get_cart_discount_tax_total();
$found = false;
foreach( $cart_items as $cart_item_key => $cart_item ) {
// Check for specific product categories
if ( has_term( $categories, 'product_cat', $cart_item['product_id'] ) ) {
$found = true; // A category is found
break; // Stop the loop
}
}
if ( $found && $subtotal < $threshold ) {
// Display an error notice (and avoid checkout)
wc_add_notice( sprintf( __( "You must order at least %s" ), wc_price($threshold) ), 'error' );
}
}
Code goes in functions.php file of your active child theme (or active theme). Tested and works.
Let's Say I have Product A which is allow to bought alone.
If something else already in cart it shows the message. "Not Allow". I tried various methods but not able to find proper solution for that.
When somebody tries to click on the "ADD TO CART" button then it must check via code that if other items in cart it is not allow to put in cart and shows the message.
PRODUCT A is allow bought alone.
I tried with the category comparison and it works. but I want to do only with the Product ID.
add_filter('woocommerce_add_to_cart_validation', 'dont_add_paint_to_cart_containing_other', 10, 5);
function dont_add_paint_to_cart_containing_other($validation, $product_id) {
// Set flag false until we find a product in cat paint
$cart_has_paint = false;
// Set $cat_check true if a cart item is in paint cat
foreach (WC()->cart->get_cart() as $cart_item_key => $cart_item) {
$products_ids = 137817;
$product = $cart_item['data'];
if (has_term('miscellaneous', 'product_cat', $product->id)) {
$cart_has_paint = true;
// break because we only need one "true" to matter here
break;
}
}
$product_is_paint = false;
if (has_term('miscellaneous', 'product_cat', $product_id)) {
$product_is_paint = true;
}
// Return true if cart empty
if (!WC()->cart->get_cart_contents_count() == 0) {
// If cart contains paint and product to be added is not paint, display error message and return false.
if ($cart_has_paint && !$product_is_paint) {
echo '<script type="text/javascript">';
echo ' alert("Hello,Sorry, “custom order” items must be purchased separately! To purchase this item, please either checkout with your current cart or remove any “custom order” items from your cart to enable you add the regular items.")'; //not showing an alert box.
echo '</script>';
$validation = false;
}
// If cart contains a product that is not paint and product to be added is paint, display error message and return false.
elseif (!$cart_has_paint && $product_is_paint) {
echo '<script type="text/javascript">';
echo ' alert("Sorry, “custom order” item must be purchased separately! To purchase any “custom order” items, please either checkout with your current cart or empty cart to enable you add the “custom order” items.")'; //not showing an alert box.
echo '</script>';
$validation = false;
}
}
// Otherwise, return true.
return $validation;
}
This code only works with the miscellaneous category I want to allow only with the Product ID.. not category..
Assuming that only 1 quantity can be purchased from product A
function filter_woocommerce_add_to_cart_validation( $passed, $product_id, $quantity, $variation_id = null, $variations = null ) {
// Product id to bought alone
$product_id_alone = 30;
// Set variable
$alone = true;
// If passed
if ( $passed ) {
// If cart is NOT empty when a product is added
if ( !WC()->cart->is_empty() ) {
// If product id added = product id alone
if ( $product_id_alone == $product_id ) {
$alone = false;
} else {
// Generate a unique ID for the cart item
$product_cart_id = WC()->cart->generate_cart_id( $product_id_alone );
// Check if product is in the cart
$in_cart = WC()->cart->find_product_in_cart( $product_cart_id );
// If product is already in cart
if ( $in_cart ) {
$alone = false;
}
}
} else {
// If product is added when cart is empty but $quantity > 1
if ( $product_id_alone == $product_id && $quantity > 1 ) {
$alone = false;
}
}
}
if ( $alone == false ) {
// Set error message
$message = 'PRODUCT A is allow bought alone.';
wc_add_notice( __( $message, 'woocommerce' ), 'error' );
$passed = false;
// Empty the cart
WC()->cart->empty_cart();
// Add specific product with quantity 1
WC()->cart->add_to_cart($product_id_alone, 1 );
}
return $passed;
}
add_filter( 'woocommerce_add_to_cart_validation', 'filter_woocommerce_add_to_cart_validation', 10, 5 );
Related: Force specific WooCommerce product to be sold in separate order
I'm using dynamic pricing to discount an item to free one another is present, i want to avoid having the client add the free product as a separate step and just let the system add it.
I started off with the snippet but I can not get this to work when the item is present
this is what i got so far:
<?php
function add_product_to_cart() {
if ( ! is_admin() ) {
global $woocommerce;
$product_id_gift = 2287;
$found = false;
$product_id = 30;
$incart_free = false;
foreach($woocommerce->cart->get_cart() as $cart_item_key => $values ) {
$_product = $values['data'];
if ( $_product->id == $product_id ){
$incart_free = true;
}
return $incart_free;
}
if( $incart_free == true ) {
//check if product already in cart
if ( sizeof( $woocommerce->cart->get_cart() ) > 0 ) {
foreach ( $woocommerce->cart->get_cart() as $cart_item_key => $values ) {
$_product = $values['data'];
if ( $_product->id == $product_id_gift )
$found = true;
}
// if product not found, add it
if ( $found != true )
$woocommerce->cart->add_to_cart( $product_id_gift );
} else {
// if no products in cart, add it
$woocommerce->cart->add_to_cart( $product_id_gift );
}
}
}
}
add_action( 'init', 'add_product_to_cart' );
?>
Thank you!
If I understood your question correctly you are looking to make an item free if certain items are in the shopping cart. Here is my solution:
1. Create a coupon for WooCommerce in Wordpress. Make the coupon amount 100% and the discount type 'Product% Discount'. Go to Usage Restriction->Products and specify the specific product you want to be free, this will make the coupon only apply to that specific product.
2. Create a function that firsts checks if there are specific items present in the cart and if so, then adds and discounts the item you want to be free to the cart. The following code will do the trick (I have tested it and it worked fine, although it is not the cleanest solution):
add_action( 'init', 'product_discount' );
function product_discount(){
//variable declerations.
global $woocommerce;
$product_id = 1; // product to add
$products= array('2', '3', '4'); //specific product(s) to be present in the cart
$coupon_code = 'abc'; // coupon code from wp
//get the cart contents.
$cart_items = $woocommerce->cart->get_cart();
//check if the cart is not empty.
if(sizeof($cart_items) > 0){
//loop through the cart items looking for the specific products.
foreach ($cart_items as $key => $item){
//check if the cart items match to any of those in the array and check if the desired product is in the cart.
if(in_array($item['product_id'], $products) && $item['product_id'] != $product_id){
//add course.
$woocommerce->cart->add_to_cart($product_id);
//discount course.
$woocommerce->cart->add_discount(sanitize_text_field($coupon_code));
}else{
break; //to prevent the product from being added again for the next loop.
}
}
}
}
Hope this helps!
Your logic is completely wrong here because if ( $_product->id == $product_id_gift ) will never gonna be true as both product_id is different.
So logic should be :
1. Check all the products that are added in to the cart
2. Check that if any product in the cart having free products or not
3. If yes, then simply add the free product.
So code would be something like this :
add_action( 'init', 'add_product_to_cart' );
function add_product_to_cart() {
if ( ! is_admin() ) {
global $woocommerce;
$product_id = 30; //Your product ID here
$free_product_id = 2287; //Free product ID here
$found = false;
//check if product already in cart
if ( sizeof( $woocommerce->cart->get_cart() ) > 0 ) {
foreach ( $woocommerce->cart->get_cart() as $cart_item_key => $values ) {
$_product = $values['data'];
if ( $_product->id == $product_id ){
$found = true;
}
}
// if product not found, add it
if ( $found )
$woocommerce->cart->add_to_cart( $free_product_id );
}
}
}
NOTE: Untested.So let me know the output as well.
In WooCommerce I use an OUTLET category with on sale products and I would like to set a minimum subtotal (30 €) for customers purchasing any "Outlet" product.
I tried to hook into woocommerce_after_calculate_totals to:
check cart items for a specific product category
display a notice when a specific product category is found and the order is lower than 30 €
and eventually redirect to cart page when user tries to checkout with an order lower than 30 €.
Here is my code:
add_action( 'woocommerce_after_calculate_totals', 'check_order_outlet_items', 10, 0 );
function check_order_outlet_items() {
global $woocommerce;
if (is_cart() || is_checkout()) {
// Check if cart contains items in Outlet cat.
$items = $woocommerce->cart->get_cart();
foreach($items as $item => $values) {
$product_id = $values['product_id'];
$terms = get_the_terms( $product_id, 'product_cat' );
foreach ($terms as $term) {
if ($term->name == "OUTLET") {
$outlet_found = 1;
break;
}
}
if ($outlet_found) {break;}
}
if ($outlet_found) {
// Calculate order amount including discount
$cart_subtotal = $woocommerce->cart->subtotal;
$discount_excl_tax_total = $woocommerce->cart->get_cart_discount_total();
$discount_tax_total = $woocommerce->cart->get_cart_discount_tax_total();
$discount_total = $discount_excl_tax_total + $discount_tax_total;
$order_net_amount = $cart_subtotal - $discount_total;
// Check if condition met
if ($order_net_amount < 30) {
if (is_checkout()) {
wp_redirect(WC()->cart->get_cart_url());
exit();
} else {
wc_add_notice( __( 'You must order at least 30 €', 'error' ) );
}
}
}
}
}
This code works perfectly in the cart page (displaying notice if cart's amount < 30 even if carts amount goes below 30 after adding a coupon) and redirecting to cart if users wants to go to checkout.
But If I go to checkout page with an amount >= 30 and then add a coupon (to lower cart amount below 30), then the Ajax recalculating totals loops and the page is blocked. But then if I reload the checkout page I'm correctly redirected to cart page.
The right hook to be used in this case is woocommerce_check_cart_items this way:
add_action( 'woocommerce_check_cart_items', 'check_cart_outlet_items' );
function check_cart_outlet_items() {
$categories = array('OUTLET'); // Defined targeted product categories
$threshold = 30; // Defined threshold amount
$cart = WC()->cart;
$cart_items = $cart->get_cart();
$subtotal = $cart->subtotal;
$subtotal -= $cart->get_cart_discount_total() + $cart->get_cart_discount_tax_total();
$found = false;
foreach( $cart_items as $cart_item_key => $cart_item ) {
// Check for specific product categories
if ( has_term( $categories, 'product_cat', $cart_item['product_id'] ) ) {
$found = true; // A category is found
break; // Stop the loop
}
}
if ( $found && $subtotal < $threshold ) {
// Display an error notice (and avoid checkout)
wc_add_notice( sprintf( __( "You must order at least %s" ), wc_price($threshold) ), 'error' );
}
}
Code goes in functions.php file of your active child theme (or active theme). Tested and works.