reachweb/statamic-livewire-filters
Add reactive, Livewire-powered filtering to your Statamic site. Build faceted search and filter interfaces that update instantly without full page reloads, backed by a simple, developer-friendly API. Ideal for collections, entries, and product listings.
Upgrade to 4.6.0, then immediately run:
composer update reachweb/statamic-livewire-filters
php artisan config:clear # or config:cache
php please static:clear # if you use static caching
Skipping those two clears is the single most common failure mode after this release: a cached config leaves blocked_query_params unset, and stale static pages may drop tag control params like limit or site on the first filter change.
Start by opening config/livewire-filters.php and reading the new blocked_query_params blocklist. It ships populated with Statamic query-control keys (status, from, site, limit, paginate, since, until, filter, and more), so the default behaviour is secure with no configuration. Confirm your app still filters the way you expect before touching it.
Your first real use case is the standard one: a {{ livewire-collection }} tag on a listing page, with search and facet filters, where filter state round-trips through the URL. Verify that:
?status=published (or similar) does not change which entries are returned.from, view, paginate, allowed_filters) are ignored when supplied via the URL.Read the security section of the docs (.../usage/livewire-collection-tag#securing-parameters) first — it explains the tag-parameter vs URL-state vs init-hook precedence that determines what survives hardening.
Three sources of filter state, with different trust levels. State set on the {{ livewire-collection }} tag or by an init hook is always kept. Client-supplied state (URL, Livewire payload) is stripped if it matches blocked_query_params. Keep trusted, app-controlled defaults on the tag; let visitors only influence keys you've deliberately exposed.
Re-opening specific control keys. If you intentionally let visitors change limit, site, or a field literally named status, add those keys to allowed_filters alongside your filter keys:
{{ livewire-collection allowed_filters="limit|site|status:is" }}
Blocklist matching is on the segment before the first colon, so blocking status also blocks status:is. Use allowed_filters to punch a targeted hole rather than editing the blocklist.
Dynamic range bounds (opt-in). Set enable_dynamic_range_bounds to true and range/dual-range sliders narrow to values that still match the other active filters. Visitor selections are never moved, and a slider with no room left is disabled. If you've published lf-range.blade.php or lf-dual-range.blade.php, merge in the range-bounds-updated listener or re-publish the views; custom views can listen for that event directly.
Custom filter components. "Clear all" now clears parameters from custom components only if they listen for clear-all-filters. Add the listener if your component owns controls that should reset. Also check whether removing a tag for a parameter with no matching filter component on the page is expected to work — it does now.
Reacting to updates. params-updated carries the hardened parameters plus a second argument (the encrypted bounds query). One-argument listeners continue to work, so existing listeners don't need changes, but new listeners should accept both. Note that an event which changes nothing no longer triggers a re-render — if you were dispatching filter-updated purely to force a refresh, call Livewire's $refresh on the collection component instead.
Subclassing. setParameters() is now protected, so don't call it from the client or from outside the component. If you override filterUpdated(), clearFilter(), or clearFilters(), add the new optional $boundsSelection = null parameter to keep signatures compatible.
Faceted counts. Counts now use exactly the same filtered state as the entries query, so facet numbers and result sets agree. The count listener is a no-op when enable_filter_values_count is off — don't rely on it firing in that configuration.
blocked_query_params isn't present in your cached config, nothing is blocked and no error is raised. Always run config:clear/config:cache as part of deploy.php please static:clear after upgrading and after any deploy that includes this version.status:is will be blocked by default. Either remove status from blocked_query_params or allow it via allowed_filters — prefer the narrower allowed_filters entry.limit/site breaks quietly. If visitors were previously able to change these through the URL, they'll stop working until you add them to allowed_filters.preset_value are now restored correctly from the URL — if you had a workaround for the old behaviour, remove it.allowed_filters is now evaluated per active query scope, so two active scope filters no longer cancel each other out. If you'd worked around that bug with a combined key, simplify it.params-updated payload to see exactly which keys survived. If a key you expect is missing, check the blocklist segment (before the colon) against your key.init hooks (trusted state), allowed_filters (per-key exceptions), blocked_query_params (global blocklist), published lf-range/lf-dual-range views (range-bounds-updated), params-updated (two args), and clear-all-filters (custom component reset). These cover most customization without touching package internals.How can I help you explore Laravel packages today?