I need to add an additional product to the cart. I have differents options to choose so I asign one checkbox to everyone of them. Then, depends the checkbox clicked it should add the right product to the cart. The problem begans when in my function it's not detected if the checkbox is checked, I have an if() but always returns the 'else'.
It should add the additional product if the checkbox is checked but it does not. The code to add the product works correctly
add_action('woocommerce_add_to_cart', 'custom_add_to_cart');
function custom_add_to_cart() {
$id = get_the_ID();
if($id = '147430'){
global $woocommerce;
$product_id_mes = 147054;
$product_id_anual = 147295;
$found = false;
if(isset($_POST['checkmes']) && $_POST['checkmes'] == 'Si'){
//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_mes )
$found = true;
}
// if product not found, add it
if ( ! $found )
WC()->cart->add_to_cart( $product_id_mes );
} else {
// if no products in cart, add it
WC()->cart->add_to_cart( $product_id_mes );
}
} else{
//if 'checkmes' isn't checked don't add the additional product
}
}
}
There are 2 problems in your code:
if($id = '147430') here you're doing the assignment. you need to use == loose comparison or === strict comparison.
You should not use the get_the_ID() function for getting the product ID, you need to use 2nd param of action which is $product_id
Other suggestions:
global $woocommerce; line if not required to add since you're using the WC() function not the global $woocommerce object.
use count() instead of sizeof function.
Related
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.
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] );
}
}
}
}
In WooCommerce, I would like to check if the products in the shopping cart have the attribute 'Varifocal' (so I can show/hide checkout fields).
I'm struggling to get an array of id's of all the variations which have the attribute 'varifocal'. It would be really appreciated if someone can point me in the right direction.
The taxonomy is pa_lenses.
I currently have the following function:
function varifocal() {
// Add product IDs here
$ids = array();
// Products currently in the cart
$cart_ids = array();
// Find each product in the cart and add it to the $cart_ids array
foreach( WC()->cart->get_cart() as $cart_item_key => $values ) {
$cart_product = $values['data'];
$cart_ids[] = $cart_product->get_id();
}
// If one of the special products are in the cart, return true.
if ( ! empty( array_intersect( $ids, $cart_ids ) ) ) {
return true;
} else {
return false;
}
}
Here is a custom conditional function that will return true when the a specific attribute argument is found in one cart item (product variation):
function is_attr_in_cart( $attribute_slug_term ){
$found = false; // Initializing
if( WC()->cart->is_empty() )
return $found; // Exit
else {
// Loop through cart items
foreach ( WC()->cart->get_cart() as $cart_item ){
if( $cart_item['variation_id'] > 0 ){
// Loop through product attributes values set for the variation
foreach( $cart_item['variation'] as $term_slug ){
// comparing attribute term value with current attribute value
if ( $term_slug === $attribute_slug_term ) {
$found = true;
break; // Stop current loop
}
}
}
if ($found) break; // Stop the first loop
}
return $found;
}
}
Code goes in functions.php file of your active child theme (or active theme). Tested and works.
USAGE (example)
if( is_attr_in_cart( 'Varifocal' ) ){
echo '"Varifocal" attribute value has been found in cart items<br>';
} else {
echo '"Varifocal" <strong>NOT FOUND!!!</strong><br>';
}
Advice: This conditional function will return false if cart is empty
First, thanks for your time.
We have certain products we offer a payment plan with, and it includes a $1 30day trial.
When a user adds a product to the cart with the "payment plan" category (id=41 below), I want the cart to display the price as $1 then X payments of $xx.xx. The back end only needs to pass the product SKU so this is purely for display reasons.
This code works, but loops for however many items are in the cart. Is there a way for me to stop the loop as soon as it senses the "payment plan" product category?
The Code:
<td><?php
function check_payment() {
//Check to see if user has product in cart
global $woocommerce;
//assigns a default negative value
$contains_special = false;
$wccart= WC()->cart->get_cart();
if ( !empty( $wccart ) ) {
foreach ( WC()->cart->get_cart() as $cart_item ) {
function is_item_special( $product_id ){
if( has_term( 'payment-plan', 'product_cat', $product_id ) ) {
return TRUE;
} else {
return false;
}
}//function
if ( is_item_special( $cart_item['product_id'] ) ) {
$contains_special = true;
$firstpayment = get_post_meta( $_product->id, 'firstpayment', true );
$getsubtotal = WC()->cart->get_cart_subtotal(); //get cart subtotal
$trimbefore = str_replace('<span class="amount">$', "", $getsubtotal); //$getsubtotal returns <span class="amount>XX.XX</span> this trims off the opening span tag
$intsubtotal = str_replace('</span>', "", $trimbefore); //trim closing span tag
$formatsubtotal = number_format((float)$intsubtotal, 2, '.', '');//makes an integer
$numberofpayments = get_post_meta( $_product->id, 'payments', true );
$afterfirsttotal = $formatsubtotal - 1.00;
$paymentamount = number_format((float)$afterfirsttotal, 2, '.', '') / $numberofpayments;
echo '$' . $firstpayment . '<br/> then ' . $numberofpayments . ' payments of $' . number_format((float)$paymentamount, 2, '.', '');
break;
} else {
wc_cart_totals_subtotal_html();
}//if/else statement
}//foreach loop
} //if cart isn't empty
} //function
?>
I'm semi-new to PHP and still trying to understand some things, so sorry if this is just obvious!
Here is something that I have used in the past (slightly modified from when I was checking for a product with a particular post meta field). From what I can tell from your question, it seems that you are looking for break which is how to quit a foreach loop once a particular condition has been satisfied.
The first function loops through the cart items looking for any item that matches our criteria. Note the if ( ! empty( WC()->cart->get_cart() ) ) which prevents the code from running on an empty cart.... which was the cause of the foreach error you were seeing earlier.
The second function checks a product for a particular condition: in your case whether or not it has a specific product category assigned. This could easily be handled inside the first function, but I refactored it out for readability.
/*
* loop through cart looking for specific item
*/
function kia_check_cart_for_specials() {
$contains_special = false;
if ( ! empty( WC()->cart->get_cart() ) ) {
foreach ( WC()->cart->get_cart() as $cart_item ) {
if ( kia_is_item_special( $cart_item['product_id'] ) ) {
$contains_special = true;
break; // found a special item so we can quit now
}
}
}
return $contains_special;
}
/*
* check if an item has special category
* change the term/condition to suit your needs
*/
function kia_is_item_special( $product_id ){
if( has_term( 'special-category', 'product_cat', $product_id ) ) {
return TRUE;
} else {
return false;
}
}
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.