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.