Consulta WP_Query donde el título comienza con una letra específica
Quiero buscar posts con WP_Query() y seleccionar solo aquellos que comiencen con una letra específica. Encontré varias publicaciones antiguas con filtros anteriores a la versión 4.4, pero desde la 4.4 se agregó una búsqueda por título a la función WP_Query.
$q = new WP_Query(array('post_type'=>'post', 'title'=>'Este Título de Canción'));
Esto devolverá solo coincidencias exactas de posts con el título "Este Título de Canción".
Lo que me gustaría hacer es devolver todos los posts que comiencen, en este ejemplo, con la letra 'E'.
También encontré esta publicación, que nunca fue realmente respondida. Es la respuesta aceptada, pero no veo cómo responde a la pregunta. ¿Cómo limitar la búsqueda a la primera letra del título?
Otras características de consulta como búsquedas de comentarios y metadatos tienen un parámetro 'compare' para agregar LIKE% a las consultas, pero el título parece no tenerlo.

No es posible directamente con WP_Query
de forma nativa, pero utilizando el filtro posts_where
para buscar un argumento personalizado en WP_Query
, es posible añadir esta funcionalidad.
Asumiendo que starts_with
es el nombre del argumento que queremos usar, podemos filtrar posts_where
para añadir una cláusula WHERE
que limite los resultados a aquellos que comiencen con el valor proporcionado si starts_with
ha sido establecido en la consulta:
function wpse_298888_posts_where( $where, $query ) {
global $wpdb;
$starts_with = esc_sql( $query->get( 'starts_with' ) );
if ( $starts_with ) {
$where .= " AND $wpdb->posts.post_title LIKE '$starts_with%'";
}
return $where;
}
add_filter( 'posts_where', 'wpse_298888_posts_where', 10, 2 );
Con este filtro añadido, podemos consultar posts de la siguiente manera:
$query = new WP_Query( array(
'starts_with' => 'M',
) );
Eso devolverá todos los posts que comiencen con "M".
Si deseas poder filtrar la consulta principal, también puedes usar este argumento en pre_get_posts
:
function wpse_298888_pre_get_posts( $query ) {
if ( $query->is_main_query() ) {
$query->set( 'starts_with', 'M' );
}
}
add_action( 'pre_get_posts', 'wpse_298888_pre_get_posts' );

Esto funciona perfectamente, pero hice un ajuste que también puede ayudar a otros. Usé REGEXP en lugar de LIKE para poder agrupar en un solo grupo los títulos que comienzan con números en el rango 0-9.
$where .= " AND $wpdb->posts.post_title REGEXP '^$starts_with'";

¿Sería posible hacer esto al revés, donde se puedan seleccionar todas las entradas y/o páginas que no comiencen con una letra/cadena particular? Quiero excluir de los resultados de búsqueda páginas específicas cuyos títulos comienzan con la misma palabra, pero quiero mantenerlo abierto por si se crean más en lugar de usar IDs estáticos. Estas no son entradas, por lo que no tienen etiquetas ni categorías.

He verificado dos veces y no veo ningún problema en el código. A menos que hayas copiado este código exactamente, es probable que tengas un error de sintaxis en algún lugar de tu código.

@VincenzoPiromalli Si filtras la consulta principal con el método pre_get_posts
, entonces cualquier paginación normal funcionará.

Solo ten en cuenta que si tienes títulos en idiomas complicados con diacríticos, el resultado podría no ser preciso. La intercalación (collation) de la base de datos del campo de título también juega un papel importante. Incluso así, el resultado podría no ser perfecto. Además, recomendaría escapar la cadena que introduces con algo como: mb_substr($starts_with, 0, 1) // para CH y letras dobles y efectivamente $wpdb->esc_like()
