PHPackages                             wezlo/filament-lookups - 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. [Utility &amp; Helpers](/categories/utility)
4. /
5. wezlo/filament-lookups

ActiveLibrary[Utility &amp; Helpers](/categories/utility)

wezlo/filament-lookups
======================

Hierarchical Lookup Management for Filament with multi-tenant support

1.0.3(1mo ago)185—0%1[1 issues](https://github.com/mustafakhaleddev/filament-lookups/issues)MITPHPPHP ^8.2

Since Apr 13Pushed 1mo agoCompare

[ Source](https://github.com/mustafakhaleddev/filament-lookups)[ Packagist](https://packagist.org/packages/wezlo/filament-lookups)[ RSS](/packages/wezlo-filament-lookups/feed)WikiDiscussions master Synced 1w ago

READMEChangelog (4)Dependencies (5)Versions (5)Used By (0)

Filament Lookups
================

[](#filament-lookups)

Hierarchical lookup management for Filament with configurable multi-tenant support.

Manage lookup tables (countries, categories, regions, statuses, etc.) with optional parent-child hierarchies. Each lookup type is defined as a PHP class with full control over permissions and behavior.

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

[](#installation)

```
composer require wezlo/filament-lookups
```

Run migrations:

```
php artisan migrate
```

Register the plugin in your panel provider:

```
use Wezlo\FilamentLookups\FilamentLookupsPlugin;

$panel
    ->plugin(FilamentLookupsPlugin::make()
        ->navigationGroup('Settings'));
```

Defining Lookup Types
---------------------

[](#defining-lookup-types)

Each lookup type is a PHP class that extends `Lookup`. Create them with the artisan command and sync to the database.

### 1. Create a Lookup class

[](#1-create-a-lookup-class)

```
php artisan make:lookup Countries
php artisan make:lookup ProductCategories
```

This creates a class in `app/Lookups/`:

```
namespace App\Lookups;

use Illuminate\Database\Eloquent\Model;
use Wezlo\FilamentLookups\Lookup;

class Countries extends Lookup
{
    public function name(): string
    {
        return 'Countries';
    }

    public function description(): ?string
    {
        return 'List of supported countries';
    }

    public function isHierarchical(): bool
    {
        return false;
    }

    public function canAdd(): bool
    {
        return true;
    }

    public function canEdit(?Model $record = null): bool
    {
        return true;
    }

    public function canDelete(?Model $record = null): bool
    {
        return false; // protect country values from deletion
    }
}
```

### 2. Sync to database

[](#2-sync-to-database)

```
php artisan lookups:sync
```

This command will:

- **Create** types for new Lookup classes
- **Update** existing types with any class changes
- **Deactivate** types whose class was removed

Run this during deployment or in your CI pipeline.

### 3. Manage values in the panel

[](#3-manage-values-in-the-panel)

The plugin registers a **Lookups** page with a sidebar listing all synced types. Click a type to view and manage its values. The create/edit/delete actions respect the permissions defined in your Lookup class.

Available Lookup Methods
------------------------

[](#available-lookup-methods)

MethodDefaultDescription`name()`Class name as headlineDisplay name`slug()`Slugified nameURL-safe identifier`description()``null`Optional description shown as subheading`isHierarchical()``false`Enable parent-child values`tenancyMode()``'shared'``'shared'`, `'tenant'`, or `'both'``sortOrder()``0`Navigation sort order`canAdd()``true`Show/hide create button`canEdit(?Model $record = null)``true`Show/hide edit action per record`canDelete(?Model $record = null)``true`Show/hide delete action per record`canView(?Model $record = null)``true`Show/hide lookup type visibility`canReorder()``true`Enable drag-to-reorderPer-Record Permissions
----------------------

[](#per-record-permissions)

The `canEdit()`, `canDelete()`, and `canView()` methods receive the current record, allowing conditional logic per row:

```
use Illuminate\Database\Eloquent\Model;
use Wezlo\FilamentLookups\Lookup;

class OrderStatus extends Lookup
{
    public function canEdit(?Model $record = null): bool
    {
        // prevent editing system-defined statuses
        return ! $record?->metadata['is_system'];
    }

    public function canDelete(?Model $record = null): bool
    {
        // only allow deleting statuses that are not in use
        return $record?->orders()->doesntExist() ?? true;
    }
}
```

When called without a record (e.g. for navigation visibility), `$record` is `null` — the default `true` applies.

Using `LookupSelect` in Forms
-----------------------------

[](#using-lookupselect-in-forms)

```
use Wezlo\FilamentLookups\Forms\Components\LookupSelect;

LookupSelect::make('country_id')
    ->lookupType('countries')
```

### Hierarchical display

[](#hierarchical-display)

```
LookupSelect::make('category_id')
    ->lookupType('product-categories')
    ->hierarchical()
```

### Dependent / cascading selects

[](#dependent--cascading-selects)

```
LookupSelect::make('region_id')
    ->lookupType('regions')
    ->live(),

LookupSelect::make('city_id')
    ->lookupType('regions')
    ->dependsOn('region_id'),
```

Using `LookupService` Programmatically
--------------------------------------

[](#using-lookupservice-programmatically)

```
use Wezlo\FilamentLookups\Services\LookupService;

$service = app(LookupService::class);

$values = $service->getValuesForType('countries');
$roots = $service->getRootValues('product-categories');
$children = $service->getChildValues($parentId);
$options = $service->getOptionsForSelect('countries');
```

Multi-Tenancy
-------------

[](#multi-tenancy)

Enable tenancy in config:

```
'tenancy' => [
    'enabled' => true,
    'tenant_model' => \App\Models\Company::class,
    'tenant_id_column' => 'tenant_id',
],
```

Set the tenancy mode per Lookup class:

```
public function tenancyMode(): string
{
    return 'both'; // 'shared', 'tenant', or 'both'
}
```

ModeBehavior**shared**Visible to all tenants**tenant**Only visible to the owning tenant**both**System defaults + tenant-specific values merged### `HasLookups` Trait

[](#haslookups-trait)

```
use Wezlo\FilamentLookups\Concerns\HasLookups;

class Company extends Model
{
    use HasLookups;
}

$company->getLookupValues('countries');
```

Configuration
-------------

[](#configuration)

```
php artisan vendor:publish --tag="filament-lookups-config"
```

OptionDescriptionDefault`lookups_path`Directory containing Lookup classes`app_path('Lookups')``lookups_namespace`PSR-4 namespace for Lookup classes`App\Lookups``tables.lookup_types`Types table name`lookup_types``tables.lookup_values`Values table name`lookup_values``tenancy.enabled`Enable multi-tenancy`false``tenancy.tenant_model`Tenant model class`null``tenancy.tenant_id_column`Tenant foreign key`tenant_id``navigation_group`Panel navigation group`Settings``register_resource`Register the Filament page`true`Plugin Configuration
--------------------

[](#plugin-configuration)

```
FilamentLookupsPlugin::make()
    ->navigationGroup('Admin')
    ->navigationIcon('heroicon-o-rectangle-stack')
    ->navigationSort(10)
    ->tenancy()
    ->tenantModel(\App\Models\Company::class)
```

License
-------

[](#license)

MIT

###  Health Score

38

—

LowBetter than 83% of packages

Maintenance69

Regular maintenance activity

Popularity15

Limited adoption so far

Community7

Small or concentrated contributor base

Maturity49

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

Every ~1 days

Total

4

Last Release

54d ago

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/25182746?v=4)[Mustafa Khaled](/maintainers/mustafakhaleddev)[@mustafakhaleddev](https://github.com/mustafakhaleddev)

---

Top Contributors

[![mustafakhaleddev](https://avatars.githubusercontent.com/u/25182746?v=4)](https://github.com/mustafakhaleddev "mustafakhaleddev (11 commits)")

---

Tags

laravelcategoriesmulti-tenantfilamenthierarchicallookups

###  Code Quality

TestsPest

### Embed Badge

![Health badge](/badges/wezlo-filament-lookups/health.svg)

```
[![Health](https://phpackages.com/badges/wezlo-filament-lookups/health.svg)](https://phpackages.com/packages/wezlo-filament-lookups)
```

###  Alternatives

[ysfkaya/filament-phone-input

A phone input component for Laravel Filament

3131.2M25](/packages/ysfkaya-filament-phone-input)[rawilk/profile-filament-plugin

Profile &amp; MFA starter kit for filament.

3913.7k](/packages/rawilk-profile-filament-plugin)[dotswan/filament-map-picker

Easily pick and retrieve geo-coordinates using a map-based interface in your Filament applications.

127173.7k3](/packages/dotswan-filament-map-picker)[stephenjude/filament-feature-flags

Filament implementation of feature flags and segmentation with Laravel Pennant.

122157.7k1](/packages/stephenjude-filament-feature-flags)[creagia/filament-code-field

A Filamentphp input field to edit or view code data.

57301.3k3](/packages/creagia-filament-code-field)[jibaymcs/filament-tour

Bring the power of DriverJs to your Filament panels and start a tour !

12351.0k](/packages/jibaymcs-filament-tour)

PHPackages © 2026

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