WordPress Filter Search Results By Category and Tag
Tags: php, webdev, wordpress
Published: 2020-12-28 21:23:26

Many WordPress themes provide a simple search form that includes a single input field for entering your search term. The search results are helpful, but what if you wanted to provide visitors with a way to filter those results by category and/or tag and change the order? Let’s learn how!

## Standard Search Form

The **action** property on a form defines the url that should load when the form is submitted.

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

Every field in a form should have a **name** property that becomes a url parameter. A standard WordPress form includes a single input field using a name value of **s**, which represents the search term.

```html
<input type="search" name="s">
```

Let’s say you search for the word **table**. You’ll see the url changes to something like:

```
https://nightwolf.dev/?s=table
```

WordPress has other url parameters that can help us achieve our goal of filtering search results.

## Query Vars

WordPress has both [public and private query vars](https://codex.wordpress.org/WordPress_Query_Vars). Public query vars can be used as url parameters. Private query vars can only be used in PHP when building a query using functions like WP_Query.

Filtering by category and/or tag as well as changing the order can all be done using the public query vars called **category_name**, **tag**, **orderby**, and **order**! We just have to build them into the resulting search url.

## Search Template

When a visitor performs a search, the template used to display the search results is called **search.php**. Let’s edit that search template to include a form with fields for filtering results.

## get_query_var

We need to check if there are url parameters present and grab their values. We can use the [get_query_var](https://developer.wordpress.org/reference/functions/get_query_var/) function.

To see if the visitor filtered the search results by category, check the **category_name** query var and save its result in a variable called $filterByCategory.

```php
$filterByCategory = get_query_var( 'category_name' );
```

To see if the visitor filtered the search results by tag, check the **tag** query var and save its result in a variable called $filterByTag.

```php
$filterByTag = get_query_var( 'tag' );
```

To see if the visitor filtered the search results by changing the order type, check the **orderby** query var and save its result in a variable called $orderBy.

```php
$orderBy = get_query_var( 'orderby' );
```

To see if the visitor filtered the search results by changing the order, check the **order** query var and save its result in a variable called $order.

```php
$order = get_query_var( 'order' );
```

## Search Term

Let’s create an input element, which will include the current search term using [the_search_query](https://developer.wordpress.org/reference/functions/the_search_query/) function.

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

## Filter By Category

Let’s create a select element, which will list all of our categories. Define the name property with the query var called **category_name**. When the form is submitted, it will include the category_name query var into the url, filtering the results by the selected category.

```html
<select name="category_name">
```

To get a list of categories, we can use the [get_categories](https://developer.wordpress.org/reference/functions/get_categories/) function. We don’t want the Uncategorized category to appear as an option so make sure to exclude that by passing arguments to the get_categories function.

```php
$args = array(
  'exclude' => '1'
);
 
$categories = get_categories( $args );
```

Let’s loop through each category and output an option element. If the current category we’re looping through equals the filterByCategory, we’ll include the selected attribute so it appears as the selected option. The option value will be the category slug and the option text will be the category name.

```php
foreach ( $categories as $category ) {
  $selected = $category->slug === $filterByCategory ? 'selected' : '';
                                          
  echo '<option value="' . $category->slug . '" ' . $selected . '>' . $category->name . '</option>';
}
```

## Filter By Tag

Let’s create a select element, which will list all of our tags. Define the name property with the query var called **tag**. When the form is submitted, it will include the tag query var into the url, filtering the results by the selected tag.

```html
<select name="tag">
```

To get a list of tags, we can use the [get_tags](https://developer.wordpress.org/reference/functions/get_tags/) function.

```php
$tags = get_tags();
```

Let’s loop through each tag and output an option element. If the current tag we’re looping through equals the filterByTag, we’ll include the selected attribute so it appears as the selected option. The option value will be the tag slug and the option text will be the tag name.

```php
foreach ( $tags as $tag ) {
  $selected = $tag->slug === $filterByTag ? 'selected' : '';
                                  
  echo '<option value="' . $tag->slug . '" ' . $selected . '>' . $tag->name . '</option>';
}
```

## Order By

Let’s create a select element with options to order by Date or Title. Define the name property with the query var called **orderby**. When the form is submitted, it will include the orderby query var into the url, changing the type of order.

```html
<select name="orderby">
```

Create an array of order by options.

```php
$orderByOptions = array( 'date' => 'Date', 'title' => 'Title' );
```

Let’s loop through each order by option and output an option element. If we have no orderBy value and the current option we’re looping through equals date, or the current option we’re looping through equals the orderByValue, we’ll include the selected attribute so it appears as the selected option. The option value will be the orderByValue and the option text will be the orderByText.

```php
foreach ( $orderByOptions as $orderByValue => $orderByText ) {
  $selected = (!$orderBy &amp;&amp; $orderByValue === 'date') || $orderByValue === $orderBy ? 'selected' : '';
 
  echo '<option value="' . $orderByValue . '" ' . $selected . '>' . $orderByText . '</option>'; 
```

## Order

Let’s create a select element with options to order by ASC or DESC. Define the name property with the query var called **order**. When the form is submitted, it will include the order query var into the url, changing the type of order.

```html
<select name="order">
```

Create an array of order options.

```php
$orderOptions = array( 'DESC', 'ASC' );
```

Let’s loop through each order option and output an option element. If we have no order value and the current option we’re looping through equals DESC, or the current option we’re looping through equals the orderOption, we’ll include the selected attribute so it appears as the selected option. Both the option value and option text will be the orderOption.

```php
foreach ( $orderOptions as $orderOption ) {
  $selected = (!$order &amp;&amp; $orderOption === 'DESC') || $orderOption === $order ? 'selected' : '';
                                          
  echo '<option value="' . $orderOption . '" ' . $selected . '>' . $orderOption . '</option>';
```
## Filtered Search Results

With all that in place, when the form is submitted, it will include the query vars into the url and update the search results based on your selections!

```
https://nightwolf.dev/?s=table&amp;category_name=articles&amp;tag=javascript&amp;orderby=date&amp;order=DESC
```

---
#### Visit our website at [https://nightwolf.dev](https://nightwolf.dev) and follow us on [Facebook](https://www.facebook.com/NightWolfDevelopment) and [Twitter](https://twitter.com/nightwolfdev)!
---