Variables de consulta personalizadas JetSmartFilters

Variables de consulta personalizadas JetSmartFilters

Variables de consulta personalizadas JetSmartFilters — ¿Necesitas filtrar contenido en WordPress con criterios que JetSmartFilters no soporta por defecto? Imagina que tienes experiencias de viaje (posts) y quieres filtrarlas por el NIT o razón social de los usuarios relacionados. Suena complejo, pero con variables de consulta personalizadas para JetSmartFilters es posible. Te explico paso a paso cómo lograrlo.

¿Por qué necesitas variables de consulta personalizadas?

JetSmartFilters es excelente para filtros básicos, pero cuando necesitas cruzar datos entre diferentes entidades (como posts y metadatos de usuarios), el plugin solo te muestra la puerta. Tú debes abrirla con código personalizado. Es como querer buscar restaurantes por el nombre del chef: necesitas conectar dos tablas de información.

Lo que vas a lograr

  • Filtrar experiencias (posts) por metacampos de usuarios relacionados
  • Entender el flujo de consultas de JetSmartFilters
  • Evitar el error que bloquea todos los resultados
  • Optimizar el rendimiento de tus filtros personalizados

Preparación: lo que necesitas antes de empezar

Antes de meter las manos en el código, asegúrate de tener:

  • WordPress 5.0 o superior (lo más probable es que ya lo tengas)
  • JetEngine y JetSmartFilters instalados y activados
  • Acceso al archivo functions.php de tu tema o mejor, un plugin personalizado
  • Conocimientos básicos de PHP (no necesitas ser experto)

Entendiendo el problema principal

Aquí está el truco: JetSmartFilters por defecto agrega términos de búsqueda al meta_query. Si el metaclave no existe en tus posts, WordPress dice «aquí no hay nada» y bloquea TODOS los resultados, incluso si tú manualmente le dices qué posts mostrar. Es como si un guardia de seguridad demasiado estricto no te dejara entrar a tu propia fiesta.

Ejemplo práctico: filtrar experiencias por datos de usuarios

Vamos con un caso real que me encontré en un proyecto:

  • Tipo de post: Experiencias de viaje (rp_us_experiences)
  • Relación: Usuarios → Experiencias (vía JetEngine, ID 11)
  • Campos a buscar: NIT de empresa (rp_us_nit) y razón social (rp_us_company_reason) del usuario
  • Objetivo: Cuando alguien busque «123456» o «Mi Empresa SAS», ver las experiencias de ese usuario

Paso 1: Crear la clase personalizada

Crea un archivo en tu plugin: wp-content/plugins/tu-plugin/includes/class-custom-jetsmartfilters.php

<?php
/**
 * Manejador personalizado para JetSmartFilters
 */
if ( ! defined( 'ABSPATH' ) ) {
    exit;
}

class Custom_JetSmartFilters {
    public function __construct() {
        // Conectarnos al filtro final de JetSmartFilters
        add_filter( 'jet-smart-filters/query/final-query', array( $this, 'filter_by_related_meta' ), 10, 1 );
    }

    public function filter_by_related_meta( $query ) {
        global $wpdb;

        // Solo aplicar a nuestro listing específico
        if ( empty( $query['jet_smart_filters'] ) || 
             false === strpos( $query['jet_smart_filters'], 'experiences' ) ) {
            return $query;
        }

        // Extraer el término de búsqueda
        $search_term = $this->get_search_term( $query );
        
        if ( empty( $search_term ) ) {
            return $query;
        }

        // Obtener IDs de posts filtrados
        $filtered_ids = $this->get_filtered_post_ids( $search_term );

        if ( empty( $filtered_ids ) ) {
            $query['post__in'] = array( 0 );
            return $query;
        }

        // Aplicar post__in
        $query['post__in'] = $this->merge_post_in( $query, $filtered_ids );
        
        // CRÍTICO: Remover meta_query de plain_query para evitar bloqueo
        $query = $this->remove_plain_query_meta( $query );

        return $query;
    }

    private function get_search_term( $query ) {
        $search_term = '';

        // Método 1: Desde meta_query
        if ( ! empty( $query['meta_query'] ) ) {
            foreach ( $query['meta_query'] as $meta ) {
                if ( isset( $meta['key'], $meta['value'] ) && 
                     'plain_query' === $meta['key'] ) {
                    $search_term = sanitize_text_field( $meta['value'] );
                    break;
                }
            }
        }

        // Método 2: Desde $_REQUEST (respaldo)
        if ( empty( $search_term ) && 
             isset( $_REQUEST['_plain_query|custom_filter'] ) ) {
            $search_term = sanitize_text_field( 
                wp_unslash( $_REQUEST['_plain_query|custom_filter'] ) 
            );
        }

        return $search_term;
    }

    private function get_filtered_post_ids( $search_term ) {
        global $wpdb;
        
        $like = '%' . $wpdb->esc_like( $search_term ) . '%';
        $relation_table = $wpdb->prefix . 'jet_rel_default';

        // Verificar que la tabla existe
        if ( $wpdb->get_var( $wpdb->prepare( 
            'SHOW TABLES LIKE %s', 
            $relation_table 
        ) ) !== $relation_table ) {
            return array();
        }

        // Consulta SQL personalizada
        $post_ids = $wpdb->get_col( $wpdb->prepare(
            "SELECT DISTINCT rel.child_object_id
             FROM {$relation_table} rel
             LEFT JOIN {$wpdb->usermeta} um1 
                ON um1.user_id = rel.parent_object_id 
                AND um1.meta_key = 'rp_us_company_reason'
             LEFT JOIN {$wpdb->usermeta} um2 
                ON um2.user_id = rel.parent_object_id 
                AND um2.meta_key = 'rp_us_nit'
             WHERE rel.child_object_id IS NOT NULL
               AND ( um1.meta_value LIKE %s OR um2.meta_value LIKE %s )
             GROUP BY rel.child_object_id",
            $like,
            $like
        ) );

        return $post_ids;
    }

    private function merge_post_in( $query, $filtered_ids ) {
        if ( ! empty( $query['post__in'] ) ) {
            $merged = array_intersect( $query['post__in'], $filtered_ids );
            return ! empty( $merged ) ? $merged : array( 0 );
        }
        return $filtered_ids;
    }

    private function remove_plain_query_meta( $query ) {
        if ( ! empty( $query['meta_query'] ) ) {
            $query['meta_query'] = array_values( array_filter(
                $query['meta_query'],
                function( $row ) {
                    return empty( $row['key'] ) || 'plain_query' !== $row['key'];
                }
            ) );
            
            if ( empty( $query['meta_query'] ) ) {
                unset( $query['meta_query'] );
            }
        }
        return $query;
    }
}

// Inicializar
new Custom_JetSmartFilters();

Paso 2: Configurar JetSmartFilters

  1. Ve a JetSmartFilters → Añadir nuevo
  2. Elige tipo «Búsqueda»
  3. Configura Variable de consulta: plain_query|custom_filter
  4. Aplica a tu listing provider
  5. Guarda el filtro

Paso 3: Añadir filtro a tu listing

  1. Edita tu JetEngine Listing Grid
  2. Añade el widget JetSmartFilters
  3. Selecciona tu filtro personalizado
  4. Guarda y prueba

Problemas comunes y soluciones

Problema 1: El filtro no muestra resultados

Síntoma: La búsqueda siempre devuelve «No se encontraron resultados».

Causa: El meta_query con plain_query está bloqueando todo.

Solución: Siempre remueve el plain_query después de extraer el término de búsqueda. Esa función remove_plain_query_meta() en el código es tu mejor amiga.

Problema 2: El hook no se ejecuta

Síntoma: Tu código no hace nada, ni siquiera errores.

Verifica:

  • El archivo está incluido en tu tema/plugin
  • La clase se instancia (esa línea new Custom_JetSmartFilters() al final)
  • El número de argumentos en add_filter() es 1

Problema 3: Filtro aplicado al listing equivocado

Síntoma: El filtro funciona, pero en todos los listings del sitio.

Solución: Ajusta la condición en tu función:

// Cambia 'experiences' por el ID de tu listing
if ( false === strpos( $query['jet_smart_filters'], 'tu-listing-id' ) ) {
    return $query;
}

Optimización de rendimiento

1. Agrega índices a la base de datos

Para miles de registros, un índice acelera la búsqueda como ponerle turbo a un carro:

CREATE INDEX idx_meta_search 
ON wp_usermeta(meta_key, meta_value(50)) 
WHERE meta_key IN ('rp_us_nit', 'rp_us_company_reason');

2. Implementa caché

Si los mismos términos se buscan frecuentemente, guarda los resultados:

private function get_filtered_post_ids( $search_term ) {
    $cache_key = 'custom_filter_' . md5( $search_term );
    $cached = get_transient( $cache_key );
    
    if ( false !== $cached ) {
        return $cached;
    }
    
    // Tu consulta SQL aquí...
    
    // Guardar por 1 hora
    set_transient( $cache_key, $post_ids, HOUR_IN_SECONDS );
    
    return $post_ids;
}

3. Limita los resultados

Para no sobrecargar la base de datos:

SELECT DISTINCT rel.child_object_id
FROM {$relation_table} rel
-- ... tus joins ...
GROUP BY rel.child_object_id
LIMIT 100  // ← Esto es importante

Técnicas avanzadas

Múltiples campos de búsqueda

¿Necesitas buscar en más de dos campos? Solo añade más LEFT JOINs:

LEFT JOIN {$wpdb->usermeta} um3 
    ON um3.user_id = rel.parent_object_id 
    AND um3.meta_key = 'otro_campo'

Y en el WHERE: OR um3.meta_value LIKE %s

Combinar con taxonomías

¿Quieres filtrar también por categorías o etiquetas? Usa wp_terms y wp_term_relationships en tu consulta.

Buenas prácticas que te ahorrarán dolores de cabeza

  • Siempre sanitiza: Usa sanitize_text_field() como en el ejemplo
  • Prepared statements: Nunca concatenes variables directamente en SQL
  • Verifica tablas: Comprueba que las tablas existen antes de consultarlas
  • Debug estratégico: Usa error_log() solo en desarrollo
  • Respeta filtros existentes: Usa array_intersect() para no pisar otros filtros

Conclusión

Crear variables de consulta personalizadas para JetSmartFilters es como aprender a conducir manual después de solo usar automático: al principio parece complicado, pero una vez lo dominas, tienes mucho más control.

Los puntos clave que debes recordar:

  1. El hook jet-smart-filters/query/final-query es tu punto de entrada
  2. Extrae el término de búsqueda del meta_query o $_REQUEST
  3. SIEMPRE remueve el plain_query del meta_query después
  4. Optimiza con índices y caché para sitios con muchos datos
  5. Prueba tus consultas SQL directamente en phpMyAdmin primero

¿Tienes dudas específicas sobre tu implementación? En la comunidad de Crocoblock hay desarrolladores que pueden ayudarte. Y si quieres profundizar en desarrollo WordPress, la documentación oficial es tu mejor aliada.

¿Qué tipo de filtros personalizados necesitas crear? Cuéntame en los comentarios y veamos cómo solucionarlo juntos.

Compartir esta información