La ricerca con campo vuoto restituisce tutti i post
Oggi ho deciso di implementare un modulo di ricerca sul mio sito che ovviamente restituisce un risultato quando l'utente cerca qualcosa, ma ho riscontrato un piccolo problema.
Il Mio Problema
Quando l'utente effettua una ricerca senza inserire nulla nel modulo di ricerca, per qualche motivo vengono restituite 5 Pagine mentre vorrei che venisse mostrato un messaggio del tipo 'Il campo di ricerca era vuoto - Cerca di nuovo'.
Come posso realizzare questo? Ho inserito il mio codice qui sotto che gestisce il pulsante searchform
e il contenuto che viene mostrato durante la ricerca.
Codice che Controlla il Modulo di Ricerca
searchform.php Questo è il modulo di ricerca dove l'utente inserisce ciò che vuole cercare (Ho l'impressione che devo inserire del codice qui per verificare se è vuoto)
<form role="search" method="get" id="searchform" action="<?php echo home_url('/'); ?>">
<div>
<label class="screen-reader-text" for="s">Cerca: </label>
<input type="text" value="" name="s" id="s" placeholder="<?php the_search_query(); ?>" />
<input type="submit" id="searchsubmit" value="Cerca" />
</div>
</form>
search.php Questo mostra all'utente cosa ha cercato e ottiene il template content-search
per mostrare il nome della/e Pagina/e.
<div class="search-result">
<div class="container">
<div class="row">
<div class="search">
<?php if (have_posts()) : ?>
<h2>Risultati di ricerca per: <?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>Ops, sembra che nulla corrisponda alla tua ricerca.</h3>
</div>';
endif;
?>
<div class="search-form"><?php get_search_form(); ?></div>
</div>
</div>
</div>
</div>
content-search.php - Questo visualizza il Titolo delle Pagine e il Permalink della Pagina
<div class="searchs">
<h4>Pagine - <a href="<?php the_permalink(); ?>"><?php the_title(); ?></a></h4>
</div>

Solo un'alternativa alla risposta informativa di @PieterGoosen.
Dopo che Pieter ha postato questa parte:
if ( ! empty( $q['s'] ) ) {
$search = $this->parse_search( $q );
}
mi è venuto in mente che potrebbe essere possibile ri-analizzare la query di ricerca, all'interno del filtro posts_search
, per stringhe di ricerca vuote. Ma il metodo parse_search()
è protetto e anche se potessimo accedervi, la ricerca vuota ci darebbe semplicemente:
AND (((wp_posts.post_title LIKE '%%') OR (wp_posts.post_content LIKE '%%')))
e questo cercherebbe semplicemente tutto. Quindi questa strada non era fruttuosa ;-)
In WordPress 4.5 è cambiato in:
if ( strlen( $q['s'] ) ) {
$search = $this->parse_search( $q );
}
In alternativa, potremmo provare a fermare la query principale, nel caso di una ricerca vuota:
/**
* Ferma la query principale nel caso di una ricerca vuota
*/
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 Penso che questo risolva il tuo problema meglio del mio approccio. Sentiti libero di rimuovere l'accettazione della mia risposta e accettare questa di birgire ;-)

In realtà è un'ottima idea, interrompendo la query principale li porta alla pagina search.php
che è esattamente quello che volevo invece di reindirizzarli alla pagina 404, anche se il metodo di @PieterGoosen funziona perfettamente se gli utenti vogliono reindirizzarli alla pagina 404. Grazie per le informazioni aggiuntive @birgire

@PieterGoosen L'ho fatto, anche se la tua risposta funziona bene, se qualcuno vuole reindirizzare una ricerca vuota a una pagina 404 allora la tua idea funziona perfettamente :)

@CoderSte fantastico, divertiti e buona fortuna con il tuo progetto ;-)

@birgire ho solo una domanda su questo - poiché lo sto usando nel mio codice mi piace capire le cose, e non capisco bene cosa sia il {, 10, 2);
.

uff, sono appena dovuto uscire nel pazzo tempo che c'è qui, mi riprendo fiato ;-) Questo riguardava soprattutto la mia idea iniziale fallita ed era solo un'appendice alla risposta di @PieterGoosen. CoderSte: in genere sono così pigro che tendo a usare molte funzioni anonime su questo sito ;-) Qui 10 è la priorità e 2 è il numero di input della callback.

L'idea è qui, ma l'ultima soluzione è sbagliata.
empty( $search )
dovrebbe essere sostituito da empty( get_search_query() )
poiché $search
contiene la query, non lo slug della ricerca. Quindi, la condizione if non è mai vera.

Non sono sicuro se si tratti di un bug intenzionale o semplicemente di un bug mai anticipato, ma è sicuramente un difetto di progettazione.
Questo comportamento esiste nei seguenti casi che ho annotato in precedenza
Impostare un array vuoto su
post__in
restituisce tutti i postPassare un termine non valido a una
tax_query
o utilizzare il camponame
con un nome contenente caratteri speciali o più di una parola rimuove la clausola di join dalla query SQL, il che comporta anche il ritorno di tutti i post. Ho fatto una risposta riguardo a questo problema
Quindi quello che succede qui è che quando passiamo una stringa valida alla nostra funzione di ricerca, la clausola WHERE
viene modificata per includere i nostri termini di ricerca. Normalmente ecco come appare la clausola WHERE
quando inseriamo un termine di ricerca chiamato 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\')
Quando passiamo una stringa vuota, la clausola di ricerca viene rimossa dalla clausola WHERE
, il che fa sì che vengano restituiti tutti i post. Ecco come appare la clausola WHERE
quando passiamo una stringa vuota
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\')
Questa è la sezione in WP_Query
responsabile di questo comportamento
if ( ! empty( $q['s'] ) ) {
$search = $this->parse_search( $q );
}
Il modo più semplice per uscire da questa situazione è restituire un 404 ogni volta che passiamo una stringa vuota come termine di ricerca. Per fare ciò, dobbiamo verificare se abbiamo una stringa di ricerca valida o meno, e quindi impostare un 404 di conseguenza. Puoi provare il seguente codice
add_action( 'pre_get_posts', function ( $q )
{
if( !is_admin() // Solo nel front end
&& $q->is_main_query() // Solo la query principale
&& $q->is_search() // Solo la pagina di ricerca
) {
// Ottieni i termini di ricerca
$search_terms = $q->get( 's' );
// Imposta un 404 se s è vuoto
if ( !$search_terms ) {
add_action( 'wp', function () use ( $q )
{
$q->set_404();
status_header(404);
nocache_headers();
});
}
}
});

Grazie per la risposta - è davvero strano perché il sito ha circa 15 pagine e ne restituisce solo 5, e le 5 che restituisce sono davvero casuali. Non ho ancora testato il tuo codice perché non sono vicino a un computer, ma quando ci sarò proverò - fondamentalmente volevo che restituisse la pagina 404
come hai suggerito, dato che è l'unica pagina con il modulo di ricerca

Molto strano, sulla mia installazione locale restituisce tutti i post di tutti i tipi di contenuto. Comunque, WP_Query
è piuttosto complicato da gestire e a volte si comporta in modo strano. ;-). Prenditi il tuo tempo e testalo completamente, fammi sapere se trovi qualche bug. Buon divertimento ;-)

Lo so, è molto strano, il fatto è che ho circa 7 pagine e alcune hanno pagine figlie, e la cosa strana è che non restituisce solo le pagine genitore, ma 2 pagine genitore e poi 3 pagine figlie. Proverò e ti farò sapere, grazie per la risposta :)

La cosa incredibile è che ogni volta che chiudo la pagina e la riapro e poi svuoto di nuovo la ricerca, restituisce pagine diverse xD Ho aggiunto il tuo codice al mio functions.php
e ha funzionato perfettamente, ma continua a mostrare la pagina 404 - ci sarebbe un modo per visualizzare un titolo diverso invece di 404, tipo "La tua ricerca non è stata trovata"? Grazie per il tuo aiuto Pieter :)

Se vuoi escludere le stringhe di ricerca con una lunghezza inferiore a un valore definito e anche la stringa di ricerca vuota, puoi utilizzare questa funzione modificata della soluzione di birgire. In questo esempio, le frasi di ricerca vuote e quelle con una sola lettera non restituiranno risultati:
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 );

Se stai utilizzando il file search.php standard, è molto più semplice aggiungere la logica all'interno del condizionale if ( have_posts())...
if ( have_posts() && $_GET['s'] != '' )
In questo modo, se il parametro di ricerca è vuoto, non esegue il loop del contenuto.

Molto più facile da implementare rispetto alla soluzione con add_filter
, e funziona perfettamente anche con un search.php
personalizzato.

Questo potrebbe causare il funzionamento errato di alcuni plugin. 1) Innanzitutto, ci sono molti hook quando la pagina di ricerca inizia a funzionare. Alcuni plugin lavorano con la query del database e la query principale restituisce risultati (tutti i post) quando l'utente inserisce una ricerca vuota. 2) In secondo luogo, alcuni plugin che lavorano con il primo processo potrebbero confondersi quando la query principale restituisce risultati ma la pagina dei risultati di ricerca non mostra alcun risultato, causando un funzionamento errato dei plugin.

Per escludere le stringhe di ricerca con una lunghezza inferiore a un valore definito e anche la stringa di ricerca vuota, puoi utilizzare questa funzione modificata della soluzione di 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 );
