Kirby ships with a search method built in, and that can get you surprisingly far. But once you have a lot of pages and content, you might want something with a proper index and the ability to fuzzy search.
Usually that is the moment you start googling Algolia or Meilisearch. Suddenly you are signing up for a service, running a separate search server, and managing yet another moving part. Not exactly the lightweight Kirby feeling we love.
This is where Loupe comes in, and the plugin Kirby Loupe, built by Arno Schlipf.
What is Kirby Loupe?
Loupe is a PHP only, SQLite based fulltext search engine. Kirby Loupe is a thin wrapper around it. "PHP only" is the magic part: no extra service, no separate server, only the SQLite extension. If your host can run Kirby, it can probably also run this.
Installing is one line with composer.
composer require arnoson/kirby-loupe
First, we tell Loupe what to index. We do that in our config.
// site/config/config.php
return [
'arnoson.kirby-loupe' => [
// Only index pages with template "command"
'pages' => fn($page) => $page->intendedTemplate()->name() === 'command',
'fields' => [
'title',
'text' => fn($page) => Str::unhtml($page->text()),
'category'
],
'searchable' => ['title', 'text'],
'filterable' => ['category'],
]
];
Then we build the index. You can add a handy panel field that gives you a "Reindex Site" button. I put that on the site.yml blueprint.
After that, Kirby Loupe hooks into the page lifecycle, so creating, updating or deleting a page updates the index automatically in the background.
Using the search
Now let's look at how we actually use the search. I created a search results page and a matching template. We will use a query param "s" for searching, which could be filled with a simple search input.
<form action="/search" method="GET">
<input type="search" placeholder="Search..." name="s" />
</form>
On the search page we can get the results like this:
$param = get('s');
$results = $param ? KirbyLoupe::search($param) : [];
The $results will hold an array of page UUIDs, so we can find the matching page via the page method:
$p = page($result['uuid']);
From there we can display the title, link, or whatever else we want from that page.
These days a full search results page is not that common, and a quick overlay search box that shows results as you type is often more useful. For the overlay, we will use a little web component, and the results will be fetched via JavaScript.
The bridge for that is a tiny route that returns search hits as JSON.
'routes' => [
[
'pattern' => 'search.json',
'action' => function () {
$hits = KirbyLoupe::search(get('s'), paginate: 8);
return Response::json($hits->values(function ($hit) {
$page = page($hit['uuid']);
return [
'label' => $page->title()->value(),
'link' => $page->url(),
];
}));
},
],
],
In this case, we limit the results to 8. In JavaScript, we can fetch that endpoint with the user input and then display the results in the overlay. Nice and tidy.
Thank you, Arno, for building this great plugin.