Skip to main content

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.json
  • src/Providers/PluginServiceProvider.php
  • database/migrations/
  • resources/js/
  • config/
  • README.md

Manifest contract (plugin.json)​

Minimum keys you should maintain:

  • slug
  • name
  • version
  • description
  • requires (php, laravel, core)
  • providers

Pagify scaffold also includes optional sections for:

  • hooks.subscribers
  • ui.menu
  • permissions
  • migrations
  • extension_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:

  1. Add migrations under plugins/{slug}/database/migrations
  2. Ensure migration paths are declared/loaded by plugin boot logic
  3. 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.json in 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_ENABLED on affected paths.
  • Re-enable plugin after fix and verify with regression tests.

Release checklist​

  1. Validate plugin.json metadata and version.
  2. Run migration and rollback checks.
  3. Verify enable/disable/uninstall flow in Admin.
  4. Run feature tests for integrated module paths.
  5. Document plugin-specific env vars and operational notes.