Plugin development
Overview
The basis of Filament plugins are Laravel packages. They are installed into your Filament project via Composer, and follow all the standard techniques, like using service providers to register routes, views, and translations. If you're new to Laravel package development, here are some resources that can help you grasp the core concepts:
- The Package Development section of the Laravel docs serves as a great reference guide.
- Spatie's Package Training course is a good instructional video series to teach you the process step by step.
- Spatie's Package Tools allows you to simplify your service provider classes using a fluent configuration object.
Filament plugins build on top of the concepts of Laravel packages and allow you to ship and consume reusable features for any Filament panel. They can be added to each panel one at a time, and are also configurable differently per-panel.
Configuring the panel with a plugin class
A plugin class is used to allow your package to interact with a panel configuration file. It's a simple PHP class that implements the Plugin
interface. 3 methods are required:
- The
getId()
method returns the unique identifier of the plugin amongst other plugins. Please ensure that it is specific enough to not clash with other plugins that might be used in the same project. - The
register()
method allows you to use any configuration option that is available to the panel. This includes registering resources, custom pages, themes, render hooks and more. - The
boot()
method is run only when the panel that the plugin is being registered to is actually in-use. It is executed by a middleware class.
<?php
namespace DanHarrin\FilamentBlog;
use DanHarrin\FilamentBlog\Pages\Settings;
use DanHarrin\FilamentBlog\Resources\CategoryResource;
use DanHarrin\FilamentBlog\Resources\PostResource;
use Filament\Contracts\Plugin;
use Filament\Panel;
class BlogPlugin implements Plugin
{
public function getId(): string
{
return 'blog';
}
public function register(Panel $panel): void
{
$panel
->resources([
PostResource::class,
CategoryResource::class,
])
->pages([
Settings::class,
]);
}
public function boot(Panel $panel): void
{
//
}
}
The users of your plugin can add it to a panel by instantiating the plugin class and passing it to the plugin()
method of the configuration:
use DanHarrin\FilamentBlog\BlogPlugin;
public function panel(Panel $panel): Panel
{
return $panel
// ...
->plugin(new BlogPlugin());
}
Fluently instantiating the plugin class
You may want to add a make()
method to your plugin class to provide a fluent interface for your users to instantiate it. In addition, by using the container (app()
) to instantiate the plugin object, it can be replaced with a different implementation at runtime:
use Filament\Contracts\Plugin;
class BlogPlugin implements Plugin
{
public static function make(): static
{
return app(static::class);
}
// ...
}
Now, your users can use the make()
method:
use DanHarrin\FilamentBlog\BlogPlugin;
use Filament\Panel;
public function panel(Panel $panel): Panel
{
return $panel
// ...
->plugin(BlogPlugin::make());
}
Configuring plugins per-panel
You may add other methods to your plugin class, which allow your users to configure it. We suggest that you add both a setter and a getter method for each option you provide. You should use a property to store the preference in the setter and retrieve it again in the getter:
use DanHarrin\FilamentBlog\Resources\AuthorResource;
use Filament\Contracts\Plugin;
use Filament\Panel;
class BlogPlugin implements Plugin
{
protected bool $hasAuthorResource = false;
public function authorResource(bool $condition = true): static
{
// This is the setter method, where the user's preference is
// stored in a property on the plugin object.
$this->hasAuthorResource = $condition;
// The plugin object is returned from the setter method to
// allow fluent chaining of configuration options.
return $this;
}
public function hasAuthorResource(): bool
{
// This is the getter method, where the user's preference
// is retrieved from the plugin property.
return $this->hasAuthorResource;
}
public function register(Panel $panel): void
{
// Since the `register()` method is executed after the user
// configures the plugin, you can access any of their
// preferences inside it.
if ($this->hasAuthorResource()) {
// Here, we only register the author resource on the
// panel if the user has requested it.
$panel->resources([
AuthorResource::class,
]);
}
}
// ...
}