CMS Framework - v2.2.2
Site Editor - Hooks and Events
The Site Editor module exposes its resolved entities through the ap.visual-editor.* filter family. These filters are how the optional artisanpack-ui/visual-editor package consumes cms-framework's templates, patterns, global styles, and menus.
Added in 2.0.0.
All filter registrations are gated behind class_exists(ArtisanPackUI\VisualEditor\VisualEditor::class) so cms-framework boots cleanly when visual-editor isn't installed.
Filter registrations
| Filter name | Shape | Source |
|---|---|---|
ap.visual-editor.templates |
array<string, ResolvedEntity> keyed by slug |
TemplateResolver::all() |
ap.visual-editor.template-parts |
array<string, ResolvedEntity> keyed by slug |
TemplatePartResolver::all() |
ap.visual-editor.patterns |
array<string, array> keyed by storage slug |
PatternResolver::toFilterMap() |
ap.visual-editor.global-styles |
?ResolvedGlobalStyles (singleton, nullable) |
GlobalStylesResolver::resolve() |
ap.visual-editor.navigation |
array<string, array> keyed by location |
MenuResolver::all() |
ap.visual-editor.resources |
array<class-string, array> of registered content types |
Auto from HasBlockContent adopters |
Merge behavior
For the keyed-map filters (templates, template-parts, patterns, navigation), cms-framework's resolved map merges under the existing map so app-level config or earlier filter contributors win on key collision.
For the singleton global-styles filter, cms-framework replaces the value (returning its own ResolvedGlobalStyles when one resolves and falling through otherwise).
For resources, cms-framework merges its content-type registrations into the existing array.
Schema guards
All filter callbacks check Schema::hasTable() for their backing tables before resolving. This lets cms-framework boot during CI bootstrap and fresh installs where migrations haven't run yet. When a table is missing, the callback returns the existing filter value unchanged.
Adding your own filter consumers
The filters are dispatched via the artisanpack-ui/hooks package. Listen to them with addFilter():
use function addFilter;
addFilter('ap.visual-editor.patterns', function (array $patterns): array {
// Add a runtime-generated pattern to the editor inserter
$patterns['my-app/dynamic-pattern'] = [
'name' => 'my-app/dynamic-pattern',
'title' => 'Dynamic Pattern',
'description' => 'A pattern generated by app code.',
'content' => '<!-- wp:paragraph --><p>Hi</p><!-- /wp:paragraph -->',
'categories' => ['featured'],
'block_types' => [],
'source' => 'app',
'synced' => false,
];
return $patterns;
});
Blade directives
@cmsGlobalStyles
Renders a <style id="cms-global-styles"> block with the resolved global-styles CSS. Themes opt in by including this directive in their root layout:
<head>
@cmsGlobalStyles
</head>
The output is cached on a content-hash key; the cache busts on GlobalStyles model saves and deletes via a model observer wired in SiteEditorServiceProvider.
Model events
The GlobalStyles model has a registered observer (in SiteEditorServiceProvider::boot()) that:
- On
saved— invalidates theGlobalStylesEmittercache so the next render re-emits CSS. - On
deleted— same.
This is the only event-driven cache invalidation in the module; the other entities resolve fresh on each request (and lean on per-request request-local caches where appropriate).