A Step-by-Step Tutorial to Customize Drupal SearchAPI Facets without AJAX
How to create SearchAPI Facets in 5 Minutes
Drupal SearchAPI Facets are used to provide search results in the form of facets. Some of the most common reasons for using faceted search are:
- It can be used to segment results into different categories, such as price and availability.
- It can be used to find specific items within a category or subcategory.
- It can be used for filtering content by date, author, or other criteria.
- It can also be used for sorting and ranking content based on popularity and relevance.
Offering a rich array of options, a Faceted search can enhance the entire user search experience and is a great way to let users narrow down their search results. For the sake of simplicity, we’ve set up our instance to use the default Database search provider service in Search API. For production sites, Apache Solr is recommended. Beginning with:
Hop over to the View tab and manually build the index if it’s still pending. The SearchAPI is now ready to accept Faceted search which we will configure on the Facets configuration page. Before that, there is one more missing piece of the puzzle - A View that works on the SearchAPI Index. A View acts as a proxy between exposed Facets and fetching search results from the SearchAPI index.
Informally this is quite the opposite of what SearchAPI and FacetAPI offer out-of-the-box. A Google search on “AJAX with Facets”, or “Post request with Facet” is sure to surprise you. You’ll find dozens of active discussions among Drupal developers to implement AJAX in Facets.
Incidentally, FacetAPI defaults to a URL processor that works over GET requests, which makes a lot of sense when building progressive search results ie. one facet is always dependent on the other. The limitations of “GET” requests (8 KB approx), and the complexity of AJAX POST requests coil up these feature requests ending up with numerous patches which are risky and not production-ready yet.
These are a few of the feature implementations that were made possible:
- Prevent page reload on Facet selection (requires storage on the client-side = sessionStorage)
- Maintain a stack of selected and removed facets.
- Allow users to select multiple facets and submit them simultaneously (risky and unpredictable).
- Clear out storage (sessionStorage) for each Facet, or all of them altogether.
FYI Reynolds is the namespace under which we’re wrapping up all the functions, yeah, there could be another way of putting this using Drupal.behaviors which is the right way to do it. Anyhow, it works, and there’s more explaining of what each of the functions would do. So let’s dive into them:
- Reynolds.facetStorageSetOrCreate(); creates an empty storage or returns it
- Reynolds.findFacetByKey(facetKey) would find a facet by its key or id
- Reynolds.removeFacetByKey(facetKey); would remove a facet from storage
- _.set(Reynolds.facetsData, facetKey, facetIdent); will merge storage entries JSON object using underscore.js
For this to work, you’ll also need a Facet hook function as below in your .theme file:
These helper functions control the click behavior with additional checks like does a facet exists or does the sessionStorage exists, and consequently the removal of a facet item based on its key. Now comes the submission part - as we’ve maintained the selections in the sessionStorage JSON object it’s relatively easy to form a submit query:
Finally, this little snippet gathers all the selected facets, converts them into proper valid facet query parameters, and redirects to the current path with query parameters. To simplify just call the Reynolds.hookFacetSubmit(); function on the page ready or window load event and you’re all set.
What about Facet summaries?
And call the function Reynolds.hookFacetSummaryRemoval(); on page load or window load event. It’s not the most robust or comprehensive solution, yet gets you closer to customizing facets without using AJAX. On an endnote, you’re not restricted to this approach, it might strike as a starting point for a full AJAX implementation. A live implementation can be found here: