Plugin Development
This guide describes how to design, scaffold, implement, and operate plugins in Pagify.
What a plugin is in Pagify
A plugin is a deployable extension package under plugins/{slug} (or a Composer package with plugin.json at package root) that can contribute:
- service providers
- hooks/subscribers
- permissions
- migrations
- extension points (field types, blocks, dashboard widgets, automation actions, menu items)
Plugin lifecycle is managed from Admin and API (/{admin_prefix}/plugins, api/v1/{admin_prefix}/plugins).
Scaffold a new plugin
From project root:
php artisan cms:make-plugin "My Plugin"
This command creates plugins/my-plugin with:
plugin.jsonsrc/Providers/PluginServiceProvider.phpdatabase/migrations/resources/js/config/README.md
Manifest contract (plugin.json)
Minimum keys you should maintain:
slugnameversiondescriptionrequires(php,laravel,core)providers
Pagify scaffold also includes optional sections for:
hooks.subscribersui.menupermissionsmigrationsextension_points
Example:
{
"slug": "my-plugin",
"name": "My Plugin",
"version": "0.1.0",
"description": "Plugin description",
"requires": {
"php": ">=8.2",
"laravel": "^12.0",
"core": "^1.0"
},
"providers": [
"Plugins\\MyPlugin\\Providers\\PluginServiceProvider"
],
"hooks": {
"subscribers": []
},
"permissions": [
"plugin.my.plugin.manage"
],
"extension_points": {
"field_types": [],
"blocks": [],
"dashboard_widgets": [],
"automation_actions": [],
"menu_items": []
}
}
Implement service provider
Use src/Providers/PluginServiceProvider.php to register container bindings, event listeners, and boot-time integration.
Recommended practice:
- keep
register()for bindings/config merge - keep
boot()for route/view/publish/event wiring - avoid heavy IO in
boot()to keep request startup fast
Hook integration
Plugins can subscribe to platform hooks and extend behaviors, including theme helper injection (theme.render.helpers).
See related guide for hook return contract and subscriber example:
Database and migrations
When your plugin needs schema changes:
- Add migrations under
plugins/{slug}/database/migrations - Ensure migration paths are declared/loaded by plugin boot logic
- Run:
php artisan migrate
If plugin APIs report state initialization issues, migrate first.
Local development workflow
Typical sequence:
php artisan optimize:clear
php artisan migrate
php artisan queue:work --queue=default --tries=3
php artisan test
Useful references:
Packaging and installation notes
Pagify plugin manager expects plugin.json at plugin/package root:
- local plugin folder:
plugins/{slug}/plugin.json - Composer package:
vendor/{vendor}/{package}/plugin.json - ZIP upload: must contain
plugin.jsonin extracted plugin root
If plugin.json is missing or invalid, installation will fail.
Safety and operations
- Keep plugin logic isolated and idempotent.
- Validate permission checks for every admin/API action.
- If a plugin crashes in runtime, safe mode can auto-disable it and return
PLUGIN_SAFE_MODE_ENABLEDon affected paths. - Re-enable plugin after fix and verify with regression tests.
Release checklist
- Validate
plugin.jsonmetadata and version. - Run migration and rollback checks.
- Verify enable/disable/uninstall flow in Admin.
- Run feature tests for integrated module paths.
- Document plugin-specific env vars and operational notes.