How to Add an Advanced Search to Your WordPress Site
The majority of WordPress search forms set a single querystring parameter named ‘s’:
<form method="get" action="<?php bloginfo('url'); ?>">
<fieldset>
<input type="text" name="s" value="" placeholder="search…" maxlength="50" required="required" />
<button type="submit">Search</button>
</fieldset>
</form>
There’s nothing wrong with that and I thought it was the only option for many, many years.
However, more advanced queries are possible without the aid of plugins (although plenty are available). Deep within the WordPress core, the application parses several other querystring parameters and uses them to return a more focused set of search results. There is some rudimentary documentation which lists the parameter names:
- attachment
- attachment_id
- author
- author_name
- cat
- category_name
- comments_popup
- day
- error
- feed
- hour
- m
- minute
- monthnum
- name
- p
- page_id
- paged
- pagename
- post_parent
- post_type
- preview
- second
- static
- subpost
- subpost_id
- tag
- tag_id
- tb
- w
- year
I’m not convinced all these work as expected and some are a little pointless, but they match the parameters you can pass to WP_Query. We can therefore create an advanced search form using HTML with a smidgen of PHP to automate the options.
Refine Search by Category
You can limit results to a category by passing its slug to the category_name
parameter, e.g.
http://yoursite.com/?s=search+term&category_name=kittens
Our search form can allow the user to refine their search to specific categories:
<form method="get" action="<?php bloginfo('url'); ?>">
<fieldset>
<input type="text" name="s" value="" placeholder="search…" maxlength="50" required="required" />
<select name="category_name">
<option value="">all categories</option>
<option value="kittens">cute kittens</option>
<option value="puppies">adorable puppies</option>
</select>
<button type="submit">Search</button>
</fieldset>
</form>
If you’d rather list all categories, add the following code between the <select>
and </select>
tags:
<?php
// generate list of categories
$categories = get_categories();
foreach ($categories as $category) {
echo '<option value="', $category->slug, '">', $category->name, "</option>\n";
}
?>
Refine Search by Tag
Search results can be limited to a tag by passing its slug to the tag
parameter, e.g.
http://yoursite.com/?s=search+term&tag=cockroach
Your search from could therefore limit results to certain tags, e.g.
<form method="get" action="<?php bloginfo('url'); ?>">
<fieldset>
<input type="text" name="s" value="" placeholder="search…" maxlength="50" required="required" />
<select name="tag">
<option value="">any tag</option>
<option value="cockroach">cockroaches</option>
<option value="snake">snakes</option>
</select>
<button type="submit">Search</button>
</fieldset>
</form>
Similarly, you can generate a list of all tags for the select
field:
<?php
// generate list of tags
$tags = get_tags();
foreach ($tags as $tag) {
echo '<option value="', $tag->slug, '">', $tag->name, "</option>\n";
}
?>
Advancing Advanced Search
What if you want to refine the search by multiple values? For example, the user could choose two or more tags and resulting pages must have them all set. We cannot achieve this using URL parameters alone but let’s start by defining an HTML search form:
<form method="get" action="<?php bloginfo('url'); ?>">
<fieldset>
<input type="text" name="s" value="" placeholder="search…" maxlength="50" required="required" />
<p>Refine search to posts containing chosen tags:</p>
<?php
// generate list of tags
$tags = get_tags();
foreach ($tags as $tag) {
echo
'<label>',
'<input type="checkbox" name="taglist[]" value="', $tag->slug, '" /> ',
$tag->name,
"</label>\n";
}
?>
<button type="submit">Search</button>
</fieldset>
</form>
Note that I’ve used a PHP array parameter named taglist
. You can use any name other than those already reserved by WordPress (see the list above).
We can now intercept a search submission in our WordPress theme’s functions.php file. The advanced_search_query
function detects whether a search is active then sets the WP_Query tag_slug__and
parameter accordingly.
// advanced search functionality
function advanced_search_query($query) {
if($query->is_search()) {
// tag search
if (isset($_GET['taglist']) && is_array($_GET['taglist'])) {
$query->set('tag_slug__and', $_GET['taglist']);
}
return $query;
}
}
Finally, we use the pre_get_posts
action hook to run our advanced_search_query
function before a query is executed:
add_action('pre_get_posts', 'advanced_search_query', 1000);
Adding advanced search facilities to WordPress is remarkably easy yet few developers realize it’s possible … perhaps because documentation and examples are a little sparse. I discovered it by accident so I hope you find this code useful in your next WordPress project.