Plugin Registration
Registering in a PanelProvider
Add TagixoFilamentPlugin::make() to the plugins() array of your Filament PanelProvider:
<?php
namespace App\Providers\Filament;
use Ccast\TagixoFilament\TagixoFilamentPlugin;
use Filament\Http\Middleware\Authenticate;
use Filament\Http\Middleware\DisableBladeIconComponents;
use Filament\Http\Middleware\DispatchServingFilamentEvent;
use Filament\Panel;
use Filament\PanelProvider;
use Filament\Support\Colors\Color;
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
->default()
->id('admin')
->path('admin')
->login()
->colors(['primary' => Color::Amber])
->discoverResources(in: app_path('Filament/Resources'), for: 'App\\Filament\\Resources')
->discoverPages(in: app_path('Filament/Pages'), for: 'App\\Filament\\Pages')
->discoverWidgets(in: app_path('Filament/Widgets'), for: 'App\\Filament\\Widgets')
->middleware([
EncryptCookies::class,
AddQueuedCookiesToResponse::class,
StartSession::class,
AuthenticateSession::class,
ShareErrorsFromSession::class,
VerifyCsrfToken::class,
SubstituteBindings::class,
DisableBladeIconComponents::class,
DispatchServingFilamentEvent::class,
])
->authMiddleware([Authenticate::class])
->plugins([
TagixoFilamentPlugin::make()
->withPages()
->withLayouts()
->withMenus()
->withGlobalVariables()
->withForms()
->withMediaGallery()
->navigationGroup('Content'),
]);
}
}
Fluent Configuration Methods
All feature toggles are chainable on the TagixoFilamentPlugin instance. Every method accepts an optional bool argument (default true) so you can conditionally disable a feature.
| Method | Default | Effect |
|---|---|---|
->withPages(bool $enabled = true) |
true |
Registers the Pages resource (list, create, edit, builder). |
->withLayouts(bool $enabled = true) |
true |
Registers the Layouts resource. |
->withMenus(bool $enabled = true) |
true |
Registers the Menus & Menu Items resources. |
->withGlobalVariables(bool $enabled = true) |
true |
Registers the Global Variables resource. |
->withForms(bool $enabled = true) |
true |
Registers the Forms resource (form schema editor). |
->withMediaGallery(bool $enabled = true) |
true |
Registers the Media Gallery resource and file-picker Livewire component. |
->usingLayout(string $view) |
built-in | Overrides the default Filament layout blade view used by builder pages. |
->navigationGroup(string $group) |
null |
Wraps all Tagixo nav items under this Filament navigation group label. |
Example — disable forms and override the navigation group:
TagixoFilamentPlugin::make()
->withForms(false)
->navigationGroup('Website'),
What the Plugin Registers Automatically
When the plugin boots inside a panel, it automatically registers the following without any extra configuration:
Routes All builder API endpoints (page/layout/menu save, global variables, media endpoints) are registered under the panel's path prefix and protected by the panel's auth middleware stack. You do not need to add any routes manually.
Livewire Components
Builder-related Livewire components (the visual editor mount component, the media picker, the form schema editor) are registered via Livewire::component() during the ServingFilament event so they are scoped to the panel request.
Render Hooks
The plugin injects builder JavaScript and CSS into the Filament head via render hooks (FilamentView::renderHook). The assets are loaded only on pages that mount the builder, not on every admin page.
Livewire Morph Guard
A render hook appends a wire:ignore wrapper around the #tagixo-vue mount point. This prevents Livewire's DOM-morph from destroying the Vue application during Livewire updates.
The Plugin Boot Sequence
Understanding the boot order prevents the most common integration mistakes:
- Service providers boot —
TagixoFilamentServiceProviderregisters base bindings (models, config, migrations). ServingFilamentevent fires — Filament dispatches this once per HTTP request when a panel is being served. The plugin registers Livewire components and routes here.register()runs on PanelProvider — theplugins([...])array is evaluated;TagixoFilamentPlugin::make()configures the plugin instance but does not yet boot it.boot()runs on PanelProvider — navigation items, render hooks, and asset injection are applied.- Navigation is built — Filament assembles the sidebar;
navigationGroup()takes effect here.
Gotcha: Do not call
TagixoFilamentPlugin::get($panel)or reference the plugin instance beforeboot()completes. In particular, do not call it from a service provider'sregister()method — the panel will not yet have processed its plugins array.
Multi-Panel Setups
If your application has more than one Filament panel (e.g. an admin panel and a tenant panel), register the plugin independently in each panel's provider:
// AdminPanelProvider
->plugins([
TagixoFilamentPlugin::make()
->withPages()
->withLayouts()
->navigationGroup('Content'),
])
// TenantPanelProvider
->plugins([
TagixoFilamentPlugin::make()
->withPages(false) // tenants cannot manage pages
->withForms()
->navigationGroup('Forms'),
])
Each panel gets its own route prefix (e.g. /admin/tagixo/... vs /tenant/tagixo/...), its own middleware stack, and its own set of registered resources. The plugin is designed to run safely in both panels simultaneously.
Warning: Do not share a single
TagixoFilamentPlugininstance across two panels. Always call::make()separately for each panel. A shared instance will have its configuration overwritten by whichever panel boots last.
Conditionally Enabling Features
Two common patterns for gating features behind config or feature flags:
Config-gated — read a value from your config/ at provider boot time:
TagixoFilamentPlugin::make()
->withForms(config('tagixo.features.forms', true))
->withMediaGallery(config('tagixo.features.media_gallery', true)),
Feature-flag-gated — integrate with a flag service:
TagixoFilamentPlugin::make()
->withMenus(Feature::active('advanced-menus')),
Octane / multi-tenant gotcha: Plugin registration happens once at boot, before any request context is available. If you are using Octane or a multi-tenant package that swaps tenants per request, feature flags that depend on the current tenant or session will not work here — they will be evaluated against the state at application boot. Gate features at the resource-policy or middleware level instead.
Custom Panel Layout Override
The builder pages use a custom Filament layout that mounts the Vue application. If you need to extend this layout (e.g. to inject a custom toolbar or change the sidebar), publish the views first:
php artisan vendor:publish --tag=tagixo-filament-views
This copies the layout stub to resources/views/vendor/tagixo-filament/. Then tell the plugin to use your overridden view:
TagixoFilamentPlugin::make()
->usingLayout('vendor.tagixo-filament.custom-builder-layout'),
Critical: Your custom layout must preserve the
id="tagixo-vue"div and theid="vb-dynamic-styles"style tag. The Vue builder mounts onto#tagixo-vueand injects scoped CSS into#vb-dynamic-stylesat runtime. Removing or renaming either element will silently break the builder with no console error — the div will simply remain empty.
Full PanelProvider Reference Example
A production-style provider with conditional plugin configuration:
<?php
namespace App\Providers\Filament;
use Ccast\TagixoFilament\TagixoFilamentPlugin;
use Filament\Http\Middleware\Authenticate;
use Filament\Http\Middleware\DisableBladeIconComponents;
use Filament\Http\Middleware\DispatchServingFilamentEvent;
use Filament\Panel;
use Filament\PanelProvider;
use Filament\Support\Colors\Color;
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
->default()
->id('admin')
->path('admin')
->login()
->colors(['primary' => Color::Blue])
->brandName('My Site Admin')
->discoverResources(in: app_path('Primix/Resources'), for: 'App\\Primix\\Resources')
->middleware([
EncryptCookies::class,
AddQueuedCookiesToResponse::class,
StartSession::class,
AuthenticateSession::class,
ShareErrorsFromSession::class,
VerifyCsrfToken::class,
SubstituteBindings::class,
DisableBladeIconComponents::class,
DispatchServingFilamentEvent::class,
])
->authMiddleware([Authenticate::class])
->plugins([
TagixoFilamentPlugin::make()
->withPages()
->withLayouts()
->withMenus()
->withGlobalVariables()
->withForms(config('features.forms', true))
->withMediaGallery(config('features.media_gallery', true))
->navigationGroup('Content'),
]);
}
}
Asset Publication Checklist
After installing or upgrading ccast/tagixo-filament, run these three commands:
# 1. Publish Filament SDK assets (JS/CSS for the builder UI inside the panel)
php artisan vendor:publish --tag=tagixo-filament-assets --force
# 2. Publish core Tagixo assets (frontend renderer JS/CSS served to public visitors)
# Note: this tag comes from ccast/tagixo core, not the Filament SDK
php artisan vendor:publish --tag=tagixo-assets --force
# 3. Clear all caches so Octane picks up the new files
php artisan optimize:clear
Clarification:
--tag=tagixo-assetsis owned by theccast/tagixocore package and publishes the public-facing builder renderer topublic/vendor/tagixo/. The--tag=tagixo-filament-assetstag is owned byccast/tagixo-filamentand publishes the admin-panel-side JS/CSS. Both must be run after an upgrade — running only one will leave either the admin panel or the public renderer on the old version.