Randomize Woocommerce Related Products

Woocommerce has a built-in related products section that pulls product recommendations from the assigned categories and tags for the current product. It works as described, but it has its drawbacks with how it works as well. We are going to look at a couple easy-to-implement code snippets that overcome the main flaws of the default Woocommerce related products section.

Default Related Products Problems

The first issue is that the recommendations get pulled from all the selected categories and tags. This can lead to much more vague and unspecific recommendations. Many people may label a product with a main category and a subcategory, so woocommerce would pull recommendations from both. Ideally though we would want this limited to the most specific category of the product for the most relevant recommendations. For example, a department store may have a main category for clothing and a subcategory for coats. When viewing a coat, we would want our related products to show other coat options, not random other items of clothing like socks or pants. This is exactly what can happen with the built-in method. This can be more of a problem when you inherit a store that labeled all products with a general main category of something like “All Products”. It’s not smart, but it happens.

Secondly, the recommendations are not randomized. So a product will show the same recommendations every time. This issue becomes more apparent as you view more and more products that share the same set of categories and tags. You are not giving your customer base the ability to quickly see as many random items from your product set to entice them.

Woocommerce Related Products Solutions

To make the related products more specific, we have a couple options that we will go over. One is excluding specific categories from the pool entirely, while the other involves selecting one specific category to use. In these snippets I remove the tags from the formula entirely and work just off of the categories. Then to fix the problem of repeated recommendations, we will be pulling more recommendations and selecting a random set to show each time. I use a pool of up to 100 products. Now let’s get to the code.

We will be editing the functions.php file in your child theme and we will also be editing the woocommerce related.php file. To ensure your edits to related.php do not get overwritten with woocommerce updates, make sure to duplicate the file into your child theme. It should be placed in your child theme in /woocommerce/single-product/related.php. You may need to create those folders if you have not made any woocommerce customizations yet.

In related.php, find the line that starts $args = apply_filters(… and add the following line of code right on the line right before that one:

$related = get_related_custom( $product->id );

That’s all we need the related.php file. We are basically calling the custom function that we are creating next and passing the product ID to it. It uses the results from the function in the query used right after.

Randomization Code Snippet

This is the base code that you need to just get it to display a random set of results each time. You can just put this in your functions.php file as is.

function get_related_custom( $id, $limit = 5 ) {
    global $woocommerce;

    // Related products are found from category and tag
    $tags_array = array(0);
    $cats_array = array(0);

    $terms = wp_get_post_terms($id, 'product_cat');
    foreach ( $terms as $term ) { $cats_array[] = $term->term_id; }

    // Don't bother if none are set
    if ( sizeof($cats_array)==1 && sizeof($tags_array)==1 ) return array();

    // Meta query
    $meta_query = array();
    $meta_query[] = $woocommerce->query->visibility_meta_query();
    $meta_query[] = $woocommerce->query->stock_status_meta_query();

    // Get the posts
    $related_posts = get_posts( apply_filters('woocommerce_product_related_posts', array(
        'orderby'        => 'rand',
        'posts_per_page' => 100,
        'post_type'      => 'product',
        'fields'         => 'ids',
        'meta_query'     => $meta_query,
        'tax_query'      => array(
            'relation'      => 'OR',
            array(
                'taxonomy'     => 'product_cat',
                'field'        => 'id',
                'terms'        => $cats_array
            ),
            array(
                'taxonomy'     => 'product_tag',
                'field'        => 'id',
                'terms'        => $tags_array
            )
        )
    ) ) );
    $related_posts = array_diff( $related_posts, array( $id ));
    return $related_posts;
}
add_action('init','get_related_custom');

Randomization Code Snippet with Yoast SEO Primary Categories

If you are using Yoast SEO aka WordPress SEO, then we can make use of some of its functionality to only display related products from a specific category. Yoast SEO allows us to choose a category as a “Primary” category, so we use this to our advantage. This code will pull only from the Primary category for its related products. We have a fallback built into our code snippet because if you are installing Yoast after the fact because it will not automatically select a Primary category on your existing products. You would need to do that manually. It will automatically set a Primary category on all future added products though. You would put this in your functions.php file instead of the previous code snippet.

function get_related_custom( $id, $limit = 5 ) {
    global $woocommerce;

    // Related products are found from category and tag
    $tags_array = array(0);
    $cats_array = array(0);
   
   ////////// CUSTOM section for yoast primary categories ///////////
    if ( class_exists('WPSEO_Primary_Term') )
    {
        // Show the post's 'Primary' category, if this Yoast feature is available, & one is set
        $wpseo_primary_term = new WPSEO_Primary_Term( 'product_cat', $id );
        $wpseo_primary_term = $wpseo_primary_term->get_primary_term();
        $term = get_term( $wpseo_primary_term );
        if (is_wp_error($term)) {
            // Default to first category (not Yoast) if an error is returned
            $terms = wp_get_post_terms($id, 'product_cat');
            foreach ( $terms as $term ) { $cats_array[] = $term->term_id; }
        } else {
            // Yoast Primary category
            $cats_array[] = $term->term_id;
        }
    }
    else
    {
        // Get categories
        $terms = wp_get_post_terms($id, 'product_cat');
        foreach ( $terms as $term ) { $cats_array[] = $term->term_id; }
    }
   //////////////////////////////////////////////////////////////
 
    // Don't bother if none are set
    if ( sizeof($cats_array)==1 && sizeof($tags_array)==1 ) return array();
 
    // Meta query
    $meta_query = array();
    $meta_query[] = $woocommerce->query->visibility_meta_query();
    $meta_query[] = $woocommerce->query->stock_status_meta_query();
 
    // Get the posts
    $related_posts = get_posts( apply_filters('woocommerce_product_related_posts', array(
        'orderby'        => 'rand',
        'posts_per_page' => 100,
        'post_type'      => 'product',
        'fields'         => 'ids',
        'meta_query'     => $meta_query,
        'tax_query'      => array(
            'relation'      => 'OR',
            array(
                'taxonomy'     => 'product_cat',
                'field'        => 'id',
                'terms'        => $cats_array
            ),
            array(
                'taxonomy'     => 'product_tag',
                'field'        => 'id',
                'terms'        => $tags_array
            )
        )
    ) ) );
    $related_posts = array_diff( $related_posts, array( $id ));
    return $related_posts;
}
add_action('init','get_related_custom');

Excluding Specific Categories

Whether you are using the Yoast SEO code snippet or the pure randomization method above, you can also exclude specific categories. In the Yoast SEO method this is not used if a Primary category is selected, but is used in the event that the fallback method in the code is used. With either method, this is a great way to fix the problem with someone having an all-encompassing “All Products” category. To exclude specific categories from showing in the woocommerce related products section, you’ll need to get the ID numbers of the categories you don’t want to include and then modify the code as follows:
Find the line(s):

foreach ( $terms as $term ) { $cats_array[] = $term->term_id; }

Replace each instance with this code:

foreach ( $terms as $term ) {
    if(($term->term_id != 319) && ($term->term_id != 317)){
        $cats_array[] = $term->term_id;
    }
}

Here we are excluding two categories, but you can alter it to exclude any number. Just replace the numbers in red with your category ID numbers.

Conclusion

The built-in Woocommerce related products section works good as it is, but we can make it much better with these two easy-to-implement code snippet options. We pick a more specific set of products and then we randomize them to create a fully superior woocommerce related products display. It may not even be worth the effort for a small store with a limited number of products, but if you have a lot of products in your store you will realize how much you actually need these changes and how much of a benefit they will be to your store.

Speak Your Mind

*