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.
Related
Hello this is similar question to the link below but just want to ask if it's possible to set a condition where it won't load the free product if the product that's been purchase is a subscription type? Thank you.
Add or remove automatically a free product in Woocommerce cart
/**
* Add another product depending on the cart total
*/
add_action( 'template_redirect', 'add_product_to_cart' );
function add_product_to_cart() {
if ( ! is_admin() ) {
global $woocommerce;
$product_id = 85942; //replace with your product id
$found = false;
$cart_total = 15; //replace with your cart total needed to add above item
if( $woocommerce->cart->total >= $cart_total ) {
//check if product already in cart
if ( sizeof( $woocommerce->cart->get_cart() ) > 0 ) {
$isVirtualOnly = false;
foreach ( $woocommerce->cart->get_cart() as $cart_item_key => $values) {
$_product = $values[‘data’];
if ($_product != null)
if ($_product->get_type() != $_virtual)
$isVirtualOnly = false;
}
if ($isVirtualOnly != true) {
foreach ( $woocommerce->cart->get_cart() as $cart_item_key => $values ) {
$_product = $values['data'];
if ( $_product->get_id() == $product_id )
$found = true;
}
// if product not found, add it
if ( ! $found )
$woocommerce->cart->add_to_cart( $product_id );
}
} else {
// if no products in cart, add it
$woocommerce->cart->add_to_cart( $product_id );
}
}
}
}
/**
* END Add another product depending on the cart total
*/
add_action( 'template_redirect', 'add_product_to_cart_conditionally' );
function add_product_to_cart_conditionally() {
if ( is_admin() ) return; // Exit
// Below define the product Id to be added:
$product_A = 37; // <== For new customers that have not purchased a product before (and guests)
$product_B = 53; // <== For confirmed customers that have purchased a product before
$product_id = has_bought() ? $product_B : $product_A;
// If cart is empty
if( WC()->cart->is_empty() ) {
WC()->cart->add_to_cart( $product_id ); // Add the product
}
// If cart is not empty
else {
// Loop through cart items (check cart items)
foreach ( WC()->cart->get_cart() as $item ) {
// Check if the product is already in cart
if ( $item['product_id'] == $product_id ) {
return; // Exit if the product is in cart
}
}
// The product is not in cart: We add it
WC()->cart->add_to_cart( $product_id );
}
}
I am trying to add a product from an on_click event at checkout.
That product's price is calculated dynamically with an external API so it is registered as having a price of 0 in woocommerce itself. I am trying to add this product to the cart (working) and then set that product's price to the one I receive from the API (not working). Here is the relevant code:
AJAX call on click:
jQuery('#theftdaminsurance').on('click', function(){
jQuery.ajax({
type: "POST",
url: "/wp-admin/admin-ajax.php",
data: {
action: 'add_product_to_cart_checkout',
// add your parameters here
price: <?php echo $year_dam_price; ?>,
productid: ins_product_id
},
success: function (output) {
document.getElementById("loaderdiv").style.display = "none";
jQuery(document.body).trigger("update_checkout");
}
});
});
I checked everything here and the call is made properly with all the right info being passed on.
Here is the function being called:
add_action('wp_ajax_add_product_to_cart_checkout', 'add_product_to_cart_checkout');
// register the ajax action for unauthenticated users
add_action('wp_ajax_nopriv_add_product_to_cart_checkout', 'add_product_to_cart_checkout');
function add_product_to_cart_checkout() {
$product_id = $_REQUEST['productid'];
$price = floatval($_REQUEST['price']);
$ebike_ids = array(17386,17385,17382,17378,17375,17372,17370,17369,17364,16132,16130,4561,4550,3490,2376);
$found = false;
//check if there is something in cart
if ( sizeof( WC()->cart->get_cart() ) > 0 ) {
//Delete all preexisting insurance products and find qty of ebikes
foreach ( WC()->cart->get_cart() as $cart_item_key => $cart_item ) {
$product_idebike = $cart_item['product_id'];
if ( ($cart_item['product_id'] == "16600") || ($cart_item['product_id'] == "16653") || ($cart_item['product_id'] == "16654") || ($cart_item['product_id'] == "16655") ||($cart_item['product_id'] == "16659") || ($cart_item['product_id'] == "16660")) {
WC()->cart->remove_cart_item( $cart_item_key );
}
//get ebike quantity
for ($x = 0; $x <= 14; $x++) {
if ($product_idebike == $ebike_ids[$x]) {
$quantity = $cart_item['quantity'];
break;
}
}
}
// if command is not to remove add relevant products
if ($price != "-1") {
WC()->cart->add_to_cart( $product_id, $quantity );
foreach( WC()->cart->get_cart() as $cart_item ){
$id = $cart_item['product_id'];
if ($product_id == $id) {
$cart_item['data']->set_price( $price );
}
}
}
}
}
Here I basically debugged everythingcarefully and everything behaves as it should but the set_price function. I cannot get it to update the product's price to the one passed in the AJAX call. The price remains 0 once the checkout is updated and before it is as well. Am i calling or using this function the wrong way?
Thanks a lot for your help!
It seems that you are making things much more complicated than they should be on your Ajax receiver function…
Note that you can add custom cart item data when using WC_Cart add_to_cart() method, so you will add your insurance price as custom cart item data and afterwards use it to set the price.
Here is your revisited Ajax PHP receiver function:
add_action('wp_ajax_add_product_to_cart_checkout', 'add_product_to_cart_checkout');
add_action('wp_ajax_nopriv_add_product_to_cart_checkout', 'add_product_to_cart_checkout');
function add_product_to_cart_checkout() {
if ( isset($_POST['productid']) && isset($_POST['price']) && ! WC()->cart->is_empty() ) {
$product_id = intval($_POST['productid']);
$price = floatval($_POST['price']);
$ebike_ids = array(17386,17385,17382,17378,17375,17372,17370,17369,17364,16132,16130,4561,4550,3490,2376);
$insurance_ids = array(16600,16653,16654,16655,16659,16660);
$found = false;
$ebike_quantity = 0;
// Loop through cart items
foreach ( WC()->cart->get_cart() as $cart_item_key => $cart_item ) {
// Delete all preexisting insurance products
if ( in_array( $cart_item['product_id'], $insurance_ids ) ) {
WC()->cart->remove_cart_item( $cart_item_key );
}
// Get ebikes total quantity
if ( in_array( $cart_item['product_id'], $ebike_ids ) ) {
$ebike_quantity += $cart_item['quantity'];
}
}
// If command is not to remove add insurance product with price as custom cart item data
if ( $price >= 0 && $cart_item['insurance_price'] > 0 ) {
WC()->cart->add_to_cart( $product_id, $ebike_quantity, 0, array(), array( 'insurance_price' => $price ) );
}
die();
}
}
Then to set the price you will use:
// Set insurance price from custom cart item data
add_action( 'woocommerce_before_calculate_totals', 'set_insurance_price' );
function set_insurance_price( $cart ) {
if ( is_admin() && ! defined( 'DOING_AJAX' ) )
return;
foreach ( $cart->get_cart() as $cart_item ) {
if( isset($cart_item['insurance_price']) && $cart_item['insurance_price'] > 0 ) {
$cart_item['data']->set_price( $cart_item['insurance_price'] );
}
}
}
Now It should works.
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
I'm trying to write a hook that hides a specific product from the shop page if it's in the cart, but I can't seem to figure out two things.
function find_product_in_cart() {
$hide_if_in_cart = array(6121, 6107, 14202, 14203);
$in_cart = false;
foreach( WC()->cart->get_cart() as $cart_item ) {
$product_in_cart = $cart_item['product_id'];
foreach ( $hide_if_in_cart as $key => $value ) {
if ( $product_in_cart === $value ) {
$in_cart = true;
}
}
if ( $in_cart ) {
echo 'Product in cart';
} else {
echo 'Not in cart!';
}
}
}
add_action('woocommerce_before_shop_loop_item', 'find_product_in_cart
The code prints out "Product in cart" everywhere, because one product with ID '14202' is in the cart. My logic is wrong somewhere...
I don't know how to hide a single product, right now I print a line of text, but I want to be able to either display: none; it or maybe use a specific function that hides product in certain scenario's.
This is the output at the moment:
https://i.gyazo.com/d85bd93598ada7aa96bee9a1d7393c3c.png
The following code will remove a specific defined products from Woocommerce shop and archive pages when they are in cart, using this dedicated Woocommerce action hook:
add_action( 'woocommerce_product_query', 'hide_specific_products_from_shop', 20, 2 );
function hide_specific_products_from_shop( $q, $query ) {
if( is_admin() && WC()->cart->is_empty() )
return;
// HERE Set the product IDs in the array
$targeted_ids = array( 6121, 6107, 14202, 14203 );
$products_in_cart = array();
// Loop through cart items
foreach( WC()->cart->get_cart() as $cart_item ){
if( in_array( $cart_item['product_id'], $targeted_ids ) ){
// When any defined product is found we add it to an array
$products_in_cart[] = $cart_item['product_id'];
}
}
// We remove the matched products from woocommerce lopp
if( count( $products_in_cart ) > 0){
$q->set( 'post__not_in', $products_in_cart );
}
}
Code goes in function.php file of your active child theme (or active theme). Tested and works.
I am aware that there's already an existing function where you can add a certain product on cart upon visiting the website. The problem is you can only do it with 1 product and I want it variable depending on the page you are visiting.
here's the existing code (added on functions.php file)
add_action( 'template_redirect', 'add_product_to_cart' );
function add_product_to_cart() {
if ( ! is_admin() ) {
$product_id = 275;
$found = false;
//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->id == $product_id )
$found = true;
}
// if product not found, add it
if ( ! $found )
WC()->cart->add_to_cart( $product_id );
} else {
// if no products in cart, add it
WC()->cart->add_to_cart( $product_id );
}
}
}
Inside my landing page called page-template.php, there's a custom field that echos the ID of a certain product selected. So when my user visits this page, I want this ID to replace the $product_id on the functions.php file. How do I achieve this?
Many thanks in advance for the help.
maybe the global variable is loaded after the function. instead of just setting the variable initiate the function passing the variable and avoid the hook:
in functions.php:
function add_product_to_cart($product_id) {
if ( ! is_admin() ) {
$found = false;
//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->id == $product_id )
$found = true;
}
// if product not found, add it
if ( ! $found )
WC()->cart->add_to_cart( $product_id );
} else {
// if no products in cart, add it
WC()->cart->add_to_cart( $product_id );
}
}
}
in page-template.php:
add_product_to_cart(275);