Im trying to display additional button [Book Your appointment] on the WooCommerce Cart page that would take user to a page with a product for booking an appointment. This part works nicely. I also try to check if product ID 444908 is already in cart. Product ID 444908 is an appointment product, and if a person has already booked an appointment the button should not be displayed as the person already have booked product in the cart.
Seems like the problem is with my IF condition. When I'm using it it doesn't show button no matter if product 444908 is or isn't in cart.
What am I doing wrong?
add_action( 'woocommerce_after_cart_totals', 'my_continue_shopping_button' );
function my_continue_shopping_button() {
$product_id = 444908;
$product_cart_id = WC()->cart->generate_cart_id( $product_id );
$in_cart = WC()->cart->find_product_in_cart( $product_cart_id );
if ( $in_cart ) {
echo '<div class="bookbtn"><br/>';
echo ' <i class="fas fa-calendar-alt"></i> Book Your Appointment';
echo '</div>';
}
}
Here's something I've been using for a while now 🙃
function is_in_cart( $ids ) {
// Initialise
$found = false;
// Loop through cart items
foreach( WC()->cart->get_cart() as $cart_item ) {
// For an array of product IDs
if( is_array($ids) && ( in_array( $cart_item['product_id'], $ids ) || in_array( $cart_item['variation_id'], $ids ) ) ){
$found = true;
break;
}
// For a unique product ID (integer or string value)
elseif( ! is_array($ids) && ( $ids == $cart_item['product_id'] || $ids == $cart_item['variation_id'] ) ){
$found = true;
break;
}
}
return $found;
}
For single product ID:
if(is_in_cart($product_id)) {
// do something
}
For array of product/variation IDs:
if(is_in_cart(array(123,456,789))) {
// do something
}
...or...
if(is_in_cart($product_ids)) {
// do something
}
In the end I used external function:
function woo_is_in_cart($product_id) {
global $woocommerce;
foreach($woocommerce->cart->get_cart() as $key => $val ) {
$_product = $val['data'];
if($product_id == $_product->get_id() ) {
return true;
}
}
return false;
}
Then I check if the product is in cart using this:
if(woo_is_in_cart(5555) !=1) {
/* where 5555 is product ID */
find_product_in_cart returns a empty string if product is not found
so you need
if ( $in_cart !="" )
info
Related
I'm basing this on a previous SO post, but in my case, the "ship to a different address" section disappears no matter what is in the cart.
I have one product that's virtual and when you add that to the cart, and it's in the cart all by itself:
Ship to area does not appear.
If any other product is in the cart, including with the other product. the Ship to does appear because you are now shipping a product.
The code I'm using is:
add_filter( 'woocommerce_cart_needs_shipping_address', 'disable_checkout_shipping_address');
function disable_checkout_shipping_address( $needs_shipping_address ) {
$products_ids = [3649];
$found = false;
$others_found = false;
foreach ( WC()->cart->get_cart() as $cart_item ){
if (in_array( $cart_item['data']->get_id(), $products_ids ) ){
$found = true;
} else {
$others_found = true;
}
}
if( $found && ! $others_found )
$needs_shipping_address = true;
return $needs_shipping_address;
}
Any advice?
You can use count( WC()->cart->get_cart() ). If the specific product is in the cart and there is only 1 product in the cart = hide, else = show.
So you get:
function filter_woocommerce_cart_needs_shipping_address( $needs_shipping ) {
// The targeted product id
$targeted_id = 3649;
// Flag
$found = false;
// Loop through cart items
foreach ( WC()->cart->get_cart() as $cart_item ) {
if ( in_array( $targeted_id, array( $cart_item['product_id'], $cart_item['variation_id'] ) ) ) {
$found = true;
break;
}
}
// True & only 1 item in cart
if ( $found && count( WC()->cart->get_cart() ) <= 1 ) {
$needs_shipping = false;
}
return $needs_shipping;
}
add_filter( 'woocommerce_cart_needs_shipping_address', 'filter_woocommerce_cart_needs_shipping_address', 10, 1 );
I have faced a problem. This functions is working fine. But now I want when add this product 454545 in the cart, then need to add also this 263654 product in the cart in five times. If I add regular/other products in the cart, then need add this product 263654 in the cart in one time as usual works like before.
add_action('woocommerce_add_to_cart', 'add_product_to_cart');
function add_product_to_cart() {
if ( !is_admin() && !is_cart() && !is_checkout()) {
$product_id = 263654; //replace with your own product id
$specific_products = 454545;
$excloud_product = 380978;
$excloud_product1 = 446740;
$found = false;
$items_count = 0;
//check if product already in cart
if ( sizeof( WC()->cart->get_cart() ) > 0 ) {
foreach ( WC()->cart->get_cart() as $cart_item_key => $values ) {
$_product = $values['data'];
if ( $_product->get_id() == $product_id || $_product->get_id() == $excloud_product ){
$product_key = $cart_item_key;
$product_qty = $cart_item['quantity'];
$found = true;
}else {
$items_count++;
}
}
// if product not found, add it
if ( ! $found ){
WC()->cart->add_to_cart( $product_id, $items_count );
}else{
WC()->cart->set_quantity( $product_key, $items_count );
}
}else{
// if no products in cart, add it
WC()->cart->add_to_cart( $product_id );
}
}
}
I think this should work.
add_action('woocommerce_add_to_cart', 'bks_add_product_to_cart');
function bks_add_product_to_cart()
{
if (!is_admin() && !is_cart() && !is_checkout()) {
$product_id = 263654; //replace with your own product id
$excloud_product = 380978;
$other_five_products = array(12321, 23123, 213123, 21323, 123213);
$found = false;
$items_count = 0;
//check if product already in cart
if (sizeof(WC()->cart->get_cart()) > 0) {
foreach (WC()->cart->get_cart() as $cart_item_key => $values) {
$_product = $values['data'];
if ($_product->get_id() == $product_id || $_product->get_id() == $excloud_product) {
$product_key = $cart_item_key;
$found = true;
} else {
$items_count++;
}
}
// if product not found, add it
if (!$found) {
WC()->cart->add_to_cart($product_id, $items_count);
////////// ADD IT WHEN NOT FOUND //////////////////////
foreach ($other_five_products as $prod) {
WC()->cart->add_to_cart($prod, 1);
}
} else {
WC()->cart->set_quantity($product_key, $items_count);
}
} else {
// if no products in cart, add it
WC()->cart->add_to_cart($product_id);
////////// ADD IT IF NO PRODUCT IS ADDED //////////////////////
foreach ($other_five_products as $prod) {
WC()->cart->add_to_cart($prod, 1);
}
}
}
}
I have added the comment where I have made the changes. Those two are the places which are adding the product to cart after calculation. I have just added for loop with the array of product you want to add $other_five_products and added them.
I found the code to check whether a user has an active subscription using the product ID...
<?php
$has_sub = wcs_user_has_subscription( '', 5861, 'active' );
if ( $has_sub) {?>
<p>You are a member of the Samurai</p>
<?php } ?>
...however, I'd like to check if they are a member of one of a few subscriptions at a time. I tried to use an array but to no avail...
<?php
$subscription_id = array(5861, 5862);
$has_sub = wcs_user_has_subscription( '', $subscription_id, 'active');
if ( $has_sub) {?>
<p>You are a member of the Samurai</p>
<?php } ?>
I guess the 'wcs_user_has_subscription' is looking for a single ID
Any ideas how I'd check for any of the IDs in that array
Gets all the active and inactive subscriptions for a user, as specified by $user_id
$subscriptions = wcs_get_users_subscriptions( $user_id );
$subscription_ids = array(5861, 5862);
foreach ( $subscriptions as $subscription_id => $subscription ) {
if(in_array($subscription, $subscription_ids)){
echo '<p>You are a member of the Samurai</p>';
}
}
add_filter( 'woocommerce_add_to_cart_validation','wpso35381172_validate_block_one_sub', 10, 2 );
function wpso35381172_validate_block_one_sub( $valid, $product_id ) {
// Get the current product
$current_user = is_user_logged_in() ? wp_get_current_user() : null;
$current_product = wc_get_product( $product_id );
$subscriptions = wcs_get_users_subscriptions( $current_user->ID );
// See if the current product user's are viewing is a subscription product
if($subscriptions)
{
if ( $current_product instanceof WC_Product_Subscription ||
$current_product instanceof WC_Product_Variable_Subscription ) {
foreach( WC()->cart->get_cart() as $cart_item_key => $values ) {
// Loop through all products in the cart
$_product = $values['data'];
// Check if current item is a subscription type
if( $_product instanceof WC_Product_Subscription ||
$_product instanceof WC_Product_Subscription_Variation ) {
// Display a notice and cancel the addition of item to cart
wc_add_notice( "Only one subscription or membership plan can be purchased." );
return false;
}
}
}
else if($subscriptions)
{
//if(WC()->cart->get_cart_contents_count() > 1)
//{
foreach( WC()->cart->get_cart() as $cart_item_key => $values ) {
$_product = $values['data'];
if( isset( $values["subscribe_product"] ) ) {
//echo "<pre>";
//print_r($values);
wc_add_notice( "Only one product allowed in cart." );
return false;
}
}
//}
}
}
else
{
if ( $current_product instanceof WC_Product_Subscription ||
$current_product instanceof WC_Product_Variable_Subscription ) {
foreach( WC()->cart->get_cart() as $cart_item_key => $values ) {
// Loop through all products in the cart
$_product = $values['data'];
// Check if current item is a subscription type
if( $_product instanceof WC_Product_Subscription ||
$_product instanceof WC_Product_Subscription_Variation ) {
// Display a notice and cancel the addition of item to cart
wc_add_notice( "Only one subscription or membership plan can be purchased." );
return false;
}
}
}
}
return $valid;
}
I am trying display if a variation of a product is already in a cart or not (in single product page). A simple comparing of the product id with products in cart object is not working for variable product as the variation id is being loaded using ajax.
Here is my code that works in case the product type is other than variable.
<?php
/*
* Check if Product Already In Cart
*/
function woo_in_cart( $product_id ) {
global $woocommerce;
if ( !isset($product_id) ) {
return false;
}
foreach( $woocommerce->cart->get_cart() as $cart_item ) {
if ( $cart_item['product_id'] === $product_id ){
return true;
} else {
return false;
}
}
}
Is there any way to make it work without jQuery?
Do you mean $product_id could be the ID of a variation? If so, you can just get the parent ID if it exists:
/*
* Check if Product Already In Cart
*/
function woo_in_cart( $product_id ) {
global $woocommerce;
if ( ! isset( $product_id ) ) {
return false;
}
$parent_id = wp_get_post_parent_id( $product_id );
$product_id = $parent_id > 0 ? $parent_id : $product_id;
foreach ( $woocommerce->cart->get_cart() as $cart_item ) {
if ( $cart_item['product_id'] === $product_id ) {
return true;
} else {
return false;
}
}
}
If you mean your cart item is a variation, and $product_id is already the parent product ID, then your code should work already as is.
The $cart_item has 2 IDs: $cart_item['product_id'] and $cart_item['variation_id'].
So product_id will always be that of the parent product.
To handle product variations outside single product pages (and simple products everywhere):
// Check if Product Already In Cart (Work with product variations too)
function woo_in_cart( $product_id = 0 ) {
$found = false;
if ( isset($product_id) || 0 == $product_id )
return $found;
foreach( WC()->cart->get_cart() as $cart_item ) {
if ( $cart_item['data']->get_id() == $product_id )
$found = true;
}
return $found;
}
To handle product variations inside single product pages, javascript is needed.
Here is an example that will show a custom message, when the selected variation is already in cart:
// Frontend: custom select field in variable products single pages
add_action( 'wp_footer', 'action_before_add_to_cart_button' );
function action_before_add_to_cart_button() {
if( ! is_product() ) return;
global $product;
if( ! is_object($product) )
$product = wc_get_product( get_the_id() );
// Only for variable products when cart is not empty
if( ! ( $product->is_type('variable') && ! WC()->cart->is_empty() ) ) return; // Exit
$variation_ids_in_cart = array();
// Loop through cart items
foreach( WC()->cart->get_cart() as $cart_item ) {
// Collecting product variation IDs if they are in cart for this variable product
if ( $cart_item['variation_id'] > 0 && in_array( $cart_item['variation_id'], $product->get_children() ) )
$variation_ids_in_cart[] = $cart_item['variation_id'];
}
// Only if a variation ID for this variable product is in cart
if( sizeof($variation_ids_in_cart) == 0 ) return; // Exit
// Message to be displayed (if the selected variation match with a variation in cart
$message = __("my custom message goes here", "woocommerce");
$message = '<p class="custom woocommerce-message" style="display:none;">'.$message.'</p>';
// jQuery code
?>
<script>
(function($){
// Utility function that check if variation match and display message
function checkVariations(){
var a = 'p.woocommerce-message.custom', b = false;
$.each( <?php echo json_encode($variation_ids_in_cart); ?>, function( k, v ){
if( $('input[name="variation_id"]').val() == v ) b = true;
});
if(b) $(a).show(); else $(a).hide();
}
// On load (when DOM is rendered)
$('table.variations').after('<?php echo $message; ?>');
setTimeout(function(){
checkVariations();
}, 800);
// On live event: product attribute select fields "blur" event
$('.variations select').blur( function(){
checkVariations();
});
})(jQuery);
</script>
<?php
}
Code goes in function.php file of your active child theme (or active theme). Tested and works.
We have an exclusive category X and others regular categories Y. What I would like:
When someone orders anything from category X, other category items cannot be added to cart and should display a warning
category Y products should not be mixed with X.
How could I achieve that?
I got this code from other post, but its outdated and not satisfactory:
<?php
// Enforce single parent category items in cart at a time based on first item in cart
function get_product_top_level_category ( $product_id ) {
$product_terms = get_the_terms ( $product_id, 'product_cat' );
$product_category = $product_terms[0]->parent;
$product_category_term = get_term ( $product_category, 'product_cat' );
$product_category_parent = $product_category_term->parent;
$product_top_category = $product_category_term->term_id;
while ( $product_category_parent != 0 ) {
$product_category_term = get_term ( $product_category_parent, 'product_cat' );
$product_category_parent = $product_category_term->parent;
$product_top_category = $product_category_term->term_id;
}
return $product_top_category;
}
add_filter ( 'woocommerce_before_cart', 'restrict_cart_to_single_category' );
function restrict_cart_to_single_category() {
global $woocommerce;
$cart_contents = $woocommerce->cart->get_cart( );
$cart_item_keys = array_keys ( $cart_contents );
$cart_item_count = count ( $cart_item_keys );
// Do nothing if the cart is empty
// Do nothing if the cart only has one item
if ( ! $cart_contents || $cart_item_count == 1 ) {
return null;
}
// Multiple Items in cart
$first_item = $cart_item_keys[0];
$first_item_id = $cart_contents[$first_item]['product_id'];
$first_item_top_category = get_product_top_level_category ( $first_item_id );
$first_item_top_category_term = get_term ( $first_item_top_category, 'product_cat' );
$first_item_top_category_name = $first_item_top_category_term->name;
// Now we check each subsequent items top-level parent category
foreach ( $cart_item_keys as $key ) {
if ( $key == $first_item ) {
continue;
}
else {
$product_id = $cart_contents[$key]['product_id'];
$product_top_category = get_product_top_level_category( $product_id );
if ( $product_top_category != $first_item_top_category ) {
$woocommerce->cart->set_quantity ( $key, 0, true );
$mismatched_categories = 1;
}
}
}
// we really only want to display this message once for anyone, including those that have carts already prefilled
if ( isset ( $mismatched_categories ) ) {
echo '<p class="woocommerce-error">Only one category allowed in cart at a time.<br />You are currently allowed only <strong>'.$first_item_top_category_name.'</strong> items in your cart.<br />To order a different category empty your cart first.</p>';
}
}
?>
Thanks
Updated (2019)
Like everything is turning around your exclusive category category X, you need to use a conditional for this category.
And you have chance because there is a special function that you can use in combination with woocommerce product categories. Lets say that **cat_x** is the slug for your exclusive category, as you know it yet product_cat is the argument to get products categories.
So with has_term () conditional function, you are going to use this:
if ( has_term ('cat_x', 'product_cat', $item_id ) ) { // or $product_id
// doing something when product item has 'cat_x'
} else {
// doing something when product item has NOT 'cat_x'
}
We need to run the cart items 2 times in a foreach loop:
To detect if there is a cat_x item in that car.
To remove other items if cat_x is detected for one item in the cart and to fire the right messages.
In the code below, I have changed to a more useful hook. This hook will check what you have in your cart. The idea is to removed other categories items in the cart when there is a 'cat_x' item added in cart.
The code is well commented. At the end you will find different notices that are fired. You will need to put your real text in each.
add_action( 'woocommerce_check_cart_items', 'checking_cart_items' );
function checking_cart_items() {
// Set your product category slug
$category = 'cat_x';
$number_of_items = sizeof( WC()->cart->get_cart() );
$found = false; // Initializing
$notice = ''; // Initializing
if ( $number_of_items > 0 ) {
// Loop through cart items
foreach ( WC()->cart->get_cart() as $cart_item ) {
$product = $cart_item['data'];
$product_id = $cart_item['product_id'];
// Detecting if the defined category is in cart
if ( has_term( $category, 'product_cat', $product_id ) ) {
$found = true;
break; // Stop the loop
}
}
// Re-loop through cart items
foreach ( WC()->cart->get_cart() as $cart_item_key => $cart_item ) {
$product = $cart_item['data'];
$product_id = $cart_item['product_id'];
if ( $found ) // If the defined product category is in cart
{
if ( $number_of_items == 1 ) { // only one defined product category
if ( empty( $notice ) ){
$notice = '1';
}
}
if ( $number_of_items >= 2 ) { // The defined product category + other categories in cart
// removing other categories items from cart
if ( ! has_term( $category, 'product_cat', $product_id ) ) {
WC()->cart->remove_cart_item( $cart_item_key ); // removing item from cart
if ( empty( $notice ) || $notice == '1' ){
$notice = '2';
}
}
}
} else { // Only other categories items
if ( empty( $notice ) ){
$notice = '3';
}
}
}
// Firing woocommerce notices
if ( $notice == '1' ) { // message for an 'cat_x' item only (alone)
wc_add_notice( sprintf( '<p class="woocommerce-error">bla bla bla one category X item in the cart</p>' ), 'success' );
} elseif ( $notice == '2' ) { // message for an 'cat_x' item and other ones => removed other ones
wc_add_notice( sprintf( '<p class="woocommerce-error">bla bla bla ther is already category X in the cart => Other category items has been removed</p>' ), 'error' );
} elseif ( $notice == '3' ) { // message for other categories items (if needed)
wc_add_notice( sprintf( '<p class="woocommerce-error">bla bla bla NOT category X in the cart</p>' ), 'success' );
}
}
}
Is not possible for me to really test this code (but it doesn't throws errors)…
#edit
We can use something else than notices… everything is possible. But it's a good starting solution, to fine tune.
You will need to replace 'cat_x' by your real category slug (in the beginning)…
Answer in 2020
Recently, I need almost the same requirement. But instead of a single category, I have to check if the item is in a group of categories.
Consider that I have 6 categories. I will group 6 categories into 3 groups. My customer can only purchase items in a single category group (but multiple categories) in a single order.
The code snippet is given below.
function sa45er_category_group_validation($valid, $product_id, $quantity) {
global $woocommerce;
if($woocommerce->cart->cart_contents_count == 0){
return $valid;
}
$target_cat_group = array(
array(17,20), // Update your product category
array(19,18), // Update your product category
);
$this_product_terms = get_the_terms( $product_id, 'product_cat' );
foreach ($this_product_terms as $term) {
$this_product_cat_ids[] = $term->term_id;
}
foreach ( $woocommerce->cart->get_cart() as $cart_item_key => $values ) {
$_product = $values['data'];
$terms = get_the_terms( $_product->get_ID(), 'product_cat' );
foreach ($terms as $term) {
$cart_cat_ids[] = $term->term_id;
}
}
$all_cats = array_merge($this_product_cat_ids,$cart_cat_ids);
$result = array();
foreach($target_cat_group as $target_cat_group_item){
$intrsct = array_intersect($all_cats, $target_cat_group_item);
if( !empty( $intrsct ) ){
$result[] = $intrsct;
}
}
if(count($result) > 1){
wc_add_notice( 'You can\'t add this product with your current cart items.', 'error' );
return false;
}
return $valid;
}
add_filter( 'woocommerce_add_to_cart_validation', 'sa45er_category_group_validation',10,3);