By default when woocommerce cart quantity is changed it updates the item price by multiplying it by the quantity. I would like to change the default behaviour and ensure that when in the cart when the quantity is changed it doesnt change the default price passed when add to cart is clicked
I have added this action hook but i cannot figure out how to stop price change when quantity is changed in a cart.
add_action( 'woocommerce_after_cart_item_quantity_update', 'on_quantity_changed_in_cart', 20, 4 );
function on_quantity_changed_in_cart( $cart_item_key, $quantity, $old_quantity, $cart){
if( ! is_cart() ) return; // Only on cart page
//here stop price from been changed by default
}
Looking to "Disable Woocommerce cart line item quantity price calculation" answer thread, I found out I need to override an action hook to replace the final cost per line:
add_filter('woocommerce_cart_product_subtotal', [$this, 'filter_woocommerce_cart_product_subtotal'], 10, 4);
public function filter_woocommerce_cart_product_subtotal($product_subtotal, $product, $quantity, $cart){
$sub_value = 0;
foreach ($cart->cart_contents as $hash => $value) {
if ($value["product_id"] === wc_get_product($product)->get_id()) {
$sub_value = $value["wcform-custom_price"];
//wcform-custom_price is passed from when adding to the cart.
}
};
return wc_price($sub_value);
}
Now on the totals as well I overriden the following
add_action( 'woocommerce_calculate_totals', [$this,'custom_item_price'],20,1);
add_filter( 'woocommerce_calculated_total', [$this,"calculateFinalTotal"], 20, 2 );
public function custom_item_price( $wc_cart ) {
$cart_contents_total = 0;
foreach ( $wc_cart->get_cart() as $cart_item_key => $cart_item ){
$cart_contents_total += $cart_item["wcform-custom_price"];
}
$wc_cart->subtotal = $cart_contents_total;
}
public function calculateFinalTotal($total,$cart){
$cart_contents_total = 0;
foreach ( $cart->get_cart() as $cart_item_key => $cart_item ){
$cart_contents_total += $cart_item["wcform-custom_price"];
}
return $cart_contents_total;;///print_r($cart->get_cart());
}
Related
I´m running a WooCommerce (WordPress 6.1.1 and WooCommerce 7.3.0), and I´m trying to set prices according to the user role.
To do this I have introduced a new field named Webprice (precio_web) in product definition using the plugin: "Advanced Custom Fields". Customer users and not logged users must use this special price.
Also I added this code in my functions.php child-theme:
add_filter('woocommerce_product_get_price', 'ui_custom_price_role', 99, 2);
add_filter('woocommerce_product_get_regular_price', 'ui_custom_price_role', 99, 2);
add_filter('woocommerce_product_variation_get_regular_price', 'ui_custom_price_role', 99, 2);
add_filter('woocommerce_product_variation_get_price', 'ui_custom_price_role', 99, 2);
function ui_custom_price_role($price, $product) {
$price = ui_custom_price_handling($price, $product);
return $price;
}
Variable add_filter('woocommerce_variation_prices_price', 'ui_custom_variable_price', 99, 3);
add_filter('woocommerce_variation_prices_regular_price', 'ui_custom_variable_price', 99, 3);
function ui_custom_variable_price($price, $variation, $product) {
$price = ui_custom_price_handling($price, $product);
return $price;
function ui_custom_price_handling($price, $product) {
//get our current user
$current_user = wp_get_current_user();
//check if the user role is the role we want or is not logged
if ((!is_user_logged_in()) || (isset($current_user - \ > roles\[0\]) && '' != $current_user - \ > roles\[0\] && in_array('customer', $current_user - \ > roles))) { //load the custom price for our product $custom_price = get_post_meta( $product-\>get_id(), 'precio_web', true );
// custom price
if (!empty($custom_price)) {
$price = $custom_price;
}
}
return $price;
}
}
So far It works, when adding items to the cart I can see the new price.
enter image description here
The problem is at checkout for some reason prices displayed are the standard, not the ones corresponding to the new field.
enter image description here
Any help is welcome. Thanks.
I was expecting that the modification of the get_price function was enough because the prices are displayed correctly. However, the order is recorded with the standard price of the item.
WooCommerce recalculates all prices during the checkout process multiple times, so you need to hook into this recalculation also. This should work for you:
add_action( 'woocommerce_before_calculate_totals', 'update_cart_price'), 99);
function update_cart_price( $cart ) {
if ( is_admin() && ! defined( 'DOING_AJAX' ) ) return;
if ( did_action( 'woocommerce_before_calculate_totals' ) >= 2 ) return;
foreach ( $cart->get_cart() as $cart_item_key => $cart_item ) {
$cart_item = $cart_item['data'];
$cart_item_product_id = $cart_item->get_id();
$product = wc_get_product( $cart_item_product_id );
$orig_price = $product->get_regular_price();
$new_price = ui_custom_price_handling( $orig_price, $product );
$cart_item->set_price( $new_price );
}
}
I would like to add items in the amount of product chosen by customer every time the add to cart button is clicked,
I tried to modify the number of products using woocommerce_add_to_cart_validation but with variable products it adds the variable product twice to the cart:
function so_validate_add_cart_item( $passed, $product_id, $quantity, $variation_id = '', $variations= '' ) {
global $product;
$product = new WC_Product($product_id);
if(!$variation_id) {
WC()->cart->add_to_cart( $product_id, ($quantity *3) - $quantity );
} else {
WC()->cart->add_to_cart( $variation_id, ($quantity *3) );
}
// do your validation, if not met switch $passed to false
return $passed;
}
add_filter( 'woocommerce_add_to_cart_validation', 'so_validate_add_cart_item', 10, 5 );
Not really an idea what your intention is, but you could use the following hook (not with ajax, check cart after applying)
function my_add_to_cart_quantity( $quantity, $product_id ) {
$quantity = $quantity * 3;
return $quantity;
}
add_filter( 'woocommerce_add_to_cart_quantity', 'my_add_to_cart_quantity', 10, 2 );
Currently i have some custom calculation of product price based on different situation. When customer added a product in to cart then the custom price is set in session data , cart_item_data['my-price'] and i implemented using add_filter( 'woocommerce_add_cart_item') function and everything seems to working now .
Now the price in view cart page, checkout page is correct with my cart_item_data['my-price'].
But the only problem i am facing is the price is not updated in woocommerce mini cart that is appeared in the menu ,How can i change this ?
When i google i see a filter
add_filter('woocommerce_cart_item_price');
but i can't understand how to use this i do the following
add_filter('woocommerce_cart_item_price','modify_cart_product_price',10,3);
function modify_cart_product_price( $price, $cart_item, $cart_item_key){
if($cart_item['my-price']!==0){
$price =$cart_item['my-price'];
}
return $price;
//exit;
}
Here individual price is getting correct , but total price is wrong
Updated (october 2021)
For testing this successfully (and as I don't know how you make calculations), I have added a custom hidden field in product add to cart form with the following:
// The hidden product custom field
add_action( 'woocommerce_before_add_to_cart_button', 'add_gift_wrap_field' );
function add_gift_wrap_field() {
global $product;
// The fake calculated price
?>
<input type="hidden" id="my-price" name="my-price" value="115">
<?php
}
When product is added to cart, this my-price custom field is also submitted (posted). To set this value in cart object I use the following function:
add_filter( 'woocommerce_add_cart_item', 'custom_cart_item_prices', 20, 2 );
function custom_cart_item_prices( $cart_item_data, $cart_item_key ) {
// Get and set your price calculation
if( isset( $_POST['my-price'] ) ){
$cart_item_data['my-price'] = $_POST['my-price'];
// Every add to cart action is set as a unique line item
$cart_item_data['unique_key'] = md5( microtime().rand() );
}
return $cart_item_data;
}
Now to apply (set) the new calculated price my-price to the cart item, I use this last function:
// For mini cart *(cart item displayed price)*
add_action( 'woocommerce_cart_item_price', 'filter_cart_item_price', 10, 2 );
function filter_cart_item_price( $price, $cart_item ) {
if ( ! is_checkout() && isset($cart_item['my-price']) ) {
$args = array( 'price' => floatval( $cart_item['my-price'] ) );
if ( WC()->cart->display_prices_including_tax() ) {
$product_price = wc_get_price_including_tax( $cart_item['data'], $args );
} else {
$product_price = wc_get_price_excluding_tax( $cart_item['data'], $args );
}
return wc_price( $product_price );
}
return $price;
}
add_action( 'woocommerce_before_calculate_totals', 'set_calculated_cart_item_price', 20, 1 );
function set_calculated_cart_item_price( $cart ) {
if ( is_admin() && ! defined( 'DOING_AJAX' ) )
return;
if ( did_action( 'woocommerce_before_calculate_totals' ) >= 2 )
return;
// Loop through cart items
foreach ( $cart->get_cart() as $cart_item ){
if( isset( $cart_item['my-price'] ) && ! empty( $cart_item['my-price'] ) || $cart_item['my-price'] != 0 ){
// Set the calculated item price (if there is one)
$cart_item['data']->set_price( $cart_item['my-price'] );
}
}
}
All code goes in function.php file of your active child theme (or active theme).
Tested and works
I would like to make a script for automatically adding a bonus product to WooCommerce cart.
The bonus product would be added into the cart on adding a specific product(s). But I've never seen any improved and fully working code with features - such as automatically removing the bonus item or removing the primary product(s) from the cart.
In this solution I've come up with the below code which has the following features:
Options
Multiple required products
Automatic adding
Automatic removing (if there's no required product in the cart)
function bonus_product() {
if (is_admin()) return;
//## OPTIONS
$options = (object) array(
'bonus_product_id' => 1891, //bonus product to add
'required_products_id' => array(1873), //at least on of the specific product(s) needs to be represented in the cart
);
//function variables
$cart_items = WC()->cart->get_cart();
$bonus_product_found = false;
$required_product_found = false;
//check if the cart is not empty
if(sizeof($cart_items) > 0) {
//checking for required products. loop through the cart items
foreach ($cart_items as $key => $item) {
//bonus product already in the cart?
if($item['product_id'] == $options->bonus_product_id) {
$bonus_product_found = true;
}
//one of required products in the cart?
if(in_array($item['product_id'], $options->required_products_id)) {
$required_product_found = true;
}
}
//adding/removing bonus product
//add bonus product to the cart
if(!$bonus_product_found && $required_product_found) {
WC()->cart->add_to_cart($options->bonus_product_id);
}
//remove bonus product from the cart if none of required items is in the cart
if($bonus_product_found && !$required_product_found) {
$cart = WC()->instance()->cart;
$cart_id = $cart->generate_cart_id($options->bonus_product_id);
$cart_item_id = $cart->find_product_in_cart($cart_id);
$cart->set_quantity($cart_item_id, 0);
}
}
}
add_action( 'init', 'bonus_product' );
I have written an alternative version, based on Add To Cart and Remove From Cart action, which seems to be more appropriate.
$bonus_options = (object) array(
'bonus_product_id' => 1891,
'required_products_id' => array( 1873 )
);
// this function called whenever there is a product added to cart
function add_bonus_product( $cart_item_key, $product_id, $quantity, $variation_id, $variation, $cart_item_data ) {
global $bonus_options;
// is the product is eligible for bonus product?
if( in_array( $product_id, $bonus_options->required_products_id) ) {
// add the bonus product to cart
WC()->cart->add_to_cart( $bonus_options->bonus_product_id, 1, 0, array(), array( "parent_product_line_item" => $cart_item_key ) );
// later if user removes the product from cart we can use the "parent_product_line_item" to remove the bonus product as well
}
}
add_action( 'woocommerce_add_to_cart', 'add_bonus_product', 10, 6 );
// this function will be called whenever there is a product removed from cart
function remove_bonus_product( $cart_item_key, $cart ) {
$cart_items = WC()->cart->get_cart();
foreach ( $cart_items as $key => $item ) {
if( $item["parent_product_line_item"] == $cart_item_key ) {
// ok this cart item is a bonus item to the product that being removed from the cart
// So remove this too
WC()->cart->remove_cart_item( $key );
}
}
}
add_action( 'woocommerce_cart_item_removed', 'remove_bonus_product', 10, 2 );
$replace_order = new WC_Cart();
$replace_order->empty_cart( true );
$replace_order->add_to_cart( "256", "1");
The above code add product 256 to the Cart 1 time. But the issue I'm having is that I want to be able to completely override the product price... as far as I can tell, the only thing I can do it apply a coupon to the Cart.
Is there a way to completely override the price to something totally custom?
Here is the code for overriding price of product in cart
add_action( 'woocommerce_before_calculate_totals', 'add_custom_price' );
function add_custom_price( $cart_object ) {
$custom_price = 10; // This will be your custome price
foreach ( $cart_object->cart_contents as $key => $value ) {
$value['data']->price = $custom_price;
// for WooCommerce version 3+ use:
// $value['data']->set_price($custom_price);
}
}
Hope it will be useful...
You need to introduce an if statement for checking product id, in above code:
add_action( 'woocommerce_before_calculate_totals', 'add_custom_price' );
function add_custom_price( $cart_object ) {
$custom_price = 10; // This will be your custome price
$target_product_id = 598;
foreach ( $cart_object->cart_contents as $value ) {
if ( $value['product_id'] == $target_product_id ) {
$value['data']->price = $custom_price;
}
/*
// If your target product is a variation
if ( $value['variation_id'] == $target_product_id ) {
$value['data']->price = $custom_price;
}
*/
}
}
Add this code anywhere and make sure that this code is always executable.
After adding this code, when you'll call:
global $woocommerce;
$woocommerce->cart->add_to_cart(598);
Only this product will be added with overridden price, other products added to cart will be ignored for overriding prices.
Hope this will be helpful.
I have tried all above code samples and latest woocommerce 3.0 is not support any of the above example. Use below code and working perfectly for me.
add_action( 'woocommerce_before_calculate_totals', 'add_custom_price' );
function add_custom_price( $cart_object ) {
$custom_price = 10; // This will be your custom price
foreach ( WC()->cart->get_cart() as $cart_item_key => $cart_item ) {
$cart_item['data']->set_price($custom_price);
}
}
After release of woocommerce version 3.0.0 product price is update on add to cart using set_price($price) function. The example is given as below :
add_action( 'woocommerce_before_calculate_totals', 'mj_custom_price' );
function mj_custom_price( $cart_object ) {
$woo_ver = WC()->version;
$custom_price = 10;
foreach ( $cart_object->cart_contents as $key => $value )
{
if($woo_ver < "3.0.0" && $woo_ver < "2.7.0")
{
$value['data']->price = $custom_price;
}
else
{
$value['data']->set_price($custom_price);
}
}
}
Many Thanks
For the Wordpress and Woocommerce latest version,Please use like this
add_action( 'woocommerce_before_calculate_totals', 'add_custom_price' );
function add_custom_price( $cart_object ) {
foreach ( $cart_object->cart_contents as $key => $value ) {
$custom_price = 5;
$value['data']->set_price($custom_price);
}
}
For eveeryone that got here from Google. The above is now deprecated as i found out updating to WooCommerce 3.0.1.
Instead of the above you now need to use set_price instead of price
Here is an example:
add_action( 'woocommerce_before_calculate_totals', 'add_custom_price' );
function add_custom_price( $cart_object ) {
$custom_price = 10; // This will be your custome price
foreach ( $cart_object->cart_contents as $key => $value ) {
$value['data']->set_price = $custom_price;
}
}
I hope this helps people in the future :)
This is how i did it, first i add my custom price to cart_item_data witch can save custom data to cart items, then i use woocommerce_before_calculate_totals, loop the cart and add the previously added price.
function add_donation_to_cart() {
$cart_item_data = array('price' => $_REQUEST['donate_amount']);
$woocommerce->cart->add_to_cart( 5395, 1, '', array(), $cart_item_data);
}
add_action( 'woocommerce_before_calculate_totals', 'add_custom_price' );
function add_custom_price( $cart ) {
foreach ( $cart->cart_contents as $key => $value ) {
$value['data']->price = $value['price'];
}
}
With WooCommerce 2.5 I found this to be a 2-part process. The first step is to change the run-time display of pricing when added to the cart via the woocommerce_add_cart_item filter. The second part is to set the persistent session data which is read during checkout via the woocommerce_get_cart_item_from_session filter. This seems to be faster than hooking the calculate totals filters (such as woocommerce_before_calculate_totals) as they are run very frequently in WooCommerce.
More details here:
woocommerce change price while add to cart
To make it dynamic ( override price for each item in cart separately ), you need to save the override product price in session with cart item key as session key using woocommerce_add_to_cart hook.
by using these session values you can calculate correct Cart Total and make the altered price appear in the Order Item as well
You can use the following
add_filter( 'woocommerce_cart_item_price', 'kd_custom_price_message' );
function kd_custom_price_message( $price ) {
$textafter = ' USD';
return $price . $textafter;
}