WooCommerce & Restricting Related Products to Tags Only

WooCommerce & Restricting Related Products to Tags Only

Posted on December 13, 2016 Mary Merritt

Over the past year we've really been enjoying WordPress ecommerce projects that utilize the WooCommerce plugin. WooCommerce comes with a good standard set of features but also offers a bevy of non-standard features through the purchase of extensions. My favorite part so far in using WooCommerce is the fast and helpful support team at WooThemes - they've been there to help us figure out quirks and answer questions through every build. Additionally, it's refreshing to see so much development time and innovation being put into a quality ecommerce plugin for WordPress. Now that we've spewed enough praise for the WooThemes team, I'll share a minor hack I put together during our last build.

Restrict "Related Products" to Tags Only

WooCommerce has a nice standard feature that shows related products on individual product pages. The documentation says related products are those that, "share the same tags or categories as the current product." The problem with how this feature works in the current version (2.x) is unfortunately that category affiliations always over-ride tags. There are likely many scenarios where you'd rather show tag-related products, and not show category-related products, but still keep your products grouped by category.

By adding a new function to your theme's functions.php file and uploading/editing one WooCommerce template file, we are able to change the "related products" behavior to only use tags when selecting related products.

We start with copying the get_related function (found in the /classes/abstracts/abstract-wc-product.php file of the WooCommerce plugin directory), renaming it as the get_related_custom function, and making a few minor edits - here's the end result:

//New "Related Products" function for WooCommerce
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);
    // Get tags
    $terms = wp_get_post_terms($id, 'product_tag');
    foreach ( $terms as $term ) $tags_array[] = $term->term_id;
    // Get categories (removed by NerdyMind)
/*
    $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' => $limit,
        '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');

You'll notice that there is a new function parameter added to the fuction named $id, which will contain the product ID number. Relatedly, all uses of the $this variable have been replaced with the $id variable.

On line 14 we've commented out the two lines that pull in products from related categories. On line 48, the array_diff function call that sets the $related_posts variable has been simplified (this was required to keep the item from being "related" to itself now that this function is no longer a member of the WC_Product class).

Now that we've added the new function to our functions.php file, we can put the function to use by uploading the WooCommerce template file related.php to our template directory: /themes/current-theme/woocommerce/single-product/related.php (if you're unfamiliar with over-riding WooCommerce templates, check out the documentation here), and making a quick edit.

On line 14 of the related.php file, we find a function call to the original get_related function, and we want to update this to use our new function:

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

As you see, the new function call passes in the product ID as a parameter.

If you complete the two steps above, you should now only see tag-related related products on individual product pages! Of course, this isn't guaranteed to always work; the Woo team could completely rewrite how the WC_Product class or the original get_related function works at some point in the future (hint, hint, nudge, nudge - for all you Woo folks, this would be a nice feature to add!), which could prompt the need for an update to or removal of this method. Despite this caveat, I am happy with this hack, and I hope you've found it useful.

What special features or functions do you want to see in WooCommerce? Have you ever used the WooCommerce plugin for an ecommerce website?


**UPDATE, February 2014** Thanks everyone for the comments! I hope this post has been helpful. We can no longer help with problems via the comments section. If you'd like to talk to us regarding WooCommerce or WordPress consulting, please contact us.