How to Alter Cart Contents in WooCommerce? - php

I am trying to remove particular product from cart via code. I only see the empty cart option which is clear all the product in cart, but i want to clear particular product in cart page.
For example:
Let say I have added two products to cart but i want cart behavior should be neither or nor mean only one product should be in cart.
If product 1 is in cart then product 2 should not allow to add in cart. If product 2 is in cart then product 1 should not allow.
I tried little set of code but i can't find the exact hook to do this actual behavior. What i am trying is instead of empty entire cart, I load the cart content which is in array of values just unset particular array using cart item key, and to load remaining content to cart. But looks like is not works for me.
function cf_alter_cart_content($value) {
global $woocommerce;
$cart_contents = $woocommerce->cart->get_cart();
foreach ($woocommerce->cart->get_cart() as $cart_item_key => $value) {
if ($value['product_id'] == '77') {
unset($cart_contents[$cart_item_key]);
unset($value['data']);
}
return $value['data'];
}
}
//add_action('wp_head', 'cf_alter_cart_content');
add_filter('woocommerce_cart_item_product', 'cf_alter_cart_content', 10, 1);
May be is there any easy way to achieve this? Not sure any suggestion would be great.

I'm using the woocommerce_before_cart filter for a similar setup where people in certain groups aren't allowed to order specific product skus. I hope this helps. You would likely want to create a custom field in each product that would be something like a comma delineated list of other skus/post_ids that it wouldn't be allowed to be ordered with.
This code checks the first group that the user is associated with (in my site's case they only ever have 1 group). The disallowed_product_skus is the list of skus that the group for the user isn't allowed to purchase.
$disallowed_product_skus = array (
<group_num> => array (
'<sku>',
)
);
add_filter ( 'woocommerce_before_cart' , 'cart_check_disallowed_skus' );
function cart_check_disallowed_skus() {
global $woocommerce;
global $disallowed_product_skus;
$assigned_group = GroupOperations::get_current_user_first_group();
$cart_contents = $woocommerce->cart->get_cart();
$keys = array_keys ( $cart_contents );
if ( array_key_exists ( $assigned_group , $disallowed_product_skus ) ) {
$disallowed_products_in_cart = false;
foreach ( $keys as $key ) {
$cart_item_product_id = $cart_contents[$key]['product_id'];
$cart_product_meta = get_post_meta ( $cart_item_product_id );
$cart_product_sku = $cart_product_meta['_sku'][0];
if ( in_array ( $cart_product_sku , $disallowed_product_skus[$assigned_group] ) ) {
$woocommerce->cart->set_quantity ( $key , 0 , true );
$disallowed_products_in_cart = true;
}
}
if ( $disallowed_products_in_cart ) {
echo '<p class="woocommerce-error">Non-approved products have been automatically removed from cart.</p>';
}
}
}

Related

Hide payment method if specific variation in Cart/Checkout | Woocommerce + Product Add-ons Plugin

I am using the https://woocommerce.com/products/product-add-ons/ plugin for adding the product addons on a whole category(on all its products). I have many options as addons on all particular category products like for Stitching, Matching addons, matching borders etc. as shown in the image below
I want to hide Cash on Delivery(COD) payment gateway if Matching Addons and Stitching are selected and are there in the cart/checkout.
Now, I have been facing difficulty finding any specific variation id to implement a solution like this: https://stackoverflow.com/a/68994195/9513172
Since in the cart/checkout, it shows with a dt class tag as shown in the image below:
Here test product link: here
After giving few hours to solve this problem, I came up with this solution for now:
add_filter('woocommerce_available_payment_gateways', 'xyz_conditional_payment_gateways', 10, 1);
function xyz_conditional_payment_gateways( $available_gateways ) {
$in_cart = false;
if ( !empty(WC()->cart) ) {
$cart_item = WC()->cart->get_cart();
$addons = array_values($cart_item)[0]['addons'];
foreach ( $addons as $subKey => $value ) {
if ($addons[$subKey]['name'] == "Stitching"){
$in_cart = true;
}
}
}
if ( $in_cart )
unset($available_gateways['cod']); // unset ‘cod’
return $available_gateways;
}

Why is this conditional removal of WooCommerce billing field not working?

I've got the following code in my functions.php file that is supposed to check if certain products are in the cart and, if they are, remove a field from the billing set of fields at checkout. However, it's not removing the field, or any other field I try. I'm wondering why that is. Other tutorials I'm following are consistent with this code and say it should work, but for me it's not. What did I get wrong?
/**
* Check if a specific product ID is in the cart
*/
function dz_product_is_in_the_cart() {
// Add your special product IDs here
$ids = array( '10771', '10773', '10774', '10943', '10944', '10945', '10946', '10947', '10948', '10949', '10950', '10951', '10952', '10953', '10943', '10943', '10943', '10943');;
// 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->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;
}
}
/**
* Conditionally remove a checkout field based on products in the cart
*/
function dz_remove_checkout_field( $fields ) {
if ( dz_product_is_in_the_cart() ) {
unset( $fields['billing']['billing_first_name'] );
}
return $fields;
}
add_filter( 'woocommerce_checkout_fields' , 'dz_remove_checkout_field' );
The billing_first_name field is a required field. So do I need to do something to unrequire it before I try to unset it?
The problem was a plugin that was inserting this field was overriding my code that tried to unrequire and remove it. I opted to disable the plugin and add and conditionally control my own field(s) with the code here: https://woocommerce.com/document/tutorial-customising-checkout-fields-using-actions-and-filters/#section-7

WooCommerce - Enable this to only allow one of this item to be bought in a single order

I tried to enable this option for a few items in the store, But It doesn’t work.
Option under Inventory tab - Enable this to only allow one of this item to be bought in a single order
I am still able to add other items in Cart.
PS: Sold individual means that multiple quantities of that product cannot be purchased in a single order. Other products can be purchased along with it.
add_filter( 'woocommerce_add_to_cart_validation', 'remove_all_other_if_individual' );
function remove_all_other_if_individual( $cart_item_data ) {
global $woocommerce;
$items = $woocommerce->cart->get_cart();
$is_sold_individual_incart = false;
foreach ( $items as $item => $values ) {
$_product = wc_get_product( $values[ 'data' ]->get_id() );
if ( $_product->is_sold_individually() )
$is_sold_individual_incart = TRUE;
}
if ( $is_sold_individual_incart )
$woocommerce->cart->empty_cart();
// Do nothing with the data and return
return true;
}

Sending Two Simple Product To Add To Cart In Single Woocommerce Button Click

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
}
}
}
}

Woocommerce: Programmatically Update Item In Cart

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;
}
}
}

Categories