Every supported way for a plugin or theme to plug into TruCMS, with the exact call and where it belongs. If what you need is not here, it is not an extension point yet; see what is not open yet.
register(): Container bindings, mergeConfigFrom(), config arrays you extend (replacers)boot(): Everything the public site, the bake endpoint, async widgets or jobs needAdminBooting: Admin-only registries: sidebar, settings, menu-builder sourcesmodule.json, migrations, views and theme overrides| Extension point | Call | Where | Guide |
|---|---|---|---|
| Admin request hook | Event::listen(AdminBooting::class, fn () => ...) | boot() | Service provider |
| Sidebar entry | MenuManager::make(string $key, fn (MenuItems $item) => ..., ?int $order) | AdminBooting | Admin menu |
| Sidebar child | MenuManager::get($key)?->subMenu(string $key, callable) | AdminBooting | Admin menu |
| Remove a core entry | MenuManager::remove($key) | AdminBooting | Admin menu |
| Settings section or tab | SettingsManager::add(['id' => ..., 'title' => ..., 'link' => [...], 'pages' => fn () => [...]]) | AdminBooting | Settings |
| Dashboard row and item | Dashboard::admin()->row($name, $order)->widget($id, $class, async: true) | boot() | Dashboard |
| Visitor account dashboard | Dashboard::user()->row(...)->widget(...) | boot() | Dashboard |
| Your own dashboard | Dashboard::for('alias.dashboard') + @dashboard('alias.dashboard') | boot() + view | Dashboard |
| Breadcrumbs | Breadcrumbs::for('admin.alias.index', fn (Trail $trail) => ...) | routes/breadcrumbs.php required in boot() | Breadcrumbs |
| Permissions | Permission::findOrCreate('manage alias', 'web') + ->can() | Migration or seeder; routes | Permissions |
| Extension point | Call | Where | Guide |
|---|---|---|---|
| Block category | Shortcode::category(string $id, string $label, int $priority = 100) | boot() | Shortcodes |
| Shortcode (block) | Shortcode::registerIfMissing(MyShortcode::class) + Blade::component(...) | boot() | Shortcodes |
| Replace a block | Shortcode::replace(MyBlogShortcode::class) | boot() | Shortcodes |
| Assets by content marker | Shortcode::registerMarker('data-my-widget', ['vite' => [...]]) | boot() | Shortcodes |
| AI visibility of a block | ShortcodeDefinition::make(...)->ai(['enabled' => false]) | Shortcode definition | AI assistant |
| Data-bound section source | app(BindingSourceRegistry::class)->register(new MyBindingSource) | boot() | Data-bound sections |
| Front widget | Widgets::register('alias-name', MyWidget::class) | boot() | Widgets |
| Menu-builder link source | MenuBuilder::register('alias-menu', fn (MenuContainer $menu) => ...) | AdminBooting | Menus |
| Page type | AppPages::register(PageDefinition::make('alias.page')->selectedBySetting(...)->pageSetup(...)) | boot() | Page types |
| Public URL for a model | implements ResolvableSlug, use HasSlug, resolvedSlugRenderer() | Model | Resolvable slugs |
| Back-fill support for your model | config(['slugs.models' => [...config('slugs.models'), MyModel::class]]) | boot() | Resolvable slugs |
| Reserve URL segments | "public_paths": ["alias"] | module.json | Manifest |
| Template-library layouts | resources/page-templates + a seeder using TemplateSources::module('Name') | Module files | Template library |
| Extension point | How | Guide |
|---|---|---|
| Restyle a plugin from a theme | resources/themes/{theme}/vendor/{alias}/... overrides {alias}::... views | Routes and views |
| Site-level string overrides | lang/modules/{alias}/{locale}/*.php (with the namespaced registerTranslations()) | Localization |
| Theme options | Entries in the theme's theme.jsondefaults | Theme options |
| Per-request option overrides | set_theme_option(), override_theme_options() | Theme options |
| Child theme | "extends": "echo" in a new theme.json | Creating a theme |
| Extension point | Call | Guide |
|---|---|---|
| Flush cached pages when data changes | ResponseCacheInvalidator::flushWhenChanged([Model::class]) (automatic for BaseModel) | Caching |
| Keep a page out of the cache | CacheProfile::keepOutOfCache(), CacheProfile::GUESTS_ONLY | Caching |
| Per-visitor fragments in cached pages | Append a replacer class to config('responsecache.replacers') | Caching |
| Scheduled task | protected function configureSchedules(Schedule $schedule): void | Events and jobs |
| Artisan command | protected array $commands = [...] | Events and jobs |
| React to payments | Listen to Vanilo\Payment\Events\PaymentCompleted and siblings | Payments |
| React to refunds | Modules\TruPayments\Events\RefundCreated, RefundStatusChanged | Payments |
| React to tickets and registrations | TicketOpenEvent, TicketMessageEvent, TicketCloseEvent, Registered | Events and jobs |
| Extension point | Call | Guide |
|---|---|---|
| Take payments for a record | app(PaymentManager::class)->createFromPayable($payable, $method, $extra) | Payments |
| New gateway: admin metadata | GatewaySettings::registerGateway('key', ['label' => ..., 'class' => ..., 'required_credentials' => [...]]) | Add a gateway |
| New gateway: registry | Vanilo\Payment\PaymentGateways::register($id, Gateway::class) | Add a gateway |
| Offer methods to your module only | "payments": true in module.json, then availableMethods(context: 'yourmodule') | Payments |
For plugins that extend the shop rather than the CMS. Read the TruCommerce module code before using them; they follow the e-commerce framework TruCommerce is built on.
| Registry | Adds |
|---|---|
Vanilo\Shipment\ShippingFeeCalculators::register($id, $class) | Shipping fee calculator types. TruCommerce only offers calculators that implement its ConfigurableShippingCalculator contract (form fields, availability, calculation); see Modules/TruCommerce/app/Support/Shipping |
Vanilo\Promotion\PromotionRuleTypes::register(), PromotionActionTypes::register() | Promotion conditions and effects |
Vanilo\Properties\PropertyTypes::register() | Product attribute (property) types |