Changing WooCommerce related-products listings more often

Somebody, on a plugin support thread, asked me how to control how often to change up the related-products listings on product pages. WooCommerce automatically uses product categories and tags to find related products to the one the customer is viewing.

WooCommerce does this by fetching a list of related products from the database, randomly choosing some of them (five by default), and then stashing the list in a transient with an expiration of one calendar day. If the transient is present on subsequent views, WooCommerce gets the list from the transient. That means the list includes the same products for a calendar day before it is reshuffled to show different products.

This shop owner wants them to remain the same for a shorter period of time, and change more often. How do we do that?

The answer is to shorten the lifetime of the transient, from one day to a shorter time interval.

So, how do we do that?

First, we need to know the name of the transient in question. It’s called 'wc_related_10242' for product id 10242. Then we need to change the expiration of that transient. Luckily, there’s a filter built into the set_transient() function with the name 'expiration_of_transient_{$transient_name}' where the transient’s name is part of the filter name. So we can change the expiration of the related products transient for product 10242 with code like this:

add_filter(
    'expiration_of_transient_wc_related_10242',   /* Silly hardcoded constant. */
    function ( $expiration, $value, $transient ) {
        return 3 * HOUR_IN_SECONDS;
    },  10, 3 );

That filter replaces the 24-hour expiration time with a three-hour one. Good.

But, there’s obviously a problem here. We don’t know the product id in advance so we can’t just add a filter for that one product. Fortunately WooCommerce has a hook, a filter, it invokes while it’s retrieving the list of related products. That filter is called 'woocommerce_product_related_posts_relate_by_category'and includes a $product_id parameter. So we can use it to find the product id and register the expiration filter. This snippet does all that.

 add_filter( 
    'woocommerce_product_related_posts_relate_by_category',
    function ( $result, $product_id ) {
        $transient = 'wc_related_' . $product_id;
        add_filter( 
            "expiration_of_transient_{$transient}",
             function ( $expiration, $value, $transient ) {
                 return 3 * HOUR_IN_SECONDS;
             }, 10, 3 );
         return $result
    }, 10, 2 );

How did I figure this out?

The site owner looked at all the transients in their system and figured out 'wc_related_10242' is the one holding the relate-products list for that product.

I used my IDE to search the code base for the string wc_related_ . That search pointed me to the function called `wc_get_related_products()` Reading the code for that function revealed the invocation of the 'woocommerce_product_related_posts_relate_by_category' filter and the setting of the transient.

Thanks to @januzi_pl for the question.

Leave a Comment