16

I have the following lines of code in my website that will display the related products at the bottom of my single product page in WooCommerce...

functions.php:

// display upsells and related products within dedicated div with different column and number of products
remove_action( 'woocommerce_after_single_product_summary', 'woocommerce_output_related_products',20);
remove_action( 'woocommerce_after_single_product', 'woocommerce_output_related_products',10);
add_action( 'woocommerce_after_single_product_summary', 'woocommerce_output_related_products', 20);

function woocommerce_output_related_products() {
    $output = null;

    ob_start();
    woocommerce_related_products(4,4); 
    $content = ob_get_clean();
    if($content) { $output .= $content; }

    echo '<div class="clear"></div>' . $output;
}

As it displays 4 products that have been categorized under the same name, how would I modify the above, to display the related tags instead?

For example, I have a product category called 'Automotive' and within this category, are a few tags - 'Holden', 'Ford', 'Toyota', 'Nissan' etc.

I would like it to display 4 products at the bottom, related to the tag of the product the user is currently viewing.

2 Answers 2

33

Firstly, you can't immediately achieve the goal you described with the code you show in your question. To understand why there isn't a direct approach with that code you have to take a look at what you're using - woocommerce_related_products() - to do what you have done so far.

Secondly, you have to understand, because otherwise you are not able to ask a on point question, which should absolutely be your goal, to assure you're getting an answer. Besides that you have to keep in mind that Wordpress Development has it's primary scope set on wordpress core related questions - if you're interested, this is under discussion on Wordpress Development Meta, one specific topic being Our wooes and future of platform plugins at WPSE. So, if you're asking questions about plugins, like woocommerce, you should break it down to make it as related to core functions as possible - see the next point - as you can't expect people to know every detail of every plugin you're using.

Thirdly, now lets get into a deeper insight what's happening. As you said, you're using woocommerce_related_products() now. If you take a look at the source you see that this function uses woocommerce_get_template() to get the related.php template. woocommerce_get_template() again uses woocommerce_locate_template() to locate the template, the latter is doing so by making use of the wordpress core function locate_template().
Now there is a connection back to core, leading to the realization that the above mentioned - and hopefully inspected - woocommerce functions are essentially wrappers to extend core functionality. Another thing that became clear by analyzing the functionality dependencies is, what I said before, you need a different approach to achieve your goal, because woocommerce_related_products() - now undeniable obvious - isn't the correct one.
If you followed me with my explanations and have read thoroughly so far, you realized that the related.php contains what you are looking for. I'm especially talking about the get_related() function, which includes the woocommerce_product_related_posts hook and makes use of the core functions wp_get_post_terms() and get_posts() - get_related() is used to get a set of ids. Additionally there is the woocommerce_related_products_args hook, which can be used to alter the arguments of the related products query inside related.php, WP_Query is used for this. The query uses the resulting ids from the get_related() call.
I think you got everything on hand now to solve your problem. Actually way more than that, this gives a almost complete overview on how to customize the related products. I did not mention every functionality - function and/or hook - out of source code inspected, but definitely all the important ones. It now should be clearer how the related products functionality of woocommerce can be traced back to wordpress core functions.

Fourthly, I come to, where you should apply your customizations and what you should have asked for. For example like this:

Woocommerce has the woocommerce_product_related_posts hook to customize the get_posts() call to determine related products.

Code:

        // 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
                        )
                )
        ) ) );

How can I customize this to achieve my goal? Which is to show related products that are in the same product category - product_cat - and have the same tag(s) - product_tag - as the single product shown.

Without giving you a concluding - at least not if you had expectation to get complete and ready made code - answer, the first thing you probably should do is change the tax_query parameter relation from OR to AND.





Notes:

  • I made this a longer descriptive answer with the above linked ongoing discussion in mind
  • I hope you don't mind, that it's not only an answer to your question, but additionally pursues to fulfill a general educational purpose
  • this is untested, because there is no actual ready made code
  • last but not least, it's foreseeable that with the release of woocoomerce 2.1 some significant code changes will be implemented, bare that in mind, but for now as of 2.0.19 the above code is valid



Edit:

You really shouldn't edit (plugin) core classes directly. It's problematic, because you have to maintain your changes on updates again, as the core files get updated and overwritten if you perform one. Especially if it's easily avoidable like in this case, below code does what you intended to do anyways, which is, implementing this change via your functions.php.

Code:

    add_filter( 'woocommerce_product_related_posts', 
                'wpse_123436_change_wc_related_products_relation_to_and' );
    function wpse_123436_change_wc_related_products_relation_to_and() {
            $get_related_products_args = array(
                'orderby' => 'rand',
                'posts_per_page' => $limit,
                'post_type' => 'product',
                'fields' => 'ids',
                'meta_query' => $meta_query,
                'tax_query' => array(
                    'relation' => 'AND',
                    array(
                        'taxonomy' => 'product_cat',
                        'field' => 'id',
                        'terms' => $cats_array
                    ),
                    array(
                        'taxonomy' => 'product_tag',
                        'field' => 'id',
                        'terms' => $tags_array
                    )
                )
            );
            return $get_related_products_args;
    }



For WooCommerce version 2.1.0 and upwards the above hook won't work, as it doesn't exist anymore, so the answer is usable until version 2.0.20. But @NathanPowell discovered a nice answer on StackOverflow regarding the from v2.1.0 on available and for the customization of the related products usable set of hooks.

9
  • Thank you very much @ialocin for the quick and detailed response. As a temporary measure, I simply changed the OR to AND in my wp-content/plugins/woocommerce/classes/abstract/abstract-wc-product.php file and will soon change this to be done from within the functions.php file. Thank you again. Commented Nov 17, 2013 at 4:28
  • @user1752759 See my edit to do this via functions.php Commented Nov 18, 2013 at 11:01
  • Perfect answer! It should be used in any guidebook on how to understand plugins and how to extend them to your needs. Not sure if these books exists though.. But still :)
    – ThdK
    Commented Apr 6, 2014 at 19:23
  • @ThdK Thanks, I don't know if it is that good, but after reading it the first time since writing it I'm still happy with the answer, besides that I surely appreciate the compliment, it's always nice to hear :) Have you tried this with WC 2.1.x? Commented Apr 7, 2014 at 9:05
  • Hi there @ialocin. The edited version at the bottom is missing a few closing brackets, and unfortunately, is no longer working as a solution in version 2.1.8. If it's not too much to trouble, could you please update this for me? Commented May 6, 2014 at 4:21
2

Let's not fool ourselves here guys. The accepted answer only got the user to his goal.

The very first problem lies here:

<?php
// display upsells and related products within dedicated div with different column and number of    products
remove_action( 'woocommerce_after_single_product_summary', 'woocommerce_output_related_products',20);
remove_action( 'woocommerce_after_single_product', 'woocommerce_output_related_products',10);
add_action( 'woocommerce_after_single_product_summary', 'woocommerce_output_related_products', 20);

An action is removed, and then placed in the EXACT position it was removed from. The goal is completely unclear.

I came across this with a search on the related products because I did not understand that TAGS and CATEGORIES are what drives the woocommerce_output_related_products function in this plugin.

The best answer to THIS question is the following link, and has everything to do with the woocommerce_output_related_products_args() filter: https://stackoverflow.com/questions/23554993/output-posts-relating-to-the-tags

4
  • This is actually quite funny. Why you might ask, because if you've read my answer carefully, then you would've seen, it uses only one filter. To be exact the only filter available at that time, but you would have known that, if you actually had read what I wrote and would have taken the time to look at the source files of the different versions. Just saying. Aside from that, the answer you linked explains the new hooks available sine v2.1 very well. Commented Oct 6, 2014 at 19:17
  • Sorry about that, it was a late night. I was hoping to explain a bit about the obvious fault in the code by the OP. Commented Oct 16, 2014 at 15:51
  • No worries, but felt I had to say something though. Commented Oct 18, 2014 at 6:40
  • Your reference link worked for me Nathan, thanks, been trying to do it for myself 2 hours now. Now I know to apply filters properly :)
    – marcovega
    Commented Jul 8, 2015 at 9:41

Not the answer you're looking for? Browse other questions tagged or ask your own question.