Findkit is often used to implement full text searching for websites but Findkit can also filter and sort search results by structured data as well. The most powerful search interfaces combine both!
A common example of this is an E-commerce search. A shop which has products as pages and you’ll want to create a product search which can for example filter and order the results by price like in this demo. Lets see how we can implement it with Findkit.
Structured Data
To add structured data to the search index we use Custom Fields which are exposed using a Findkit Meta Tag. The meta tag can be generated with custom code on your CMS or when using WordPress with our plugin filter.
The meta tag for a product page would look like this
<script id="findkit" type="application/json">
{
"customFields": {
"price": {
"type": "number",
"value": 10
},
"stock": {
"type": "number",
"value": 34
},
}
}
</script>
See the Custom Fields documentation for details. When the site is crawled for the next time these custom fields will be added to the index.
Filtering
To filter based on the custom fields we add a filter
Search Param to the FindkitUI instance.
const ui = new FindkitUI({
publicToken: "<token>",
minTerms: 0,
params: {
filter: {
price: { $lt: 100 }
}
}
})
The filter syntax is inspired by MongoDB filters. We also set to minTerms:0
in order to be able to browse the products without typing any search terms.
This static filter is not very useful yet. We need to make a custom user interface so end users can modify it as they please. To do it we can use a HTML form:
<form>
<input type="number" name="min" />
<input type="number" name="max" />
</form>
and we bind the form changes to FindkitUI and update the Search Params accordingly:
const form = document.querySelector("form");
form.addEventListener("input", () => {
ui.updateParams((params) => {
const data = Object.fromEntries(new FormData(form));
const $and = [];
if (data.min) {
$and.push({ price: { $gte: data.min } });
}
if (data.max) {
$and.push({ price: { $lte: data.max } });
}
params.filter.$and = $and;
});
});
See the Filtering documentation for details.
Linkable State
This is pretty much it but this implementation has a serious usability issue. When user clicks on a search result but decides to come back using the browser back button, the search filters are gone. To fix this we must save the form state to the URL using the Custom Router Data feature in FindkitUI.
In the form change handler we save the form state with ui.setCustomRouterData()
before updating the filters
form.addEventListener("input", () => {
// Save form state to the URL
ui.setCustomRouterData(Object.fromEntries(new FormData(form)));
ui.updateParams(/* ... */);
});
and to restore the form state we need to use the custom-router-data
event which emits the previously saved Custom Router Data:
ui.on("custom-router-data", (e) => {
// For full form support see https://findk.it/update-form
for (const [name, value] of Object.entries(e.data)) {
form.elements.namedItem(name).value = value;
}
// Update the filter here too, since programmatic form update
// does not trigger the "input" events
ui.updateParams(/* ... */);
});
See the Custom Router Data documentation for details.
Live Demo
Here’s a live demo of a search made using this pattern. Checkout the source for full details or try even making changes to it in Codesandbox.
This is very simple demo but checkout the earlier demo which adds sorting by price, filtering by category, language and stock availability. Here’s the source and Codesandbox for it as well.
Next Steps
In any e-commerce site it is important to keep the index up to date as product prices change etc. this can be done by setting real-time updates where the pages are instantly recrawled when they are updated.
Since the search results are customizable using Hit slot overrides we can and an “Add to cart” action to each result. In the next article we take a look on to how implement it for WooCommerce as well as how to extract the product data to Custom Field in practice.