fresns/plugin-manager
Laravel plugin manager for building modular, scalable apps. Treat each plugin as an independent mini-app with its own views, controllers, and models. Supports PHP 8+ and Laravel 9–13, with simple Composer install and optional config publishing.
## Getting Started
### Minimal Steps to First Use
1. **Installation**
```bash
composer require fresns/plugin-manager:^3.4.0
php artisan vendor:publish --provider="Fresns\PluginManager\Providers\PluginServiceProvider"
config/plugin-manager.php file exists in your project.Create a Plugin Skeleton
php artisan plugin:make my-first-plugin
plugins/MyFirstPlugin/ with:
routes/web.php (plugin-specific routes)routes/api.php (API routes)Providers/PluginServiceProvider.php (plugin bootstrapping)views/ (Blade templates)app/ (Models, Controllers, etc.)app/Http/Controllers instead of app/Controllers).Register the Plugin
config/plugin-manager.php under the plugins array:
'plugins' => [
'MyFirstPlugin' => [
'enabled' => true,
'path' => base_path('plugins/MyFirstPlugin'),
'laravel_version' => '11.x', // Explicitly declare for compatibility
],
],
php artisan plugin:migrate my-first-plugin
First Use Case: Plugin Route
plugins/MyFirstPlugin/routes/web.php:
Route::get('/hello', function () {
return 'Hello from MyFirstPlugin!';
})->middleware('web'); // Explicit middleware declaration (L11+ best practice)
/hello (ensure the plugin is enabled).plugins/ to understand isolation.config/plugin-manager.php for global settings (e.g., laravel_version compatibility flag).plugin:make (create new plugins, now defaults to L11+ structure).plugin:enable/disable (toggle plugins).plugin:migrate (run plugin migrations).plugin:clear-cache (refresh plugin assets/routes).plugin:check-compatibility (validates plugin against Laravel version).MyFirstPlugin\Http\Controllers).boot() in Providers/PluginServiceProvider.php for plugin-specific logic.
public function boot()
{
// Laravel 11+ uses boot() for middleware/route model binding
$this->routes();
$this->loadViewsFrom(__DIR__.'/resources/views', 'plugins.my-first-plugin');
}
PluginServiceProvider to bind plugin-specific services:
public function register()
{
$this->app->singleton('my-plugin.service', function () {
return new MyPluginService();
});
}
// plugins/MyFirstPlugin/routes/web.php
Route::prefix('my-plugin')->middleware(['web', 'auth'])->group(function () {
Route::get('/dashboard', [DashboardController::class, 'index']);
});
PluginServiceProvider:
public function boot()
{
$this->router->middlewareGroup('auth.my-plugin', [
\App\Http\Middleware\Authenticate::class,
\MyFirstPlugin\Http\Middleware\VerifyPluginRole::class,
]);
}
config/plugin-manager.php:
'middleware' => [
'web' => ['auth.my-plugin'],
'api' => ['throttle.my-plugin'],
],
@include('plugins::my-first-plugin.view-name') in parent app views.$this->publishes([
__DIR__.'/public' => public_path('plugins/my-first-plugin'),
], 'public');
New: Supports Laravel Mix/Vite integration:
$this->mix(__DIR__.'/resources/js/app.js', 'plugins/my-first-plugin');
PluginServiceProvider:
Blade::directive('pluginAlert', function ($expression) {
return "<?php echo Fresns\\PluginManager\\Blade::alert($expression); ?>";
});
database/migrations).php artisan plugin:migrate my-first-plugin
Schema::connection('plugin_db') if configured in config/plugin-manager.php.
New: Supports Laravel 11.x schema builder improvements:
Schema::connection('plugin_db')->create('my_plugin_table', function (Blueprint $table) {
$table->id();
$table->timestamps();
$table->foreignId('user_id')->constrained()->cascadeOnDelete();
});
PluginServiceProvider:
public function boot()
{
event(new \MyFirstPlugin\Events\PluginEvent());
}
PluginEnabled, PluginDisabled) in your app’s EventServiceProvider.
New: Supports Laravel 11.x event dispatching:
event(new \MyFirstPlugin\Events\PluginUpdated());
config/plugin-manager.php:
'plugins' => [
'MyFirstPlugin' => [
'dependencies' => ['AuthPlugin', 'DatabasePlugin'],
'laravel_version' => '11.x',
],
],
composer.json:
"autoload": {
"psr-4": {
"MyFirstPlugin\\": "plugins/MyFirstPlugin/src/"
}
}
Then run composer dump-autoload.$this->app->bind('my-plugin.service', function () {
return app('plugins.my-first-plugin')->service();
});
PluginManager::getPlugin('MyFirstPlugin') to access plugin instances.
New: Supports Laravel 11.x container improvements:
$plugin = app()->make(\Fresns\PluginManager\Contracts\Plugin::class, ['name' => 'MyFirstPlugin']);
PluginTestCase:
use Fresns\PluginManager\Testing\PluginTestCase;
class MyFirstPluginTest extends PluginTestCase
{
protected $plugin = 'MyFirstPlugin';
protected $laravelVersion = '11.x'; // Explicitly declare
public function test_plugin_route()
{
$this->get('/my-plugin/hello')
->assertStatus(200)
->assertSee('Hello from MyFirstPlugin!');
}
}
$this->mock(Fresns\PluginManager\Contracts\Plugin::class, function ($mock) {
$mock->shouldReceive('isEnabled')->andReturn(true);
});
composer require for plugin updates, then run:
php artisan plugin:update my-first-plugin
How can I help you explore Laravel packages today?