Диагностика проблемы с медленной фильтрацией по иерархии категорий
При использовании сложной иерархии категорий в WooCommerce нередко возникает ситуация, когда AJAX-фильтры на страницах каталога работают с задержками или полностью не отвечают. Особенно это заметно при большом количестве товаров и вложенных категорий. Основные симптомы:
- Долгая загрузка результатов фильтрации;
- Фильтр не обновляет список товаров без перезагрузки страницы;
- Ошибки в консоли браузера, связанные с AJAX-запросами;
- Неправильное отображение выбранных категорий в фильтре.
Для диагностики проблем используйте инструменты разработчика браузера (Network, Console) и проверьте SQL-запросы к базе через плагин Query Monitor. Часто причиной становится неэффективный запрос к базе из-за избыточных JOIN или отсутствия кеширования.
Пошаговое решение: оптимизация фильтрации по иерархии категорий
1. Использование правильных хуков для фильтрации товаров
Для кастомной фильтрации товаров по категориям с учетом иерархии используйте хук pre_get_posts. Пример кода для фильтрации по выбранной категории и ее дочерним категориям:
add_action('pre_get_posts', function($query) {
if (is_admin() || !$query->is_main_query()) {
return;
}
if (is_shop() || is_product_category()) {
$cat = get_queried_object();
if ($cat && isset($cat->term_id)) {
$child_cats = get_terms(array(
'taxonomy' => 'product_cat',
'child_of' => $cat->term_id,
'fields' => 'ids',
'hide_empty' => false
));
$cat_ids = array_merge(array($cat->term_id), $child_cats);
$tax_query = array(
array(
'taxonomy' => 'product_cat',
'field' => 'term_id',
'terms' => $cat_ids,
'include_children' => false,
'operator' => 'IN'
)
);
$query->set('tax_query', $tax_query);
}
}
});2. Кеширование результатов запросов и данных категорий
Чтобы уменьшить нагрузку, кешируйте результат вызова get_terms() и сложных запросов. Используйте Transients API:
function get_cached_child_categories($parent_id) {
$cache_key = 'child_cats_' . $parent_id;
$cached = get_transient($cache_key);
if ($cached !== false) {
return $cached;
}
$terms = get_terms(array(
'taxonomy' => 'product_cat',
'child_of' => $parent_id,
'fields' => 'ids',
'hide_empty' => false
));
set_transient($cache_key, $terms, 12 * HOUR_IN_SECONDS);
return $terms;
}Вызовите эту функцию вместо get_terms() в фильтре выше.
3. Использование AJAX с правильными параметрами
Убедитесь, что AJAX-запросы фильтра посылаются с верными параметрами категорий и корректно обрабатываются на бэкенде. Для кастомного AJAX обработчика добавьте в functions.php:
add_action('wp_ajax_filter_products', 'filter_products_callback');
add_action('wp_ajax_nopriv_filter_products', 'filter_products_callback');
function filter_products_callback() {
$cat_id = intval($_POST['cat_id']);
if (!$cat_id) {
wp_send_json_error('Invalid category ID');
}
$child_cats = get_cached_child_categories($cat_id);
$cat_ids = array_merge(array($cat_id), $child_cats);
$args = array(
'post_type' => 'product',
'tax_query' => array(
array(
'taxonomy' => 'product_cat',
'field' => 'term_id',
'terms' => $cat_ids,
'include_children' => false
)
),
'posts_per_page' => 20
);
$query = new WP_Query($args);
ob_start();
if ($query->have_posts()) {
while ($query->have_posts()) {
$query->the_post();
wc_get_template_part('content', 'product');
}
} else {
echo '<p>Товары не найдены</p>';
}
wp_reset_postdata();
$content = ob_get_clean();
wp_send_json_success(array('html' => $content));
}Проверка результата после внедрения
- Откройте страницу каталога с фильтрами и выберите категорию с дочерними категориями.
- Убедитесь, что товары обновляются быстро без полной перезагрузки страницы.
- Проверьте консоль браузера на отсутствие ошибок AJAX.
- С помощью Query Monitor проверьте, что количество SQL-запросов уменьшилось.
Частые ошибки и способы их исправления
- Ошибка: Фильтр не учитывает дочерние категории.
Причина: Не используется параметрchild_ofилиinclude_childrenв запросах.
Исправление: Используйтеget_terms(['child_of' => $parent_id])и правильно формируйтеtax_query. - Ошибка: AJAX-запросы не обрабатываются.
Причина: Нет регистрации AJAX-хуков или неправильный action.
Исправление: Добавьте обработчики дляwp_ajax_иwp_ajax_nopriv_. - Ошибка: Долгая загрузка страниц с фильтрацией.
Причина: Отсутствие кеширования, большое количество SQL-запросов.
Исправление: Внедрите Transients API для кеша категорий и результатов.
Практические советы по безопасности и производительности
- Всегда проверяйте и валидируйте входящие AJAX-параметры, например, через
intval()илиsanitize_text_field(). - Очищайте кеш при обновлении категорий товаров, чтобы не показывать устаревшие данные. Для этого используйте хуки
edited_product_catиcreated_product_cat:
add_action('edited_product_cat', 'clear_category_cache');
add_action('created_product_cat', 'clear_category_cache');
function clear_category_cache($term_id) {
delete_transient('child_cats_' . $term_id);
}- Используйте пагинацию при больших объемах товаров, чтобы не загружать сразу все результаты.
- Минимизируйте использование тяжелых JOIN и meta_query в фильтрах, если это возможно.
Сравнение вариантов решения фильтрации по иерархии категорий
| Вариант | Описание | Плюсы | Минусы |
|---|---|---|---|
| Стандартный WooCommerce фильтр | Использование встроенных виджетов и фильтров | Простота, интеграция с темой | Медленная работа на больших каталогах, проблемы с AJAX |
Кастомный pre_get_posts с кешированием | Настройка фильтра через хук с кешем категорий | Ускоряет запросы, учитывает иерархию | Требует разработки и поддержки |
| Кастомный AJAX-обработчик | Фильтрация через AJAX запросы с кешем и WP_Query | Быстрая динамическая фильтрация без перезагрузки | Нужна доработка фронтенда и безопасности |