This post is for you who want to add code that adjusts the prices in your WordPress WooCommerce webshop. You can either increase the prices or discount them. And how and from where the adjustments come, depend entirely on your case. Your webshop could operate with percentage discounts set on each registered user, a custom global setting in WooCommerce settings, a hardcoded fixed sum, or something set on each product or product category.

I have tried to make the code as general as possible so you can adjust it to your case. In my case the price adjustments come from a percentage discount added as user meta.

The code is updated to work for WooCommerce 3.x and above. I cannot guarantee that it will work for lower versions.

Step 1: Make a place for your code

The first step is easy; you need a place to add your code. This depends entirely on you. You could add this directly in your theme’s functions.php, or somewhere in your plugin files. I like to work with classes which will keep everything nicely together in one place. For simpleness sake I’ll put the class a subdirectory /src/ in my theme, and include and instantiate it in functions.php.

ChangePrices.php
<?php
class ChangePrices {
	public function __construct() {
	
	}
}
functions.php
require_once(get_stylesheet_directory().'/src/ChangePrices.php');
new ChangePrices();

Modify this step to suit your case.

Step 2: Decide how the price adjustments should work

This step might already be clear for you – this is where you need to know how and where to get the price adjustment. The end goal should be a number that you add, subtract, multiply or divide the prices with.

In my case I have a user meta on each user that contains a percentage discount; a number between 0 and 99. The site administrator can set a discount on each user. I won’t show the code for adding the user meta field, as this might not be for you and it’s easily done with e.g. Advanced Custom Fields.

In my class I keep a class variable which in constructor will be set to a multiplier. Depending on whether a user is logged in I’ll fetch the saved discount from the user and create a multiplier from it. As default the multiplier should be 1. Price * 1 = same price as before. But for a discount on for example 10% the multiplier would be 0.9. Price * 0.9 = price discounted with 10%.

ChangePrices.php
<?php
class ChangePrices {
	private $user_discount_multiplier;

	public function __construct() {
		$this->user_discount_multiplier = $this->getUserDiscount();
	}

	public function getUserDiscount() {
		if ((is_admin() && !defined('DOING_AJAX')) || (!is_user_logged_in()) ) {
			return 1;
		}

		$user = wp_get_current_user();
		$discount = (int)get_user_meta($user->ID, 'webshop_discount_percentage', true);

		return ($discount < 1 || $discount > 99) ? 1 : abs(($discount/100)-1);
	}
}

Now that I have a ready-to-use multiplier, it’s time to look into actually adjusting prices in WooCommerce.

Step 3: Price filters in WooCommerce

In WooCommerce there’s one filter for simple, grouped and external product types, and another for variable product types. I recommend that you add both filters to cover all product types. In addition to this, WooCommerce operates with three additional price filters:

  • Regular prices (woocommerce_product_get_regular_price and woocommerce_product_variation_get_regular_price)
  • Sale prices ( woocommerce_product_get_sale_price and woocommerce_product_variation_get_sale_price)
  • The current active price (woocommerce_product_get_price and woocommerce_product_variation_get_price). The current active price will be fetched from either the regular price or sale price.

Now, you could simply filter the current active price and call it a day, but it depends on how you want to handle the display of prices in your webshop. Remember that products on sale by default show the old price (regular price) in strikethrough and the sale price (active price) next to it. If you filter only x_get_price and a product is on sale, the old price will be shown undiscounted.

Because of this, I choose to filter both the active current price (x_get_price) and the regular price (x_get_regular_price), because I don’t want to confuse my webshop users.

Writing the price filter

All four filters will refer to the same function. Inside the function we simply multiply the provided price with the class variable. Remember that if no discount is set, the multiplier is 1 which results in no change in price.

ChangePrices.php
<?php
class ChangePrices {
	private $user_discount_multiplier;

	public function __construct() {
		$this->user_discount_multiplier = $this->getUserDiscount();

		add_filter('woocommerce_product_get_price', [$this, 'adjustPrice'], 99, 2);
		add_filter('woocommerce_product_get_regular_price', [$this, 'adjustPrice'], 99, 2);
		add_filter('woocommerce_product_variation_get_price', [$this, 'adjustPrice'], 99, 2);
		add_filter('woocommerce_product_variation_get_regular_price', [$this, 'adjustPrice'], 99, 2);
	}

	public function adjustPrice($price, $product) {
		return $price * $this->user_discount_multiplier;
	}

	public function getUserDiscount() {
		....

Note that all filters provide the product object as second parameter. If you wanted to adjust prices depending on products, you can adjust the code to do so.

If you check your webshop while being logged in as an user with a discount, you should now see discounted prices! However, we’re not quite done yet. WooCommerce made some changes in 2.4.7 (read more here) which affect dynamic pricing for variable products.

Handling variable product prices

To make dynamic pricing work on variable products, you should add the filters mentioned in the blog post linked above; woocommerce_variation_prices_price (and the corresponding regular price filter woocommerce_variation_prices_regular_price), and the filter woocommerce_get_variation_prices_hash. The hash filter is handling WooCommerce’s internal cache – and we need to tell WooCommerce to clear it properly when we modify the prices by code.

The first two price filters follow the same procedure as adjustPrice(), however I assign a different function for them because the parameters are different. As for the hash filter function we need to add to the hash array to identify when cache should be cleared. Adding the user ID is a good idea since the multiplier is unique for each user.

ChangePrices.php
<?php
class ChangePrices {
	private $user_discount_multiplier;

	public function __construct() {
		$this->user_discount_multiplier = $this->getUserDiscount();

		add_filter('woocommerce_product_get_price', [$this, 'adjustPrice'], 99, 2);
		add_filter('woocommerce_product_get_regular_price', [$this, 'adjustPrice'], 99, 2);
		add_filter('woocommerce_product_variation_get_price', [$this, 'adjustPrice'], 99, 2);
		add_filter('woocommerce_product_variation_get_regular_price', [$this, 'adjustPrice'], 99, 2);

		add_filter('woocommerce_variation_prices_price', [$this, 'adjustVariablePrice'], 99, 3);
		add_filter('woocommerce_variation_prices_regular_price', [$this, 'adjustVariablePrice'], 99, 3);

		add_filter('woocommerce_get_variation_prices_hash', [$this, 'variationPricesHash']);
	}

	public function variationPricesHash($hash) {
		$hash[] = get_current_user_id();
		return $hash;
	}

	public function adjustVariablePrice($price, $variation, $product) {
	    return $price * $this->user_discount_multiplier;
	}

	public function adjustPrice($price, $product) {
		...

Finally, that should be it!

Note that you have access to the complete product object in all filters (even variation object in the last two). This is useful for cases when you want to adjust prices based on product information; such as excluding certain products from discount, or apply a discount based on a product’s categories. It should be pretty straightforward for you to adjust the code to what you need for your case.

The full final code

As usual I hope you have learned something by following this post step by step, but I’ll provide the full class for reference:

ChangePrices.php
<?php
class ChangePrices {

	var $user_discount_multiplier;

	public function __construct() {
		$this->user_discount_multiplier = $this->getUserDiscount();

		add_filter('woocommerce_product_get_price', [$this, 'adjustPrice'], 99, 2);
		add_filter('woocommerce_product_get_regular_price', [$this, 'adjustPrice'], 99, 2);
		add_filter('woocommerce_product_variation_get_price', [$this, 'adjustPrice'], 99, 2);
		add_filter('woocommerce_product_variation_get_regular_price', [$this, 'adjustPrice'], 99, 2);

		add_filter('woocommerce_variation_prices_price', [$this, 'adjustVariablePrice'], 99, 3);
		add_filter('woocommerce_variation_prices_regular_price', [$this, 'adjustVariablePrice'], 99, 3);

		add_filter('woocommerce_get_variation_prices_hash', [$this, 'variationPricesHash']);
	}

	public function variationPricesHash($hash) {
		$hash[] = get_current_user_id();
		return $hash;
	}

	public function adjustVariablePrice($price, $variation, $product) {
	    return $price * $this->user_discount_multiplier;
	}

	public function adjustPrice($price, $product) {
		return $price * $this->user_discount_multiplier;
	}

	public function getUserDiscount() {
		if ((is_admin() && !defined('DOING_AJAX')) || (!is_user_logged_in()) ) {
			return 1;
		}

		$user = wp_get_current_user();
		$discount = (int)get_user_meta($user->ID, 'webshop_discount_percentage', true);

		return ($discount < 1 || $discount > 99) ? 1 : abs(($discount/100)-1);
	}
}