23

IN WooCommerce, I need to multiply all product prices by a number. So I have used the following (via a plugin):

add_filter('woocommerce_get_regular_price', array( $this, 'my_custom_price'), 99);
add_filter('woocommerce_get_price', array( $this, 'my_custom_price'), 99);

function my_custom_price( $original_price ) {
  global $post, $woocommerce;

  //Logic for calculating the new price here
  $new_price = $original_price * 2;

  //Return the new price (this is the price that will be used everywhere in the store)
  return $new_price;
 }

But, that doesn't work for variation products. I have tried the following hooks with no luck:

add_filter('woocommerce_get_variation_regular_price', array( $this, 'my_custom_price'), 99);
add_filter('woocommerce_get_variation_price', array( $this, 'my_custom_price'), 99);

The only one that works half way is this one:

add_filter('woocommerce_variation_prices_price', array( $this, 'my_custom_price'), 99);

But that just changed the overall price, not the selected variation price. See the image below, price is BsF. 200 and the overall price is right, 200 x 2 = 400, but the variation price when selected still shows 200:

Note: I need it to actually change, so display html hooks wont work.

Variation Price

Is there anything I'm missing, or something wrong?

LoicTheAztec
  • 229,944
  • 23
  • 356
  • 399
KronosL
  • 299
  • 3
  • 4
  • 11

1 Answers1

42

Update (December 2020)

  • 2 code versions for themes and plugins (works in Woocommerce 3.3.x too)
  • Cached variations prices in Woocommerce 3 (Update and addition):
    Now using woocommerce_get_variation_prices_hash filter hook much more efficient, instead of wc_delete_product_transients()… See this related thread
  • Added product price filter widget hooks (see at the end).

1) Plugin version with a constructor function:

The hooks that you are using are deprecated in WooCommerce 3+

To make it work for all products prices, including variations prices, you should use this:

## The following goes inside the constructor ##

// Simple, grouped and external products
add_filter('woocommerce_product_get_price', array( $this, 'custom_price' ), 99, 2 );
add_filter('woocommerce_product_get_regular_price', array( $this, 'custom_price' ), 99, 2 );
// Variations 
add_filter('woocommerce_product_variation_get_regular_price', array( $this, 'custom_price' ), 99, 2 );
add_filter('woocommerce_product_variation_get_price', array( $this, 'custom_price' ), 99, 2 );

// Variable (price range)
add_filter('woocommerce_variation_prices_price', array( $this, 'custom_variable_price' ), 99, 3 );
add_filter('woocommerce_variation_prices_regular_price', array( $this, 'custom_variable_price' ), 99, 3 );

// Handling price caching (see explanations at the end)
add_filter( 'woocommerce_get_variation_prices_hash', array( $this, 'add_price_multiplier_to_variation_prices_hash' ), 99, 3 );


## This goes outside the constructor ##

// Utility function to change the prices with a multiplier (number)
public function get_price_multiplier() {
    return 2; // x2 for testing
}

public function custom_price( $price, $product ) {
    return (float) $price * get_price_multiplier();
}

public function custom_variable_price( $price, $variation, $product ) {
    return (float) $price * get_price_multiplier();
}

public function add_price_multiplier_to_variation_prices_hash( $price_hash, $product, $for_display ) {
    $price_hash[] = get_price_multiplier();
    return $price_hash;
}

The code tested and perfectly works (only) in WooCommerce 3+.


2) For theme version: functions.php file on active child theme (or active theme):

// Utility function to change the prices with a multiplier (number)
function get_price_multiplier() {
    return 2; // x2 for testing
}

// Simple, grouped and external products
add_filter('woocommerce_product_get_price', 'custom_price', 99, 2 );
add_filter('woocommerce_product_get_regular_price', 'custom_price', 99, 2 );
// Variations
add_filter('woocommerce_product_variation_get_regular_price', 'custom_price', 99, 2 );
add_filter('woocommerce_product_variation_get_price', 'custom_price', 99, 2 );
function custom_price( $price, $product ) {
    return (float) $price * get_price_multiplier();
}

// Variable (price range)
add_filter('woocommerce_variation_prices_price', 'custom_variable_price', 99, 3 );
add_filter('woocommerce_variation_prices_regular_price', 'custom_variable_price', 99, 3 );
function custom_variable_price( $price, $variation, $product ) {
    // Delete product cached price  (if needed)
    // wc_delete_product_transients($variation->get_id());

    return (float) $price * get_price_multiplier();
}

// Handling price caching (see explanations at the end)
add_filter( 'woocommerce_get_variation_prices_hash', 'add_price_multiplier_to_variation_prices_hash', 99, 3 );
function add_price_multiplier_to_variation_prices_hash( $price_hash, $product, $for_display ) {
    $price_hash[] = get_price_multiplier();
    return $price_hash;
}

Tested and works on woocommerce 3+


For products in sale you have those hooks:

  • woocommerce_product_get_sale_price (Simple, grouped and external products)
  • woocommerce_variation_prices_sale_price (Variable products (min-max))
  • woocommerce_product_variation_get_sale_price (Products variations)

Cached prices and woocommerce 3:

The 3 filters hooks involved in variations cached prices are:

  • woocommerce_variation_prices_price
  • woocommerce_variation_prices_regular_price
  • woocommerce_variation_prices_sale_price

Introduced in Woocommerce 3, woocommerce_get_variation_prices_hash filter hook will allow to refresh variations cached prices in a much more efficient way, without deleting related transients anytime that this hooks are executed.

So performances will stay boosted (Thanks to Matthew Clark that pointed this better way)

See: Caching and dynamic pricing – upcoming changes to the get_variation_prices method


For filtering product prices with a widget (min and max price), use the following hooks:

  • woocommerce_price_filter_widget_min_amount that has one argument $price
  • woocommerce_price_filter_widget_max_amount that has one argument $price
LoicTheAztec
  • 229,944
  • 23
  • 356
  • 399
  • Thank you! Now it works only if I delete DB transients with a plugin to see the changes. Is there any way to delete those transients automatically with a function?? – KronosL Aug 23 '17 at 00:24
  • Can you please guide me how to add it properly to my_custom_price function? Thanks in advance, great answear! – KronosL Aug 23 '17 at 00:37
  • 1
    @KronosL Updated my answer with `wc_delete_product_transients($post->ID);` … as this seems specific when used from a plugin. When you use that hooks through the theme, this problem doesn't exist. After this will not be enough… so you will have to search a bit. – LoicTheAztec Aug 23 '17 at 00:55
  • that doesnt seem to work all prices are turning into 0 – kos Jan 20 '18 at 15:52
  • @kos I have tested, corrected and updated the code... There is 2 versions now, so choose the good one depending if it's for a plugin or the active theme function.php file. – LoicTheAztec Jan 20 '18 at 23:43
  • Actually, instead of calling `wc_delete_product_transients()` (which is defeating the performance boost the transient was designed to employ), you can simply hook into the [woocommerce_get_variation_prices_hash](https://docs.woocommerce.com/wc-apidocs/hook-docs.html) filter to cause different transients to be saved and reused. See [this blog post](https://woocommerce.wordpress.com/2015/09/14/caching-and-dynamic-pricing-upcoming-changes-to-the-get_variation_prices-method/) on the official WooCommerce development blog. – Matthew Clark Sep 06 '18 at 22:31
  • @MatthewClark I have updated my answer code and explanations related to `woocommerce_get_variation_prices_hash` filter hook usage instead of using inefficient `wc_delete_product_transients()`. Thanks. – LoicTheAztec Sep 12 '18 at 15:15
  • @LoicTheAztec my edit was correct, no? You've put woocommerce_variation_prices_sale_price twice – JayIsTooCommon Jun 28 '19 at 15:44
  • @Leonid Sorry but my answer here is related to the OP question (provided code and details) **that has nothing to do product prices in widgets**… So I didn't forget anything. The hooks that I use in my answer are directly related to `WC_Product` price getter methods. – LoicTheAztec Sep 04 '19 at 18:17
  • Yes, but then when using your code, the standard WooCommerce filtering widget will not work correctly. – Leonid Sep 05 '19 at 05:31