PHPackages                             degecko/laravel-nova-multifilter - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Admin Panels](/categories/admin)
4. /
5. degecko/laravel-nova-multifilter

ActiveLibrary[Admin Panels](/categories/admin)

degecko/laravel-nova-multifilter
================================

Combine multiple filter columns into a single Nova filter panel

v1.0.0(1mo ago)014MITPHPPHP ^8.2

Since Apr 13Pushed 1mo agoCompare

[ Source](https://github.com/degecko/laravel-nova-multifilter)[ Packagist](https://packagist.org/packages/degecko/laravel-nova-multifilter)[ RSS](/packages/degecko-laravel-nova-multifilter/feed)WikiDiscussions main Synced 1w ago

READMEChangelogDependencies (3)Versions (2)Used By (0)

Laravel Nova MultiFilter
========================

[](#laravel-nova-multifilter)

Combine multiple filter columns into a single Nova filter panel. Supports select dropdowns, text search, date ranges, number ranges, bitwise flags, and custom filter handlers.

Installation
------------

[](#installation)

```
composer require degecko/laravel-nova-multifilter
```

The service provider and assets are registered automatically via Laravel's package discovery.

### Building Assets

[](#building-assets)

```
npm install
npm run prod
```

During development:

```
npm run watch
```

Usage
-----

[](#usage)

In your Nova resource's `filters()` method:

```
use DeGecko\NovaMultiFilter\MultiFilter;

public function filters(NovaRequest $request): array
{
    return [
        new MultiFilter('Search', [
            'name' => '%w%',                    // LIKE search (word-boundary aware)
            'email' => '%#%',                    // LIKE search (contains)
            'status' => ['active', 'inactive'],  // Select dropdown
            'created_at' => ['from' => null, 'to' => null], // Date range
        ]),
    ];
}
```

Column Types
------------

[](#column-types)

### Select Dropdown

[](#select-dropdown)

Pass an array of options. Use a flat array for value-only options, or an associative array for value =&gt; label pairs:

```
// Flat array — values are used as both the option value and label
'status' => ['active', 'inactive', 'banned'],

// Associative — keys are stored, values are displayed
'role' => ['admin' => 'Administrator', 'editor' => 'Editor', 'user' => 'User'],
```

### Text Search (LIKE)

[](#text-search-like)

Use a string pattern where `#` is replaced with the user's input:

```
'name' => '%w%',    // Word-boundary search (splits on non-alphanumeric)
'email' => '%#%',   // Simple contains
'phone' => '#%',    // Starts with
```

The `%w%` pattern is special: it splits the input on non-alphanumeric characters and wraps each part with `%`, giving word-boundary-aware matching. For example, searching "John Doe" becomes `%John%Doe%`.

### Date Range

[](#date-range)

Pass `from`/`to` keys to render two date pickers. Either bound is optional — leaving one empty creates an open-ended range:

```
'created_at' => ['from' => null, 'to' => null],
'updated_at' => ['from' => null, 'to' => null],
```

### Number Range

[](#number-range)

Add `'type' => 'range'` to render number inputs instead of date pickers:

```
'age' => ['from' => null, 'to' => null, 'type' => 'range'],
'price' => ['from' => null, 'to' => null, 'type' => 'range'],
```

### Bitwise Flags

[](#bitwise-flags)

For integer columns storing bitwise flags. Labels are auto-formatted from the keys:

```
'permissions' => ['bitwise', [
    'can_edit' => 1,
    'can_delete' => 2,
    'can_publish' => 4,
]],
```

### Column Aliases

[](#column-aliases)

Prefix a column with a different display name using `as`:

```
'email as E-mail' => '%#%',
'created_at as Registered' => ['from' => null, 'to' => null],
```

The part before `as` is used for the query; the part after is displayed as the label.

Composing with Nova Filters
---------------------------

[](#composing-with-nova-filters)

You can pass existing Nova filter instances directly as columns. Their options will be extracted and their `apply()` method will be called when the value changes:

```
use App\Nova\Filters\StatusFilter;
use App\Nova\Filters\CategoryFilter;

new MultiFilter('Filters', [
    'status' => new StatusFilter,
    'category' => new CategoryFilter,
    'name' => '%w%',
]),
```

Custom Handlers
---------------

[](#custom-handlers)

Register custom handler callbacks for columns that need special query logic:

```
(new MultiFilter('Search', [
    'name' => '%w%',
    'active' => ['Yes', 'No'],
]))->handlers([
    'active' => fn($value, $query) => $query->where('is_active', $value === 'Yes'),
]),
```

Defaults
--------

[](#defaults)

Set default filter values that are applied on page load:

```
(new MultiFilter('Filters', [
    'status' => ['active', 'inactive', 'banned'],
    'role' => ['admin', 'editor', 'user'],
]))->defaults([
    'status' => 'active',
]),
```

Query Tap
---------

[](#query-tap)

Apply a scope or constraint to all filtered queries via the `tap` parameter:

```
// Scope to current tenant
new MultiFilter('Search', $columns, tap: fn($q) => $q->where('tenant_id', auth()->user()->tenant_id)),

// Include soft-deleted records
new MultiFilter('Search', $columns, tap: fn($q) => $q->withTrashed()),
```

Debugging
---------

[](#debugging)

Chain `->log()` to output the raw SQL query to the Laravel log after filters are applied:

```
(new MultiFilter('Search', $columns))->log(),
```

Full Example
------------

[](#full-example)

```
use DeGecko\NovaMultiFilter\MultiFilter;
use App\Nova\Filters\StatusFilter;

public function filters(NovaRequest $request): array
{
    return [
        (new MultiFilter('User Search', [
            'name' => '%w%',
            'email as E-mail' => '%#%',
            'phone' => '#%',
            'status' => new StatusFilter,
            'role' => ['admin' => 'Admin', 'editor' => 'Editor', 'user' => 'User'],
            'created_at as Registered' => ['from' => null, 'to' => null],
            'age' => ['from' => null, 'to' => null, 'type' => 'range'],
            'permissions' => ['bitwise', ['can_edit' => 1, 'can_delete' => 2, 'can_publish' => 4]],
        ], tap: fn($q) => $q->where('tenant_id', auth()->user()->tenant_id)))
        ->defaults(['role' => 'user'])
        ->handlers([
            'custom' => fn($value, $query) => $query->whereHas('profile', fn($q) => $q->where('bio', 'like', "%$value%")),
        ])
        ->log(),
    ];
}
```

How It Works
------------

[](#how-it-works)

The MultiFilter renders all columns in a single horizontal filter panel. Each column type (select, text, date range, bitwise) gets the appropriate input widget. Changes are debounced (100ms) and applied as a combined filter value.

On the backend, each column's value is applied to the query based on its type:

- **Arrays** - `where($column, $value)` or date range with `whereDate`
- **Strings** - `where($column, 'like', $pattern)`
- **Bitwise** - `whereRaw("$column & ?", [$value])`
- **Handlers** - delegated to the callback or Nova filter's `apply()` method

License
-------

[](#license)

MIT

###  Health Score

39

—

LowBetter than 84% of packages

Maintenance89

Actively maintained with recent releases

Popularity8

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity46

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Unknown

Total

1

Last Release

57d ago

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/5130992?v=4)[Cosmin Gheorghita](/maintainers/degecko)[@degecko](https://github.com/degecko)

---

Top Contributors

[![degecko](https://avatars.githubusercontent.com/u/5130992?v=4)](https://github.com/degecko "degecko (1 commits)")

---

Tags

filterlaravellaravel-novamulti-filternovanova-5phplaravelfilteradminnovamulti-filter

###  Code Quality

TestsPHPUnit

### Embed Badge

![Health badge](/badges/degecko-laravel-nova-multifilter/health.svg)

```
[![Health](https://phpackages.com/badges/degecko-laravel-nova-multifilter/health.svg)](https://phpackages.com/packages/degecko-laravel-nova-multifilter)
```

###  Alternatives

[whitecube/nova-page

Static pages content management for Laravel Nova

23996.4k1](/packages/whitecube-nova-page)[markwalet/nova-modal-response

A Laravel Nova asset for Modal responses on an action.

17818.7k](/packages/markwalet-nova-modal-response)[khalin/nova-link-field

A Laravel Nova Link field.

31576.5k2](/packages/khalin-nova-link-field)[digital-creative/nova-dashboard

The missing dashboard for nova.

7170.9k1](/packages/digital-creative-nova-dashboard)[marianvlad/nova-ssl-card

A Laravel Nova card for SSL certificates.

1219.9k](/packages/marianvlad-nova-ssl-card)[sparclex/nova-creatable-belongs-to

BelongsTo field for laravel nova which allows to choose or create a resource

141.9k](/packages/sparclex-nova-creatable-belongs-to)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
