Skip to content

webkernelphp/component-modules-essentials

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

7 Commits
 
 
 
 
 
 
 
 

Repository files navigation

Webkernel Plugin Component

A collection of essential traits that streamline Filament plugin development by taking care of the boilerplate, so you can focus on shipping real features faster

Table of Contents

Features

  • Easily Configure
    • ** Navigation** - Complete control over resource navigation (labels, icons, groups, sorting, badges)
    • ️ Label - Model labels, plural forms, title attributes, and casing options
    • ** Global Search** - Searchability controls, result limits, and case sensitivity options
    • ** Resource Tenant options** - Tenant scoping and relationship configuration
    • ** Parent Resource** - Hierarchical resource relationships
  • ️ Multi-Resource Configuration - Different settings per Resource in a single plugin
  • ** 3-Tier Default System** - User overrides → Plugin defaults → Filament defaults
  • ** Dynamic Values** - Closure support for conditional logic and real-time data
  • ** Developer-Friendly** - Minimal boilerplate with maximum customization

Requirements

Installation

composer require bezhansalleh/filament-plugin-essentials

For Plugin Developers

1. Add traits to your plugin class

<?php

namespace YourVendor\YourPlugin;

use Webkernel\Component\Plugin\Concerns\Plugin;
use Filament\Contracts\Plugin;

class YourPlugin implements Plugin
{
    use Plugin\HasNavigation;
    use Plugin\HasLabels;
    use Plugin\HasGlobalSearch;
    use Plugin\WithMultipleResourceSupport; // For multi-forResource plugins

    public static function make(): static
    {
        return app(static::class);
    }

    public function getId(): string
    {
        return 'your-plugin';
    }

    // ... rest of plugin implementation
}

2. Add matching traits to your forResource classes

<?php

namespace YourVendor\YourPlugin\Resources;

use Webkernel\Component\Plugin\Concerns;
use Filament\Resources\Resource;

class UserResource extends Resource
{
    use Concerns\Resource\HasNavigation;
    use Concerns\Resource\HasLabels;
    use Concerns\Resource\HasGlobalSearch;

    protected static ?string $model = User::class;

    // Required: Link resource to plugin
    public static function getEssentialsPlugin(): ?YourPlugin
    {
        return YourPlugin::get();
    }

    // ... rest of forResource implementation
}

3. Set defaults for your plugin (optional)

class YourPlugin implements Plugin
{
    use HasNavigation, HasLabels, HasGlobalSearch;

    protected function getPluginDefaults(): array
    {
        return [
            // Global defaults (apply to all resources)
            'navigationGroup' => 'Your Plugin',
            'navigationIcon' => 'heroicon-o-puzzle-piece',
            'modelLabel' => 'Item',
            'pluralModelLabel' => 'Items',
            'globalSearchResultsLimit' => 25,

            // Resource-specific defaults (optional)
            'resources' => [
                UserResource::class => [
                    'modelLabel' => 'User',
                    'pluralModelLabel' => 'Users',
                    'navigationIcon' => 'heroicon-o-users',
                    'globalSearchResultsLimit' => 50,
                ],
                PostResource::class => [
                    'modelLabel' => 'Post',
                    'pluralModelLabel' => 'Posts',
                    'navigationIcon' => 'heroicon-o-document-text',
                    'navigationSort' => 10,
                ],
            ],
        ];
    }
}

How Plugin Users Can Configure Your Plugin

When plugin developers use these traits, users of their plugins get a fluent API to configure them. The available configuration options depend on which traits the plugin developer chose to include.

Configure any plugin that uses these traits:

use YourVendor\YourPlugin\YourPlugin;

public function panel(Panel $panel): Panel
{
    return $panel
        ->plugins([
            YourPlugin::make()
                ->navigationLabel('Custom Label')
                ->navigationIcon('heroicon-o-star')
                ->modelLabel('Custom Item')
                ->globalSearchResultsLimit(30),
        ]);
}

Multi-forResource configuration

YourPlugin::make()
    // Configure UserResource
    ->forResource(UserResource::class)
        ->navigationLabel('Users')
        ->modelLabel('User')
        ->globalSearchResultsLimit(25)

    // Configure PostResource
    ->forResource(PostResource::class)
        ->navigationLabel('Posts')
        ->modelLabel('Article')
        ->globalSearchResultsLimit(10)

Dynamic values with closures

YourPlugin::make()
    ->navigationLabel(fn() => 'Users (' . User::count() . ')')
    ->navigationBadge(fn() => User::whereNull('email_verified_at')->count())
    ->modelLabel(fn() => auth()->user()->isAdmin() ? 'Admin User' : 'User')

Plugin & Resource Trait Mapping

Each plugin trait has a corresponding forResource trait that must be added to your forResource classes:

use Webkernel\Component\Plugin\Concerns\Plugin; // plugin
use Webkernel\Component\Plugin\Concerns\Resource; // forResource
Plugin Trait Resource Trait
Plugin\HasNavigation Resource\HasNavigation
Plugin\HasLabels Resource\HasLabels
Plugin\HasGlobalSearch Resource\HasGlobalSearch
Plugin\BelongsToParent Resource\BelongsToParent
Plugin\BelongsToTenant Resource\BelongsToTenant
Plugin\WithMultipleResourceSupport (No forResource trait needed - enables multi-forResource configuration)

Configuration Options Provided by Each Trait

HasNavigation

$plugin
    ->navigationLabel('Label')                  // string|Closure|null
    ->navigationIcon('heroicon-o-home')         // string|Closure|null
    ->activeNavigationIcon('heroicon-s-home')   // string|Closure|null
    ->navigationGroup('Group')                  // string|Closure|null
    ->navigationSort(10)                        // int|Closure|null
    ->navigationBadge('5')                      // string|Closure|null
    ->navigationBadgeColor('success')           // string|array|Closure|null
    ->navigationParentItem('parent.item')       // string|Closure|null
    ->slug('custom-slug')                       // string|Closure|null
    ->registerNavigation(false);                // bool|Closure

Copy-paste defaults:

protected function getPluginDefaults(): array
{
    return [
        'navigationLabel' => 'Your Label',
        'navigationIcon' => 'heroicon-o-home',
        'activeNavigationIcon' => 'heroicon-s-home',
        'navigationGroup' => 'Your Group',
        'navigationSort' => 10,
        'navigationBadge' => null,
        'navigationBadgeColor' => null,
        'navigationParentItem' => null,
        'slug' => null,
        'registerNavigation' => true,
    ];
}

HasLabels

$plugin
    ->modelLabel('Model')                       // string|Closure|null
    ->pluralModelLabel('Models')                // string|Closure|null
    ->recordTitleAttribute('name')              // string|Closure|null
    ->titleCaseModelLabel(false);               // bool|Closure

Copy-paste defaults:

protected function getPluginDefaults(): array
{
    return [
        'modelLabel' => 'Item',
        'pluralModelLabel' => 'Items',
        'recordTitleAttribute' => 'name',
        'titleCaseModelLabel' => true,
    ];
}

HasGlobalSearch

$plugin
    ->globallySearchable(true)                  // bool|Closure
    ->globalSearchResultsLimit(50)             // int|Closure
    ->forceGlobalSearchCaseInsensitive(true)    // bool|Closure|null
    ->splitGlobalSearchTerms(false);            // bool|Closure

Copy-paste defaults:

protected function getPluginDefaults(): array
{
    return [
        'globallySearchable' => true,
        'globalSearchResultsLimit' => 50,
        'forceGlobalSearchCaseInsensitive' => null,
        'splitGlobalSearchTerms' => false,
    ];
}

BelongsToParent

$plugin->parentResource(ParentResource::class); // string|Closure|null

Copy-paste defaults:

protected function getPluginDefaults(): array
{
    return [
        'parentResource' => null,
    ];
}

BelongsToTenant

$plugin
    ->scopeToTenant(true)                       // bool|Closure
    ->tenantRelationshipName('organization')    // string|Closure|null
    ->tenantOwnershipRelationshipName('owner'); // string|Closure|null

Copy-paste defaults:

protected function getPluginDefaults(): array
{
    return [
        'scopeToTenant' => true,
        'tenantRelationshipName' => null,
        'tenantOwnershipRelationshipName' => null,
    ];
}

WithMultipleResourceSupport

Enables per-forResource configuration:

class YourPlugin implements Plugin
{
    use HasNavigation;
    use WithMultipleResourceSupport;
}

// Usage:
$plugin
    ->forResource(UserResource::class)
        ->navigationLabel('Users')
    ->forResource(PostResource::class)
        ->navigationLabel('Posts');

Todo

  • Add support for pages
  • ...features you want to see? Open an issue

About

[READ ONLY] Plugin construction toolkit for Webkernel. Provides reusable traits for navigation, labels, global search, tenancy, and multi-resource configuration in Filament-based plugins.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages