johannschopplich / kirby-algolia-docsearch
Index and search your Kirby site with Algolia DocSearch
Package info
github.com/johannschopplich/kirby-algolia-docsearch
Type:kirby-plugin
pkg:composer/johannschopplich/kirby-algolia-docsearch
Fund package maintenance!
Requires
- php: >=8.2
- algolia/algoliasearch-client-php: ^3.4
- getkirby/composer-installer: ^1
Requires (Dev)
- getkirby/cms: ^5 || ^6
- phpunit/phpunit: ^12
Suggests
None
Provides
None
Conflicts
None
Replaces
None
README
Kirby Algolia DocSearch
Kirby Algolia DocSearch is a plugin for Kirby CMS that indexes your pages into Algolia for the DocSearch search modal. It builds the records itself, so you don't need Algolia's paid crawler.
Features β’ DocSearch Setup β’ Options β’ Limits
When to Use
| I want to⦠| Use |
|---|---|
| Index the whole site | kirby algolia-docsearch:index |
| Index the site from the Panel | Janitor field with algolia-docsearch:index |
| Keep the index current on every edit | hooks option |
| Index unlisted pages, too | filter option |
| Index a field instead of the rendered HTML | content closure |
| Add data to each search hit | attributes option |
| Tune Algolia's index settings | indexSettings option |
| Index from my own code | algolia()->index() |
Features
π¦ Indexing Without the Crawler
The plugin renders every listed page of the configured templates, extracts the text of one HTML tag, and writes one DocSearch record per page. Run the Kirby CLI command to replace the index with the current state of the site:
kirby algolia-docsearch:index
With Janitor installed, the same command runs from a button in the Panel:
fields: algoliaIndex: label: johannschopplich.algolia-docsearch.index.start type: janitor command: algolia-docsearch:index
π Page Hooks
With the hooks option enabled, the index follows changes in the Panel. Index the site once, and the hooks keep it current from there:
- Saving content or changing the title in a translation updates that language's index. In the default language, it updates every language's index, since translations show its content for fields they don't translate.
- Changing the slug or status, moving, changing the template, and deleting update every language's index. When a page's URL or draft state changes, its descendants follow.
The hooks stay off while Kirby's debug option is on.
π One Index per Language
On a multi-language site, each language gets its own index: the index option plus the language code, e.g. example-en and example-de. Labels take one string per language:
'label' => [ 'default' => [ 'en' => 'Page', 'de' => 'Seite' ] ]
π§© Content From HTML or a Closure
By default, a record's content is the text inside the rendered page's <body>. Point the content option to another tag, such as main, or return the text from a closure. This one indexes a blocks field instead of the rendered page:
'content' => fn (\Kirby\Cms\Page $page, string|null $languageCode) => strip_tags($page->content($languageCode)->get('text')->toBlocks()->toHtml())
The closure receives the language code of the index it writes to. For different content per template, pass an array of closures keyed by template name, with default for the rest.
Requirements
- Kirby 5 or 6
Installation
Composer (Recommended)
composer require johannschopplich/kirby-algolia-docsearch
Manual Installation
Download a release and extract it to /site/plugins/kirby-algolia-docsearch.
DocSearch Setup
The plugin only fills the index. The search button and modal come from the DocSearch library, which you add to your frontend:
npm install @docsearch/js @docsearch/css
import docsearch from "@docsearch/js/docsearch"; import "@docsearch/css"; docsearch({ container: "#docsearch", appId: "YOUR_APP_ID", apiKey: "YOUR_SEARCH_API_KEY", indices: ["example"], });
The @docsearch/js/docsearch entry is keyword search only. Use your Algolia Search API key here, never the key from the plugin options. On a multi-language site, pick the index of the current language, e.g. from the lang attribute of your <html> element:
indices: [`example-${document.documentElement.lang}`],
See the DocSearch documentation for the CDN build and styling.
Options
All options are namespaced under johannschopplich.algolia-docsearch:
| Option | Default | Description |
|---|---|---|
appId |
β | Algolia application ID. Required. |
apiKey |
β | Algolia API key with write access, such as the Admin API key. It stays on the server. Required. |
index |
β | Index name. Multi-language sites get one index per language, suffixed with the language code. Required. |
templates |
[] |
Templates to index. Pages of other templates are left out, so nothing is indexed until you set this. |
filter |
listed pages | Closure fn (Page $page): bool that decides which pages of those templates get indexed. Drafts never are. |
exclude.pages |
[] |
Page IDs to leave out, as case-insensitive regular expressions matched against the whole ID, e.g. blog/.*. |
content |
body |
HTML tag whose text becomes the record's content, a closure fn (Page $page, string|null $languageCode): string, or an array of closures per template with a default key. |
label.default |
β | Hit label (DocSearch's lvl0) as a string or an array per language code. Required unless label.templates covers every template. |
label.templates |
[] |
Labels per template, in the same shapes as label.default. |
attributes |
[] |
Extra record fields as closures fn (Page $page, string|null $languageCode), keyed by field name. |
searchableAttributes |
[] |
Attributes appended to DocSearch's searchable attributes. |
indexSettings |
[] |
Algolia index settings. Each key replaces the plugin's value for that setting, including what searchableAttributes and attributes add to it. |
hooks |
false |
Update the index on page changes in the Panel. See Page Hooks. |
Example config.php:
return [ 'johannschopplich.algolia-docsearch' => [ 'appId' => 'ALGOLIA_APP_ID', 'apiKey' => 'ALGOLIA_ADMIN_API_KEY', 'index' => 'example', 'templates' => ['default', 'article', 'project'], 'filter' => fn (\Kirby\Cms\Page $page) => $page->isListed() || $page->isUnlisted(), 'exclude' => [ 'pages' => ['blog/drafts-.*'] ], 'content' => 'main', 'label' => [ 'default' => 'Page', 'templates' => [ 'article' => 'Article', 'project' => 'Project' ] ], 'indexSettings' => [ 'ranking' => ['words', 'typo', 'attribute', 'proximity', 'exact', 'custom'] ], 'hooks' => true ] ];
Limits
- One record per page. Algolia's free plan rejects records larger than 10 KB. For long pages, shorten the text a
contentclosure returns, e.g. withStr::short($text, 5000). - Custom attributes need a request. DocSearch asks for its own list of attributes with every search. To receive the fields from
attributesin your hits, list them insearchParameters.attributesToRetrieveof the index entry inindices, together with DocSearch's own:hierarchy.lvl0tohierarchy.lvl6,content,type, andurl.
Credits
- Wolf-Dieter Grabner for sponsoring the initial version of this plugin.
- Lukas Bestle and Nico Hoffmann for the Algolia integration of getkirby.com.
License
MIT License Β© 2023-PRESENT Johann Schopplich