HUSKY - Products Filter Professional for WooCommerce

Как исправить фильтрацию по иерархии категорий в магазине woocommerce (нормализация БД)

Если у вас возникает проблема, когда фильтрация по родительским категориям не даёт результатов, хотя товары привязаны к дочерним категориям, это руководство поможет это исправить.

Проблема

Симптом: При фильтрации по родительской категории не показывается ни одного товара, хотя товары есть в её дочерних категориях.

Пример:

  • Структура категорий: Federal Actions > SEC > Enforcement
  • Товар привязан к: Enforcement (только дочерняя категория)
  • Фильтрация по Federal Actions или SEC возвращает: Нет результатов
  • Фильтрация по Enforcement возвращает: Товар показан

Почему это происходит

WordPress/WooCommerce требует, чтобы товары были явно отмечены всеми родительскими категориями в иерархии, а не только дочерней категорией.

Когда вы привязываете товар к дочерней категории через админ-интерфейс WordPress, WooCommerce не отмечает товар автоматически всеми родительскими категориями в таблице связей терминов. Это требование структуры данных, а не ограничение HUSKY.

Правильная привязка категорий должна включать:

  • Дочернюю категорию: Enforcement
  • Родительскую категорию: SEC
  • Категорию верхнего уровня: Federal Actions

Как проверить, есть ли у вас эта проблема

  1. Перейдите на страницу редактирования товара: wp-admin/post.php?post=YOUR_PRODUCT_ID&action=edit
  2. Посмотрите на метабокс Categories справа
  3. Проверьте, отмечены ли все родительские категории в иерархии
  4. Если отмечена только дочерняя категория → у вас есть эта проблема

Решение: автоматическая нормализация иерархии категорий

Это решение состоит из двух частей:

  1. Решение на будущее: автоматически отмечать родительские категории при сохранении товаров
  2. Немедленное решение: нормализовать все существующие товары

Часть 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
    ];
}

Как использовать:

  1. Добавьте код в ваш functions.php
  2. Перейдите по адресу: https://yoursite.com/?normalize_cats=1 (нужно быть авторизованным как администратор)
  3. Подождите завершения скрипта
  4. Вы увидите результаты с информацией о том, сколько товаров было обновлено
  5. Удалите этот код после однократного запуска

Ожидаемый результат:

Category Normalization Results
Array
(
    [success] => 1
    [normalized] => 156
    [total] => 919
)

Это означает, что у 156 товаров из 919 не было родительских категорий, и это было исправлено.

Проверка исправления

После реализации обеих частей:

  1. Перейдите на страницу вашего магазина с фильтрами HUSKY
  2. Попробуйте отфильтровать по родительской категории
  3. Теперь должны появиться товары из дочерних категорий
  4. Попробуйте углубляться по иерархии — все уровни должны работать

Почему это не сделано в HUSKY по умолчанию?

Это закономерный вопрос. Вот причины:

  1. Изменение структуры данных: это изменяет основные связи данных WooCommerce
  2. Не универсально: некоторые сайты намеренно привязывают только дочерние категории по своей бизнес-логике
  3. Производительность: на очень больших каталогах это добавляет нагрузку при каждом сохранении товара
  4. Конфликты: может мешать другим плагинам, управляющим связями категорий

Будущее улучшение: мы можем добавить это как опциональную настройку в HUSKY, которую пользователи смогут включить при необходимости, но это не будет поведением по умолчанию.

Альтернатива: ручная привязка категорий

Если вы предпочитаете ручной контроль, можно:

  1. Редактировать каждый товар
  2. В метабоксе Categories вручную отметить все нужные родительские категории
  3. Сохранить товар

Это даёт детальный контроль, но требует много времени для больших каталогов.

Решение проблем

Скрипт показывает 0 нормализованных товаров

  • Возможно, у ваших товаров уже правильно привязаны родительские категории
  • Проверьте несколько товаров вручную

Фильтрация всё равно не работает после нормализации

  • Очистите все кэши (WordPress, сервер, браузер)
  • Убедитесь, что HUSKY использует правильную таксономию (product_cat)
  • Проверьте конфликты с другими плагинами фильтрации
  • Убедитесь, что товары опубликованы (не черновики)

Товары пропадают из фильтра дочерней категории

Этого не должно происходить, но если это случилось:

  • Скрипт сохраняет все существующие привязки категорий
  • Проверьте, не мешает ли другой плагин
  • Восстановите из резервной копии и обратитесь в поддержку

Пользовательские таксономии

Это решение также работает для пользовательских таксономий, созданных с CPT UI или похожими плагинами. Просто замените 'product_cat' на slug вашей пользовательской таксономии:

// 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: если возможно, сначала протестируйте на тестовом сайте
  • Одноразовый скрипт: удалите скрипт нормализации после однократного запуска
  • Сохраните код части 1: хук save_post_product должен оставаться навсегда

Итог

Добавить в functions.php навсегда:

  • Хук автоматической отметки родительских категорий (Часть 1)

Запустить один раз и удалить:

  • Скрипт нормализации (Часть 2)

Ожидаемые результаты:

  • Фильтрация по родительской категории работает правильно
  • Фильтрация по дочерней категории продолжает работать
  • Углубление по иерархии работает корректно
  • Будущие товары автоматически включают родительские категории