Cómo solucionar el filtrado de jerarquía de categorías en la tienda de woocommerce (normalizar db)
Si estás experimentando problemas donde el filtrado por categorías principales no devuelve resultados, a pesar de que los productos están asignados a categorías secundarias, esta guía te ayudará a solucionarlo.
El Problema
Síntoma: Cuando se filtra por una categoría principal, no se muestran productos, a pesar de que existen productos en sus categorías secundarias.
Ejemplo:
- Estructura de categoría:
Federal Actions > SEC > Enforcement - El producto está asignado a:
Enforcement(solo categoría hija) - Filtrado por
Federal ActionsoSECdevuelve: No hay resultados - Filtrado por
Enforcementdevuelve: Producto mostrado
Por qué sucede esto
WordPress/WooCommerce requiere productos para que se marquen explícitamente con todas las categorías principales en la jerarquía, no solo en la categoría hija.
Cuando asignas un producto a una categoría hija a través de la interfaz de administración de WordPress, WooCommerce no marca automáticamente el producto con todas las categorías padre en la tabla de relaciones de términos. Este es un requisito de la estructura de datos, no una limitación de HUSKY.
La asignación correcta de categorías debe incluir:
- Categoría secundaria:
Enforcement - Categoría padre:
SEC - Categoría abuela:
Federal Actions
Cómo verificar si tiene este problema
- Ir a una página de edición de producto:
wp-admin/post.php?post=YOUR_PRODUCT_ID&action=edit - Mira el metabox de Categorías en el lado derecho
- Comprueba si todas las categorías principales en la jerarquía se verifican
- Si solo se marca la subcategoría → Tienes este problema
Solución: Normalización Automática de Jerarquía de Categorías
Esta solución consta de dos partes:
- Corrección a prueba de futuro: Marcar automáticamente las categorías principales al guardar productos
- Solución inmediata: Normalizar todos los productos existentes
Parte 1: Marcar Automáticamente Categorías Padre (Productos Futuros)
Add this code to your child theme’s 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);
}
}
}
Lo que hace esto:
- Se activa cada vez que se guarda un producto
- Obtiene todas las categorías asignadas
- Encuentra todas las categorías padre para cada categoría asignada
- Marca el producto con la jerarquía completa
- Borra todas las cachés relevantes
Resultado: A partir de ahora, cada producto guardado incluirá automáticamente todas las categorías padres.
Parte 2: Normalizar Productos Existentes (Solución Única)
Este script corregirá todos los productos existentes en tu base de datos. Agrega esto temporal código a tu 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
];
}
Cómo usar:
- Agrega el código a tu
functions.php - Ir a:
https://yoursite.com/?normalize_cats=1(debe iniciar sesión como administrador) - Espera a que el script se complete
- Verás resultados que muestran cuántos productos se actualizaron
- Elimina este código después de ejecutarlo una vez
Salida esperada:
Category Normalization Results
Array
(
[success] => 1
[normalized] => 156
[total] => 919
)
Esto significa que 156 de 919 productos no tenían categorías principales y se han corregido.
Probando la solución
Después de implementar ambas partes:
- Ve a tu página de tienda con filtros HUSKY
- Intenta filtrar por un categoría padre
- Los productos de las categorías secundarias ahora deberían aparecer
- Intenta profundizar en la jerarquía; todos los niveles deberían funcionar
¿Por qué no hacer esto predeterminado en HUSKY?
Esta es una pregunta legítima. Aquí está el por qué:
- Cambio de estructura de datos: Esto modifica las relaciones de datos principales de WooCommerce
- No Universal: algunos sitios asignan intencionalmente solo categorías secundarias para una lógica comercial específica
- Rendimiento: En catálogos muy grandes, esto añade sobrecarga a cada guardado de producto
- Conflictos: puede interferir con otros plugins que administran relaciones de categorías
Mejora futura: Podemos añadir esto como una opción_opcional en HUSKY que los usuarios pueden habilitar si es necesario, pero no será el comportamiento predeterminado.
Alternativa: Asignación Manual de Categorías
Si prefieres control manual, puedes:
- Editar cada producto
- En el metabox de Categorías, marca todas las categorías principales relevantes manualmente
- Guardar el producto
Esto te da control granular pero consume mucho tiempo para catálogos grandes.
Solución de problemas
El script muestra 0 productos normalizados
- Tus productos podrían ya tener las categorías padres correctas asignadas
- Check a few products manually to verify
El filtrado todavía no funciona después de la normalización
- Limpia todas las cachés (WordPress, servidor, navegador)
- Asegúrate de que HUSKY esté usando la taxonomía correcta (
product_cat) - Compruebe los conflictos con otros plugins de filtro
- Verifica que los productos estén publicados (no en borrador)
Los productos desaparecen del filtro de categoría secundaria
Esto no debería suceder, pero si sucede:
- El script conserva todas las asignaciones de categorías existentes
- Comprueba si otro plugin está interfiriendo
- Restaurar desde copia de seguridad y contactar soporte
Taxonomías personalizadas
This solution also works for taxonomías personalizadas creados con CPT UI o plugins similares. Simplemente cambia 'product_cat' a tu slug de taxonomía personalizado:
// 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');
Notas importantes
- Requiere Tema Hijo: usa siempre un tema hijo para evitar la pérdida de código durante las actualizaciones del tema
- Haz una copia de seguridad primero: Haz una copia de seguridad de tu base de datos antes de ejecutar el script de normalización
- Probar en Staging: Prueba primero en un sitio de staging si es posible
- Script de una sola vez: Eliminar el script de normalización después de ejecutarlo
- Mantener código Parte 1: El
save_post_productel hook debe permanecer permanentemente
Resumen
Añadir a functions.php permanentemente:
- Gancho de marcado automático de categorías principales (Parte 1)
Ejecutar una vez y eliminar:
- Script de normalización (Parte 2)
Resultados esperados:
- El filtrado de categoría padre funciona correctamente
- El filtrado de categorías secundarias continúa funcionando
- La jerarquía de desglose funciona correctamente
- Los productos futuros incluyen automáticamente categorías padres