WooCommerce Internals: How to filter just about anything
WooCommerce is an advanced shopping cart system, most of which doesn’t show itself from the outside, with a lot of internals. At the time of writing, WooCommerce reconmends using it’s objects (WC_Product, WC_Cart) taking it into an object-orientated platform as opposed to how much of WordPress operates in a functional style (although this is changing over time).
Part of the way these objects work is over some base classes which allows for WooCommerce to expose some really powerful functionality for custom developers. Essentially, each object, so long as it’s accessed correctly, can be filtered on it’s value. This allows you to filter on many different parts of an online shop such as VAT, payment methods, product pricing etc.
How to dig through WooCommerce internals for filters
In order to find a filter you can use, you might need to dig through the WooCommerce source code (which is nicely available on GitHub for searching). Let’s take a fairly simple example of changing the price of a product. This will change the price displayed to a customer, and what goes into the order.
Firstly, we start from WC_Product_Simple which is the default type of product and we can’t see anything relating to prices yet, so we go up one level:
class WC_Product_Simple extends WC_Product {
Code language: PHP (php)
Inside WC_Product, we can see from get_price()
which uses the magic function we are looking for get_prop()
:
/**
* Returns the product's active price.
*
* @param string $context What the value is for. Valid values are view and edit.
* @return string price
*/
public function get_price( $context = 'view' ) {
return $this->get_prop( 'price', $context );
}
Code language: PHP (php)
This function comes from the base class WC_Data. Along with fetching the data from the array loaded from the database, it provides a filter. The filter is ran if the context is view
which is used in most places.
/**
* Gets a prop for a getter method.
*
* Gets the value from either current pending changes, or the data itself.
* Context controls what happens to the value before it's returned.
*
* @since 3.0.0
* @param string $prop Name of prop to get.
* @param string $context What the value is for. Valid values are view and edit.
* @return mixed
*/
protected function get_prop( $prop, $context = 'view' ) {
$value = null;
if ( array_key_exists( $prop, $this->data ) ) {
$value = array_key_exists( $prop, $this->changes ) ? $this->changes[ $prop ] : $this->data[ $prop ];
if ( 'view' === $context ) {
$value = apply_filters( $this->get_hook_prefix() . $prop, $value, $this );
}
}
return $value;
}
Code language: PHP (php)
This shows the filter is the result of the prefix, and then the name of the prop. Once we know how these filter names are put together, we can add filters to these props.
The formula for producing these filters is woocommerce_
object type _get_
property name. To get the object type, we can look back in WC_Product where we can easily find it:
class WC_Product extends WC_Abstract_Legacy_Product {
/**
* This is the name of this object type.
*
* @var string
*/
protected $object_type = 'product';
Code language: PHP (php)
This means to change the price of a product, we can use the filter woocommerce_product_get_price
to modify the price. While you could easily find out this information from other posts, this works for any property. For example in order to change the weight of a product with woocommerce_product_get_weight
. Another example you could filter the stock status to check with an external service with woocommece_product_get_stock_status
.
This filter takes two parameters, the value and then the whole object being filtered. This allows you to check other properties of a product. For example you can check other custom postmeta fields to see if the customer should get a discount.
Filter a products price
Based on the information above, we can now filter a products price for example:
add_filter( 'woocommerce_product_get_price', 'example_get_price', 10, 2 );
function example_get_price( $price, $product )
{
if(is_user_logged_in() && !is_admin()) {
$price = $price * 0.8;
}
return $price;
}
Code language: PHP (php)
In this example, we discount prices by 20% if a customer is logged in. Also note we check if we are currently inside the admin panel (wp-admin). Take care when writing filters, as they also affect the admin panel which can give shop managers incorrect information.
Conclusion
This post has took us through the WooCommerce internals, to find the WC_Product class which eventually has properties we can filter on. Using this knowledge, advanced requirements for WooCommerce stores can be acomplished.
Comments, or got a project involving complex e-commerce needs? Do get in touch.