Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Filament Modifiable Plugins Laravel Package

timo-de-winter/filament-modifiable-plugins

A Filament package that lets you modify installed plugins from your admin panel, providing a simple way to manage plugin settings and behaviour without editing code. Integrates with Laravel and Filament for centralized plugin configuration.

View on GitHub
Deep Wiki
Context7

Getting Started

Install the package with Composer and publish its assets before touching any panel configuration:

composer require timo-de-winter/filament-modifiable-plugins
php artisan vendor:publish --tag="filament-modifiable-plugins-config"
php artisan vendor:publish --tag="filament-modifiable-plugins-migrations"
php artisan migrate

Where to look first, in this order:

  1. The published config file — it defines which plugins are exposed as modifiable, how state is persisted, and any caching layer. This is the file you will edit most often.
  2. The published migration — read the columns to understand what is actually stored (plugin identifier, panel scope, payload/settings, enabled flag). Your seeders and queries depend on this shape.
  3. The PanelProvider — the package is registered as a Filament plugin, so the ->plugin(...) call is your integration point.

First use case: stop hardcoding ->plugin(SomePlugin::make()) per panel. Register the modifiable-plugins plugin on the panel once, then move each optional plugin into the package's registry so an admin can toggle it and edit its settings from the UI without a deploy. A good pilot is a low-risk plugin (e.g. a widget or a secondary resource) rather than something the panel's core navigation depends on.

Implementation Patterns

Panel-scoped state. Treat every stored setting as (plugin, panel, tenant?). Wrap reads in a single accessor/helper rather than scattering queries through providers — you want one place to add caching later.

Typed reads, not raw arrays. Cast stored settings into a DTO or a readonly value object per plugin. Filament form state is array; leaking that array into business logic makes later schema changes painful.

Cache the resolved registry. Resolving enabled plugins on every request means a query per panel boot. Cache the resolved list keyed by panel (and tenant) and flush explicitly on save, on deploy, and in config:cache flows.

Idempotent seeding across environments. Ship a seeder using updateOrCreate keyed on the plugin identifier + panel so a fresh install matches production defaults. Without it, a new environment boots with nothing enabled and looks broken.

Multi-panel and multi-tenant scoping. If you run several panels, decide deliberately what "no row" means — inherited default, enabled, or disabled. Make that decision explicit in the resolver, not implicit in a first() call.

Custom UI when needed. If the shipped settings page does not fit, build a Filament Resource or custom Page over the underlying model and reuse the package's save path so cache invalidation and events still fire.

Testing. Use RefreshDatabase, disable the package cache in the test environment, and assert on the resolver (what plugins a panel ends up with) rather than on rendered HTML. Factory states for enabled/disabled/configured cover most cases.

Gotchas and Tips

  • Cache staleness is the number one bug report. Toggling in the UI but seeing no change almost always means a cached registry. Clear it in your save listener and in your deploy script.
  • Boot order on fresh installs. Panel registration can run before migrations in CI or a fresh container, so guard DB reads (Schema::hasTable) or provide a config-level fallback default. Otherwise php artisan migrate itself can fail while resolving panels.
  • Authorization is not the same as the toggle. A "disabled" plugin may still have registered routes and policies. Enforce access with policies; treat the toggle as UI/feature-flag convenience only.
  • vendor:publish --force will clobber your config. Keep published config in version control and diff it after every upgrade instead of blindly republishing. The migration file is likewise yours to own once published.
  • Upgrade drift. This release jumps several minor versions. Read the changelog for renamed config keys and published-migration drift before upgrading; a config key rename fails silently when a default is used.
  • Debugging aid. When a panel resolves the wrong plugin set, dump the registry after boot (a dd() inside the resolver or a temporary listener on the panel booted event) — this distinguishes "not saved" from "saved but not read".
  • Extension points over overrides. Prefer the package's events/listeners and swappable model binding in config over subclassing internals; the internal classes are the most likely thing to shift between minor releases.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
coleus/frame
thtg88/journalism
filagora/filagora-ai-forums
rlacerda83/query-parser
socialdept/atp-orm
cboxdk/laravel-assistant-client
socialdept/atp-resolver
socialdept/tenant-domains
tautvydasr/blade-class-names
socialdept/color-scales
maherelgamil/controller
coleus/widgets
coleus/table
coleus/users
coleus/music
coleus/health
coleus/calendar
coleus/notes
coleus/support
coleus/settings