How to implement Faceted Search in WordPress

7 min readNov 3, 2020


We discuss how to implement faceted search while building a WordPress site. Specifically, we will cover some key features of the FacetWP plugin and discuss how to implement advanced features such as building custom queries and implementing hooks.

The Use Case

We recently implemented a faceted search for an insurance client of ours: Burns and Wilcox. You can see the implementation here:

You will notice a few key aspects of this faceted search:

  • It brings up a list of experts at Burns and Wilcox
  • This list is filtered by proximity to your location (that is automatically detected). If the location is removed, then we were expected to show national results.
  • You can choose the results from a search radius (50 miles, 100 miles, 250 miles etc)
  • You can filter by two different facets : Practice Area and Specialty
  • You can narrow your search results by typing in the name of an expert
  • The client needed to sort these results based on the seniority of the expert
  • Finally, there was a lot of conditional logic around when you could show search results vs. not.

Clearly, a complex facet to implement!

Introduction to FacetWP

FacetWP is the premier WordPress plugin for implementing faceted search. A few key highlights of the product are shown below:


Proximity search

FacetWP’s “proximity facet” lets you find results near a specified location. The process to achieve this is as follows:

First, we need to enable “latitude/longitude” coordinates for the Expert’s custom post type. For eg. we need to be able to say that Expert A is located at so-so latitude/longitude. To achieve this, we used a plugin called Address geocoder. Then we mapped the location datasource in FacetWP to this field.

Second, when a user comes to this page, we need to determine his lat/long. After a user gives us permission to track his location, we make a call to the Google API that returns his lat/long.

The lat/long information is then stored in the browser cookie which is picked up by FacetWP.

This information is used by FacetWP to provide features to limit the search to a user-defined radius (such as 50 miles, 100 miles etc)

The actual query for pulling up the list of experts within a 50/100 mile radius of the user’s location is executed within the “templates” provided by FacetWP.

Search by Name

“Search by name” requires robust search capabilities that are not offered in FacetWP. It integrates with two options: WPCore Search and Relevanssi. Using WP core search limitsyou to the post title, excerpt, and body. However, if you need more flexibility, you can use an advanced plugin like Relevanssi. This lets you search other advanced custom post data such as custom fields, taxonomy terms, PDF contents, etc.

After you have installed the plugin, additional options will show up in the search settings of FacetWP as shown below:

So when a user searches for say “John”, the following sequence is executed:

  • The search term “John” is passed by FacetWP to Relevanssi
  • Relevanssi returns the relevant results for “John” based on its search index
  • These results are filtered by the Facet, to show only the results that satisfy the proximity criteria (Eg. Show all Johns within a 50 mile radius)

Facet Dimensions

FacetWP lets you create “facets” as shown below:

As you can see, you can do a few main things:

  • Decide which aspect you want to filter the resultset on. In this example, you are filtering by the “specialty” of the expert. (see example below)
  • There are different types of facets: checkbox, dropdown, date range etc (see image below)
  • You also have a few other options such as the number of values you want to show in the facet, what you want to happen when a user clicks on a value, how you want to sort the list of values etc

Custom Query Implementation

“Custom Query” is an advanced feature that is used when the query is more complex than can be handled within FacetWP. For example, in the scenario above, the client had complex rules around which person should be shown first, based on their seniority, physical location and role. This couldn’t be handled within the basic query capabilities of FacetWP. So, we had to go with custom queries.

First Option : WP Hooks

FacetWP hooks can be added to functions.php theme file but we wouldn’t recommend it because the site will completely crash should there be errors. So we downloaded the Custom Hooks Plugin and activated it in the wp-admin. This allowed us to add relevant code in custom-hooks.php. The advantage of this approach is that WordPress will simply disable the plugin should it trigger a PHP fatal error, instead of the whole site coming down.

Now we can separate the custom query from facetwp admin by placing it anywhere in the theme php templates and add a facetwp argument. This would then enable FacetWP to detect the query.

Second Option: Custom WP_Query

If you’re trying to show facets on a WP page template (with a custom WP_Query), FacetWP won’t be able to auto-detect the query. You can nudge FacetWP into detecting the query by adding the query argument as shown below:

As an example, we wrote a custom query in a separate template instead of the FacetWP admin. This query will get detected by the Facetwp by setting the argument “facetwp” to true.

$emp_args = [ ‘posts_per_page’ => 1,
‘post_type’ => ’employees’,
‘facetwp’ => true,
‘post__in’ => $empid,
‘orderby’ => ‘date’,
‘ meta_query’ => [ [
‘key’ => ‘office_code’,
‘value’ => ‘IL01’,
‘compare’ => ‘LIKE’,
] ],
‘no_found_rows’ => true,
‘post_status’ => ‘publish’ ];

Third Option: facetwp_query_args

This filter lets you override the Query Arguments field from FacetWP templates. The Query arguments array (used by WP_Query) tells WP which posts to retrieve from the database.

As an example, in this hook we have a query argument for filtering the employees with the ‘practice_area’ taxonomy attached to it. Also we added conditional logic for restricting the query arguments for a particular template named ‘experts_template’.

add_filter(‘facetwp_query_args’, function ($query_args, $class){
if (‘experts_template’ == $class->ajax_params[‘template’]) {
$query_args[‘tax_query’] = [
‘taxonomy’ => ‘practice_area’,
‘operator’ => ‘EXISTS’,
return $query_args;
}, 10, 2);

Final Option: facetwp_pre_filtered_post_ids

In this option, we can choose the initial bucket of post IDs before any filtering is applied. This is especially useful due to the WP limitation that prevents “post__in” and “post__not_in” from being used simultaneously.

For example, in this following hook we are preventing a particular post from appearing in the query result using the post ID.

add_filter( ‘facetwp_pre_filtered_post_ids’, function( $post_ids, $class ) {
if ( false !== ( $key = array_search( 42, $post_ids ) ) ) {
unset( $post_ids[ $key ] );
return $post_ids;
}, 10, 2 );

A very useful Add-on

There is a very useful FacetWP plugin called Conditional Logic. This plugin can set up many different conditions related to facet and facet template, and can be a great replacement for tons of custom js that might otherwise be needed.

For eg. the client requirements were as follows:

When the user first comes to the page, there would be no location selected. When both name + location are empty, we were required to show some static text (as shown above).

If the user typed in the “Search by Name” field, then we had to show results.

Similarly, if the user selected his location, then we were required to show the results. At this stage, however, if you “cleared location”, then you were required to hide the results again (shown below)

As you can see, there was a lot of conditional logic around how the facets should behave. Implementing this manually would have required a ton of custom javascript. With the Conditional Logic plugin, we were able to simply define the rules (see below) and the plugin executed all the logic.


In this post, we discussed how to implement faceted search while building a WordPress site. Specifically, we covered some key features of the FacetWP plugin and discussed how to implement advanced features such as building custom queries and implementing conditional logic.