Фильтр WooCommerce по категории не возвращает результатов: исправление иерархии категорий
Если фильтр WooCommerce по категориям не возвращает результатов для родительских категорий, даже если товары назначены дочерним категориям, это руководство поможет вам решить эту проблему.
Проблема
Симптом: При фильтрации по родительской категории товары не отображаются, хотя они существуют в ее дочерних категориях.
Пример:
- Структура категории:
Federal Actions > SEC > Enforcement - Товар назначен:
Enforcement(только дочерняя категория) - Фильтрация по
Federal ActionsorSECвозвращает: Нет результатов - Filtering by
Enforcementreturns: Товар показан
Почему это происходит
WordPress/WooCommerce требует явно отмечать товары всеми родительскими категориями в иерархии, а не только дочерней категорией.
Когда вы назначаете товар дочерней категории через интерфейс администратора WordPress, WooCommerce автоматически не помечает товар всеми родительскими категориями в таблице отношений терминов. Это требование структуры данных, а не ограничение HUSKY.
Правильное назначение категории должно включать:
- Дочерняя категория:
Enforcement - Родительская категория:
SEC - Категория-бабушка:
Federal Actions
Как проверить, есть ли у вас эта проблема
- Перейдите на страницу редактирования товара:
wp-admin/post.php?post=YOUR_PRODUCT_ID&action=edit - Посмотрите на метабокс "Категории" справа
- Проверьте, отмечены ли all parent categories в иерархии
- Если отмечена только дочерняя категория → У вас эта проблема
Решение: Автоматическая нормализация иерархии категорий
Это решение состоит из двух частей:
- Решение на будущее: Автоматически отмечать родительские категории при сохранении товаров
- Немедленное решение: Нормализовать все существующие товары
Часть 1: Автоматическая маркировка родительских категорий (будущие товары)
Добавьте этот код в свой дочерний файл темы functions.php:
/**
* Automatically mark all parent categories when product is saved
* This ensures hierarchy filtering works correctly
*/
add_action('save_post_product', 'auto_mark_parent_categories', 10, 1);
function auto_mark_parent_categories($product_id) {
// Clear cache
clean_object_term_cache($product_id, 'product_cat');
// Get currently assigned categories
$terms = wp_get_post_terms($product_id, 'product_cat', ['fields' => 'ids']);
if (!is_wp_error($terms) AND !empty($terms)) {
$all_terms = [];
// For each assigned category, get all its parents
foreach ($terms as $term_id) {
$all_terms[] = $term_id;
// Get all ancestor categories
$ancestors = get_ancestors($term_id, 'product_cat', 'taxonomy');
if (!empty($ancestors)) {
$all_terms = array_merge($all_terms, $ancestors);
}
}
// Assign product to all categories including parents
wp_set_object_terms($product_id, array_unique($all_terms), 'product_cat');
// Clear caches
clean_post_cache($product_id);
clean_object_term_cache($product_id, 'product_cat');
if (function_exists('wc_delete_product_transients')) {
wc_delete_product_transients($product_id);
}
}
}
Что это делает:
- Срабатывает каждый раз при сохранении товара
- Получает все назначенные категории
- Находит все родительские категории для каждой назначенной категории
- Отмечает товар полной иерархией
- Очищает все соответствующие кэши
Результат: С этого момента любой сохраненный товар будет автоматически включать все родительские категории.
Часть 2: Нормализация существующих товаров (разовое исправление)
Этот скрипт исправит все существующие товары в вашей базе данных. Добавьте этот временный код в свой functions.php:
/**
* One-time script to normalize all existing products
* Access: yourdomain.com/?normalize_cats=1 (must be logged in as admin)
*/
add_action('init', function () {
if (isset($_GET['normalize_cats']) AND current_user_can('manage_options')) {
$result = normalize_all_products_categories();
echo '<h2>Category Normalization Results</h2>';
echo '<pre>';
print_r($result);
echo '</pre>';
die();
}
});
function normalize_all_products_categories() {
global $wpdb;
// Get all product IDs
$args = [
'post_type' => 'product',
'post_status' => 'any',
'posts_per_page' => -1,
'fields' => 'ids'
];
$product_ids = get_posts($args);
$log = [];
$normalized_count = 0;
foreach ($product_ids as $product_id) {
// Get current categories
$terms = wp_get_post_terms($product_id, 'product_cat', ['fields' => 'ids']);
if (!is_wp_error($terms) AND !empty($terms)) {
$all_terms = [];
// Collect all parent categories
foreach ($terms as $term_id) {
$all_terms[] = $term_id;
// Get ancestors
$ancestors = get_ancestors($term_id, 'product_cat', 'taxonomy');
if (!empty($ancestors)) {
$all_terms = array_merge($all_terms, $ancestors);
}
}
$all_terms = array_unique($all_terms);
// Only update if we're adding new parent categories
if (count($all_terms) > count($terms)) {
wp_set_object_terms($product_id, $all_terms, 'product_cat');
$normalized_count++;
$log[] = "Product #{$product_id}: added " . (count($all_terms) - count($terms)) . " parent categories";
}
}
}
// Log to WordPress error log
error_log("=== Category Normalization Complete ===");
error_log(implode("\n", $log));
error_log("Total normalized: {$normalized_count} products");
return [
'success' => true,
'normalized' => $normalized_count,
'total' => count($product_ids),
'details' => $log
];
}
Как использовать:
- Добавьте код в свой
functions.php - Перейдите по адресу:
https://yoursite.com/?normalize_cats=1(должен быть выполнен вход в качестве администратора) - Подождите, пока скрипт завершится
- Вы увидите результаты, показывающие, сколько товаров было обновлено
- Удалите этот код после однократного запуска
Ожидаемый вывод:
Category Normalization Results
Array
(
[success] => 1
[normalized] => 156
[total] => 919
)
Это означает, что 156 из 919 товаров не имели родительских категорий и были исправлены.
Тестирование исправления
После реализации обеих частей:
- Перейдите на страницу вашего магазина с фильтрами HUSKY
- Попробуйте фильтровать по родительской категории
- Товары из дочерних категорий теперь должны отображаться
- Попробуйте пройтись по иерархии — все уровни должны работать
Почему бы не сделать это настройкой по умолчанию в HUSKY?
Это обоснованный вопрос. Вот почему:
- Изменение структуры данных: Это изменяет основные связи данных WooCommerce
- Не универсально: Некоторые сайты намеренно присваивают только дочерние категории для конкретной бизнес-логики
- Производительность: На очень больших каталогах это увеличивает нагрузку на каждое сохранение товара
- Конфликты: Может конфликтовать с другими плагинами, управляющими связями категорий
Будущее улучшение: Мы можем добавить это как опциональную настройку в HUSKY, которую пользователи смогут включить при необходимости, но это не будет поведением по умолчанию.
Альтернатива: ручное назначение категорий
Если вы предпочитаете ручное управление, вы можете:
- Отредактировать каждый товар
- В метабоксе "Категории" отметьте все соответствующие родительские категории вручную
- Сохраните товар
Это дает вам детальный контроль, но занимает много времени для больших каталогов.
Устранение неполадок
Скрипт показывает 0 нормализованных товаров
- Ваши товары, возможно, уже имеют правильно назначенные родительские категории
- Проверьте несколько товаров вручную, чтобы убедиться
Фильтрация все еще не работает после нормализации
- Очистите все кэши (WordPress, сервер, браузер)
- Убедитесь, что HUSKY использует правильную таксономию (
product_cat) - Проверьте конфликты с другими плагинами фильтрации
- Убедитесь, что товары опубликованы (не черновики)
Товары исчезают из фильтра дочерних категорий
Такого не должно происходить, но если это случилось:
- Скрипт сохраняет все существующие назначения категорий
- Проверьте, не вмешивается ли другой плагин
- Восстановите из резервной копии и свяжитесь с поддержкой
Пользовательские таксономии
Это решение также работает для пользовательских таксономий , созданных с помощью CPT UI или аналогичных плагинов. Просто измените 'product_cat' на слаг вашей пользовательской таксономии:
// Example for custom taxonomy 'modality'
$terms = wp_get_post_terms($product_id, 'modality', ['fields' => 'ids']);
wp_set_object_terms($product_id, array_unique($all_terms), 'modality');
Важные замечания
- Требуется дочерняя тема: Всегда используйте дочернюю тему, чтобы избежать потери кода при обновлении темы
- Сначала сделайте резервную копию: Сделайте резервную копию вашей базы данных перед запуском скрипта нормализации
- Тестируйте на staging-сайте: По возможности сначала протестируйте на staging-сайте
- Одноразовый скрипт: Удалите скрипт нормализации после его запуска
- Сохраните код Части 1:
save_post_productхук должен остаться навсегда
Итог
Добавьте в functions.php навсегда:
- Хук автоматической маркировки родительских категорий (Часть 1)
Запустить один раз и удалить:
- Скрипт нормализации (Часть 2)
Ожидаемые результаты:
- Фильтрация родительских категорий работает корректно
- Фильтрация дочерних категорий продолжает работать
- Режим древовидного раскрытия работает правильно
- Будущие товары автоматически включают родительские категории