From folder to activation.
Layout
plugins/my-plugin/
plugin.json
src/MyPluginServiceProvider.php
routes/admin.php
routes/public.php # optional
views/
migrations/
composer.json # optional third-party deps
Slug rules
Directory name must match plugin.json → slug: lowercase letters, numbers, hyphens only (^[a-z0-9]+(?:-[a-z0-9]+)*$).
Minimal plugin.json
{
"name": "My Plugin",
"slug": "my-plugin",
"version": "1.0.0",
"author": "Example Co",
"main_class": "MyPlugin\\MyPluginServiceProvider"
}
Service provider
<?php
namespace MyPlugin;
use App\Plugin\PluginBootContext;
use App\Plugin\PluginServiceProviderInterface;
final class MyPluginServiceProvider implements PluginServiceProviderInterface
{
public function boot(PluginBootContext $context): void
{
$context->registerAdminNavItem('My plugin', 'plugin.my_plugin.admin');
}
}
Activate
- Copy plugin into
plugins/my-plugin/or install from catalog. - Run
composer plugin-deps:prodif the plugin hascomposer.json. - Go to Extensions → Plugins.
- Review compatibility report.
- Click Activate — migrations run,
boot()executes.
Catalog install
Extensions → Plugins → Browse catalog installs from struxapoint.com/struxa-dist/repo.json (or STRUXA_DIST_CATALOG_URL). After install, activate separately.
Troubleshooting
- Activation blocked — Read compatibility report: PHP version, CMS version, missing dependencies, conflicts.
- Class not found — Check
main_classand PSR-4 autoload inplugin.json.