Wiring screens into the admin and public site.
Admin routes
routes/admin.php:
<?php
use Slim\App;
use App\Plugin\PluginBootContext;
use App\Middleware\RequireCmsStaff;
return function (App $app, PluginBootContext $ctx): void {
$app->group('/admin', function ($group) use ($ctx) {
$group->get('/my-plugin', $handler)->setName('plugin.my_plugin.admin');
})->add(new RequireCmsStaff($ctx->auth(), $ctx->pdo()));
};
Register nav item
In boot():
$context->registerAdminNavItem('My plugin', 'plugin.my_plugin.admin');
Public routes
routes/public.php registers storefront paths. Reserve URL segments in boot():
$context->registerPluginReservedSlugs(['my-catalog']);
Twig views
Render with namespace @plugin_my_plugin/... (hyphens in slug become underscores):
return $twig->render($response, '@plugin_my_plugin/dashboard.twig', $data);
Plugin public pages that use the core marketing shell should extend public/root.twig. Storefront-themed plugin pages extend the active theme's layouts/base.twig.
CSRF and permissions
POST forms need CSRF tokens via Twig helpers. Check staff permissions inside handlers for sensitive operations beyond login gate.
Conditional load
"load": { "public": false, "admin": true, "cli": true }
Skips public boot cost for admin-only plugins.