La búsqueda vacía devuelve todas las entradas
Hoy he decidido implementar un formulario de búsqueda en mi sitio que obviamente devuelve un resultado cuando el usuario busca algo, pero me he encontrado con un pequeño problema.
Mi Problema
Cuando el usuario realiza una búsqueda sin introducir nada en el formulario de búsqueda, por alguna razón devuelve 5 Páginas, mientras que me gustaría que devolviera un mensaje que diga algo como 'El campo de búsqueda estaba vacío - Buscar de nuevo'.
¿Cómo podría hacer que esto suceda? He insertado mi código a continuación que controla mi botón de searchform
y el contenido que muestra al buscar.
Código que Controla el Formulario de Búsqueda
searchform.php Este es el formulario de búsqueda donde el usuario introduce lo que quiere buscar (Tengo la sensación de que necesito agregar código aquí para verificar si está vacío)
<form role="search" method="get" id="searchform" action="<?php echo home_url('/'); ?>">
<div>
<label class="screen-reader-text" for="s">Buscar: </label>
<input type="text" value="" name="s" id="s" placeholder="<?php the_search_query(); ?>" />
<input type="submit" id="searchsubmit" value="Buscar" />
</div>
</form>
search.php Esto muestra al usuario lo que ha buscado y obtiene la plantilla content-search
para mostrar el/los nombre(s) de la(s) Página(s).
<div class="search-result">
<div class="container">
<div class="row">
<div class="search">
<?php if (have_posts()) : ?>
<h2>Resultados de búsqueda para: <?php the_search_query(); ?></h2>
<div class="light-separator small center"></div>
<?php
while (have_posts()) : the_post();
get_template_part('content-search', get_post_format());
endwhile;
else :
echo '
<div class="no-content">
<h3>Ups, parece que no hay resultados que coincidan con tu búsqueda.</h3>
</div>';
endif;
?>
<div class="search-form"><?php get_search_form(); ?></div>
</div>
</div>
</div>
</div>
content-search.php - Esto muestra el Título de las Páginas y el Enlace Permanente de la Página
<div class="searchs">
<h4>Páginas - <a href="<?php the_permalink(); ?>"><?php the_title(); ?></a></h4>
</div>

Solo una alternativa a la respuesta informativa de @PieterGoosen.
Después de que Pieter publicó esta parte:
if ( ! empty( $q['s'] ) ) {
$search = $this->parse_search( $q );
}
se me ocurrió que podría ser posible volver a analizar la consulta de búsqueda, dentro del filtro posts_search
, para cadenas de búsqueda vacías. Pero el método parse_search()
es protegido e incluso si pudiéramos acceder a él, la búsqueda vacía solo nos daría:
AND (((wp_posts.post_title LIKE '%%') OR (wp_posts.post_content LIKE '%%')))
y eso simplemente buscaría todo. Así que ese camino no fue fructífero ;-)
En WordPress 4.5 cambió a:
if ( strlen( $q['s'] ) ) {
$search = $this->parse_search( $q );
}
En su lugar, podríamos intentar detener la consulta principal, en el caso de una búsqueda vacía:
/**
* Detiene la consulta principal en caso de una búsqueda vacía
*/
add_filter( 'posts_search', function( $search, \WP_Query $q )
{
if( ! is_admin() && empty( $search ) && $q->is_search() && $q->is_main_query() )
$search .=" AND 0=1 ";
return $search;
}, 10, 2 );

@CoderSte Creo que esto debería resolver tu problema mejor que mi enfoque. No dudes en rechazar mi respuesta y aceptar esta de birgire ;-)

Esa es realmente una buena idea, al detener la consulta principal los lleva a la página search.php
que es lo que realmente quería en lugar de devolverlos a la página 404, aunque el método de @PieterGoosen funciona perfectamente si los usuarios quieren redirigirlos a la página 404. Gracias por la información adicional @birgire

@PieterGoosen Lo he hecho, aunque tu respuesta también funciona bien, si alguien quiere redirigir una búsqueda vacía a un 404 entonces tu idea funciona perfectamente :)

@birgire solo tengo una pregunta sobre esto - como estoy usando esto en mi código me gusta entender las cosas, y no entiendo muy bien qué es el {, 10, 2);
.

uf, acabo de tener que salir al clima loco que hace aquí, solo recuperando el aliento de nuevo, ;-) Esto fue principalmente sobre mi idea inicial fallida y solo pretendía ser un apéndice a la respuesta de @PieterGoosen. CoderSte: generalmente soy tan vago que tiendo a usar funciones anónimas mucho en este sitio ;-) Aquí 10 es la prioridad y 2 es el número de entradas del callback.

La idea está aquí, pero la última solución es incorrecta.
empty( $search )
debería ser reemplazado por empty( get_search_query() )
ya que $search
contiene la consulta, no el slug de búsqueda. Por lo tanto, la condición if nunca es verdadera.

No estoy seguro si esto es un error intencional o simplemente un error que nunca se anticipó, pero definitivamente es un fallo en el diseño.
Este comportamiento existe en los siguientes casos que noté anteriormente:
Establecer un array vacío en
post__in
devuelve todas las publicacionesPasar un término inválido a un
tax_query
o usar el camponame
con un nombre que contiene caracteres especiales o más de una palabra elimina la cláusula JOIN de la consulta SQL, lo que también resulta en que se devuelvan todas las publicaciones. Hice una respuesta sobre este problema
Lo que sucede aquí es que cuando pasamos una cadena válida a nuestra función de búsqueda, la cláusula WHERE
se modifica para incluir nuestros términos de búsqueda. Normalmente así es como se ve la cláusula WHERE
cuando ingresamos un término de búsqueda llamado search
:
AND (((wp_posts.post_title LIKE \'%search%\')
OR (wp_posts.post_content LIKE \'%search%\')))
AND wp_posts.post_type IN (\'post\', \'page\', \'attachment\', \'information\', \'event_type\', \'cameras\')
AND (wp_posts.post_status = \'publish\'
OR wp_posts.post_author = 1
AND wp_posts.post_status = \'private\')
Cuando pasamos una cadena vacía, la cláusula de búsqueda se elimina del WHERE
, lo que hace que se devuelvan todas las publicaciones. Así es como se ve la cláusula WHERE
cuando pasamos una cadena vacía:
AND wp_posts.post_type IN (\'post\', \'page\', \'attachment\', \'information\', \'event_type\', \'cameras\')
AND (wp_posts.post_status = \'publish\' OR wp_posts.post_author = 1
AND wp_posts.post_status = \'private\')
Esta es la sección en WP_Query
responsable de esto:
if ( ! empty( $q['s'] ) ) {
$search = $this->parse_search( $q );
}
La forma más fácil de solucionar esto es devolver un error 404 cada vez que pasamos una cadena vacía como términos de búsqueda. Para esto necesitamos verificar si tenemos una cadena de búsqueda válida o no, y luego establecer un 404 según corresponda. Puedes probar lo siguiente:
add_action( 'pre_get_posts', function ( $q )
{
if( !is_admin() // Solo afecta el front-end
&& $q->is_main_query() // Solo afecta la consulta principal
&& $q->is_search() // Solo afecta la página de búsqueda
) {
// Obtener los términos de búsqueda
$search_terms = $q->get( 's' );
// Establecer 404 si s está vacío
if ( !$search_terms ) {
add_action( 'wp', function () use ( $q )
{
$q->set_404();
status_header(404);
nocache_headers();
});
}
}
});

Gracias por la respuesta - es realmente extraño ya que el sitio tiene como 15 páginas y solo devuelve 5, y las 5 que devuelve son realmente aleatorias. No he probado tu código todavía ya que no estoy cerca de una computadora, pero cuando llegue a una lo intentaré - básicamente quería que devolviera la página 404
como has sugerido, ya que esa es la única página con el formulario de búsqueda

Bastante extraño, en mi instalación local devuelve todas las publicaciones de todos los tipos de contenido. Pero de todos modos, WP_Query
es bastante complicado de manejar y a veces se comporta de manera extraña. ;-). Tómate tu tiempo y prueba esto completamente y avísame si encuentras algún error. Disfruta ;-)

Lo sé, es muy extraño, el tema es que tengo como 7 páginas y algunas tienen páginas hijas, y lo raro es que no solo devuelve las páginas principales, devuelve 2 páginas principales y luego 3 páginas hijas. Probaré y te aviso, gracias por tu respuesta :)

Lo increíble es que cada vez que cierro la página y la vuelvo a abrir, y luego hago una búsqueda vacía de nuevo, me devuelve páginas diferentes xD. Agregué tu código a mi functions.php
y funcionó perfectamente, solo que sigue mostrando la Página 404 - ¿habría alguna manera de mostrar un título diferente en lugar de 404, como mostrar algo como "Tu búsqueda no fue encontrada"? Gracias por tu ayuda Pieter :)

Si deseas excluir cadenas de búsqueda con una longitud menor a un valor definido y también la cadena de búsqueda vacía, puedes usar esta función modificada de la solución de birgire. En este ejemplo, las búsquedas vacías y las frases de búsqueda con solo una letra no darán resultados:
add_filter( 'posts_search', function( $search, \WP_Query $q )
{
$sphrase = get_search_query();
$slen = strlen($sphrase);
$minlen = 2;
if( ! is_admin() && $slen < $minlen && $q->is_search() && $q->is_main_query() ){
$search .=" AND 0=1 ";
}
return $search;
}, 10, 2 );

Si estás utilizando el archivo estándar search.php, es mucho más fácil simplemente agregar lógica dentro del condicional if ( have_posts())...
if ( have_posts() && $_GET['s'] != '' )
De esta manera, si el parámetro de búsqueda está vacío, no ejecuta el bucle de contenido.

Mucho más fácil de implementar que la solución con add_filter
, y funciona perfectamente con un search.php
personalizado también.

Esto puede causar que algunos plugins funcionen incorrectamente. 1) Primero, hay muchos hooks mientras la página de búsqueda empieza a trabajar. Algunos plugins trabajan con la consulta a la base de datos y la consulta principal devuelve resultados (todos los posts) cuando el usuario realiza una búsqueda vacía. 2) Segundo, algunos plugins que trabajan con el primer proceso pueden confundirse cuando la consulta principal devuelve resultados pero la página de resultados no muestra ningún resultado, causando que los plugins funcionen incorrectamente.

Para excluir cadenas de búsqueda con una longitud menor a la definida y también la cadena de búsqueda vacía, puedes usar esta función modificada de la solución de birgire:
add_filter( 'posts_search', function( $search, \WP_Query $q )
{
$sphrase = get_search_query();
$slen = strlen($sphrase);
$minlen = 2;
if( ! is_admin() && $slen < $minlen && $q->is_search() && $q->is_main_query() ){
$search .=" AND 0=1 ";
}
return $search;
}, 10, 2 );
