Empty search input returns all posts

The question:

So today I’ve decided to implement a search form onto my site that obviously returns a result when the user searches for it, but I’ve run into a little problem.

My Problem

When the user searches for a result without inputting anything into the search form for some reason it returns 5 Pages whereas I would like it to return a Message that says something along the lines of ‘Search Fields was empty – Search Again’.

How would I go about making this happen? I’ve inserted my code below that controls my searchform button and the content it outputs when search.

Code Controlling the Search Form

searchform.php This is the Search form which is where the user inputs what they want (I have a feeling I need to enter some code here to check if it is empty)

<form role="search" method="get" id="searchform" action="<?php echo home_url('/'); ?>">
    <div>
        <label class="screen-reader-text" for="s">Search: </label>
        <input type="text" value="" name="s" id="s" placeholder="<?php the_search_query(); ?>" />
        <input type="submit" id="searchsubmit" value="Search" />
    </div>
</form>

search.php This is showing the user what they have searched for and the getting the template content-search to show the Page name(s).

<div class="search-result">
    <div class="container">
        <div class="row">
            <div class="search">
                <?php if (have_posts()) : ?>

                    <h2>Search Result For: <?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>Ooopss, looks like nothing matches your result.</h3>
                        </div>';
                    endif;
                ?>
                <div class="search-form"><?php get_search_form(); ?></div>
            </div>        
        </div>
    </div>
</div>

content-search.php – This displays the Pages Title and the Permalink for the Page

<div class="searchs">
    <h4>Pages - <a href="<?php the_permalink(); ?>" rel="nofollow noreferrer noopener"><?php the_title(); ?></a></h4>
</div>

The Solutions:

Below are the methods you can try. The first solution is probably the best. Try others if the first one doesn’t work. Senior developers aren’t just copying/pasting – they read the methods carefully & apply them wisely to each case.

Method 1

Just an alternative to the informative answer by @PieterGoosen.

After Pieter posted this part:

if ( ! empty( $q['s'] ) ) {
    $search = $this->parse_search( $q );
}

it came to mind that it might be possible to re-parse the search query, within the posts_search filter, for empty search string. But the parse_search() method is protected and even if we could access it, the empty search would just give us:

AND (((wp_posts.post_title LIKE '%%') OR (wp_posts.post_content LIKE '%%'))) 

and that would just search for everything. So that path wasn’t fruitful 😉

In WordPress 4.5 it has changed to

if ( strlen( $q['s'] ) ) {
    $search = $this->parse_search( $q );
}

Instead we could try to halt the main query, in the case of an empty search:

/**
 * Halt the main query in the case of an empty search 
 */
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 );

Method 2

I’m not sure if this is an intended bug or just a bug that was never anticipated, but it is definitely a flaw in design.

This behavior exists in the following cases that I took note of before

  • Setting an empty array to post__in returns all posts

  • Passing an invalid term to a tax_query or using the name field with a name with special characters or more than one word removes the join clause from the SQL query which also results in all posts being returned. I did an answer regarding this issue

So what happens here is that when we pass a valid string to our search function, the WHERE clause is altered to include our search terms. Normally this is how the WHERE clause looks when we enter a search term called 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')

When we pass an empty string, the search clause is removed from the WHERE clause which causes all posts to be returned. This is how the WHERE clause looks like when we pass an empty string

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')

This is the section in WP_Query which is responsible for this

if ( ! empty( $q['s'] ) ) {
    $search = $this->parse_search( $q );
}

The easiest way to get out of this is to return a 404 whenever we pass an empty string as search terms. For this we need to check if we have a valid search string or not, and then set a 404 according to that. You can try the following

add_action( 'pre_get_posts', function ( $q )
{
    if(    !is_admin() // Only target the front end
        && $q->is_main_query() // Only target the main query
        && $q->is_search() // Only target the search page
    ) {
        // Get the search terms
        $search_terms = $q->get( 's' );

        // Set a 404 if s is empty
        if ( !$search_terms ) {
            add_action( 'wp', function () use ( $q )
            {
                $q->set_404();
                status_header(404);
                nocache_headers();
            });
        }
    }
});

Method 3

If you want to exclude search strings with shorter than a defined length and the empty search string too, you can use this altered function of birgire’s solution. In this example empty and search phrases with only one letter give no results:

    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 );

Method 4

If you are using the standard search.php file, it’s a lot easier to just add logic in the if ( have_posts()) conditional…

if ( have_posts() && $_GET['s'] != '' )

That way if the search parameter is empty, it doesn’t perform the content loop.

Method 5

To exclude search strings with shorter than a defined length and the empty search string too, you can use this altered function of birgire’s solution:

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 );


All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

Leave a Comment