wotz / filament-brigada-cms
The conventions, defaults and shared UI behind a Brigada Filament CMS
Requires
- php: ^8.3
- alizharb/filament-activity-log: ^2.0
- awcodes/filament-sticky-header: ^4.0
- awcodes/richer-editor: ^2.1
- azgasim/filament-unsaved-changes-modal: ^1.0
- bezhansalleh/filament-shield: ^4.1
- filament/filament: ^5.5
- illuminate/contracts: ^12.0|^13.0
- livewire/livewire: ^4.0
- oddvalue/laravel-drafts: ^3.1
- parfaitementweb/filament-password-input: ^4.1
- pboivin/filament-peek: ^4.0
- pxlrbt/filament-environment-indicator: ^3.4
- spatie/eloquent-sortable: ^5.0
- spatie/laravel-package-tools: ^1.12
- spatie/laravel-sluggable: ^4.0
- spatie/laravel-translatable: ^6.11
- wezlo/filament-search-spotlight: ^1.0
- wotz/filament-admin-bar: ^2.1
- wotz/filament-architect: ^3.1
- wotz/filament-belongs-to-many: ^2.2
- wotz/filament-brigada-theme: ^0.1
- wotz/filament-custom-tiptap-extensions: ^2.2
- wotz/filament-image-or-video: ^2.2
- wotz/filament-link-picker: ^2.2
- wotz/filament-live-preview: ^0.2
- wotz/filament-media-library: ^4.6
- wotz/filament-menu: ^3.2
- wotz/filament-redirects: ^3.0
- wotz/filament-resource-picker: ^2.1
- wotz/filament-seo: ^4.0
- wotz/filament-settings: ^2.3
- wotz/filament-table-filter-presets: ^0.5
- wotz/filament-translatable-strings: ^3.0
- wotz/filament-translatable-tabs: ^3.0
- wotz/laravel-locale-collection: ^2.1
- wotz/laravel-online-scope: ^2.1
- wotz/laravel-translatable-routes: ^2.1
Requires (Dev)
- larastan/larastan: ^3.0
- laravel/pint: ^1.0
- nunomaduro/collision: ^8.0
- orchestra/testbench: ^10.0|^11.0
- pestphp/pest: ^3.0|^4.0
- pestphp/pest-plugin-laravel: ^3.0|^4.0
- phpstan/extension-installer: ^2.0
- phpstan/phpstan-deprecation-rules: ^2.0
- phpstan/phpstan-phpunit: ^2.0
Suggests
- petercoles/multilingual-country-list: Localised country lists
- spatie/laravel-sitemap: XML sitemap generation
- wotz/filament-mail-templates: Editable transactional mail templates
- wotz/filament-social-media-links: Social profile links
- wotz/laravel-livewire-forms: Front-end form building
- wotz/laravel-social-media-share: Share buttons
Provides
None
Conflicts
None
Replaces
None
README
The conventions, defaults and shared UI behind a Brigada Filament CMS — the parts that were previously copied out of a project skeleton and then drifted.
Pulls in wotz/filament-brigada-theme
and the standard plugin set, so a project gets a styled, configured panel from one
composer require.
Installation
composer require wotz/filament-brigada-cms
Import the stylesheets from your panel theme, with the other @import rules at the top —
CSS drops an @import that follows any other rule:
@import '../../../../vendor/wotz/filament-brigada-theme/resources/css/filament-brigada-theme.css'; @import '../../../../vendor/wotz/filament-brigada-cms/resources/css/filament-brigada-cms.css';
Extend the panel provider:
use Wotz\FilamentBrigadaCms\Providers\BrigadaPanelProvider; class AdminPanelProvider extends BrigadaPanelProvider { protected function id(): string { return 'admin'; } }
Then npm run build.
What you get
Panel — the standard plugin set (theme, shield, activity log, sticky header, menu,
settings, media library, SEO, redirects, admin bar, environment indicator, unsaved-changes
modal, spotlight), Filament's global search replaced by the ⌘K spotlight over navigation,
records and actions, and the middleware stack.
Defaults, all applied through configureUsing, so an explicit call in a resource
always wins:
| Non-clickable rows | cell text stays selectable; records open through row actions |
| Persisted table state | sort, search and column searches, not just filters |
| Humanised labels | Amount including vat → Amount including VAT |
| Collapsed nav groups | and a default group label |
| Date and money formats | d M Y H:i:s, EUR |
Shared UI — the ⌘K trigger, expand/collapse-all for the sidebar, a panel error page,
a loading skeleton, CopyTranslationAction, and the HasReadOnlyBadge concern for
resources synced from elsewhere.
Drafts and live preview — oddvalue/laravel-drafts and wotz/filament-live-preview
are wired up: the plugins are registered, draft previews are disabled inside the panel, and
two concerns add the actions to a resource's pages.
use Wotz\FilamentBrigadaCms\Filament\Concerns\HandlesDraftsOnEdit; class EditPage extends EditRecord { use HandlesDraftsOnEdit; // Publish, Save to new draft, Version switcher }
Opting a resource in
The package registers the plugins, but nothing appears until a resource opts in — a panel with the plugins loaded and no traits applied shows no Preview or draft actions at all.
On the model:
use Oddvalue\LaravelDrafts\Concerns\HasDrafts; use Wotz\FilamentBrigadaCms\Models\Concerns\HandlesTranslatableDrafts; class Page extends Model { use HandlesTranslatableDrafts { HandlesTranslatableDrafts::getDraftableAttributes insteadof HasDrafts; } use HasDrafts; }
The insteadof is required, not stylistic: both traits define getDraftableAttributes(),
and PHP fatals on the collision without it.
HandlesTranslatableDrafts matters more than it looks: laravel-drafts copies raw
attributes, so a spatie/laravel-translatable model loses every locale but the current one
the first time a draft is saved. On a model that is not translatable, use HasDrafts alone.
Add the columns with the migration helper the drafts package ships:
Schema::table('pages', fn (Blueprint $table) => $table->drafts());
On the pages:
class EditPage extends EditRecord { use HandlesDraftsOnEdit; use HasLivePreviewComponent; // from wotz/filament-live-preview protected function getHeaderActions(): array { return [ ...$this->getDraftHeaderActions(), // your own actions after these DeleteAction::make(), ]; } protected function getPreviewModalView(): ?string { return 'page.show'; } protected function getPreviewModalDataRecordKey(): ?string { return 'page'; } }
The create page is the same shape, with its own helper:
class CreatePage extends CreateRecord { use HandlesDraftsOnCreate; use HasLivePreviewComponent; protected function getHeaderActions(): array { return [ ...$this->getDraftHeaderActions(), $this->getCancelFormAction(), ]; } // getPreviewModalView() and getPreviewModalDataRecordKey() as above }
Live preview renders your own front-end view, so it only applies to resources that have one — and it has to be wired on both the create and edit pages, not just edit. If a project has no use for either, drop them:
protected function plugins(): array { $plugins = parent::plugins(); unset($plugins['live-preview'], $plugins['peek']); return $plugins; }
Overriding
Every method on BrigadaPanelProvider is a seam. Append rather than replace:
protected function plugins(): array { // Keyed, so you can reconfigure one without rebuilding the list. $plugins = parent::plugins(); $plugins['shield']->navigationGroup(NavigationGroup::General); return [...$plugins, 'live-preview' => LivePreviewPlugin::make()]; } protected function userMenuItems(): array { return [...parent::userMenuItems(), Action::make('maintenanceMode')…]; }
Views override the Laravel way — resources/views/vendor/filament-brigada-cms/… wins.
Classes can be swapped through the container. And everything above is togglable in config:
php artisan vendor:publish --tag=filament-brigada-cms-config
Add your project's own acronyms there rather than editing the package:
'acronyms' => [..., 'bc', 'btw', 'kkg', 'ogm'],
Panel error page
Point your resources/views/errors/admin.blade.php at the packaged one:
@include('filament-brigada-cms::errors.panel')
Developing this package
Improvements are meant to be made in the package, while working on a real project — not made in the project and cherry-picked back. Point the project at a local checkout:
composer config repositories.brigada-cms path ../filament-brigada-cms composer require wotz/filament-brigada-cms:@dev
vendor/wotz/filament-brigada-cms is then a symlink to your checkout, so you edit the
package directly with the project running against it. Commit and tag in the package; every
other project picks it up on composer update.
Remove the path repository before committing the project:
composer config --unset repositories.brigada-cms
Licence
MIT. See LICENSE.md.