WP_Query con "post_title LIKE 'algo%'"

30 may 2011, 15:11:57
Vistas: 188K
Votos: 56

Necesito hacer una consulta WP_Query con un LIKE en el post_title.

Comencé con esta WP_Query regular:

$wp_query = new WP_Query( 
    array (
        'post_type'        => 'wp_exposants',
        'posts_per_page'   => '1',
        'post_status'      => 'publish',
        'orderby'          => 'title', 
        'order'            => 'ASC',
        'paged'            => $paged
    )
); 

Pero lo que realmente quiero hacer se ve así en SQL:

$query = "
        SELECT      *
        FROM        $wpdb->posts
        WHERE       $wpdb->posts.post_title LIKE '$param2%'
        AND         $wpdb->posts.post_type = 'wp_exposants'
        ORDER BY    $wpdb->posts.post_title
";
$wpdb->get_results($query);

La salida muestra los resultados que espero, pero uso el regular <?php while ( $wp_query->have_posts() ) : $wp_query->the_post(); ?> para mostrar los resultados.
Y eso no funciona con $wpdb->get_results().

¿Cómo puedo lograr lo que describí aquí?

0
Todas las respuestas a la pregunta 6
5
54

Yo resolvería esto con un filtro en WP_Query. Uno que detecte una variable de consulta adicional y la use como prefijo del título.

add_filter( 'posts_where', 'wpse18703_posts_where', 10, 2 );
function wpse18703_posts_where( $where, &$wp_query )
{
    global $wpdb;
    if ( $wpse18703_title = $wp_query->get( 'wpse18703_title' ) ) {
        $where .= ' AND ' . $wpdb->posts . '.post_title LIKE \'' . esc_sql( $wpdb->esc_like( $wpse18703_title ) ) . '%\'';
    }
    return $where;
}

De esta manera, aún puedes llamar a WP_Query, solo pasas el título como argumento wpse18703_title (o cambias el nombre a algo más corto).

30 may 2011 17:06:03
Comentarios

Este parece estar faltando el $wpdb->prepare().

kaiser kaiser
6 nov 2012 17:46:12

@kaiser: Ha pasado mucho tiempo, pero creo que esto no era posible con prepare(). $wpdb->prepare('LIKE "%s%%"', 'banana') devolvería "LIKE ''banana'%'", así que tenemos que construir la consulta nosotros mismos y hacer el escape también.

Jan Fabry Jan Fabry
6 nov 2012 21:36:02

@JanFabry ¡Feliz de verte de nuevo! :) Pásate por el chat algún momento, ¿eh? StopPress estaría encantado de verte. Sobre ese prepare(). Sí, es complicado y tuve que intentarlo varias veces antes de solucionarlo. De algo que acabo de hacer: $wpdb->prepare( ' AND {$wpdb->posts}.post_title LIKE %s ', esc_sql( '%'.like_escape( trim( $term ) ).'%' ) ). Y estoy bastante seguro de que el esc_sql() es innecesario y solo paranoico.

kaiser kaiser
7 nov 2012 12:35:13

Parece que no puedes buscar una cadena con ' (apóstrofe) dentro. Supongo que es por el escape ? Todavía no encontré la solución

Vincent Decaux Vincent Decaux
30 ago 2018 18:10:29

Tuve que eliminar el & de &$wp_query porque de lo contrario obtenía un error de PHP expected to be a reference, value given

ecairol ecairol
28 may 2021 23:23:27
8
24

Simplificado:

function title_filter( $where, &$wp_query )
{
    global $wpdb;
    // 2. extraer la consulta personalizada aquí:
    if ( $search_term = $wp_query->get( 'search_prod_title' ) ) {
        $where .= ' AND ' . $wpdb->posts . '.post_title LIKE \'%' . esc_sql( like_escape( $search_term ) ) . '%\'';
    }
    return $where;
}

$args = array(
    'post_type' => 'product',
    'posts_per_page' => $page_size,
    'paged' => $page,
    // 1. definir una variable de consulta personalizada aquí para pasar el término:
    'search_prod_title' => $search_term,
    'post_status' => 'publish',
    'orderby'     => 'title', 
    'order'       => 'ASC'
);

add_filter( 'posts_where', 'title_filter', 10, 2 );
$wp_query = new WP_Query($args);
remove_filter( 'posts_where', 'title_filter', 10 );
return $wp_query;
19 abr 2013 16:24:00
Comentarios

Por favor incluye una explicación junto con tu código.

s_ha_dum s_ha_dum
19 abr 2013 16:49:54

Gran simplificación

Timo Huovinen Timo Huovinen
10 nov 2014 21:52:08

El código creo que se explica por sí mismo, al menos para mí. Gracias por compartir el script completo.

Hassan Dad Khan Hassan Dad Khan
8 ago 2017 09:55:26

Usa '$wpdb->esc_like(' en lugar de 'esc_sql( like_escape('

fdrv fdrv
19 feb 2018 19:16:23

@fdrv Tienes razón pero según la documentación de wp, $wpdb->esc_like todavía necesita esc_sql(). Así que creo que el código correcto sería esc_sql( $wpdb->esc_like( $search_term ) )

Syed Waqas Bukhary Syed Waqas Bukhary
18 oct 2019 21:31:40

like_escape obsoleto desde 4.0.0 Usa wpdb::esc_like

Empty Brain Empty Brain
14 mar 2020 08:46:32

remove_filter solo utiliza 3 argumentos, el último puede eliminarse.

Skatox Skatox
24 jun 2020 18:03:22

Logré que lo anterior funcionara pero por alguna razón cuando ejecuté mi búsqueda estaba devolviendo datos de otros post_types aunque había especificado el tipo de publicación en el array $args. Terminé añadiéndolo a la consulta del título lo cual funcionó para mí $where .= ' OR ' . $wpdb->posts . '.post_title LIKE \'%' . $wpdb->esc_like( $search_term ) . '%\' AND '. $wpdb->posts . '.post_type = \'huguenot-family\'';

philip philip
2 feb 2021 14:10:44
Mostrar los 3 comentarios restantes
4
21

Quería actualizar este código en el que trabajaron para WordPress 4.0 y versiones superiores, ya que esc_sql() está obsoleto en 4.0 y versiones posteriores.

function title_filter($where, &$wp_query){
    global $wpdb;

    if($search_term = $wp_query->get( 'search_prod_title' )){
        /*usando esc_like() aquí en lugar de esc_sql()*/
        $search_term = $wpdb->esc_like($search_term);
        $search_term = ' \'%' . $search_term . '%\'';
        $where .= ' AND ' . $wpdb->posts . '.post_title LIKE '.$search_term;
    }

    return $where;
}

El resto de las cosas sigue igual.

También quiero señalar que puedes usar la variable s dentro de los argumentos de WP_Query para pasar términos de búsqueda, lo que también buscará en el título de la publicación, creo.

Así:

$args = array(
    'post_type' => 'post',
    's' => $search_term,
    'post_status' => 'publish',
    'orderby'     => 'title', 
    'order'       => 'ASC'        
);
$wp_query = new WP_Query($args);
2 ene 2015 07:36:51
Comentarios

¿Qué es exactamente search_prod_title? ¿Debería cambiarlo por algo más?

Antonios Tsimourtos Antonios Tsimourtos
24 mar 2017 19:20:18

¿Desde cuándo está obsoleto esc_sql? No lo está. Sin embargo, $wpdb->escape sí lo está... https://developer.wordpress.org/reference/functions/esc_sql/

Jeremy Jeremy
2 feb 2018 19:36:34

Ten en cuenta que el parámetro s también busca en el contenido de la publicación, lo cual puede no ser el objetivo deseado. =)

Christine Cooper Christine Cooper
19 abr 2018 13:43:29

like_escape obsoleto desde 4.0.0 Usar wpdb::esc_like

Empty Brain Empty Brain
14 mar 2020 08:40:20
3
18

Con algunas soluciones vulnerables publicadas aquí, presento una versión un poco simplificada y saneada.

Primero, creamos una función para el filtro posts_where que permite mostrar solo publicaciones que coincidan con condiciones específicas:

function cc_post_title_filter($where, &$wp_query) {
    global $wpdb;
    if ( $search_term = $wp_query->get( 'cc_search_post_title' ) ) {
        $where .= ' AND ' . $wpdb->posts . '.post_title LIKE \'%' . $wpdb->esc_like( $search_term ) . '%\'';
    }
    return $where;
}

Ahora agregamos cc_search_post_title a nuestros argumentos de consulta:

$args = array(
    'cc_search_post_title' => $search_term, // buscar solo en el título de la publicación
    'post_status' => 'publish',
);

Y finalmente envolvemos el filtro alrededor de la consulta:

add_filter( 'posts_where', 'cc_post_title_filter', 10, 2 );
$query = new WP_Query($args);
remove_filter( 'posts_where', 'cc_post_title_filter', 10 );

Usando get_posts()

Ciertas funciones que recuperan publicaciones no ejecutan filtros, por lo que las funciones del filtro posts_where que agregues no modificaran la consulta. Si planeas usar get_posts() para consultar tus publicaciones, debes establecer suppress_filters en false en tu arreglo de argumentos:

$args = array(
    'cc_search_post_title' => $search_term,
    'suppress_filters' => FALSE,
    'post_status' => 'publish',
);

Ahora puedes usar get_posts():

add_filter( 'posts_where', 'cc_post_title_filter', 10, 2 );
$posts = get_posts($args);
remove_filter( 'posts_where', 'cc_post_title_filter', 10 );

¿Qué pasa con el parámetro s?

El parámetro s está disponible:

$args = array(
    's' => $search_term,
);

Si bien agregar tu término de búsqueda en el parámetro s funciona y buscará en el título de la publicación, también buscará en el contenido de la publicación.

¿Qué pasa con el parámetro title que se agregó en WP 4.4?

Pasar un término de búsqueda al parámetro title:

$args = array(
    'title' => $search_term,
);

Es sensible a mayúsculas y usa LIKE, no %LIKE%. Esto significa que buscar hola no devolverá publicaciones con título Hola Mundo o Hola.

19 abr 2018 15:58:35
Comentarios

Excelente. Estaba buscando 'post_title' como parámetro y, obviamente, no encontré nada.

MastaBaba MastaBaba
13 sept 2019 18:55:30

Estoy recibiendo un error con wp query o get posts: "E_WARNING Error en el archivo »class-wp-hook.php« en la línea 288: Se esperaba que el parámetro 2 para cc_post_title_filter() fuera una referencia, pero se proporcionó un valor"

Elkrat Elkrat
3 mar 2020 19:28:10

@Elkrat Elimina el & de &$wp_query en cc_post_title_filter.

Mattimator Mattimator
6 may 2020 00:04:16
2

Basándome en respuestas anteriores, para brindar flexibilidad en la situación donde deseas buscar una publicación que contenga una palabra en un campo meta O en el título de la publicación, ofrezco esa opción mediante el argumento "title_filter_relation". En esta implementación, solo permito entradas "OR" o "AND" con un valor predeterminado de "AND".

function title_filter($where, &$wp_query){
    global $wpdb;
    if($search_term = $wp_query->get( 'title_filter' )){
        $search_term = $wpdb->esc_like($search_term); //en lugar de esc_sql()
        $search_term = ' \'%' . $search_term . '%\'';
        $title_filter_relation = (strtoupper($wp_query->get( 'title_filter_relation'))=='OR' ? 'OR' : 'AND');
        $where .= ' '.$title_filter_relation.' ' . $wpdb->posts . '.post_title LIKE '.$search_term;
    }
    return $where;
}

Aquí hay un ejemplo del código en acción para un tipo de publicación muy simple "faq" donde la pregunta es el título mismo de la publicación:

add_filter('posts_where','title_filter',10,2);
$s1 = new WP_Query( array(
    'post_type' => 'faq',
    'posts_per_page' => -1,
    'title_filter' => $q,
    'title_filter_relation' => 'OR',
    'post_status' => 'publish',
    'orderby'     => 'title', 
    'order'       => 'ASC',
    'meta_query' => array(
        'relation' => 'OR',
        array(
            'key' => 'faq_answer',
            'value' => $q,
            'compare' => 'LIKE'
        )
    )
));
remove_filter('posts_where','title_filter',10,2);
29 abr 2015 01:44:12
Comentarios

Buena idea, añadir "query vars" personalizadas a los argumentos de consulta pasados a WP_Query para poder acceder a ellos dentro del filtro posts_where.

Tom Auger Tom Auger
4 feb 2017 23:32:55

parece una buena respuesta, el único problema es que no funciona para mí :-(

luke_mclachlan luke_mclachlan
28 mar 2022 14:04:48
0

El enfoque óptimo para realizar una consulta WP_Query con una búsqueda 'LIKE' en el post_title es incluir el argumento de consulta 'search_columns'. Si estás construyendo el WP_Query manualmente, debes especificarlo de la siguiente manera:

'search_columns' => ['post_title']

Puedes encontrar más detalles en el código fuente de WordPress en Trac: https://core.trac.wordpress.org/browser/tags/6.3/src/wp-includes/class-wp-query.php#L1426

Sin embargo, si tu intención es modificar consultas generadas por plugins de terceros o temas que crearon la consulta, puedes lograrlo utilizando el hook de filtro 'post_search_columns'.

La documentación oficial proporciona información detallada sobre cómo usar este hook: https://developer.wordpress.org/reference/hooks/post_search_columns/

28 sept 2023 13:34:38