Visual Editor - v1.0.0
Patterns
Patterns are reusable block snippets that authors drop into post or template content. They come in two flavours — synced (referenced by id; edits propagate everywhere the pattern is used) and unsynced (inlined at insert time; later edits don't propagate).
This page covers the two flavours, authoring patterns in the site editor, the library + inserter integration, and the REST surface.
1. Synced vs unsynced
| Aspect | Synced | Unsynced |
|---|---|---|
| Storage | Pattern store (wp_block shape) — one canonical record. |
Inlined into the host's block tree at insert time. |
| Reference | core/block block with { ref: <id> }. |
Inlined raw blocks. |
| Editing | Edit once, updates everywhere. | Edit per-page; original pattern untouched. |
| Use case | Site-wide hero, repeating CTA, footer disclaimer. | Layout starter, "boilerplate" insertable, theme starter content. |
Synced patterns are persistent first-class entities with a slug, title, content, and lifecycle. Unsynced patterns are template fragments — they live in the pattern library but produce inlined blocks when inserted.
The flavour is set at authoring time: every pattern record has a
synced: bool field that decides which behaviour applies on insert.
2. Authoring patterns
The Patterns section of the site editor's navigator lists every pattern the system knows about, grouped by source (theme / user) and category.
Create
The "New pattern" button prompts for:
- Title
- Slug (auto-generated from title; editable)
- Synced toggle
- Category (any string; auto-suggests from existing categories)
- Block types (optional — restrict which blocks the pattern can be
inserted near; matches Gutenberg's
blockTypesfilter)
The pattern then opens in the canvas — author it like any other block tree and save.
Edit
Click a pattern in the navigator to load it into the canvas. For synced patterns, edits update every page that references the pattern on next render. For unsynced patterns, edits only affect future inserts — existing inline copies stay as-is.
Delete
Delete from the navigator's overflow menu. For synced patterns this breaks every reference (the renderer emits an empty placeholder). Delete with care; the editor surfaces a "this pattern is referenced N times" warning before confirming.
3. The pattern library and inserter
Patterns appear in two places in the editor:
- Inserter sidebar — Patterns tab, grouped by category, searchable. Drag a pattern into the canvas to insert.
- Site-editor navigator — Patterns section, listing all patterns for authoring.
Filtering: the inserter filters by category and by the pattern's
blockTypes restriction. A pattern with blockTypes: ['core/group']
only appears when a group is selected.
4. The core/block block (pattern reference)
Synced patterns render via the core/block block:
{
"name": "core/block",
"attributes": { "ref": 42 }
}
Attributes:
| Attribute | Type | Purpose |
|---|---|---|
ref |
number | The pattern's id in the pattern store. |
On render, the resolver looks up the pattern record by id and inlines its content. Missing references emit an empty placeholder.
Unsynced patterns produce no core/block block — they paste raw blocks
into the host tree at insert time. From the renderer's perspective an
unsynced pattern is invisible after insertion.
5. Theme-provided patterns
Themes can ship patterns alongside templates by declaring them in config:
// config/artisanpack/visual-editor.php
'site-editor' => [
'patterns' => [
'hero' => [
'title' => 'Hero',
'categories' => ['layout'],
'content' => '<!-- wp:cover {...} --><!-- /wp:cover -->',
],
],
],
Static patterns are merged with DB-stored user patterns. They show up in the inserter alongside user-created patterns and get a "theme" badge in the navigator. Editing a theme pattern in the site editor creates a user override (same fallback-chain pattern as templates).
6. REST API
| Method | Path | Purpose |
|---|---|---|
GET |
/visual-editor/api/patterns |
List patterns (filter by ?category=... or ?synced=true). |
POST |
/visual-editor/api/patterns |
Create a pattern. |
GET |
/visual-editor/api/patterns/{slug} |
Fetch a pattern. |
PUT |
/visual-editor/api/patterns/{slug} |
Update a pattern. |
DELETE |
/visual-editor/api/patterns/{slug} |
Delete a user pattern. |
The slug regex allows user/<slug> segments — cms-framework's user-source
patterns are namespaced this way to keep them distinct from theme patterns.
7. Categories
Pattern categories are free-form strings. Common conventions:
featured— patterns surfaced first in the inserter.layout— full-page or full-section starters.text— text-heavy snippets (testimonial, quote, CTA).media— media-heavy snippets (hero, gallery, video).header/footer— chrome patterns.
The inserter groups patterns by category and shows the most-used category first.
8. Rendering on the public site
The Blade renderer's <x-ve-blocks> resolves core/block references by
calling the pattern resolver and inlining the content. The React and Vue
renderers fetch via GET /visual-editor/api/patterns/{slug} and inline
client-side.
Performance: synced patterns are cached per request — a page that references the same pattern five times only fetches once. For long-term caching across requests, wrap the pattern resolver in a Laravel cache or decorate it.
9. Pattern locking
Patterns can lock their contained blocks against editing — useful for "do not modify" boilerplate:
{
"name": "core/group",
"attributes": {
"templateLock": "all" // "all" | "insert" | "contentOnly" | false
},
"innerBlocks": [ /* ... */ ]
}
all — no move, no insert, no remove. insert — no insert/remove but
can rearrange. contentOnly — only edit text/media within blocks, not
structure. See WordPress's block locking documentation
for the full contract.
See also
- Site editor — the surface that edits patterns
- Templates — patterns inside templates
- Renderers — rendering
core/blockreferences