whilesmart / laravel-plugin-engine
A flexible plugin engine for Laravel applications
Package info
github.com/whilesmartphp/laravel-plugin-engine
pkg:composer/whilesmart/laravel-plugin-engine
Requires
- php: ^8.1
- illuminate/console: ^11.0
- illuminate/database: ^11.45
- illuminate/filesystem: ^11.0
- illuminate/support: ^11.0
Requires (Dev)
- laravel/pint: ^1.0
- laravel/sanctum: ^4.0
- mockery/mockery: ^1.5
- orchestra/testbench: ^9.0
- phpunit/phpunit: ^11.0
This package is auto-updated.
Last update: 2026-07-04 13:09:33 UTC
README
A flexible and powerful plugin system for Laravel applications.
Features
- Plugin discovery and registration
- Enable/disable plugins
- Plugin dependencies
- Console commands for plugin management
- Event-driven architecture
- Easy to extend
Installation
- Install the package via Composer:
composer require whilesmart/laravel-plugin-engine
- Publish the configuration file (optional):
php artisan vendor:publish --provider="WhileSmart\LaravelPluginEngine\Providers\PluginServiceProvider" --tag=config
Configuration
Publish the configuration file:
php artisan vendor:publish --provider="WhileSmart\LaravelPluginEngine\Providers\PluginServiceProvider" --tag=config
Edit the config/plugins.php file to configure the plugin system:
return [ 'path' => base_path('plugins'), // Path where plugins are stored 'namespace' => 'Plugins', // Root namespace for plugins 'log_channel' => env('PLUGIN_ENGINE_LOG_CHANNEL'), // Log channel, null = app default 'log_level' => env('PLUGIN_ENGINE_LOG_LEVEL', 'warning'), // Minimum level the engine logs at ];
Logging
The engine logs through its own configurable channel and minimum level, independent of the application's logging:
PLUGIN_ENGINE_LOG_CHANNEL: any channel fromconfig/logging.php. Leave unset to use the application's default channel.PLUGIN_ENGINE_LOG_LEVEL: messages below this level are dropped. Defaults towarning, so routine discovery output stays out of production logs. Set todebugto trace plugin discovery and registration.
Usage
Available Commands
plugin:list- List all available pluginsplugin:info {id}- Show information about a pluginplugin:enable {id}- Enable a pluginplugin:disable {id}- Disable a pluginplugin:install {package}- Install a plugin from a Composer package, a repository URL, or a local pathplugin:discover- Discover and register all available pluginsplugin:cache- Compile discovered plugins into a cache fileplugin:clear- Remove the plugin cache file
Plugin dependencies
When a plugin is installed from a URL or a local path, the engine reads the
plugin's own composer.json and installs its require dependencies into the
host application, so the plugin's classes are available at runtime.
For hosts that embed several plugins, enable
wikimedia/composer-merge-plugin
so each plugin keeps owning its dependencies while Composer resolves them
together into the single host vendor/:
// host composer.json "extra": { "merge-plugin": { "include": ["plugins/*/composer.json"] } }, "config": { "allow-plugins": { "wikimedia/composer-merge-plugin": true } }
With this configured, installing a plugin runs a targeted composer update;
otherwise the engine falls back to composer require for the plugin's
dependencies.
Caching
By default, plugins are discovered by scanning the plugins directory and parsing each manifest on every boot. In production, compile the result to a cache file instead, alongside the framework's other caches:
php artisan plugin:cache
The compiled file is loaded on boot and the filesystem scan is skipped.
Run this on every deploy, next to config:cache and route:cache.
plugin:enable, plugin:disable, and plugin:discover refresh an existing
cache automatically. To return to live discovery:
php artisan plugin:clear
Creating a Plugin
- Create a new directory in the
pluginsdirectory (or your configured path) - Create a
plugin.jsonfile with the following structure:
{
"id": "example-plugin",
"name": "Example Plugin",
"description": "A sample plugin",
"version": "1.0.0",
"namespace": "Plugins\\Example",
"provider": "Plugins\\Example\\ExampleServiceProvider",
"enabled": true,
"requires": {
"php": ">=8.1",
"laravel/framework": "^10.0"
}
}
- Create a service provider for your plugin:
<?php namespace Plugins\Example; use Illuminate\Support\ServiceProvider; class ExampleServiceProvider extends ServiceProvider { public function register() { // Register bindings } public function boot() { // Boot logic $this->loadRoutesFrom(__DIR__.'/routes/web.php'); $this->loadViewsFrom(__DIR__.'/resources/views', 'example'); $this->loadMigrationsFrom(__DIR__.'/database/migrations'); } }
Plugin Structure
plugins/
example-plugin/
src/
Http/
Controllers/
Models/
Providers/
ExampleServiceProvider.php
resources/
views/
routes/
web.php
database/
migrations/
plugin.json
README.md
Events
The plugin system dispatches several events that you can listen for:
WhileSmart\PluginEngine\Events\PluginEnabling- Fired before a plugin is enabledWhileSmart\PluginEngine\Events\PluginEnabled- Fired after a plugin is enabledWhileSmart\PluginEngine\Events\PluginDisabling- Fired before a plugin is disabledWhileSmart\PluginEngine\Events\PluginDisabled- Fired after a plugin is disabledWhileSmart\PluginEngine\Events\PluginInstalled- Fired after a plugin is installedWhileSmart\PluginEngine\Events\PluginDiscovered- Fired when a plugin is discovered
Development
The repository ships a dockerized environment, so PHP and Composer are not required on the host:
make install # build the container and install dependencies make test # run the test suite make pint # fix code style make check # run style check and tests make shell # open a shell in the container
License
This project is open-source and licensed under the MIT License.