Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Statamic Livewire Filters Laravel Package

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.

View on GitHub
Deep Wiki
Context7

Getting Started

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:

  1. Filtering works normally from the UI.
  2. A crafted URL with ?status=published (or similar) does not change which entries are returned.
  3. Tag-level parameters (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.

Implementation Patterns

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.

Gotchas and Tips

  • Cached config silently disables the whole fix. If 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.
  • Static caching regression from 4.5.1. Pages cached under the previous version can drop tag control params on the first filter change. Run php please static:clear after upgrading and after any deploy that includes this version.
  • Legitimate fields named like control keys. A filter targeting 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.
  • URL-driven 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.
  • Colon-prefixed state keys are rejected outright, since Statamic evaluates those as Antlers expressions. Don't construct filter state keys dynamically from user input.
  • Toggle filters with numeric or boolean preset_value are now restored correctly from the URL — if you had a workaround for the old behaviour, remove it.
  • Range slider reset now clears the filter when moved back to default. Previously it could leave a stale applied state; verify any custom reset logic you layered on top.
  • 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.
  • Debugging hardening: log or dump the 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.
  • Removing a filter is now one round trip, and "Clear all" likewise. If you have JS relying on two render cycles or on an interstitial state, re-test — you may now be observing the final state earlier than before.
  • Extension points to keep in mind: 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.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
jinas/dhivatar
store-doc/laravel-storage-driver
plus-it/laravel-translation-manager
diephp/perhaps
diephp/telegraph
osmaviation/spreadsheet
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console
pnscripts/filament-broadquill-lite
pnscripts/laravel-sentfold-lite
vleap/mx-sdk-laravel-internal
twidpay/utils
htetmyathlaing/scout-elasticsearch-driver
artisan-toolbox/front-awesome
ls/client-assistant
users-au/laravel-client
cgv/localized-resource