magna-cms/plugin-sdk
A Laravel/PHP SDK for building plugins and extensions for Magna CMS. It provides the core contracts, service providers, and integration hooks needed to package, register, and ship custom CMS functionality.
The SDK is a host-dependent package: it does nothing on its own, so the first hour is about standing up a Magna CMS install to develop against, not about reading the SDK source.
composer create-project or clone the CMS repo, php artisan migrate, seed an admin user). Confirm you can log into the admin panel before touching the SDK.magna-cms/plugin-sdk. Wire it in via a path repository so you get live reload without tagging releases:
{
"repositories": [{ "type": "path", "url": "../my-plugin", "options": { "symlink": true } }],
"require": { "magna-cms/plugin-sdk": "^1.0", "my-vendor/my-plugin": "*" }
}
composer.json — Laravel/Illuminate version ceilings. This tells you which Magna releases you can target and is the most common source of install pain.src/ root — find the base Plugin/ServiceProvider class and the abstract contract every plugin must implement. Everything else is detail.config/ — the publishable config file name and its defaults (plugin discovery paths, asset paths, cache keys).stubs/ or examples/ if present — the fastest way to learn the expected directory layout.README last, not first; on a package this young the code is more reliable than the prose.Service provider as the spine. Nearly all SDK interaction funnels through one provider that extends the SDK's base class. Keep it thin: register bindings, call the SDK's registration methods for menus/routes/hooks, and delegate real work to dedicated classes.
class MyPluginServiceProvider extends PluginServiceProvider
{
public function register(): void
{
$this->mergeConfigFrom(__DIR__.'/../config/my-plugin.php', 'my-plugin');
}
public function boot(): void
{
$this->registerMenu(); // SDK-provided; check exact signature in src/
$this->loadViewsFrom(__DIR__.'/../resources/views', 'my-plugin');
$this->loadMigrationsFrom(__DIR__.'/../database/migrations');
}
}
Namespace everything. Views (my-plugin::), config (my-plugin.), routes (my-plugin. name prefix), translations, migrations (timestamped, but also uniquely named), and cache keys. CMS plugins live inside a shared admin shell; unprefixed index or settings will eventually collide with the host or another plugin.
Extend through hooks, don't fork the admin. The productive pattern is: SDK/event hook fires → your listener enriches data → your view or API response renders it. Find the available hook names by grepping the SDK for doAction/applyFilters-style calls or event dispatches, and treat that list as your API surface. Direct view overrides on host templates are the fragile path — they break on every CMS upgrade.
Settings page pattern. Persist plugin settings through the CMS's own settings store (or a small dedicated table) rather than config/, which is read-only at runtime. Pair a settings form route with a FormRequest for validation, and gate the whole thing behind the host's permission system instead of inventing your own roles.
Migrations and assets. Ship migrations in database/migrations and load them from the provider; publish assets via php artisan vendor:publish --tag=my-plugin-assets. Treat published assets as one-way — upgrades won't overwrite them, so version your asset filenames when the CSS/JS changes shape.
Testing. Use orchestra/testbench with the SDK's provider plus your own in getPackageProviders(). That gets you fast tests without a full Magna install. Reserve one manual smoke test against a real install for each release, because admin-panel integration (menus, permissions, layout) is exactly what testbench can't verify.
Local iteration loop. path repository + symlink, php artisan view:clear && php artisan config:clear && php artisan cache:clear after provider or config changes, then reload the admin page. Automate that clear-and-reload into a Composer script; you will run it hundreds of times.
"1.0.3", not "^1.0") until you've read the source, and vendor-review the boot() path before shipping. The API can change between patch releases without a large user base to complain about it.composer show magna-cms/plugin-sdk and don't trust the metadata for version selection.config:cache/route cache holding a stale provider list. Clear all three caches before debugging your own code.composer.json conflict block.Schema::hasTable() guards and never drop a table another plugin might touch.vendor/. With the symlinked path repository it's tempting, and it will silently diverge from what other developers get. If the SDK genuinely lacks an extension point, subclass it in your own package and bind the subclass — don't patch in place.config/logging.php) so plugin noise doesn't drown the host's logs.php artisan queue:restart — otherwise hooks fire against old code and the failure looks like a random logic bug.How can I help you explore Laravel packages today?