Plugins Usage Guide
This guide explains how to use Filament Tenancy plugins to configure central administration panels (landlord) and tenant panels.
Introduction
Section titled “Introduction”Filament Tenancy provides two main plugins to integrate multi-tenancy with Filament:
- TenancyLandlordPlugin: For the central administration panel (admin/landlord)
- TenancyTenantPlugin: For tenant panels
These plugins automatically configure the necessary middlewares and access restrictions to ensure security and isolation between tenants.
Prerequisites
Section titled “Prerequisites”Before using the plugins, make sure you have:
- ✅ Filament installed (
composer require filament/filament:"^4.0") - ✅ Run
php artisan filament-tenancy:install - ✅ Have at least one Filament panel created
Quick Implementation Guide
Section titled “Quick Implementation Guide”This guide will show you step by step how to configure both panels (Admin and Tenant) with Filament Tenancy plugins.
Step 1: Create the Admin Panel (Landlord)
Section titled “Step 1: Create the Admin Panel (Landlord)”Create or modify the file app/Providers/Filament/AdminPanelProvider.php:
<?php
namespace App\Providers\Filament;
use AngelitoSystems\FilamentTenancy\FilamentPlugins\TenancyLandlordPlugin;use Filament\Http\Middleware\Authenticate;use Filament\Http\Middleware\DisableBladeIconComponents;use Filament\Http\Middleware\DispatchServingFilamentEvent;use Filament\Pages;use Filament\Panel;use Filament\PanelProvider;use Filament\Widgets;use Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse;use Illuminate\Cookie\Middleware\EncryptCookies;use Illuminate\Foundation\Http\Middleware\VerifyCsrfToken;use Illuminate\Routing\Middleware\SubstituteBindings;use Illuminate\Session\Middleware\AuthenticateSession;use Illuminate\Session\Middleware\StartSession;use Illuminate\View\Middleware\ShareErrorsFromSession;
class AdminPanelProvider extends PanelProvider{ public function panel(Panel $panel): Panel { return $panel ->id('admin') // 👈 Panel ID (must match landlord_panel_id in config) ->path('admin') // 👈 Panel path (e.g., https://app.example.com/admin) ->login() ->colors([ 'primary' => \Filament\Support\Colors\Color::Blue, ]) ->discoverResources(in: app_path('Filament/Resources'), for: 'App\\Filament\\Resources') ->discoverPages(in: app_path('Filament/Pages'), for: 'App\\Filament\\Pages') ->pages([ Pages\Dashboard::class, ]) ->discoverWidgets(in: app_path('Filament/Widgets'), for: 'App\\Filament\\Widgets') ->widgets([ Widgets\AccountWidget::class, ]) ->middleware([ EncryptCookies::class, AddQueuedCookiesToResponse::class, StartSession::class, AuthenticateSession::class, ShareErrorsFromSession::class, VerifyCsrfToken::class, SubstituteBindings::class, DisableBladeIconComponents::class, DispatchServingFilamentEvent::class, ]) ->authMiddleware([ Authenticate::class, ]) ->plugin(TenancyLandlordPlugin::make()); // 👈 Landlord plugin (IMPORTANT) }}Key Points:
- The
id('admin')must matchlandlord_panel_idinconfig/filament-tenancy.php(default isadmin) - The plugin
TenancyLandlordPlugin::make()is added at the end with->plugin() - This panel will only be accessible from central domains (e.g.,
app.example.com/admin)
Step 2: Create the Tenant Panel
Section titled “Step 2: Create the Tenant Panel”Create the file app/Providers/Filament/TenantPanelProvider.php:
<?php
namespace App\Providers\Filament;
use AngelitoSystems\FilamentTenancy\FilamentPlugins\TenancyTenantPlugin;use Filament\Http\Middleware\Authenticate;use Filament\Http\Middleware\DisableBladeIconComponents;use Filament\Http\Middleware\DispatchServingFilamentEvent;use Filament\Pages;use Filament\Panel;use Filament\PanelProvider;use Filament\Widgets;use Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse;use Illuminate\Cookie\Middleware\EncryptCookies;use Illuminate\Foundation\Http\Middleware\VerifyCsrfToken;use Illuminate\Routing\Middleware\SubstituteBindings;use Illuminate\Session\Middleware\AuthenticateSession;use Illuminate\Session\Middleware\StartSession;use Illuminate\View\Middleware\ShareErrorsFromSession;
class TenantPanelProvider extends PanelProvider{ public function panel(Panel $panel): Panel { return $panel ->id('tenant') // 👈 Panel ID (must match tenant_panel_id in config) ->path('admin') // 👈 Panel path (e.g., https://tenant1.example.com/admin) ->login() ->colors([ 'primary' => \Filament\Support\Colors\Color::Green, ]) ->discoverResources(in: app_path('Filament/Tenant/Resources'), for: 'App\\Filament\\Tenant\\Resources') ->discoverPages(in: app_path('Filament/Tenant/Pages'), for: 'App\\Filament\\Tenant\\Pages') ->pages([ Pages\Dashboard::class, ]) ->discoverWidgets(in: app_path('Filament/Tenant/Widgets'), for: 'App\\Filament\\Tenant\\Widgets') ->widgets([ Widgets\AccountWidget::class, ]) ->middleware([ EncryptCookies::class, AddQueuedCookiesToResponse::class, StartSession::class, AuthenticateSession::class, ShareErrorsFromSession::class, VerifyCsrfToken::class, SubstituteBindings::class, DisableBladeIconComponents::class, DispatchServingFilamentEvent::class, ]) ->authMiddleware([ Authenticate::class, ]) ->plugin(TenancyTenantPlugin::make()); // 👈 Tenant plugin (IMPORTANT) }}Key Points:
- The
id('tenant')must matchtenant_panel_idinconfig/filament-tenancy.php(default istenant) - The plugin
TenancyTenantPlugin::make()is added at the end with->plugin() - This panel will only be accessible from tenant domains (e.g.,
tenant1.example.com/admin) - Note the discovery paths:
Filament/Tenant/Resourcesto keep resources separated
TenancyLandlordPlugin
Section titled “TenancyLandlordPlugin”The landlord plugin is used for the central administration panel where all tenants are managed.
Features
Section titled “Features”- ✅ Access only from central domains without active tenant
- ✅
PreventTenantAccessmiddleware to block access from tenant context - ✅ Automatic connection to central database (landlord)
- ✅ Automatic registration of
TenantResourceto manage tenants
TenancyTenantPlugin
Section titled “TenancyTenantPlugin”The tenant plugin is used for individual tenant panels.
Features
Section titled “Features”- ✅ Access only when there’s an active and resolved tenant
- ✅
PreventLandlordAccessmiddleware to block access without tenant - ✅ Automatic connection to tenant database
- ✅ Dynamic branding based on tenant name
Troubleshooting
Section titled “Troubleshooting”Error: “Access denied: Admin panel cannot be accessed from tenant context”
Section titled “Error: “Access denied: Admin panel cannot be accessed from tenant context””Cause: You’re trying to access the admin panel from a tenant domain.
Solution:
- Access the admin panel from a central domain (e.g.,
app.example.com/admin) - Or configure the tenant panel if you want to access from the tenant domain
Error: “Access denied: Tenant panel requires an active tenant context”
Section titled “Error: “Access denied: Tenant panel requires an active tenant context””Cause: You’re trying to access the tenant panel from a central domain without tenant.
Solution:
- Access the tenant panel from a tenant domain (e.g.,
tenant1.example.com/admin) - Make sure the tenant exists and is active in the database
Best Practices
Section titled “Best Practices”-
Resource Separation: Keep landlord and tenant resources in separate directories:
app/Filament/Resources/→ Admin panel resourcesapp/Filament/Tenant/Resources/→ Tenant panel resources
-
Models with Traits: Use the correct traits in your models:
BelongsToTenantfor tenant modelsUsesLandlordConnectionfor central models
-
Domain Configuration: Configure central domains correctly:
'central_domains' => ['app.example.com','admin.example.com',env('APP_DOMAIN', 'localhost'),],