WooCommerce – update product price programmatically

How to set a custom price for a WooCommerce product

There are many reasons you might want to update a WooCommerce product price programmatically. For instance, in Bookings for WooCommerce the booking (product) price is set dynamically according to certain parameters – e.g. length of stay, etc. In Product Extras, you can specify extra fields for your products (like checkboxes and text fields) which will add extra cost to the product when selected. In this article, I’ll share some simple code to achieve this.

How to update WooCommerce product prices programmatically

Let’s say, as an example, that you are selling computers on your WooCommerce store and you want to add an option to each product that, when selected, will update the product price in the cart.

If we take a look at an example product from the Product Extras demo (screenshot below), we can see that if the user chooses the ‘Add extended warranty’ checkbox, another £250 will be added to the product price.

WooCommerce update product price programmatically

The product price is updated programmatically in the cart by using two WooCommerce hooks:

woocommerce_add_cart_item_data

woocommerce_before_calculate_totals

The woocommerce_add_cart_item_data filter

The woocommerce_add_cart_item_data filter allows us to add custom data to products when they’re added to the cart. When the user clicks the ‘Add to cart’ button, we use the filter to set a new variable in the product’s item data that defines the updated price. Like this:

function add_cart_item_data( $cart_item_data, $product_id, $variation_id ) {
// Has our option been selected?
if( ! empty( $_POST['extended_warranty'] ) ) {
$product = wc_get_product( $product_id );
$price = $product->get_price();
// Store the overall price for the product, including the cost of the warranty
$cart_item_data['warranty_price'] = $price + 250;
}
return $cart_item_data;
}
add_filter( 'woocommerce_add_cart_item_data', 'add_cart_item_data', 10, 3 );

When the user adds the product to their cart, this code checks to see if a checkbox with the extended_warranty name attribute has been set.

If the checkbox has been set then we used the $product_id variable passed by the filter to get the $product object, then use the get_price method to get the product price:

$product = wc_get_product( $product_id );
$price = $product->get_price();

Then we store our updated price in a new element in the $cart_item_data object.

$cart_item_data['warranty_price'] = $price + 250;

Note that I’ve hardcoded a value here. You will undoubtedly want to use your own value.

The woocommerce_before_calculate_totals action

Now that we have our updated price stored as a variable in the cart item data, we can use it when the user arrives on the cart page. We do that like this:

function before_calculate_totals( $cart_obj ) {
if ( is_admin() && ! defined( 'DOING_AJAX' ) ) {
return;
}
// Iterate through each cart item
foreach( $cart_obj->get_cart() as $key=>$value ) {
if( isset( $value['warranty_price'] ) ) {
$price = $value['warranty_price'];
$value['data']->set_price( ( $price ) );
}
}
}
add_action( 'woocommerce_before_calculate_totals', 'before_calculate_totals', 10, 1 );

As you can guess from the name of the action, woocommerce_before_calculate_totals runs just before the cart total is calculated. We pass it the cart object, then iterate through each item in the cart to check for our extended_warranty variable. If we find it, we update the price for the product using the set_price method.

Why not set the price variable at the cart page?

If you try to calculate the updated price directly in the cart using woocommerce_before_calculate_totals, you might find that the extra price is added twice or even multiple times. That’s because woocommerce_before_calculate_totals can be called more than once on the cart page.

Prevent customers purchasing products from archive pages

Thanks to Rick for pointing this out in the comments below. If you have custom fields in your product, you might want to prevent your users from purchasing those products direct from the shop or archive pages. You can use the filter below to achieve this:

<?php
/**
* Prevent products being purchased from archive
* @return Boolean
*/
function pewc_filter_is_purchasable( $is_purchasable, $product ) {
if( is_archive() ) {
return false;
}
return $is_purchasable;
}
add_filter( 'woocommerce_is_purchasable', 'pewc_filter_is_purchasable', 10, 2 );

Further resources

woocommerce_add_cart_item_datahttps://docs.woocommerce.com/wc-apidocs/source-class-WC_Cart.html#897

woocommerce_before_calculate_totalshttps://docs.woocommerce.com/wc-apidocs/source-class-WC_Cart.html#1097

Photo by Samuel Zeller on Unsplash. It has no relevance to the content of the article.

Extra fields, options and addons for WooCommerce products


Popular Posts

7 thoughts on “WooCommerce – update product price programmatically

How would this be used with a percentage. I have a nonprofit company that needs a checkbox to increase the price by a percentage of the donation to cover processing fees of 2.9%

Reply

Hi Steve

For percentage based pricing, you just make the calculation as a percentage of the product price rather than adding a set amount to the product price.

Version 2 of Product Extras is due to be released shortly and will feature percentage based pricing.

Gareth

Reply

Hi there. Thanks. I have another question about this title.
Assume that we buy products with a currency (let’s say Dollars) and we have to sell them with another currency (let’s say Euro) that its rate may change occasionally. So we have to product all prices to a rate value. From one of your posts I could add a custom field that I enter the dollar price. Now, I want to set all of my products based on that price and change them all (for example 1 Euro equals 1.16 Dollars right now, so I want to product all prices to 1/1.16 to convert them to Euro for all products).
I used a code that is described in there: https://stackoverflow.com/questions/52289723/changing-displayed-price-by-get-post-meta-ruins-the-cart-price-in-wordpress
But I had the problem described there. So, do you have any suggestion?
Thanks

Reply

At quick glance, looking at the code you posted on the Stack Overflow link, you’re trying to use the $price variable as an array, $price[0], when it’s just a simple value. I think that’s why you’re getting a 0 for your result.

Reply

Hello. Thank you for your time posting this valuable info.

In my case, I used this method to add a custom charge. I was so happy to have this functionality without adding yet another plugin.

The next day I received an order and it was processed without the custom charge. I tried doing test orders and always the custom charge is there. So I was wondering how the customer got away without the custom charge.

I found out that the customer ordered from the archive page and not from the product single page. The info given here works perfect in the single page, but since I have “Add to Cart” buttons in the archive page (category page), if the product is added from there, the custom charge is overridden.

Any easy way to make it work from category too? If not, I will just hide the “Add to Cart” buttons in the category page or change it somehow to “More Info” and force to order from the single page.

I had a loss in that order, but still very happy that this is working without a plugin (already have about 40 plugins running).

Kind regards

Reply

You’re absolutely right. I’ve updated the article to filter the Add to Cart buttons on archive pages.

Reply

Leave a Reply

Your email address will not be published. Required fields are marked *