pollora / meilifacets
Faceted search, filtering and suggestions powered by Meilisearch for Pollora projects.
Requires
- php: ^8.4
- amphibee/meiliscout: dev-feat/meilifacets
- composer/installers: ^2.0
- illuminate/console: ^13.0
- illuminate/contracts: ^13.0
- illuminate/support: ^13.0
- illuminate/view: ^13.0
- league/uri: ^7.5
Requires (Dev)
- ext-dom: *
- driftingly/rector-laravel: ^2.6
- laravel/pint: ^1.30
- phpunit/phpunit: ^12.5
- rector/rector: ^2.6
Suggests
- ext-intl: Orders facet values as the site language does; without it, NameOrder falls back to a byte comparison that misplaces accented labels.
Provides
None
Conflicts
- pollora/framework: <13.4 || >=14.0
Replaces
None
This package is auto-updated.
Last update: 2026-10-02 16:07:56 UTC
README
Faceted product listings and a site-wide search panel for Pollora projects, served by Meilisearch straight from the visitor's browser.
You want to…
- know what the module does;
- understand how a page is served;
- know what you get without writing PHP;
- check that it fits your stack;
- know the rules the module is built on;
- find the right page;
- work on the module itself.
<x-meilifacets::listing> <x-meilifacets::listing.active-values /> <x-meilifacets::listing.sort /> <x-meilifacets::listing.reset /> <x-meilifacets::listing.facets /> <x-meilifacets::listing.results /> <x-meilifacets::listing.pagination /> </x-meilifacets::listing>
<header class="site-header"> {{-- logo, menu… --}} <x-meilifacets::search /> </header>
What it is
Two features, both served by Meilisearch:
- Listing filters. Facets by taxonomy or product attribute, a price range, sorting, pagination, active filters, a search field that narrows the list, and a mobile drawer.
- Site search. A magnifier in the header opens a panel with one section per content type: products, posts, pages and any indexed custom post type, with a result count and a link to the full results.
What it does not do: it does not index anything itself, and it does not replace WordPress's routing or templates. MeiliScout, a WordPress plugin, builds and pushes the documents.
How it works
first render browser ──► WordPress / Pollora ──► Meilisearch filters of the URL applied by PHP
every later gesture browser ─────────────────────────► Meilisearch one request, no WordPress in the loop
indexing WordPress ──► MeiliScout ────────► Meilisearch MeiliFacets adds its fields to each document
- The server renders the first page with the filters of the URL already applied. The page is complete without JavaScript, and search engines see real content.
- After that, every tick, sort, page or search term is a single request from the browser to Meilisearch. The client rewrites the address bar, so a filtered view can be bookmarked and shared.
- The engine computes the results and the facet counts in a few milliseconds. A full WordPress page load is avoided on every click, while WordPress keeps the URLs, the routing and the SEO.
- MeiliScout indexes, MeiliFacets queries. The module adds its own fields (
facets,card,price…) to the documents MeiliScout builds, and declares the index settings it needs.
What you get without writing PHP
On a WooCommerce project, with MeiliScout indexing products:
- a product listing named
products, filtered by category and brand; - sorting by relevance, price low to high, price high to low and newest; « On sale » is added when you declare a price filter;
- cards with the image, title, link and the price as the shop displays it, taxes included or not;
- a site search over every public post type MeiliScout indexes, products first.
Everything else (other facets, the price filter, your own card, other sorts) is a configuration key, a view override or a container binding. See Quick start.
Requirements
| PHP | 8.4 or later |
| Framework | Pollora 13.4 or later, on Laravel 13. Laravel modules (nwidart/laravel-modules) ship with Pollora |
| Indexing | MeiliScout (amphibee/meiliscout), a WordPress plugin, currently its dev-feat/meilifacets branch |
| Engine | a Meilisearch server |
| Products | WooCommerce, for the product listing and its prices. The site search works without it |
| Optional | ext-intl, so that facet values ordered by name follow the site's language |
The details, and the step-by-step setup, are in Installation.
Design principles
- The URL is the state. WordPress's own paths are kept, filters travel as query parameters, and the server applies them on first render.
- Behaviour in the module, appearance in the theme. Every view can be overridden from the theme. The stylesheets are neutral and tuned with CSS custom properties.
- Hooks, not classes. The browser client binds to
data-meiliattributes, never to a class name. A theme changes tags and classes freely as long as it keeps the hooks. - Every shop-specific choice is a contract with a default. Facets, sorts, the card, the searched fields and the searched types each sit behind a PHP interface. A project with nothing to declare gets a working listing; a project that binds its own implementation wins.
- The browser key is public, so the index exposes little. The search key travels to every visitor. The index
only lets it read
IDandcard, and it must only hold published content. See Going to production.
Documentation
Reading this documentation
- Commands are written without a container runner:
php artisan …,wp meiliscout index,composer …. Prefix them with yours when PHP runs in a container (ddev exec php artisan …,ddev wp …,docker compose exec …). <theme>stands for the active theme's folder. A view override lives under<theme>/resources/views/modules/meilifacets/….- Component tags are written with their full prefix:
<x-meilifacets::listing.facet>.
Map
| Section | Pages |
|---|---|
| Getting started | Installation · Going to production · Quick start |
| Listing and filters | How a listing works · Facets · Price filter · Results, sorting and pagination · Mobile drawer and filter bar · Listing other content |
| Site search | Site search · Composing the search panel · Searchable content types |
| Relevance and indexing | What gets indexed · Search relevance · Indexed prices (WooCommerce) |
| Customising | Overriding views · Your own card · Styles and design tokens · PHP extension points · Translating the interface |
| Accessibility | Accessibility and motion |
| Reference | Overview · Blade components · data-meili hooks · CSS custom properties · Configuration and environment · PHP contracts · WordPress filters and actions · Index settings and document fields · Errors and console messages · Commands |
| When something goes wrong | Troubleshooting and FAQ |
| Releases | Changelog · Upgrading |
The maintainers' design notes, in French, are in docs/internal/: decisions, measurements and known
traps gathered while building the module. They are not needed to use it.
Development
Run these from a clone of the module's repository, not from a copy installed in a project. The repository keeps its
own node_modules, which only serves the system that installed it. Node 24.12 or later is required.
npm install composer install composer check # Pint, ESLint, tsc, Rector, standalone PHP tests, client tests, bundle up to date composer test # standalone PHP tests only (Unit suite) npm test # client tests only composer build # rebuild resources/assets/dist after changing the client
The Feature tests render Blade views and need a host application. Run them from a Pollora project where the module
is installed, with a PHPUnit suite that includes Modules/MeiliFacets/tests/Feature.
Commits follow Conventional Commits. Before opening a pull request,
composer check and the Feature tests should both pass. The current release is 0.1.0, a beta: see the
changelog.
License
GPL-2.0-or-later.