Custom search form with empty parameters

The question:

I’m building a custom search form with keywords and drop down lists (categories, date, and country (have a separate plugin for this)).

In the searchform.php I have the input field and then select>option tags.

<!-- searchform.php (form) -->

<form action="/" method="get">

        <input type="text" name="s" id="search" value="<?php the_search_query(); ?>" />

        <select name="category">

            <select name="country">

              <option value=""></option>

              <option value="UK">UK</option>

              <option value="USA">USA</option>

              <option value="Brazil">Brazil</option>

              <option value="Poland">Poland</option>

              <option value="Canada">Canada</option>

            </select>

            <select name="year">

              <option value=""></option>

              <option value="2012">2012</option>

              <option value="2011">2011</option>

              <option value="2010">2010</option>

            </select>   

</form>



<?php

// search.php (results)

$args = array(

        's' => $_GET['s'],      

        'country' => $_GET['country'],

        'year' => $_GET['year']

);



$the_query = new WP_Query( $args );



if ( $the_query->have_posts() ) : while ( $the_query->have_posts() ) : $the_query->the_post(); ?>

        // Do Stuff

        <h3 class="search-title"><?php country_tag($post->ID); ?><a href="#" rel="nofollow noreferrer noopener" rel="nofollow noreferrer noopener" data-siteurl="<?php bloginfo('url'); ?>" rel="<?php the_ID(); ?>" title="<?php the_title_attribute(); ?>" class="search-post-title"><?php the_title(); ?></a></h3>



<?php 

endwhile;

endif;

?>

Problem: Currently if I leave the selects empty it sends them as empty strings in the get url (?s=keyword&country=&year=). This means that nothing will be found in the search. (I am guessing because its saying ‘find matching posts with ‘keyword’ AND an empty string). So I want ?s=keyword to be passed if others are unused.

Perhaps I’ve setup the code wrong, likely as I’ve just started playing around with WP_Query.

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

That’s certainly something you must solve on the server side, only omitting the arguments in URL would cause errors when accessing the non-existent keys in the $_GET array.

You should build your arguments array dynamically based on whether the values are set ot not.

Example:

$args = array();

foreach(array('s', 'country', 'year') as $key)
{
    // if key is available and not empty, include argument in the query
    if(isset($_GET[$key]) && trim($_GET[$key]) !== '')
    {
        $args[$key] = $_GET[$key];
    }
}

// 's' is neccessary for a search query, so only continue if it's available
if(isset($args['s']))
{
    $the_query = new WP_Query($args);
    ...
}

Update:

After figuring out what this country plugin is, I had a look at it. It manipulates the query, but it only checks whether the country key is present, not if it’s empty, and it does this check on the global query object, so even if there is no country in your custom query, it will be present in the global query object because the plugin added the country key to the list of variables that will be fetched automatically (in case you didn’t knew, WordPress will automatically query the posts for you). You may want to contact the plugin author and tell him about the problem so that he fixes it, until then, here’s a quick and dirty fix for the current version:

// Hooks...
add_filter('posts_join', 'country_search_join', 10, 2);
add_filter('posts_where', 'country_search_where', 10, 2);
add_filter('posts_groupby', 'country_search_groupby', 10, 2);
add_filter('query_vars', 'country_queryvars');
add_action('init', 'country_flush_rewrite_rules');
add_action('generate_rewrite_rules', 'country_add_rewrite_rules');
add_action('plugins_loaded', 'country_widget_init');
add_action('admin_menu', 'manage_countries_menu');


// Join clause for the META table if a country is queried.
function country_search_join($join, &$wp_query)
{
    global $wpdb;

    if(isset($wp_query->query_vars['country']) && trim($wp_query->query_vars['country']) !== '') {
        $join .= " left join $wpdb->postmeta on $wpdb->posts.ID = $wpdb->postmeta.post_id ";
    }
    return $join;
}


// Add a where clause if a country is queried.
function country_search_where($where, &$wp_query)
{
    global $wpdb;

    if(isset($wp_query->query_vars['country']) && trim($wp_query->query_vars['country']) !== '') {
        $where = $where . " and {$wpdb->postmeta}.meta_key = 'Country' and {$wpdb->postmeta}.meta_value = '" . $wp_query->query_vars['country'] . "' ";
    }
    return $where;
}


// Add a group by clause if a country is queried to make sure posts are only returned once.
function country_search_groupby($groupby, &$wp_query)
{
    global $wpdb;

    if(!isset($wp_query->query_vars['country']) || trim($wp_query->query_vars['country']) === '') {
        return $groupby;
    }

    // Group on post ID
    $mygroupby = "{$wpdb->posts}.ID";

    // Is this group by already there?
    if(preg_match( "/$mygroupby/", $groupby)) {
        return $groupby;
    }

    // Is the group by empty?
    if(!strlen(trim($groupby))) {
        return $mygroupby;
    }

    // Append new group by clause.
    return $groupby . ", " . $mygroupby;
}

Now that i understand what exactly the plugin is doing there, i’d recommend not using a custom query, the query made by WordPress should be fine, ie something like this should do it:

<?php while ( have_posts() ) : the_post(); ?>

    <h3 class="search-title"><?php country_tag($post->ID); ?><a href="#" rel="nofollow noreferrer noopener" rel="nofollow noreferrer noopener" data-siteurl="<?php bloginfo('url'); ?>" rel="<?php the_ID(); ?>" title="<?php the_title_attribute(); ?>" class="search-post-title"><?php the_title(); ?></a></h3>

<?php endwhile; ?>


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