В стандартной реализации WooCommerce блок «Похожие товары» не всегда работает так, как ожидается в реальных магазинах. Особенно это заметно, когда товары распределены по вложенным категориям и в дочерней категории находится всего несколько позиций.
Задача, которую мы решаем:
- сначала выводить похожие товары из той же категории, что и текущий товар;
- если товаров недостаточно — подключать родительские категории;
- остановиться, как только будет набрано нужное количество товаров.
Такой подход делает блок похожих товаров более логичным и полезным для пользователя.
Реализация
Ниже приведён пример реализации через фильтр woocommerce_related_products, который полностью переопределяет стандартную логику WooCommerce:
1function slug_related_products_by_cat( $related_posts, $product_id, $args ) {
2 $limit = $args['limit'] ?? 4;
3 $exclude = $args['excluded_ids'] ?? [];
4
5 $terms = get_the_terms( $product_id, 'product_cat' );
6 if ( !$terms ) {
7 return $related_posts;
8 }
9
10 $leaf_terms = [];
11 foreach ( $terms as $term ) {
12 $is_parent_of_selected = in_array( $term->term_id, wp_list_pluck( $terms, 'parent' ), true );
13 if ( !$is_parent_of_selected ) {
14 $leaf_terms[] = $term;
15 }
16 }
17
18 $slugs = [];
19 foreach ( $leaf_terms as $term ) {
20 $slugs[] = $term->slug;
21
22 foreach ( get_ancestors( $term->term_id, 'product_cat' ) as $parent_id ) {
23 $parent = get_term( $parent_id, 'product_cat' );
24 if ( $parent ) {
25 $slugs[] = $parent->slug;
26 }
27 }
28 }
29
30 $slugs = array_values( array_unique( $slugs ) );
31
32 $found = [];
33 foreach ( $slugs as $slug ) {
34 $need = $limit - count( $found );
35 if ( $need <= 0 ) {
36 break;
37 }
38
39 $ids = wc_get_products( [
40 'status' => 'publish',
41 'limit' => $need,
42 'return' => 'ids',
43 'orderby' => 'rand',
44 'category' => [ $slug ],
45 'exclude' => array_merge( $exclude, $found ),
46 ] );
47
48 $found = array_merge( $found, $ids );
49 }
50
51 return $found ? array_slice( array_values( array_unique( $found ) ), 0, $limit ) : $related_posts;
52}
53add_filter( 'woocommerce_related_products', 'slug_related_products_by_cat', 10, 3 );
Какие сценарии он покрывает
Реализация корректно работает в обоих распространённых сценариях:
-
Товар привязан ко всем уровням категорий
Например:Clothing → Men → Hoodies.
В этом случае сначала используются самые глубокие категории, а затем — родители. -
Товар привязан только к конечной категории
Например: толькоHoodies.
Родительские категории автоматически подтягиваются через иерархию.
В результате блок похожих товаров всегда остаётся релевантным и не зависит от того, как именно категории назначены товару в админке.
Использование в шаблоне
После добавления кода с фильтром woocommerce_related_products никаких дополнительных действий для подключения логики не требуется.
WooCommerce автоматически применит её при выводе блока «Похожие товары».
Дальше всё зависит от того, как именно ты хочешь выводить related products.
Стандартный вывод WooCommerce
Самый простой и рекомендуемый вариант — использовать стандартную функцию WooCommerce:
1<?php woocommerce_output_related_products(); ?>
В этом случае:
- WooCommerce сам определит текущий товар;
- применит все настройки;
- использует нашу кастомную логику подбора товаров.
Обычно этот вызов уже есть в шаблоне single-product.php.
Задать количество товаров и колонки
Если нужно управлять количеством товаров и сеткой вывода:
1<?php woocommerce_related_products([
2 'posts_per_page' => 6,
3 'columns' => 3,
4]); ?>
Переместить блок в другое место шаблона
По умолчанию related products выводятся после краткого описания товара. Если нужно изменить позицию, можно удалить стандартный вывод и добавить свой.
1remove_action( 'woocommerce_after_single_product_summary', 'woocommerce_output_related_products', 20 );
2
3add_action( 'woocommerce_after_single_product_summary', 'woocommerce_output_related_products', 35 );
Этот код обычно добавляют в functions.php темы.