Change variation price when custom selection is made - php

I have a woocommerce variable product outside of loop and not on single product page, I want to change variation price based on the selection of a form. If an area is selected change variation price with the custom price added in the custom field created for that variation(area1 or area2). My code works for displaying the correct price after selection but when I add the variation to cart the default price of the variation is added to cart not the custom price.
<form class="areas-form" method="POST" action="">
Select Your Area
<select name="area" onchange="this.form.submit()">
<option value="" disabled selected>--select--</option>
<option value="area1">Area 1</option>
<option value="area2">Area 2</option>
</select>
</form>
add_filter( 'woocommerce_product_variation_get_price', 'varient_price', 99, 2 ); // this code is added in functions.php
function varient_price($price, $variation){
if ( $variation->product_type == 'variation' ) {
if(isset($_POST["area"])){
$area=$_POST["area"];
}
$price = get_post_meta( $variation->variation_id, $area.'_price',true);
return $price;
}
}

As per your question comment, rest display and other things you are managing.
Here, I have just attached the woocommerce hooks and calculation to get your area price to set in your selected variation.
Firstly, you need to get the dynamic price in your select option as per area wise.
Secondly, below code will help you to set your parameter request to be add into cart meta:
function add_area_data_cart_meta( $cart_item_data, $product_id ) {
if( isset( $_POST['area'] ) ) {
$cart_item_data[ "area" ] = $_POST['area'];
}
return $cart_item_data;
}
add_filter( 'woocommerce_add_cart_item_data', 'add_area_data_cart_meta', 99, 2 );
Third, before product get add to cart. The above code will fetch your area price value which we have added using above code and below code will set your area price as new price in the cart.
function calculate_area_price_as_variation_price( $cart_object ) {
if( !WC()->session->__isset( "reload_checkout" )) {
/* Gift wrap price */
$additionalPrice = 100;
foreach ( WC()->cart->get_cart() as $key => $value ) {
if( isset( $value["area"] ) ) {
if( method_exists( $value['data'], "set_price" ) ) {
/* Woocommerce 3.0 + */
$value['data']->set_price( $value["area"] );
} else {
/* Version before 3.0 */
$value['data']->price = ( $value["area"] );
}
}
}
}
}
add_action( 'woocommerce_before_calculate_totals', 'calculate_area_price_as_variation_price', 99 );
Please let me know if you find any issues.
Thanks.

Related

Update woocommerce price of a product based on php

I have a custom add to cart button in php for a single product:
Final total<br>
$<?php echo $row['purchase-price'] ?>.00<br><br>
<button onclick="window.location.href='https://yourdomain.com/checkout/?add-to-cart=362166';">Add to cart</button>
After clicking the button, it returned a "Sorry, this product cannot be purchased." error. I havent set the product price since the amount in <?php echo $row['purchase-price'] ?> is always changing. How to pass the amount set in php and pass it to product's final price?
First you will restrict your code to single product and archives pages only:
add_filter( 'woocommerce_product_get_price', 'double_price', 10, 2 );
function double_price( $price, $product ){
if( is_shop() || is_product_category() || is_product_tag() || is_product() ) {
global $wpdb;
//your query to get price from custom db
//FOR GET PRODUCT ID $product->get_id();
$price = $row['purchase-price'];
}
return $price;
}
Then for cart and checkout pages, you will change the cart item price this way:
add_filter( 'woocommerce_add_cart_item', 'set_custom_cart_item_prices', 20, 2 );
function set_custom_cart_item_prices( $cart_data, $cart_item_key ) {
global $wpdb;
//your query to get price from custom db
$new_price = $row['purchase-price'];
//FOR GET PRODUCT ID $cart_item['data']->get_id();
// Set and register the new calculated price
$cart_data['data']->set_price( $new_price );
$cart_data['new_price'] = $new_price;
return $cart_data;
}
add_filter( 'woocommerce_get_cart_item_from_session', 'set_custom_cart_item_prices_from_session', 20, 3 );
function set_custom_cart_item_prices_from_session( $session_data, $values, $key ) {
if ( ! isset( $session_data['new_price'] ) || empty ( $session_data['new_price'] ) )
return $session_data;
// Get the new calculated price and update cart session item price
$session_data['data']->set_price( $session_data['new_price'] );
return $session_data;
}
And in the last hit your custom url
<button onclick="window.location.href='https://yourdomain.com/?add-to-cart=362166&quantity=1';">Add to cart</button>

Set a custom add to cart price via the URL (GET) in WooCommerce

I am developing a wordpress and woocommerce-based website where information on cooking-related training is provided and various kitchen materials are sold.
Those who want to participate in the trainings apply by filling out a form. Kitchen supplies are also sold through woocommerce.
Trainings are added to the website with a type of content called training.
Some trainings are requested to be sold over the woocommerce structure. However, these "Trainings" that want to be sold are wanted to remain in the form of educational content. In addition, it is requested not to be added or moved as a product.
First of all, I created a virtual product called Education. I hid the product in the store.
Then I added a custom field for Tutorials called price. The price of each training to be sold will be entered here.
I have a button "Register for Training" on the training detail page, I changed it to "Buy" for the trainings wanted to sell and the link
?add-to-cart=340&custom_price=600&quantity=1
I gave in the form.
Here 340 is the id of the virtual product I created.
When the Buy button is clicked, the virtual product called Education is added to the basket. But I want to update the name and price of this training according to which training detail page is printed.
The codes I added to functions.php.
add_action( 'woocommerce_before_calculate_totals', 'before_calculate_totals' );
function before_calculate_totals( $_cart ){
// loop through the cart_contents
foreach ( $_cart->cart_contents as $cart_item_key => &$item ) {
// you will need to determine the product id you want to modify, only when the "donation_amount" is passed
if ( $item['product_id'] == 340 && isset( $_GET['custom_price'] ) ){
// custom price from POST
$custom_price = $_GET['custom_price'] > 0 ? $_GET['custom_price'] : 0;
// save to the cart data
//$item['data']->price = $custom_price;
// new versions of WooCommerce may require (instead of line above)...
$item['data']->set_price($custom_price);
}
}
}
function ipe_product_custom_price( $cart_item_data, $product_id ) {
if( isset( $_POST['custom_price'] ) && !empty($_POST['custom_price'])) {
$cart_item_data[ "custom_price" ] = $_POST['custom_price'];
}
return $cart_item_data;
}
add_filter( 'woocommerce_add_cart_item_data', 'ipe_product_custom_price', 99, 2 );
I wanted to update the price with these codes, but it didn't work.
How do I dynamically update the information of the virtual product? Or what different method would you suggest?
There are some mistakes in your code and some missing things to make it work. Try the following:
// Set custom data as custom cart data in the cart item
add_filter( 'woocommerce_add_cart_item_data', 'add_custom_price_as_custom_cart_item_data', 30, 3 );
function add_custom_price_as_custom_cart_item_data( $cart_item_data, $product_id, $variation_id ) {
if( ! isset($_GET['custom_price']) ) {
$cart_item_data['custom_price'] = (float) esc_attr( $_GET['custom_price'] );
$cart_item_data['unique_key'] = md5( microtime().rand() ); // Make each item unique
}
return $cart_item_data;
}
// Change cart item price
add_action( 'woocommerce_before_calculate_totals', 'change_cart_item_price' );
function change_cart_item_price( $cart ){
if ( is_admin() && ! defined( 'DOING_AJAX' ) )
return;
// loop through the cart_contents
foreach ( $cart->get_cart() as $cart_item ) {
// you will need to determine the product id you want to modify, only when the "donation_amount" is passed
if ( isset($cart_item['custom_price']) ) {.
$item['data']->set_price($cart_item['custom_price']);
}
}
}
// Display the custom price on minicart too
add_filter( 'woocommerce_cart_item_price', 'change_minicart_item_price', 10, 3 );
function change_minicart_item_price( $price_html, $cart_item, $cart_item_key ) {
if( ! is_cart() && isset( $cart_item['custom_price'] ) ) {
$args = array( 'price' => floatval($cart_item['custom_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_html;
}
Code goes in functions.php file of your active child theme (or active theme). It should works.

Custom cart item price based on user input in Woocommerce

in our Woocommerce store we have some minimum price for any products . And in every product inner page there is two filed where customer can type width , height of the product . And then they can add this product to cart, then price is changed based on given width and height.
For example if the minimum price for a product is 50 . And customer add width =2, height=3 , then the price for this product is going to 50*2*3=300
So to arrange this we add this code to function.php
add_filter( 'woocommerce_add_cart_item', 'add_custom_cart_item_data', 10, 2 );
function add_custom_cart_item_data( $cart_item_data, $cart_item_key ) {
$result=$_POST['width']*$_POST['height']*$cart_item_data['data']->price;
$cart_item_data['new-price'] =$result;
$cart_item_data['data']->set_price($result);
return $cart_item_data;
}
So this is working correctly .
But the problem is once it is coming to checkout page then the product price is showing as 50 , but it is 300 actually.
so to overcome this i use the following code
add_filter( 'woocommerce_cart_item_subtotal', 'update_with_custom_details', 10, 3 );
function update_with_custom_details( $subtotal, $cart_item, $cart_item_key ) {
$subtotal =" £".$cart_item['line_total'];
return $subtotal;
}
now it is showing £300, but i know this code is wrong.
The code is wrong because when customer apply a 50% coupon code for this product then the discount is coming as 25 , Because it calculating based on 50*.5=25; But actually product new price is 300, so the discount should be 300*5=150;
So how i can update the product price in cart page, checkout page ,mini cart etc ?
Please help .
Please see this also
Woocommerce product custom price is not accepted by wocommerce coupon
Update 2: The correct way to do it need to be done in two steps:
We calculate the price on add to cart event hook and save it as custom cart item data.
We set that calculated price in woocommerce_before_calculate_totals hook
The code:
// Save custom field value in cart item as custom data
add_filter( 'woocommerce_add_cart_item_data', 'calculate_custom_cart_item_prices', 30, 3 );
function calculate_custom_cart_item_prices( $cart_item_data, $product_id, $variation_id ) {
if ( isset($_POST['width']) && isset($_POST['height']) ) {
// Get the correct Id to be used (compatible with product variations)
$the_id = $variation_id > 0 ? $variation_id : $product_id;
$product = wc_get_product( $the_id ); // Get the WC_Product object
$product_price = (float) $product->get_price(); // Get the product price
// Get the posted data
$width = (float) sanitize_text_field( $_POST['width'] );
$height = (float) sanitize_text_field( $_POST['height'] );
$new_price = $width * $height * $product_price; // Calculated price
$cart_item_data['calculated-price'] = $new_price; // Save this price as custom data
}
return $cart_item_data;
}
// Set custom calculated price in cart item 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( ! empty( $cart_item['calculated-price'] ) ){
// Set the calculated item price (if there is one)
$cart_item['data']->set_price( $cart_item['calculated-price'] );
}
}
}
Code goes in function.php file of your active child theme (or theme). Tested and works.
For testing purpose, I have used the following code that output 2 custom fields on single product pages:
// 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
?>
<div>
<label class="product-custom-text-label" for="servicetime"><?php _e( 'Custom text:', 'woocommerce'); ?><br>
<input type="text" id="user-width" name="width" value=""><br>
<input type="text" id="user-height" name="height" value="">
</label>
</div><br>
<?php
}

Changing WooCommerce cart price after applied coupon code

I have created a product on WooCommerce, and added two options on product detail page using the hook woocommerce_before_add_to_cart_button. Now when customers add product to cart from product detail page they have two options their. They can choose one option from these two options.
Then I have stored the user selected value in cart meta using the woocommerce hook woocommerce_add_cart_item_data.
I am using the code from this answer: Save product custom field radio button value in cart and display it on Cart page
This is my code:
// single Product Page options
add_action("woocommerce_before_add_to_cart_button", "options_on_single_product");
function options_on_single_product(){
$dp_product_id = get_the_ID();
$product_url = get_permalink($dp_product_id);
?>
<input type="radio" name="custom_options" checked="checked" value="option1"> option1<br />
<input type="radio" name="custom_options" value="option2"> option2
<?php
}
//Store the custom field
add_filter( 'woocommerce_add_cart_item_data', 'save_custom_data_with_add_to_cart', 10, 2 );
function save_custom_data_with_add_to_cart( $cart_item_meta, $product_id ) {
global $woocommerce;
$cart_item_meta['custom_options'] = $_POST['custom_options'];
return $cart_item_meta;
}
And this is what I have tried:
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'];
$custom_options = $value['custom_options'];
$coupon_code = $value['coupon_code'];
if($custom_options == 'option2')
{
if($coupon_code !='')
{
global $woocommerce;
if ( WC()->cart->has_discount( $coupon_code ) ) return;
(WC()->cart->add_discount( $coupon_code ))
//code for second discount
}
else{
$percentage = get_post_meta( $product_id , 'percentage', true );
//print_r($value);
$old_price = $value['data']->regular_price;
$new_price = ($percentage / 100) * $old_price;
$value['data']->set_price( $new_price );
}
}
}
}
Now what I am trying to get with that last snippet is:
If Option1 is selected by the customer then woocommerce regular process is run.
If Option2 is selected then firstly coupon code applied to cart (if code entered by the customer) and then the price is divide by some percentage (stored in product meta) is applied afterward.
But it’s not working as expected because the changed product price is maid before and coupon discount is applied after on this changed price.
What I would like is that the coupon discount will be applied first on the product regular price and then after change this price with my custom product discount.
Is this possible? How can I achieve that?
Thanks.
This is not really possible … Why? … Because (the logic):
You have the product price
Then the coupon discount is applied to that price (afterwards)
==> if you change the product price, the coupon is will be applied to that changed price
What you can do instead:
You don't change product price
if entered the coupon is applied and …
If "option2" product is added to cart:
Apply a custom discount (a negative fee) based on the product price added after using WC_cart add_fee() method…
For this last case you will have to fine tune your additional discount.
If the coupon has not been applied or it's removed there is no additional discount.
Your custom function will be hooked in woocommerce_cart_calculate_fees action hook instead:
add_action( 'woocommerce_cart_calculate_fees', 'option2_additional_discount', 10, 1 );
function option2_additional_discount( $cart_obj ) {
if ( is_admin() && ! defined( 'DOING_AJAX' ) )
return;
$discount = 0;
$applied_coupons = $cart_obj->get_applied_coupons();
foreach ( $cart_obj->get_cart() as $item_values ) {
if( 'option2' == $item_values['custom_options'] && !empty($applied_coupons) ){
$product_id = $item_values['product_id'];
$percentage = get_post_meta( $product_id , 'percentage', true );
$quantity = $item_values['quantity'];
$product_reg_price = $item_values['data']->regular_price;
$line_total = $item_values['line_total'];
$line_subtotal = $item_values['line_subtotal'];
$percentage = 90;
## ----- CALCULATIONS (To Fine tune) ----- ##
$item_discounted_price = ($percentage / 100) * $product_reg_price * $item_values['quantity'];
// Or Besed on line item subtotal
$discounted_price = ($percentage / 100) * $line_subtotal;
$discount += $product_reg_price - $item_discounted_price;
}
}
if($discount != 0)
$cart_obj->add_fee( __( 'Option2 discount', 'woocommerce' ) , - $discount );
}
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.
Adding a negative fee using the WC_Cart->add_fee() method wasn't working for me. When i check the WC Cart class, it even states you are not allowed to use a negative ammount.
See the docs.
I did the following:
create a placeholder coupon with a 'secure' code, e.g. custom_discount_fjgndfl28. Set a discount ammount of 0, so when somebody (somehow) uses this coupon outside your program the discount is still 0.
Use filter woocommerce_get_shop_coupon_data, and set all the coupon data you want for that coupon/session.
Hook into woocommerce_before_calculate_totals and set your custom coupon to the cart.
At this point the Cart should calculate everything correctly. And when it becomes an order, it also has the correct discount ammount.
Note: the coupon code is also used as a label in some templates. Use filter woocommerce_cart_totals_coupon_label to change it.
Example functions:
/**
* NOTE: All the hooks and filters below have to be called from your own
* does_it_need_custom_discount() function. I used the 'wp' hook for mine.
* Do not copy/paste this to your functions.php.
**/
add_filter('woocommerce_get_shop_coupon_data', 'addVirtualCoupon', 10, 2);
function addVirtualCoupon($unknown_param, $curr_coupon_code) {
if($curr_coupon_code == 'custom_discount_fjgndfl28') {
// possible types are: 'fixed_cart', 'percent', 'fixed_product' or 'percent_product.
$discount_type = 'fixed_cart';
// how you calculate the ammount and where you get the data from is totally up to you.
$amount = $get_or_calculate_the_coupon_ammount;
if(!$discount_type || !$amount) return false;
$coupon = array(
'id' => 9999999999 . rand(2,9),
'amount' => $amount,
'individual_use' => false,
'product_ids' => array(),
'exclude_product_ids' => array(),
'usage_limit' => '',
'usage_limit_per_user' => '',
'limit_usage_to_x_items' => '',
'usage_count' => '',
'expiry_date' => '',
'apply_before_tax' => 'yes',
'free_shipping' => false,
'product_categories' => array(),
'exclude_product_categories' => array(),
'exclude_sale_items' => false,
'minimum_amount' => '',
'maximum_amount' => '',
'customer_email' => '',
'discount_type' => $discount_type,
);
return $coupon;
}
}
add_action('woocommerce_before_calculate_totals', 'applyFakeCoupons');
function applyFakeCoupons() {
global $woocommerce;
// $woocommerce->cart->remove_coupons(); remove existing coupons if needed.
$woocommerce->cart->applied_coupons[] = $this->coupon_code;
}
add_filter( 'woocommerce_cart_totals_coupon_label', 'cart_totals_coupon_label', 100, 2 );
function cart_totals_coupon_label($label, $coupon) {
if($coupon) {
$code = $coupon->get_code();
if($code == 'custom_discount_fjgndfl28') {
return 'Your custom coupon label';
}
}
return $label;
}
Please Note: i copied these functions out of a class that handles much more, it's only to help you get going.

Dynamically calculate product price based on custom fields values when added-to-cart

I found the code to add existing product:
global $woocommerce;
$woocommerce->cart->add_to_cart(16);
But I need to add product, with price that determined by 2 inputs:
Age
Quality
I calculate the product's price by the formula age*quality.
I know it's possible to add product with variations, but it's so many possible variations.
Is it possible to set the product price dynamically based on custom fields calculation values?
Thanks
For the cart items (when product is added-to cart), is possible to set a custom dynamic calculated price based on product custom fields values.
1) First we add in the single product pages your 2 custom fields (Here a normal text input field and a select field) for "Age" and "Quality":
// Add product custom fields inside the product add-to-cart form
add_action('woocommerce_before_add_to_cart_button', 'custom_data_hidden_fields');
function custom_data_hidden_fields() {
echo '<div class="imput_fields custom-imput-fields">
<label class="age_prod">Age: <br><input type="text" id="age_prod" name="age_prod" value="" /></label>
<label class="quality_prod">Quality: <br>
<select name="quality_prod" id="quality_prod">
<option value="1" selected="selected">1</option>
<option value="2">2</option>
<option value="3">3</option>
<option value="4">4</option>
<option value="5">5</option>
</select>
</label>
</div><br>';
}
2) When product is add-to-cart, we save these custom post data values with the added cart item:
// Save product custom fields values after submission into the cart item data
add_filter( 'woocommerce_add_cart_item_data', 'save_custom_data_hidden_fields', 10, 2 );
function save_custom_data_hidden_fields( $cart_item_data, $product_id ) {
$data = array();
if( isset( $_REQUEST['age_prod'] ) ) {
$cart_item_data['custom_data']['age'] = $_REQUEST['age_prod'];
}
if( isset( $_REQUEST['quality_prod'] ) ) {
$cart_item_data['custom_data']['quality'] = $_REQUEST['quality_prod'];
}
// below statement make sure every add to cart action as unique line item
$cart_item_data['custom_data']['unique_key'] = md5( microtime().rand() );
return $cart_item_data;
}
3) Finally in this last step, you get all necessary data from cart to make your own calculation, and to update the price for each cart item dynamically.
I have make a temporary calculation, just to show that the code is working as expected.
Here In the code below, you will have to customize the calculation to feet your needs (as you don't give any details about that in your question).
As you will see below, it's an easy step to make your own calculation, as you get your custom fields values for each cart item and also the original price of the product.
Here is the code that will make this dynamic calculation based on your custom field values:
// Replace the item price by your custom calculation
add_action( 'woocommerce_before_calculate_totals', 'add_custom_item_price', 10 );
function add_custom_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 ) {
// Product ID
$product_id = version_compare( WC_VERSION, '3.0', '<' ) ? $cart_item['data']->id : $cart_item['data']->get_id();
// Product original price
$original_price = version_compare( WC_VERSION, '3.0', '<' ) ? $cart_item['data']->price : $cart_item['data']->get_price();
$original_price = $item_values['data']->price;
## --- Get your custom cart item data --- ##
if( isset($cart_item['custom_data']['age']) )
$age = $cart_item['custom_data']['age'];
if( isset($cart_item['custom_data']['quality']) )
$quality = $cart_item['custom_data']['quality'];
// CALCULATION FOR EACH ITEM:
## Make HERE your own calculation to feet your needs <== <== <== <==
$new_price = $original_price + ( ($age * 0.1) + $quality );
## Set the new item price in cart
if( version_compare( WC_VERSION, '3.0', '<' ) )
$cart_item['data']->price = $new_price;
else
$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.
Code is tested and works perfectly.
DISPLAYING THE CUSTOM PRICE IN SINGLE PRODUCT PAGE:
Read this to understand how override the WoocCommerce templates via your theme
For that you will need to edit the template single-product/price.php.
And you will need to add some javascript/jQuery to this single product page to make the product price updated, when customer will set some values in your product custom fields.
But this is another question.
Related answer: WooCommerce - Adding a custom price to each product in cart

Categories