I am trying to dynamically add to a products price when a user checks out based on what they have entered in the product page. The setting of the price is only working on a non variation product.
I need to be able to set the price on the variations of the products as well.
The code that I am using:
function add_cart_item_data( $cart_item_meta, $product_id, $variation_id ) {
$product = wc_get_product( $product_id );
$price = $product->get_price();
$letterCount = strlen($_POST['custom_name']);
$numberCount = strlen($_POST['custom_number']);
if($letterCount != '0') {
$letterPricing = 20 * $letterCount;
$numberPricing = 10 * $numberCount;
$additionalPrice = $letterPricing + $numberPricing;
$cart_item_meta['custom_price'] = $price + $additionalPrice;
}
return $cart_item_meta;
}
function calculate_cart_total( $cart_object ) {
if ( is_admin() && ! defined( 'DOING_AJAX' ) ) {
return;
}
foreach ( $cart_object->cart_contents as $key => $value ) {
if( isset( $value['custom_price'] ) ) {
$price = $value['custom_price'];
$value['data']->set_price( ( $price ) );
}
}
}
I have completely revisited your code:
// Set custom data as custom cart data in the cart item
add_filter( 'woocommerce_add_cart_item_data', 'add_custom_data_to_cart_object', 30, 3 );
function add_custom_data_to_cart_object( $cart_item_data, $product_id, $variation_id ) {
if( ! isset($_POST['custom_name']) || ! isset($_POST['custom_number']) )
return $cart_item_data; // Exit
if( $variation_id > 0)
$product = wc_get_product( $variation_id );
else
$product = wc_get_product( $product_id );
$price = $product->get_price();
// Get the data from the POST request and calculate new custom price
$custom_name = sanitize_text_field( $_POST['custom_name'] );
if( strlen( $custom_name ) > 0 )
$price += 20 * strlen( $custom_name );
$custom_number = sanitize_text_field( $_POST['custom_number'] );
if( strlen( $custom_number ) > 0 )
$price += 10 * strlen( $custom_number );
// Set new calculated price as custom cart item data
$cart_item_data['custom_data']['price'] = $price;
return $cart_item_data;
}
// Set the new calculated price of the cart item
add_action( 'woocommerce_before_calculate_totals', 'set_new_cart_item_price', 50, 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 );
}
}
}
This code goes on function.php file of your active child theme (or theme).
Tested and works as well with product variations.
Related
I have written a function that should add discount amounts on the woo cart, depends on product combination and custom fields.
If the action is wp_footer i can see get_post_meta works well.
But if I write action to be woocommerce_cart_calculate_fees seems not to work fine.
Can anyone help me with getting into the right direction? Thanks
Here is my code and screenshot below for it:
add_action('woocommerce_cart_calculate_fees', 'action_woocommerce_cart_calculate_fees2');
function action_woocommerce_cart_calculate_fees2($cart) {
// if ( is_admin() && ! defined( 'DOING_AJAX' ) )
// return;
//if ( did_action( 'woocommerce_before_calculate_totals' ) >= 1 )
//return;
//$cart = WC()->cart->get_cart();
foreach ( $cart as $cart_item_key => $cart_item ) {
// Get product id
$product_id = $cart_item['product_id'];
$product = wc_get_product($product_id);
//echo $product_id . "<br>";
$is_enable = get_post_meta( $product_id, '_enable_promo_for_current_product', true );
if ($is_enable == 'yes') {
$product_arr[] = $product_id;
}
}
foreach ( $product_arr as $val ) {
$product = wc_get_product($val);
$otstapka = get_post_meta( $val, '_procent_otstapka_promo', true );
if (empty($otstapka)) {
$otstapka = 10;
}
$value = get_post_meta( $val, 'wc_product_ids', true );
if ( ! empty( $value ) ) {
$promo_product = wc_get_product( $value );
$name = $promo_product->name;
$price = $promo_product->get_price();
$sale_price = $price * (1 - ($otstapka / 100));
$otstapka2 = $price - $sale_price;
$product_promo_id = $promo_product->get_id();
if ( check_variation_is_in_cart($val) ) {
$cart->add_fee('Отстъпка за промо пакет', -$otstapka2, false);
}
}
}
}
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.
We have some products in shop , and we are giving some coupons to customer .
product -> ABC price 10
coupon code is 'newcp' discount 20%;
so when people add the product to cart price will be 10 .
Then they apply coupon then original product price shown as 10 and calculate 20% from that and at the end the total will be 8
But now we need to change this as per specific condition
When people apply product coupon newbc
1)if coupon is newcp , then change order_item_price as order_item_price +3[ only if category is Fruit] , and this price should be shown in cart page, checkout page , order email
2)Calculate discount from the new price calculate discouunt from 13
3)If people remove coupon then price will again return to 10
I made 2 solutions , but not working.
Solution 1
add_action('woocommerce_before_calculate_totals', 'add_custom_price', 10, 1);
function add_custom_price($cart_obj)
{
if (is_admin() && !defined('DOING_AJAX')) return;
foreach($cart_obj->get_cart() as $key => $value)
{
$product_id = $value['product_id'];
$coupon_code = $value['coupon_code'];
if ($coupon_code != '' && $coupon_code == "newcp")
{
global $woocommerce;
if (WC()->cart->has_discount($coupon_code)) return;
else
{
if (has_term('fruits', 'product_cat', $product_id))
{
$value['data']->set_price(CURRENT_CART_PRICE + 3);
}
}
}
}
}
Solution 2
add_action( 'woocommerce_before_calculate_totals', 'add_custom_price', 10, 1);
function add_custom_price( $cart_object) {
global $woocommerce;
if ( is_admin() && ! defined( 'DOING_AJAX' ) )
return;
$coupon = False;
if ($coupons = WC()->cart->get_applied_coupons() == False )
$coupon = False;
else {
foreach ( WC()->cart->get_applied_coupons() as $code ) {
$coupon = $code;
}
}
if ($coupon == "newcp"){
foreach ( $cart_object->get_cart() as $cart_item )
{
$price = $cart_item['data']->price+3;
$cart_item['data']->set_price( $price );
}
}
}
Please help .
Here is a possible way to achieve that:
// Add custom calculated price conditionally as custom data to cart items
add_filter( 'woocommerce_add_cart_item_data', 'custom_add_cart_item_data', 20, 2 );
function custom_add_cart_item_data( $cart_item_data, $product_id ){
// Your settings below
$product_categories = array('fruits');
$addition = 3;
$product = wc_get_product($product_id);
$the_id = $product->is_type('variation') ? $product->get_parent_id() : $product_id;
if ( has_term( $product_categories, 'product_cat', $the_id ) )
$cart_item['custom_price'] = $product->get_price() + $addition;
return $cart_item;
}
// Set conditionally a custom item price
add_action('woocommerce_before_calculate_totals', 'add_custom_price', 20, 1);
function add_custom_price( $cart ) {
if ( is_admin() && ! defined( 'DOING_AJAX' ) )
return;
if ( did_action( 'woocommerce_before_calculate_totals' ) >= 2 )
return;
// Only for a DEFINED coupon code ( to be set below )
$coupon_code = 'newcp';
if ( ! $cart->has_discount( $coupon_code ) ) return;
foreach( $cart->get_cart() as $cart_item ) {
if ( isset($cart_item['custom_price']) ) {
$cart_item['data']->set_price( (float) $cart_item['custom_price'] );
}
}
}
Code goes in function.php file of the active child theme (or active theme). Tested and works.
I am unable to override price on second time purchase.
The use case would be: If a user has already bought product "944" then the price would be 0 for next time orders.
Meaning, the customer would pay only for first order of that specific product and it would be free for next orders.
Here my code:
// Enter the ID of the product that shouldn't be purchased again
$no_repeats_id = 944;
$no_repeats_product = wc_get_product( $no_repeats_id );
// Get the current product to check if purchasing should be disabled
global $product;
if ( $no_repeats_product->is_type( 'variation' ) ) {
// Bail if we're not looking at the product page for the non-purchasable product
if ( ! $no_repeats_product->parent->id === $product->id ) {
return;
}
// Render the purchase restricted message if we are
if ( wc_customer_bought_product( wp_get_current_user()->user_email, get_current_user_id(), $no_repeats_id ) ) {
sv_render_variation_non_purchasable_message( $product, $no_repeats_id );
}
} elseif ( $no_repeats_id === $product->id ) {
if ( wc_customer_bought_product( wp_get_current_user()->user_email, get_current_user_id(), $no_repeats_id ) ) {
// Create your message for the customer here
add_action( 'woocommerce_before_calculate_totals', 'add_custom_price' );
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 = 944;
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_action( 'woocommerce_single_product_summary', 'sv_purchase_disabled_message', 31 );
Here is the way to make it work in woocommerce 3+ too:
add_action( 'woocommerce_before_calculate_totals', 'conditionally_change_cart_items_price', 10, 1 );
function conditionally_change_cart_items_price( $cart_object ) {
if ( is_admin() && ! defined( 'DOING_AJAX' ) )
return;
if ( did_action( 'woocommerce_before_calculate_totals' ) >= 2 )
return;
// Set Here your targeted product ID
$targeted_product_id = 944;
// Set Here your custom price (1st purshase)
$custom_price = 10; // First purshase for product ID 944
// Detecting if customer has already bought The targeted product (944)
if( is_user_logged_in() ){
$customer = wp_get_current_user();
$customer_id = $customer->ID; // customer ID
$customer_email = $customer->email; // customer email
if( wc_customer_bought_product( $customer_email, $customer_id, $targeted_product_id) )
$custom_price = 0; // Set to 0 for other purchases (product ID 944)
}
foreach ( $cart_object->get_cart() as $cart_item ) {
// When targeted product is in cart we change the price
if ( $cart_item['product_id'] == $targeted_product_id ) {
// Woocommerce 3+ compatibility
if ( version_compare( WC_VERSION, '3.0', '<' ) )
$cart_item['data']->price = $custom_price;
else
$cart_item['data']->set_price( $custom_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 even in WooCommerce 3+
I'm creating a WooCommerce add-on to customize the product, based on selected options by the visitor and custom price is calculated and stored into session table also.
I am able to get that value in cart page also.
My problem: I would like to change the default price of the product and replace it with new calculated value in the WooCommerce process as cart, checkout, payment, mail notifications, order...
Any advice please?
Thanks
Ce right hook to get it working is woocommerce_before_calculate_totals. But you will have to complete (replace) the code to get the new price in the hooked function below:
add_action( 'woocommerce_before_calculate_totals', 'custom_cart_items_prices', 10, 1 );
function custom_cart_items_prices( $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 ) {
// Get the product id (or the variation id)
$product_id = $cart_item['data']->get_id();
// GET THE NEW PRICE (code to be replace by yours)
$new_price = 500; // <== Add your code HERE
// Updated cart item price
$cart_item['data']->set_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 3+. But as you don't give any code I can't test it for real getting the new price from session…
function save_subscription_wrap_data( $cart_item_data, $product_id ) {
$include_as_a_addon_subscription = get_field('include_as_a_addon_subscription',$product_id);
$subscricption_product_data = get_field('subscricption_product',$product_id);
$current_user = is_user_logged_in() ? wp_get_current_user() : null;
$subscriptions = wcs_get_users_subscriptions( $current_user->ID );
if($include_as_a_addon_subscription == "yes")
{
foreach ( $subscriptions as $subscription_id => $subscription ) {
$subscription_status = $subscription->get_status();
}
if($subscription_status == 'active')
{
$cart_item_data[ "subscribe_product" ] = "YES";
}
}
return $cart_item_data;
}
add_filter( 'woocommerce_add_cart_item_data', 'save_subscription_wrap_data', 99, 2 );
function render_meta_on_cart_and_checkout1( $cart_data, $cart_item = null ) {
$meta_items = array();
if( !empty( $cart_data ) ) {
$meta_items = $cart_data;
}
if( isset( $cart_item["subscribe_product"] ) ) {
$meta_items[] = array( "name" => "Product Type", "value" => "Package Addon" );
}
return $meta_items;
}
add_filter( 'woocommerce_get_item_data', 'render_meta_on_cart_and_checkout1', 100, 2 );
function calculate_gift_wrap_fee( $cart_object ) {
if( !WC()->session->__isset( "reload_checkout" )) {
$additionalPrice = 100;
foreach ( WC()->cart->get_cart() as $key => $value ) {
if( isset( $value["subscribe_product"] ) ) {
if( method_exists( $value['data'], "set_price" ) ) {
$orgPrice = floatval( $value['data']->get_price() );
//$value['data']->set_price( $orgPrice + $additionalPrice );
$value['data']->set_price(0);
} else {
$orgPrice = floatval( $value['data']->price );
//$value['data']->price = ( $orgPrice + $additionalPrice );
$value['data']->price = (0);
}
}
}
}
}
add_action( 'woocommerce_before_calculate_totals', 'calculate_gift_wrap_fee', 99 );