Events & Modules
Hook into lifecycle events and extend the core with first-class modules.
Event system #
VelvetCMS\Core\EventDispatcher is a tiny pub/sub utility:
$events->listen('page.saved', function(Page $page) {
// fire webhooks, invalidate external cache, etc.
}, priority: 10);
- Listeners are stored per event with a priority (higher runs first).
dispatch()iterates listeners, allowing them to mutate and return a new payload.fire()is an alias when you do not care about the return value.- Core fires events such as
app.booting,page.loading,page.saved,cache.hit,markdown.parsed,exception.reporting, etc.
Module lifecycle #
The lifecycle is still discover → compile → load → register → boot, but all of the manifest formats, CLI workflows, and troubleshooting steps now live under Module Basics and State & Tooling. This section concentrates on how modules interact with events: once compiled, ModuleManager instantiates each entry class, calls register() so you can bind services/listeners, then boot() so you can attach routes, commands, and theme paths. Example: the Docs module adds documentation routes under its configurable base path (defaults to /docs) and injects its template path via $theme->addPath($module->path('theme')).
Manifests #
Every module ships a module.json defining metadata, dependencies, and config. See Module Basics for the full schema.
ModuleManager::validate() ensures:
- Entry class exists and implements
VelvetCMS\Contracts\Module. - Version constraints against
core,php, and other modules pass viaVersionRegistry::satisfies()(usescomposer/semver). - Conflicts list is respected.
BaseModule helper #
Extend VelvetCMS\Core\BaseModule for conveniences:
$this->path('theme')resolves files relative to the module root.name(),version(),description()read from manifest.manifest()exposes the raw JSON data.
Enabling/disabling modules #
Refer to State & Tooling for the exact CLI commands. Architecturally, toggling state only edits storage/modules.json; compilation reads that file to determine which manifests stay in the load order.
Version registry #
VelvetCMS\Core\VersionRegistry aggregates version metadata for the core and modules. It loads config/version.php, merges compiled module data, and gives you:
$registry = VersionRegistry::instance();
$registry->getVersion('core');
$registry->isCompatible('docs', 'core');
$registry->getModulesRequiringCore('^1.0');
CLI commands like version and list use it to display readable status lines.
Use events + modules to customize VelvetCMS without forking the core—the entire architecture was built for that.