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

Nova Searchable Filter Laravel Package

sereny/nova-searchable-filter

A Laravel Nova filter package that adds searchable select filters to your admin panels, letting you narrow resources by related records through a searchable dropdown instead of long, unwieldy option lists.

View on GitHub
Deep Wiki
Context7

Getting Started

This is a small, single-purpose Nova utility: a belongsTo filter that searches related records asynchronously instead of loading every option into a select. With 4 stars, zero dependents, and a last release in August 2023, treat it as a convenience package rather than foundation code. Verify Nova compatibility before adopting it—it was released in the Nova 4 era and may need patching for Nova 5.

Minimal adoption path:

  1. Install and pin the version:
    composer require sereny/nova-searchable-filter
    
  2. Confirm the service provider is auto-discovered and inspect the actual package surface before writing code:
    • vendor/sereny/nova-searchable-filter/README.md
    • vendor/sereny/nova-searchable-filter/src/
    • the package’s Vue component/dist assets
    • the base filter class and its expected properties or methods
  3. Generate a normal Nova filter and switch its parent class:
    php artisan nova:filter UserFilter
    
  4. Point the filter at the relationship and implement apply():
    use Illuminate\Http\Request;
    use Sereny\NovaSearchableFilter\Filters\SearchableFilter;
    
    class UserFilter extends SearchableFilter
    {
        public $name = 'User';
    
        // Confirm exact property/method names in the package base class.
        public $relationship = 'user';
        public $searchColumns = ['name', 'email'];
    
        public function apply(Request $request, $query, $value)
        {
            return $query->where('user_id', $value);
        }
    }
    
  5. Register it on the resource:
    public function filters(Request $request)
    {
        return [
            new UserFilter,
        ];
    }
    

The first real use case is an Order resource with a user_id foreign key and tens of thousands of users. A standard Nova select filter becomes unusable; this package replaces it with a search box that queries only matching users. Test that workflow immediately: open the resource index, type into the filter, watch the network request, select a result, and confirm the index query is constrained correctly.

Implementation Patterns

One filter per relationship, with an explicit apply(). Even if the package can infer the foreign key, keep apply() explicit. It makes the filter readable and protects you if the package’s internals change:

public function apply(Request $request, $query, $value)
{
    return $query->where('user_id', $value);
}

Reusable base filter for repeated belongsTo filters. If several resources filter by the same kind of relationship, create an internal abstract filter:

abstract class BelongsToSearchFilter extends SearchableFilter
{
    abstract protected function foreignKey(): string;

    public function apply(Request $request, $query, $value)
    {
        return $query->where($this->foreignKey(), $value);
    }
}

Then each concrete filter only defines its relationship, search columns, and foreign key.

Scope searchable options to the current user or tenant. A searchable endpoint can easily leak related record names. If the package exposes an options/search query extension point, override it and apply the same authorization scope used elsewhere:

protected function searchQuery(Request $request)
{
    return User::query()
        ->where('tenant_id', $request->user()->tenant_id)
        ->select(['id', 'name'])
        ->orderBy('name');
}

Check the base class for the exact method name (options(), searchQuery(), or similar). If no hook exists, override the component’s data endpoint or wrap the relationship with a global scope.

Keep labels meaningful. Search on name, email, or a username, but display something a human recognizes. If users can have duplicate names, include a secondary identifier in the label, such as Jane Doe ([email protected]).

Handle nullable filters deliberately. A clearable filter should send null or an empty value. In apply(), decide whether an empty value means “no constraint”:

public function apply(Request $request, $query, $value)
{
    return $value ? $query->where('user_id', $value) : $query;
}

Combine with other filters without alias collisions. If two filters constrain the same relationship, use distinct column aliases or explicit where clauses so Nova’s filter serialization does not overwrite one with the other.

Test the filter logic outside Vue. Add a feature test that invokes apply() with a request and value, then asserts the generated SQL constraints. The searchable dropdown itself is UI; the important behavior is the query it produces.

Gotchas and Tips

  • Maintenance risk is the main gotcha. Four stars, zero dependents, and no release since August 2023 means there is little community pressure to fix Nova 5 or Laravel 11 issues. Pin the version and budget time to fork or patch if you rely on it.
  • Verify the base class contract first. Small packages often expose properties in one release and methods in another. Read vendor/sereny/nova-searchable-filter/src before copying code from a blog post or the README.
  • Asset caching causes “nothing happens” bugs. If the filter renders as a plain select or the search box never queries, check that the package’s compiled assets are published/loaded, then clear Nova and browser caches. Run php artisan route:list --path=nova-api to confirm any package endpoints are registered.
  • Search is usually LIKE '%term%'. That does not use a normal B-tree index well. For large related tables, index the search columns, cap results, require a minimum query length, or move to a dedicated search index. Watch slow-query logs in production.
  • Authorization must be enforced server-side. The search endpoint returns labels and IDs. Do not rely on the fact that a user cannot see a record in Nova; scope the options query by tenant and policy.
  • Soft-deleted related records break labels. If a filter value points to a soft-deleted user, the options query may not return it, and the filter may display a raw ID or blank label. Include the currently selected record in the result set with withTrashed() or a separate “selected value” lookup.
  • The selected option may not be in the first result page. A good searchable filter must resolve the currently selected ID separately from the search results. If this package does not, expect the filter label to fall back to an ID after a page reload.
  • Filter values arrive as strings. Comparing a string "10" against an integer column can behave differently on PostgreSQL than MySQL. Cast explicitly in apply() if needed.
  • Stale filter state persists in URLs and localStorage. Nova remembers filters. After deleting a related record, users may see an old filter value. Provide a clear button and test the “cleared” state.
  • Debug through the network tab first. If search returns nothing, inspect the request URL, query string, response JSON, and the generated SQL. Add temporary DB::listen() logging around the filter endpoint rather than guessing at the Vue component.
  • Extend, don’t edit vendor code. Override the search query or apply() in your filter, or publish the Vue component if the package supports it. Direct edits to vendor/ disappear on the next composer install.
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.
shitoudev/permissionmanager
johannesclimacus/laravel-tui
hocvt/seotools
vitalybaev/sypexgeo
amphibee/themosis-ignition
gito-me/fast-excel
frankyso/laravel-ipaymu
geolize-studio/laravel-chile
boomerangui/chat
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