Dynamic search filter for WordPress categories
A common scenario: you have a bunch of categories, say, Label > Artist > Track. Following is an approach for a hierarchical category search filter on your WordPress site.
The basics
Here is the requirement:
- A form with three select elements to reflect this hierarchy:
Label > Artist > Release
- Choosing an option from a preceding select element dynamically populates the following select element
Category structure
The category hierarchy looks something like this:
Music > Label > Artist > Release
Music
is really just a container to keep everything tidy and discrete. As the top-most parent category it will generate the contents for the first child select element, Label
.
Label
, Artist
and Release
are not actual categories but describe the type of category contained in each select element; the immediate children of the top-most Music
category will be music label names, the grand-children will be musician names, and so on. For example:
Label: Raster Noton > Artist: Kyoka > Release: Ufunfunfufu
The key to this approach is to use wp_dropdown_categories() to generate each select element. Whenever an option is selected we can use this function's child_of argument to dynamically generate the following select element's contents.
The following will generate the first select element for categories of type Label
:
Tip: set 'hide_empty'
to 0 during development if you want to see more than empty select elements. If this argument is not set you'll need to assign categories to posts to make them visible.
Regarding the above example:
'child_of'
has a value of 1, the category ID of theMusic
category I'm using here. Use whichever method you prefer to find the top-most category ID for your set of terms.- Both
'depth'
and'hierarchical'
keys are given a value of 1 to ensure only the immediate children are included. - Additional select elements for
Artist
- andRelease
-type categories can be generated in the same way, the only difference being a change in value for the'child_of'
key.
The next step is to set up an AJAX request to return contextual select elements based on user selection.
Switched at birth
Here is what needs to happen:
- Capture the value whenever a
select
element changes - AJAX the value to a custom function
- Return a new
wp_dropdown_categories()
object - Update the next
select
element
Listen / request / receive
Listening for change and making an AJAX request with jQuery:
If you're not overly familiar with WordPress, the URL set in the request above points to WordPress' native implementation of AJAX. Even though it's called admin-ajax
it can be used for both back- and front-end requests.
Update the child
The AJAX request posts a value to a custom function which will construct a new child select element. The function is very simple, as simple as setting the passed Label
value as the value of child_of:
Each action uses the native wp_ajax_ action hook to trigger the success attribute of the request. Looking back at the data attribute of the request…
… you'll notice the value of the action attribute—update_label
—is appended to wp_ajax_
. The first time I worked with this hook I didn't follow this convention and consequently never received a success value.
The other thing to note is the fact there is two actions: one is for logged-in users, the other for non-logged-in users.
At this point the basic moving parts for the search filter are in place—sans sanity and security checks. There's also need for additional logic to initially disable all select children, and enable a child whenever its immediate parent changes.