The post editor is the surface authors use to edit a single resource
(post, page, custom CPT). It's mounted via the
<x-visual-editor /> Blade component and built on
top of @wordpress/block-editor, with chrome restyled to DaisyUI through
@artisanpack-ui/react.
This page is a tour of the surface: what's where, how to extend each region, what API endpoints back it.
1. Layout
┌───────────────────────────────────────────────────────────────────────┐
│ Topbar: Title · Status · Preview · Save · Inserter toggle │
├──────────────┬──────────────────────────────────────┬─────────────────┤
│ │ │ │
│ Block │ Canvas │ Inspector │
│ library │ (iframe-wrapped editor) │ sidebar │
│ sidebar │ │ │
│ │ │ │
├──────────────┴──────────────────────────────────────┴─────────────────┤
│ Footer: breadcrumbs, autosave indicator, block count │
└───────────────────────────────────────────────────────────────────────┘
- Topbar — document chrome (title, status, preview, save, inserter toggle).
- Block library sidebar (left, collapsible) — browsable list of all registered blocks, grouped by category. Also surfaces patterns.
- Canvas (center) — iframe-wrapped block editor. Isolated styles so the front-end theme renders inside without leaking out.
- Inspector sidebar (right) — block-level controls (alignment, color, typography, spacing, advanced).
- Footer — breadcrumbs through the block tree, autosave status, block count.
2. Canvas
The canvas is an iframe-wrapped BlockEditorProvider from
@wordpress/block-editor. Iframe isolation gives blocks access to the
theme's typography and color CSS without leaking editor chrome styles
into the content.
Theme CSS injection is driven by the active global-styles record (see
Global styles). The CSS is fetched from
GET /visual-editor/api/global-styles/lookup → GET /global-styles/{id}
on boot and injected into the iframe via the React renderer's
<GlobalStyles> component.
Block selection, drag-and-drop, undo/redo, and keyboard shortcuts come
from @wordpress/block-editor unchanged.
The topbar's View with template switch composes the resolved template's header and footer around the canvas as a read-only preview, so authors can judge their content in context without leaving the editor. Template chrome is edited in the site editor, reached from the composed canvas's Edit template ↗ deep link. See Composed view.
3. Inspector sidebar
The right sidebar renders InspectorControls for the currently selected
block. Every forked artisanpack/* block ships a complete control set:
- Alignment + dimensions
- Color (text, background, link, gradient)
- Typography (font family, size, line height, letter spacing)
- Spacing (margin, padding, block gap)
- Border (radius, style, width, color)
- Advanced (HTML anchor, additional CSS class)
Block authors add their own controls inside <InspectorControls> from
their edit.tsx — see Custom blocks §5.
The sidebar is also where the document-settings panel renders (status,
slug, excerpt, featured image, author, comments). Visibility is controlled
by the supports attribute on <x-visual-editor /> — fields you don't
want shown can be turned off without code changes.
4. Block library sidebar
Opens with the topbar inserter button. Lists every block returned by
GET /visual-editor/api/blocks, grouped by category (from block.json)
and filtered by the enabled-block allow/deny lists.
The same panel also surfaces patterns — both synced (referenced from the pattern store) and unsynced (template snippets to drop inline). See Patterns.
Slash command (typed inline in any rich-text block) routes through the
same registry — /heading, /image, /pattern hero, etc.
5. Media library integration
Image, cover, video, audio, file, and post-featured-image blocks all
route media picking through Gutenberg's editor.MediaUpload hook.
The package ships two implementations:
- Stub (
media-bridge/media-upload-stub.tsx) — registered by default. Shows a placeholder picker that does nothing. Useful in the dev sandbox and in apps that don't have a media library yet. - Real bridge — host apps that ship
artisanpack-ui/media-library(or any compatible store) callregisterArtisanpackMediaBridge(MediaModal, uploadMedia)from@artisanpack-ui/visual-editorbefore mounting the editor. The bridge swaps the stub for aMediaModalthat opens the host's picker UI.
import { registerArtisanpackMediaBridge } from '@artisanpack-ui/visual-editor';
import { MediaModal, uploadMedia } from '@artisanpack-ui/media-library';
registerArtisanpackMediaBridge(MediaModal, uploadMedia);
Selected media is fetched server-side from
GET /visual-editor/api/attachments/{id} and returned in the
WordPress-shape Attachment object Gutenberg blocks expect (id,
source_url, alt_text, media_details).
The active bridge slug is recorded in
config('artisanpack.visual-editor.media.bridge') (default
'artisanpack-ui/media-library'); the server-side adapter that
converts host media records into WP-shape attachments is set in
config('artisanpack.visual-editor.media.adapter') (default:
GutenbergAttachmentAdapter). Swap the adapter to integrate with a
different media store.
6. Document settings panel
Inside the inspector sidebar, the document panel exposes:
| Field | Source | supports key |
|---|---|---|
| Title | :initialTitle |
always shown |
| Slug | :initialSlug |
always shown |
| Status | :initialStatus |
always shown |
| Excerpt | :initialExcerpt |
excerpt |
| Featured image | :initialFeaturedImage |
featuredImage |
| Author | :initialAuthorId + :authorOptions |
always shown |
| Comments | :initialCommentsOpen |
comments |
Pass supports = ['excerpt' => true, 'featuredImage' => false, 'comments' => true]
to opt fields in or out — see Blade component reference.
Document-field changes write back to the model via the same content endpoint, batched with block changes.
Since v1.15.3 (#992), Post Title, Post Excerpt and Post Content blocks
in the canvas show the entry being edited, for posts, pages and custom
content types. Title and excerpt are editable inline and stay in sync
with the Title and Excerpt fields above; Post Content shows a read-only
preview of the canvas. For custom content types without
onMetadataChange, title and excerpt are saved through
PUT /visual-editor/api/{resource}/{id}/entry (see
Content model).
7. Autosave + save flow
- Author edits a block.
- After ~1s of idle, the editor dispatches
ve:editor:changeonwindow. - The autosave request fires:
PUT /visual-editor/api/{resource}/{id}/content. - On 200, the editor dispatches
ve:editor:autosavewith{ resource, id, blocks, updatedAt }. - ⌘S or topbar Save bypasses the debounce and dispatches
ve:editor:savewith the same payload.
See Livewire integration for the pattern of bridging these events back to a server-rendered shell.
8. Keyboard shortcuts
Standard Gutenberg shortcuts: ⌘B/⌘I/⌘U, ⌘K (link),
⌘⇧K (unlink), ⌘Z/⌘⇧Z (undo/redo), ⌘⌥M (insert media),
⌘S (save), / (slash inserter), ?? (open shortcut help modal).
The shortcut help modal is restyled with @artisanpack-ui/react's
Modal so it picks up the host theme.
9. Embedding
The post editor is the same surface whether mounted via Blade, Livewire, or Inertia. Embedding recipes:
See also
- Blade component reference
- Composed view — edit content inside its resolved template
- Custom blocks
- Renderers — get saved content back onto the public site
- Theming — restyle editor chrome

