WooCommerce – update product price programmatically

samuel zeller 16570

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 WooCommerce Product Add Ons Ultimate, 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.

If you’re looking for a way to create complex cost calculations using a formula based on user inputs, you should take a look at this article on measurement price calculators and setting WooCommerce product prices by formula.

And for detailed guidance on how to add custom cart item data in WooCommerce, take a look at this article.

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 WooCommerce Product Add Ons Ultimate 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

WooCommerce Product Add-Ons Ultimate featured image

WooCommerce Product Add-Ons Ultimate

Personalise products with extra fields and custom options

Find Out More

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

WooCommerce Product Add-Ons Ultimate featured image

WooCommerce Product Add-Ons Ultimate

Personalise products with extra fields and custom options

Find Out More

15 comments

  1. User image

    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%

  2. User image

    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 WooCommerce Product Add Ons Ultimate is due to be released shortly and will feature percentage based pricing.

    Gareth

  3. User image

    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

    • User image

      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.

  4. User image

    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

  5. User image

    The code works perfectly thanks. If a customer ticks the warranty box, how would I get that to display in the basket? The new price displays correctly but I’d like to display “Extended Warranty – £250” to my item description in the basket/checkout.

  6. User image

    So I ended up writing the code myself. This will display the warranty information inside the basket.

    function display_warranty_option( $item_data, $cart_item ) {
    if (!empty($cart_item[‘extended_warranty’])) {
    $item_data[] = array(
    ‘key’ => ‘Extended Warranty’,
    ‘value’ => wc_clean($cart_item[‘extended_warranty’]),
    ‘display’ => ‘Extended warranty included.’,
    );
    }

    return $item_data;
    }

    add_filter(‘woocommerce_get_item_data’, ‘display_warranty_option’, 10, 2);

  7. User image

    I want to change the pricing on display. Can you give me any reference how to change product price on display as I have already gone through this tutorial https://www.cloudways.com/blog/change-woocommerce-price-display/ and having an error while running the code that I have mentioned below. Is there any alternative to do this?

    function cw_change_product_price_display( $price ) {
    $price .= ‘ At Each Item Product’;
    return $price;
    }
    add_filter( ‘woocommerce_get_price_html’, ‘cw_change_product_price_display’ );
    add_filter( ‘woocommerce_cart_item_price’, ‘cw_change_product_price_display’ );

  8. User image

    Hi @Gareth.Is That Possible to Update Product Price And In-Stock Status In WooCommerce DataBase?
    We Read This Info From A Remote DataBase And Insert Into WooCommerce DataBase.
    Thanks

  9. User image

    Hello, thanks for a good article. In my case I want to use addons to my main product that has a percentage price of both the main product + all addons added by the user. Is that possible? Trying to add percentage based price addons today will only result in showing the 10% cost of the main product, and the addons aren’t counted in the 10% prices.

    Any ideas?

Leave a Reply

Your email address will not be published. All fields are required.