New cart item price based on a GET parameter in Woocommerce - php

There is a field on the main page with a numerical parameter:
length
and button - add to cart like:
add to cart
I would like to calculate the price of the goods from this parameter.
I understood how to change the price when adding to the basket but I can not understand how to transfer the numerical parameter of the field to the function in functions.php
The biggest problem is that the field is not on the single product page.
I think that you can pass a parameter through a link by type:
add to cart
But I could not get it in function yet.
add_action( 'woocommerce_before_shipping_calculator', 'add_custom_price' );
global $woocommerce;
foreach ( WC()->cart->get_cart() as $cart_item_key => $cart_item ) {
if($cart_item['data']->id == ####){
$original_price = $cart_item['data']->price;
$length = $_GET('length');
$new_price = $original_price + $length;
$cart_item['data']->set_price($new_price);
}
}
}

Using the following 2 hooked functions will allow you to set a new cart item price calculated on a Get "length" parameter this way:
// Set custom text and calculated price as custom cart data in the cart item
add_filter( 'woocommerce_add_cart_item_data', 'save_new_price_in_cart_object', 30, 3 );
function save_new_price_in_cart_object( $cart_item_data, $product_id, $variation_id ) {
if( ! isset( $_GET['length'] ) )
return $cart_item_data;
// Get an instance of the WC_Product object
$product = $variation_id > 0 ? wc_get_product($variation_id) : wc_get_product($product_id);
$product_price = (float) $product->get_price(); // Get the product price
// Get lenght
$length = esc_attr( $_GET['length'] );
// Set the new calculated price as custom cart data for the cart item
$cart_item_data['custom_data']['price'] = $product_price + $length;
return $cart_item_data;
}
// Set the new calculated price of the cart item
add_action( 'woocommerce_before_calculate_totals', 'set_new_cart_item_price', 90, 1 );
function set_new_cart_item_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 ) {
if( isset( $cart_item['custom_data']['price'] ) ) {
// Get the new calculated price
$new_price = (float) $cart_item['custom_data']['price'];
// Set the new calculated price
$cart_item['data']->set_price( $new_price );
}
}
}
Code goes in function.php file of your active child theme (or active theme).
Tested and works

Related

Apply a discount based on ACF field to cart total in WooCommerce

I'm trying to create a discount programmatically for orders on my store. My users have a variable discount rate e.g. 10%. I want to apply their discount to the order before checkout, however, some items in the store are not applicable for a discount.
These items have a toggle set so I can check which products do or do not allow the discount to be applied.
Currently, I'm looping through the order to check which items are applicable and using a 'fixed_cart'coupon to add the discount.
This works, however, the in the admin the coupon applies to all line items even the items which should be skipped. Making it impossible to work how much to refund to customers when a refund is required.
Checking the cart items
$tradeDiscountTotal = 0;
foreach( WC()->cart->get_cart() as $cart_item ) {
if(!get_field('trade_discount_exempt', $cart_item['product_id'])) {
$tradeDiscountTotal += $cart_item['line_subtotal'];
}
}
Applying the total discount for this order
$coupon->set_discount_type('fixed_cart');
$coupon->set_amount($tradeDiscountTotal);
return $coupon;
How can I create a bespoke discount for each order and ensure the products that are discounted are represented correctly in the admin area?
UPDATE
A solution is to create a coupon manually with a percentage discount with for example 10%.
Then we add the following codes based on the couponcode
First part to ensure that a discount of 0 is applied to products that meet the condition
Second part to ensure that the coupon is automatically added to the shopping cart
So we get:
Discount amount on trade_discount_exempt = 0
function filter_woocommerce_coupon_get_discount_amount( $discount, $price_to_discount , $cart_item, $single, $coupon ) {
// Product ID in cart
$product_id = $cart_item['product_id'];
// If 'trade_discount_exempt'
if ( get_field( 'trade_discount_exempt', $product_id ) ) {
$discount = 0;
}
return $discount;
}
add_filter( 'woocommerce_coupon_get_discount_amount', 'filter_woocommerce_coupon_get_discount_amount', 10, 5 );
Apply coupon programmatically if NOT trade_discount_exempt in cart
function action_woocommerce_before_calculate_totals( $cart ) {
if ( is_admin() && ! defined( 'DOING_AJAX' ) )
return;
if ( did_action( 'woocommerce_before_calculate_totals' ) >= 2 )
return;
// Only cart
if( ! is_cart() )
return;
// Coupon code
$coupon_code = 'testcoupon';
// Format
$coupon_code = wc_format_coupon_code( $coupon_code );
// Iterating though each cart items
foreach ( $cart->get_cart() as $cart_item_key => $cart_item ) {
// Product ID in cart
$product_id = $cart_item['product_id'];
// NOT 'trade_discount_exempt'
if ( ! get_field( 'trade_discount_exempt', $product_id ) ) {
// Applied coupons
$applied_coupons = $cart->get_applied_coupons();
// Is applied
$is_applied = in_array( $coupon_code, $applied_coupons );
// NOT applied
if ( ! $is_applied ) {
// Apply
$cart->apply_coupon( $coupon_code );
break;
}
}
}
}
add_action( 'woocommerce_before_calculate_totals', 'action_woocommerce_before_calculate_totals', 10, 1 );
Optional: Here are 2 other possible solutions:
1. Use the woocommerce_calculated_total filter hook, apply a discount globally on cart
function filter_woocommerce_calculated_total( $total, $cart ) {
// Discount (percentage)
$percentage = 10; // 10 %
// Set variable, used in loop
$new_total = 0;
// Iterating though each cart items
foreach ( $cart->get_cart() as $cart_item_key => $cart_item ) {
// Product ID in cart
$product_id = $cart_item['product_id'];
// NOT 'trade_discount_exempt'
if( ! get_field( 'trade_discount_exempt', $product_id ) ) {
// Product price
$price = $cart_item['data']->get_price();
// Caclulate new price
$new_price = $price * ( 1 - ( $percentage / 100 ) );
// Add new price to new total
$new_total += $new_price;
}
}
// New total greater than
if ( $new_total > 0 ) {
$total = $new_total;
}
return $total;
}
add_filter( 'woocommerce_calculated_total', 'filter_woocommerce_calculated_total', 10, 2 );
2. Use the woocommerce_before_calculate_totals action hook, grant the discount on the product price
function action_woocommerce_before_calculate_totals( $cart ) {
if ( is_admin() && ! defined( 'DOING_AJAX' ) )
return;
if ( did_action( 'woocommerce_before_calculate_totals' ) >= 2 )
return;
// Discount (percentage)
$percentage = 10; // 10 %
// Iterating though each cart items
foreach ( $cart->get_cart() as $cart_item_key => $cart_item ) {
// Product ID in cart
$product_id = $cart_item['product_id'];
// NOT 'trade_discount_exempt'
if( ! get_field( 'trade_discount_exempt', $product_id ) ) {
// Product price
$price = $cart_item['data']->get_price();
// Caclulate new price
$new_price = $price * ( 1 - ( $percentage / 100 ) );
// Set price
$cart_item['data']->set_price( $new_price );
}
}
}
add_action( 'woocommerce_before_calculate_totals', 'action_woocommerce_before_calculate_totals', 10, 1 );

Overwrite cart item title and price from Toolset CRED form data in Woocommerce

I'm trying to overwrite the price for a product in the WooCommerce cart.
The problem is that I'm using Divi which includes an ajax cart update. So when I reload the checkout page I can see my overwritten changes for 1-2 seconds (during the ajax loading) and after this the cart details get overwritten again by the default values. I've tried everythink, different hooks, delays, priority changes but nothing works.
This is my initial code:
add_filter( 'woocommerce_calculate_totals', 'custom_cart_items_prices', 1000, 1 )
function custom_cart_items_prices( $cart_object ) {
$title = $_GET['form-title'];
$money = $_GET['money'];
if ($title && $money) {
if ( is_admin() && ! defined( 'DOING_AJAX' ) )
return;
// Iterating through cart items
foreach ( $cart_object->get_cart() as $cart_item ) {
// Get an instance of the WC_Product object
$wc_product = $cart_item['data'];
// Get the product name (WooCommerce versions 2.5.x to 3+)
$original_name = method_exists( $wc_product, 'get_name' ) ? $wc_product->get_name() : $wc_product->post->post_title;
// SET THE NEW NAME
$new_name = $title;
// Set the new name (WooCommerce versions 2.5.x to 3+)
if( method_exists( $wc_product, 'set_name' ) )
$wc_product->set_name( $new_name );
else
$wc_product->post->post_title = $new_name;
}
// Updated cart item price
$cart_item['data']->set_price( $money );
}}
Picture during the loading (Everything looks great):
When the loading is completed:
Update - I've also tried a different approach as I am using a custom form made with CRED Toolset and Toolset Woocommerce plugins where customer create a product with a custom title and price, adding to cart a default existing product (and redirected to checkout page). I am trying to replace the cart item title and price by the submitted form data.
Here is my code:
// Change the product ID
add_filter('cred_commerce_add_product_to_cart', function( $product_id, $form_id, $post_id ) {
error_log($form_id);
if( $form_id == 55 ) {
if (!session_id()) {
session_start();
}
$_SESSION['target_post_id'] = $post_id;
if(isset($_POST['product-id'])){
$product_id = $_POST['product-id'];
$_SESSION['target_post_id'] = $post_id;
}
}
return $product_id;
}, 20, 3);
// change the price in cart
add_action('woocommerce_before_calculate_totals', function(){
session_start();
if($form_id != 55 && !isset($_SESSION['target_post_id']))return;
global $woocommerce;
$post_id = $_SESSION['target_post_id'];
$price = 0;
foreach ( $woocommerce->cart->get_cart() as $key => $cart_item ) {
$product_id = $cart_item['data']->get_id();
$adult_price = get_post_meta($product_id, 'wpcf-prezzo-1', true);
$adult_num = get_post_meta($post_id, 'wpcf-adult-number', true);
$child_price = get_post_meta($product_id, 'wpcf-prezzo-2', true);
$child_num = get_post_meta($post_id, 'wpcf-children-number', true);
$price = $adult_price * $adult_num + $child_price * $child_num;
$cart_item['data']->set_price($price);
}
}, 999);
But it doesn't work either.
How can I get the submitted form data (custom title and price) and to overwrite the cart item title and price in Woocommerce?
Try the following instead as you are using the toolset plugin with a custom form, where you will use WC_Sessions to store the product ID and change the price:
add_filter( 'cred_commerce_add_product_to_cart', 'cred_commerce_add_product_to_cart', 20, 3 );
function cred_commerce_add_product_to_cart( $product_id, $form_id, $post_id ) {
if( $form_id == 55 && $post_id > 0 ) {
WC()->session->set( 'cp_id', $post_id );
}
return $product_id;
}
add_filter( 'woocommerce_add_cart_item_data', 'filter_add_cart_item_data', 30, 4 );
function filter_add_cart_item_data( $cart_item_data, $product_id, $variation_id ){
if ( WC()->session->get('cp_id') ) {
$cp_id = WC()->session->get('cp_id');
$product = wc_get_product($cp_id);
$cart_item_data['cp_price'] = $product->get_regular_price();
$cart_item_data['cp_title'] = $product->get_title();
}
return $cart_item_data;
}
add_action( 'woocommerce_before_calculate_totals', 'custom_cart_items_price', 30, 1 );
function custom_cart_items_price( $cart ) {
if ( is_admin() && ! defined( 'DOING_AJAX' ) )
return;
if ( did_action( 'woocommerce_before_calculate_totals' ) >= 2 )
return;
// Iterating through cart items
foreach ( $cart->get_cart() as $cart_item ) {
if( isset($cat_item['cp_price']) && isset($cat_item['cp_title']) ){
$cart_item['data']->set_price( $cat_item['cp_price'] );
$cart_item['data']->set_name( $cat_item['cp_title'] );
}
}
}
Code goes in function.php file of your active child theme (or active theme). It should works.
Some related answers:
Set cart item price from a hidden input field custom price in Woocommerce 3
Custom cart item price based on user input in Woocommerce
Conditionally alter specific product price in Woocommerce
Change cart item prices in Woocommerce 3
Deactivate all of your plugins and voila!
You will suprisingly understand that its a cause of one.
Enabling them one by one back, will let you know which one is conflicting.
And.. Please consider using WordPress stack exchange for WordPress-specific questions.
1 woocommerce_add_cart_item_data
add_filter( 'woocommerce_add_cart_item_data', function($cart_item_data, $product_id, $variation_id ){
if ( empty( $_GET['form-title'] ) || empty( $_GET['money'] ) ) {
return;
}
$title = $_GET['form-title'];
$money = $_GET['money'];
$cart_item_data['form-title'] = $title ;
$cart_item_data['money'] = $money ;
return $cart_item_data;
} ,100,4);
2 woocommerce_before_calculate_totals
add_action( 'woocommerce_before_calculate_totals', 'update_custom_price', 10, 1 );
function update_custom_price( $cart_object ) {
if ( is_admin() && ! defined( 'DOING_AJAX' ) ) {
return;
}
foreach ( $cart_object->cart_contents as $cart_item_key => $cart_item ) {
if(isset($cart_item["money"]) ){
$money = $cart_item["money"] ;
$cart_item['data']->set_price( $money);
}
if(isset($cart_item["form-title"]) ){
$title = $cart_item["form-title"] ;
}
$wc_product = $cart_item['data'];
// Get the product name (WooCommerce versions 2.5.x to 3+)
$original_name = method_exists( $wc_product, 'get_name' ) ? $wc_product->get_name() : $wc_product->post->post_title;
// SET THE NEW NAME
$new_name = $title;
// Set the new name (WooCommerce versions 2.5.x to 3+)
if( method_exists( $wc_product, 'set_name' ) )
$wc_product->set_name( $new_name );
else
$wc_product->post->post_title = $new_name;
}
}
return $cart_object ;
}
Hope this will help.

Automatically recalculate quantity when clicking on update cart in Woocommerce

So by using the docs on the WooCommerce site I've been able to add a new product to the basket automatically which works great.
I calculate the number of products by taking the current quantity in the cart and multiplying it by a percentage modifier, this also works.
My problem comes when I update the cart with a new quantity as the bonus product quantity doesn't get updated.
add_action( 'template_redirect', 'add_product_to_cart' );
function add_product_to_cart() {
if ( ! is_admin() ) {
$product_id = 265;
$found = false;
// Get the current cart quantity
foreach ( WC()->cart->get_cart() as $cart_item ) {
$quantity = $cart_item['quantity'];
$percentage = .25;
$bonus = $quantity * $percentage;
}
//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, $bonus );
} else {
// if no products in cart, add it
WC()->cart->add_to_cart( $product_id, $bonus );
}
}
}
Does anyone have an idea on how to get this to automatically recalculate when update cart is clicked?
Preliminary remarks:
Your code doesn't work when cart is empty as $bonus variable is not defined and you get an error…
Also as you are setting a variable float number for quantity: So if the quantity is not an integer, customer can't change and update the cart items quantities.
This is kind of complex, your bonus quantity need to be updated in another hooked function when:
A product is added to cart
Customer update quantities in cart page
Customer remove items from cart
Also, there is small errors like $_product->id that should instead $_product->get_id() in WC 3+
So your revisited code with additional hooked functions will be:
add_action( 'template_redirect', 'auto_add_product_to_cart', 50 );
function auto_add_product_to_cart() {
if ( ! is_admin() ) {
$cart = WC()->cart; // <== Cart object
$product_id = 37; // <== Specific product to be auto added
$bonus_rate = .25; // <== Bonus rate
$found = false;
// Check if product already in cart
if ( ! $cart->is_empty() ) {
$contents_count = $cart->get_cart_contents_count(); // The cart items count
$bonus_qty = $contents_count * $bonus_rate; // Bonus quantity calculation
// Loop through cart items
foreach ( $cart->get_cart() as $cart_item ) {
if ( $cart_item['data']->get_id() == $product_id ){
$found = true;
break; // Stop the loop
}
}
// Product is not found in the loop, we add it
if( ! $found )
$cart->add_to_cart( $product_id, $bonus_qty );
} else {
// There is no items in cart, we add it
$cart->add_to_cart( $product_id, $bonus_rate );
}
}
}
// Calculate, set and update bonus quantity
add_action( 'woocommerce_before_calculate_totals', 'conditional_bonus_quantity_calculation', 20, 1 );
function conditional_bonus_quantity_calculation( $cart ) {
if ( is_admin() && ! defined( 'DOING_AJAX' ) )
return;
if ( did_action( 'woocommerce_before_calculate_totals' ) >= 2 )
return;
$bonus_rate = .25; // <== Bonus rate
$product_id = 37; // <== Specific product to be auto added
$contents_count = $cart->get_cart_contents_count(); // Total cart items count
// Loop through cart items to check our specific product
foreach ( $cart->get_cart() as $cart_item_key => $cart_item ) {
// If specific product is in cart
if ( $cart_item['data']->get_id() == $product_id ){
$calc_qty = $cart_item['quantity'] < 1 ? 1 : $cart_item['quantity'];
// Bonus quantity calculation
if( $contents_count > 1 )
$bonus_qty = round( $contents_count - $calc_qty ) * $bonus_rate;
else
$bonus_qty = $bonus_rate;
// Update item quantity
$cart->set_quantity( $cart_item_key, $bonus_qty, false );
}
}
}
// Allowing float numbers quantity (step by .25) for a specific product
add_filter( 'woocommerce_quantity_input_args', 'custom_quantity_input_args', 20, 2 );
function custom_quantity_input_args( $args, $product ) {
// Only for your specific product ID on cart page
if( $product->get_id() != 37 && is_cart() ) return $args;
//$args['input_value'] = 0.25; // Default starting value (Optional)
$args['min_value'] = 0.25;
$args['step'] = 0.25;
$args['pattern'] = '[0-9.]*';
$args['inputmode'] = 'numeric';
return $args;
}
// Allowing float numbers in Stock management
remove_filter('woocommerce_stock_amount', 'intval');
add_filter('woocommerce_stock_amount', 'floatval');
Code goes in function.php file of the active child theme (or active theme).
Tested and works.

Updating woocommerce price when added to cart [duplicate]

I have set up a hidden input item using woocommerce_before_add_to_cart_button hook
function add_gift_wrap_field() {
?>`<input type="hidden" id="price_val" name="added_price" value="100.34">`<?php
}
add_action( 'woocommerce_before_add_to_cart_button', 'add_gift_wrap_field' );
Saving fields against the product:
function save_gift_wrap_fee( $cart_item_data, $product_id ) {
if( isset( $_POST['added_price'] ) ) {
$cart_item_data = array();
$cart_item_data[ "gift_wrap_fee" ] = "YES";
$cart_item_data[ "gift_wrap_price" ] = 100;
}
return $cart_item_data;
}
add_filter( 'woocommerce_add_cart_item_data', 'save_gift_wrap_fee', 99, 2 );
Now I can echo out the $_POST['added_price'] inside this woocommerce_before_calculate_totals hook.
The code I written is shown below:
function calculate_gift_wrap_fee( $cart_object ) {
if( !WC()->session->__isset( "reload_checkout" )) {
/* Gift wrap price */
$additionalPrice = number_format($_POST['added_price'], 2);
$additionalPrice = floatval($additionalPrice);
//echo $additionalPrice; exit(); shows the value
foreach ( $cart_object->cart_contents as $key => $value ) {
if( isset( $value["gift_wrap_fee"] ) ) {
/* Woocommerce 3.0 + */
$orgPrice = floatval( $value['data']->get_price() );
$value['data']->set_price( $orgPrice + $additionalPrice ); //not adding the $additionalPrice here.
}
}
}
}
add_action( 'woocommerce_before_calculate_totals', 'calculate_gift_wrap_fee', 99 );
What am I doing wrong here?
Here is the complete clean, tested and working solution based on your code question.
Here I have included your custom field key/value in the cart object for the related cart item, instead of getting the Post value in your calculate_gift_wrap_fee() function.
This way it's not possible to loose the custom field value and the new price calculation is reliable.
I have commented 'gift_wrap_fee' and 'gift_wrap_price' as they are not really needed now (but you can uncomment them if you like).
Here is this code:
// The hidden product custom field
add_action( 'woocommerce_before_add_to_cart_button', 'add_gift_wrap_field' );
function add_gift_wrap_field() {
?>
<input type="hidden" id="price_val" name="added_price" value="100.34">
<?php
}
// Adding the custom field to as custom data for this cart item in the cart object
add_filter( 'woocommerce_add_cart_item_data', 'save_custom_fields_data_to_cart', 10, 2 );
function save_custom_fields_data_to_cart( $cart_item_data, $product_id ) {
$bool = false;
$data = array();
if( ! empty( $_REQUEST['added_price'] ) ) {
$cart_item_data['custom_data']['added_price'] = $_REQUEST['added_price'];
// Below this 2 values are not really needed (I think)
// (You can uncomment them if needed)
## $cart_item_data['custom_data']['gift_wrap_fee'] = 'YES';
## $cart_item_data['custom_data']['gift_wrap_price'] = 100;
// below statement make sure every add to cart action as unique line item
$cart_item_data['custom_data']['unique_key'] = md5( microtime().rand() );
WC()->session->set( 'custom_data', $data );
}
return $cart_item_data;
}
// Changing the cart item price based on custom field calculation
add_action( 'woocommerce_before_calculate_totals', 'calculate_gift_wrap_fee', 10, 1 );
function calculate_gift_wrap_fee( $cart ) {
if ( is_admin() && ! defined( 'DOING_AJAX' ) )
return;
if ( did_action( 'woocommerce_before_calculate_totals' ) >= 2 )
return;
// Iterating though cart items
foreach ( $cart->get_cart() as $cart_item ) {
// Continue if we get the custom data for the current cart item
if( ! empty( $cart_item['custom_data'] ) ){
// Get the custom field "added price" value
$added_price = number_format( $cart_item['custom_data']['added_price'], 2 );
// The WC_Product object
$product = $cart_item['data'];
// Get the price (WooCommerce versions 2.5.x to 3+)
$product_price = method_exists( $product, 'get_price' ) ? floatval(product->get_price()) : floatval($product->price);
// New price calculation
$new_price = $product_price + $added_price;
// Set the calculeted price (WooCommerce versions 2.5.x to 3+)
method_exists( $product, 'set_price' ) ? $product->set_price( $new_price ) : $product->price = $new_price;
}
}
}
Code goes in function.php file of your active child theme (or theme) or also in any plugin file.
This code is tested and works on WooCommerce versions from 2.5.x to 3+.

WooCommerce Price overriding not working

I have set up a hidden input item using woocommerce_before_add_to_cart_button hook
function add_gift_wrap_field() {
?>`<input type="hidden" id="price_val" name="added_price" value="100.34">`<?php
}
add_action( 'woocommerce_before_add_to_cart_button', 'add_gift_wrap_field' );
Saving fields against the product:
function save_gift_wrap_fee( $cart_item_data, $product_id ) {
if( isset( $_POST['added_price'] ) ) {
$cart_item_data = array();
$cart_item_data[ "gift_wrap_fee" ] = "YES";
$cart_item_data[ "gift_wrap_price" ] = 100;
}
return $cart_item_data;
}
add_filter( 'woocommerce_add_cart_item_data', 'save_gift_wrap_fee', 99, 2 );
Now I can echo out the $_POST['added_price'] inside this woocommerce_before_calculate_totals hook.
The code I written is shown below:
function calculate_gift_wrap_fee( $cart_object ) {
if( !WC()->session->__isset( "reload_checkout" )) {
/* Gift wrap price */
$additionalPrice = number_format($_POST['added_price'], 2);
$additionalPrice = floatval($additionalPrice);
//echo $additionalPrice; exit(); shows the value
foreach ( $cart_object->cart_contents as $key => $value ) {
if( isset( $value["gift_wrap_fee"] ) ) {
/* Woocommerce 3.0 + */
$orgPrice = floatval( $value['data']->get_price() );
$value['data']->set_price( $orgPrice + $additionalPrice ); //not adding the $additionalPrice here.
}
}
}
}
add_action( 'woocommerce_before_calculate_totals', 'calculate_gift_wrap_fee', 99 );
What am I doing wrong here?
Here is the complete clean, tested and working solution based on your code question.
Here I have included your custom field key/value in the cart object for the related cart item, instead of getting the Post value in your calculate_gift_wrap_fee() function.
This way it's not possible to loose the custom field value and the new price calculation is reliable.
I have commented 'gift_wrap_fee' and 'gift_wrap_price' as they are not really needed now (but you can uncomment them if you like).
Here is this code:
// The hidden product custom field
add_action( 'woocommerce_before_add_to_cart_button', 'add_gift_wrap_field' );
function add_gift_wrap_field() {
?>
<input type="hidden" id="price_val" name="added_price" value="100.34">
<?php
}
// Adding the custom field to as custom data for this cart item in the cart object
add_filter( 'woocommerce_add_cart_item_data', 'save_custom_fields_data_to_cart', 10, 2 );
function save_custom_fields_data_to_cart( $cart_item_data, $product_id ) {
$bool = false;
$data = array();
if( ! empty( $_REQUEST['added_price'] ) ) {
$cart_item_data['custom_data']['added_price'] = $_REQUEST['added_price'];
// Below this 2 values are not really needed (I think)
// (You can uncomment them if needed)
## $cart_item_data['custom_data']['gift_wrap_fee'] = 'YES';
## $cart_item_data['custom_data']['gift_wrap_price'] = 100;
// below statement make sure every add to cart action as unique line item
$cart_item_data['custom_data']['unique_key'] = md5( microtime().rand() );
WC()->session->set( 'custom_data', $data );
}
return $cart_item_data;
}
// Changing the cart item price based on custom field calculation
add_action( 'woocommerce_before_calculate_totals', 'calculate_gift_wrap_fee', 10, 1 );
function calculate_gift_wrap_fee( $cart ) {
if ( is_admin() && ! defined( 'DOING_AJAX' ) )
return;
if ( did_action( 'woocommerce_before_calculate_totals' ) >= 2 )
return;
// Iterating though cart items
foreach ( $cart->get_cart() as $cart_item ) {
// Continue if we get the custom data for the current cart item
if( ! empty( $cart_item['custom_data'] ) ){
// Get the custom field "added price" value
$added_price = number_format( $cart_item['custom_data']['added_price'], 2 );
// The WC_Product object
$product = $cart_item['data'];
// Get the price (WooCommerce versions 2.5.x to 3+)
$product_price = method_exists( $product, 'get_price' ) ? floatval(product->get_price()) : floatval($product->price);
// New price calculation
$new_price = $product_price + $added_price;
// Set the calculeted price (WooCommerce versions 2.5.x to 3+)
method_exists( $product, 'set_price' ) ? $product->set_price( $new_price ) : $product->price = $new_price;
}
}
}
Code goes in function.php file of your active child theme (or theme) or also in any plugin file.
This code is tested and works on WooCommerce versions from 2.5.x to 3+.

Categories