I only have one product to display, but I offer two options for it: A payment plan (handled through a subscription plugin) and a single payment. I have them displayed on my site as a grouped and both options have an "Add to Cart" Button. I don't want either option to be in the cart at the same time as the other. What I would like to do is either,
A) Empty the cart before each time the add to cart is clicked.
or
B) Check if the cart contains a product already (via productid), and remove the payment plan if the full pay is selected, or vice versa. Here is something I've come up with for this option, but I'm a bit lost and it's not functioning quite right.
global $woocommerce;
if ($product_id = 66){
foreach ( $woocommerce->cart->get_cart() as $cart_item_key => $cart_item ) {
echo $cart_item_key;
if($cart_item['product_id'] == '69'){
//remove single product
$woocommerce->cart->remove_cart_item($cart_item_key);
}
}
}
elseif ($product_id = 69){
foreach ( $woocommerce->cart->get_cart() as $cart_item_key => $cart_item ) {
echo $cart_item_key;
if($cart_item['product_id'] == '66'){
//remove single product
$woocommerce->cart->remove_cart_item($cart_item_key);
}
}
}
I'm thinking of adding this to the add_to_cart method before the try/catch to throw any errors. Can anyone help me figure a better solution?
Emptying the cart would be very easy
add_filter( 'woocommerce_add_to_cart_validation', 'so_31392001_empty_cart', 10, 3 );
function so_31392001_empty_cart( $valid, $product_id, $quantity ) {
WC()->cart->empty_cart();
return $valid;
}
Related
I am working on this woocommerce search function that uses AJAX to fetch products on every keystroke and that gives the possibility to add or remove units of a certain product to cart right from the instant search results modal.
In each search result there is this group of two buttons that allow the client to add 1 or remove 1 product from cart at a time. I managed to make the add to cart button work but can't seem to find a good solution to remove just one single unit from cart instead of all of them at once.
I have tried this:
function remove_product_from_cart_programmatically() {
if ( is_admin() ) return;
$product_id = 282;
$product_cart_id = WC()->cart->generate_cart_id( $product_id );
$cart_item_key = WC()->cart->find_product_in_cart( $product_cart_id );
if ( $cart_item_key ) WC()->cart->remove_cart_item( $cart_item_key );
}
but it removes all products with that ID at once.
I want to be able to remove unit by unit in case there are items in cart with that ID.
This is the code I have right now for the remove from cart button:
add_action('wp_ajax_search_remove_from_cart', 'search_remove_from_cart');
add_action('wp_ajax_nopriv_search_remove_from_cart', 'search_remove_from_cart');
// handle the ajax request
function search_remove_from_cart()
{
$product_id = $_REQUEST['product_id'];
WC()->cart->remove_cart_item($product_id);
$products_in_cart = WC()->cart->get_cart_item_quantities($product_id);
$updated_qty = $products_in_cart[$product_id];
// in the end, returns success json data
wp_send_json_success(["Product removed from cart Successfuly!", $updated_qty]);
// or, on error, return error json data
wp_send_json_error(["Could not remove the product from cart"]);
}
Is there any function to remove only one unit of a certain product from cart?
Thank you all !
You have to change the quantity instead of removing the product. Number of product units in the cart = quantity.
Try something like this:
function remove_from_cart(){
$product_id = 47;
$cart = WC()->cart;
$product_cart_id = $cart->generate_cart_id( $product_id );
$cart_item_key = $cart->find_product_in_cart( $product_cart_id );
if ( $cart_item_key ){
$quantity = $cart->get_cart_item($cart_item_key)['quantity'] - 1;
$cart->set_quantity($cart_item_key, $quantity);
}
}
I have a function on my Woocommerce website that enables customers to set a custom amount to pay for a specific product, based on a value I'm passing through the URL.
I'm using the woocommerce_before_calculate_totals hook, and up until I upgraded to WC 3.3.5, it was working fine. Now, when I run the code, the checkout initially shows the custom amount.
However, once the loader has finished updating, it resets the price to '0' (i.e. displaying £0.00 the checkout page's total fields).
Here's that code:
add_action( 'woocommerce_before_calculate_totals', 'pay_custom_amount', 99);
function pay_custom_amount() {
$payment_value = $_GET['amount'];
foreach ( WC()->cart->get_cart() as $cart_item_key => $cart_item ) {
if($cart_item['data']->id == 21 ){
$cart_item['data']->set_price($payment_value);
}
}
}
Well, colour me baffled. I've trawled Stack Overflow for solutions but can't see any similar problems. I see the hook runs multiple times but gather this is normal.
If anyone know what might be happening here, it would be great if you could share.
You can't get a price from an URL and set it in woocommerce_before_calculate_totals action hook. This needs to be done differently.
In the below code:
the first hooked function will get that "amount" from the URl and will set it (register it) in cart item object as custom data.
the 2nd hooked function will read that amount from custom cart item data and will set it as the new price.
Now your the target product ID in your code need to be the same ID that the added to cart product.
The code:
// Get the custom "amount" from URL and save it as custom data to the cart item
add_filter( 'woocommerce_add_cart_item_data', 'add_pack_data_to_cart_item_data', 20, 2 );
function add_pack_data_to_cart_item_data( $cart_item_data, $product_id ){
if( ! isset($_GET['amount']) )
return $cart_item_data;
$amount = esc_attr( $_GET['amount'] );
if( empty($amount) )
return $cart_item_data;
// Set the custom amount in cart object
$cart_item_data['custom_price'] = (float) $amount;
$cart_item_data['unique_key'] = md5( microtime() . rand() ); // Make each item unique
return $cart_item_data;
}
// Alter conditionally cart item price based on product ID and custom registered "amount"
add_action( 'woocommerce_before_calculate_totals', 'change_conditionally_cart_item_price', 30, 1 );
function change_conditionally_cart_item_price( $cart ) {
if ( is_admin() && ! defined( 'DOING_AJAX' ) )
return;
if ( did_action( 'woocommerce_before_calculate_totals' ) >= 2 )
return;
// HERE set your targeted product ID
$targeted_product_id = 21;
foreach ( $cart->get_cart() as $cart_item ) {
// Checking for the targeted product ID and the registered "amount" cart item custom data to set the new price
if($cart_item['data']->get_id() == $targeted_product_id && isset($cart_item['custom_price']) )
$cart_item['data']->set_price($cart_item['custom_price']);
}
}
Code goes in function.php file of your active child theme (or active theme). Tested and works.
I'm trying to add a custom URL on the "Proceed to checkout" button for a specific product category.
I've successfully added a custom URL on it by using the following code, however now I want to show a different URL based on the products, in the cart.
add_filter('woocommerce_get_checkout_url', 'dj_redirect_checkout');
function dj_redirect_checkout($url) {
global $woocommerce;
if(is_cart()){
$checkout_url = 'https://example.com';
}
else {
//other url or leave it blank.
}
return $checkout_url;
}
For example, I've two categories (Tradeline 1 & Tradeline 2) on my WooCommerce website. I would like to place a different URL on the "Proceed to checkout" button for the other category if it is in the cart.
Any help would be appreciated.
Thank You So Much.
you should loop through cart items and check if any item has one of the terms you wanna target. You should use slugs of "Tradeline 1", "Tradeline 2", probably it is "tradeline-1".
Here is a quick POC:
$cat_in_cart = false;
foreach ( WC()->cart->get_cart() as $cart_item_key => $cart_item ) {
$product = $cart_item['data'];
if ( has_term( 'tradeline-1', 'product_cat', $product->get_id() ) ) {
$cat_in_cart = true;
break;
}
}
if( $cat_in_cart == true ) // do stuff
Useful reference: https://businessbloomer.com/woocommerce-check-product-category-cart/
Cheers!
I am adding two different products in my website and they both combines together to form one single product, what i am trying to achieve is that when i click on the add to cart button, I want to send two product id's to "add to cart" which means two different products, one is the page from where the a"dd to cart" is clicked and the second one is manual product id which i've assigned to hidden text box.
I tried the ajax call but that didn't work. Also I don't want to go with woocommerce paid extensions for bundle products and other types.
So it would be great if i can make some changes to add to cart.
Try something simple, like "Woocommerce Free Gift" plugin, there is a free version as well. You can setup automatic product add to cart on certain circumstances.
Otherwise, you need to modify your functions.php, whenever you are adding "product A" -> add "product B". Something likes this:
add_action( 'init', 'add_product_to_cart' );
function add_product_to_cart() {
if ( ! is_admin() ) {
global $woocommerce;
$product_id = ID_OF_PRODUCT_A;
$product_b = ID_OF_PRODUCT_B;
$found = false;
if( $woocommerce->cart->total > 0 ) {
//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( $product_b );
} else {
// do something
}
}
}
}
I need to programmatically and dynamically change the price of an item in the cart.
I’ve tried varying combinations of Woocommerce action hooks, the cart and session objects, but nothing quite seems to do the trick. I thought this wouldn’t be so challenging.
add_action( 'woocommerce_before_calculate_totals', 'change_cart_item_price' );
function change_cart_item_price( $cart_object ) {
foreach ( $cart_object->cart_contents as $key => $value ) {
if( 123 == $value['data']->id ) {
$new_price = function_to_get_new_price( $value, get_current_user_id( ) );
$value['data']->price = $new_price;
}
}
}
The above code changes the price for each item only on the checkout page, or when updating the cart (ie: the hook is called when removing an item from the cart), but not indefinitely.
I'm using the Woocommerce Gravity Forms add-on. I have one product in particular, which will be ordered multiple times by a given user. The user will be allowed 5x free with only shipping fees, and each above 5 will be $20. I have this much coded and functional with Gravity Forms hooks that dynamically populate fields. Shipping is specific to fields within the gravity form, therefore I am leaving that calculation to Gravity Forms.
My issue is that if a user reduces the quantity of this product from their order (removes one of the items from the cart), it should re-calculate the price of each item of the same product within the cart, otherwise they could be over-charged (an item that used to be the 6th is now the 4th, but the price remains the same, which it shouldn't)
Therefore, I would like to re-calculate the price of each item in the cart, based on the quantity of this particular product, every time something is removed from the cart.
--- EDIT ---
The above code works, but I'm realizing the issue must be a custom loop I'm using to display the prices...
foreach ( WC()->cart->get_cart() as $cart_item_key => $cart_item ) {
$_product = $cart_item['data'];
if( 123 == $_product->post->ID ) {
$price_not_updated = $cart_item['data']->price;
}
}
I figured it out... I looked at the woocommerce cart docs and essentially realized that the prices I was getting had yet to be calculated. So, before running the loop, I had to do the action that I was initially hooking into to change the prices.
Thanks for your help!
function getUpdatedCartPrices() {
do_action( 'woocommerce_before_calculate_totals', WC()->cart );
$horray_updated_prices_works = array();
foreach ( WC()->cart->get_cart() as $cart_item_key => $cart_item ) {
$_product = $cart_item['data'];
if( 123 == $_product->post->ID ) {
$horray_updated_prices_works[] = $cart_item['data']->price;
}
}
}
I changed the function to have a second parameter so that you can use it dynamically with any product as long as you call the proper id. I also set the function return value to either a success or error message. This way you can know if it was changed, and if so, to what price. Hope this helps.
by the way, having this function called again when the cart is updated should solve the recalculation issue. It would be great if i could see the code for your $function_to_get_new_price() function.
add_action( 'woocommerce_before_calculate_totals', 'change_cart_item_price' );
function change_cart_item_price($id, $cart_object ) {
foreach ( $cart_object->cart_contents as $key => $value ) {
if( $id == $value['data']->id ) {
$new_price = function_to_get_new_price( $value, get_current_user_id( ) );
$value['data']->price = $new_price;
$successMsg = "The price of item $value['data']->id was set to $value['data']->price".;
return $successMsg;
}else{
$errorMsg = "Price was not changed!";
return $errorMsg;
}
}
}