Public pages and theme integration
Public plugin surfaces belong to an organization's visitor-facing site. The plugin owns behavior and data; the active theme owns the shell, typography, spacing, and responsive presentation.
Theme slots
Declare required slots in plugin.json, then render only those slots from SitePlugin::render():
{
"requires": {
"capabilities": ["slots.home_after_hero.v1"]
},
"slots": ["home_after_hero"],
"slot_priorities": {
"home_after_hero": 30
}
}
public function render(
PluginSlot $slot,
PluginRenderContext $context,
array $settings,
): ?View {
if ($slot !== PluginSlot::HomeAfterHero || $context->path !== null) {
return null;
}
return view('plugin.orders::site.featured', compact('context', 'settings'));
}
The current slots are home_after_hero, page_after_content, and before_footer. Lower priority renders first.
Full public pages
Implement ContributesPages:
public function pages(): array
{
return [
new PluginPage(
id: 'orders',
slug: 'orders',
title: 'Orders',
showInNavigation: true,
layout: PluginPageLayout::FullWidth,
order: 40,
),
new PluginPage(
id: 'order',
slug: 'orders/{order}',
title: 'Order details',
showInNavigation: false,
layout: PluginPageLayout::Contained,
),
];
}
renderPage() returns PluginPageResponse. Static navigable pages merge into theme navigation. Dynamic placeholders capture one path segment and cannot be direct navigation links. Public page resolution happens before CMS slug resolution; activation blocks known CMS collisions.
Plugin-theme relationship
Business plugins depend on capabilities, not theme names. If a plugin requires pages, navigation, or slots, list those capabilities in the manifest. A compatible theme must render the matching slot and plugin-page partial.
Use direct theme constraints only for a real theme-addon whose markup is intentionally designed for named themes. Super Admin and organization dashboard surfaces are platform UI and never participate in theme compatibility.
Public actions
POST routes are separate from page declarations. Apply web, organization.route, enabled plugin availability, CSRF, throttling, bounded validation, and publication checks. Never assume a rendered form makes its action safe.
Preview and SEO
Drivers receive PluginRenderContext::$isPreview. Published routes hide drafts; signed preview may show them. Themes own canonical metadata and layout, while plugin page responses provide page titles and escaped content.
Fundraising demonstrates all three public patterns: a featured home slot, navigable project index, dynamic project detail, and a separately guarded donation POST.