Carve Markup for WordPress
August 10, 2026 · View on GitHub
A WordPress plugin for the Carve markup language - a Djot-inspired, post-Markdown dialect.
Render Carve in posts, pages and comments, powered by the markup-carve/carve-php engine.
Features
- Carve rendering in posts/pages (per-post "Render as Carve" toggle), the
[carve]…[/carve]shortcode, and comments. - Gutenberg block with a source editor and preview. Its optional Tiptap visual editor loads directly from the Carve AST and preserves unsupported constructs as source instead of dropping them through an HTML conversion.
- In-browser live preview. Carve has a real JS engine (
@markup-carve/carve), so the block previews instantly client-side, no server round-trip. Runnpm run buildto bundle the engine (assets/js/vendor/carve.js); without it the editor falls back to the REST render endpoint. - Content profiles (
full/article/comment/minimal) + safe mode (XSS hardening) via carve-php'sProfile+SafeMode. - Table of contents, heading permalinks, smart quotes, Mermaid, tab normalization, Torchlight syntax highlighting - carve-php extensions, toggled in settings.
- Media embeds via
:youtube[ID]/:vimeo[ID]/:media[URL], with a WordPress oEmbed fallback when the media-embed extension is off. - Multi-format paste. Paste Markdown / Djot / BBCode / HTML and convert to Carve in place, using carve-php's
*ToCarveconverters.POST /wp-json/carve/v1/ingest. - Frontmatter → meta/SEO. Typed
---yaml/---json/---tomlfrontmatter maps to excerpt, SEO description (Yoast/AIOSEO when present), canonical, and_wpcarve_frontmattermeta. Non-destructive. - Bulk migrate: convert existing posts to Carve in bulk.
wp carve migrate- analyzes each post (skips block-editor / foreign-shortcode content), auto-detects Markdown vs HTML, converts safely (--dry-run,--force); or Tools → Carve Migrate for the same thing without CLI (the post list doubles as the dry-run preview).wp carve lint- read-only health check reporting render errors and visual-editor round-trip caveats. - Import / export: Tools → Carve Import loads a Markdown / Djot / HTML / Carve file as a draft; an "Export Carve" row action downloads a post's
.crvsource. - Render caching + REST. Rendered HTML is cached in post meta at save (fast views);
POST /wp-json/carve/v1/renderserves headless WordPress.
Requirements
- PHP 8.2+, WordPress 6.3+ (the blocks use Block API v3)
Installation (from source)
cd wp-content/plugins
git clone https://github.com/markup-carve/wp-carve.git
cd wp-carve
composer install --no-dev
npm install && npm run build # optional: enables innovation A (instant preview)
Activate "Carve Markup", then configure under Settings → Carve Markup.
REST API
| Route | Body | Returns |
|---|---|---|
POST /wp-json/carve/v1/render | { carve, context } | { html } |
POST /wp-json/carve/v1/ingest | { source, from } | { carve, from } |
Both require the edit_posts capability.
Hooks
wpcarve_rendered_html(filter):(string $html, string $carve, string $context)wpcarve_converter(action):(\MarkupCarve\Carve\CarveConverter $converter, string $context)- register further carve-php extensions.wpcarve_source(filter):(string $carve, string $context)- modify source before conversion.
See docs/hooks.md for the full list (oEmbed, OG image, diagram renderer API, KaTeX base).
Documentation
See docs/: settings,
profiles & rendering, hooks,
WP-CLI, Carve syntax.
Roadmap
- Visual editor: a Tiptap WYSIWYG editor ships behind the
visual_editor_modesetting; headings, marks, lists, quotes, code blocks, tables, math, footnotes, admonitions and nested containers (tabs, code-groups) all round-trip (see docs/visual-editor.md). Interactive per-widget editing of tabs/code-groups (a tab bar in the editor) is future work. - Native per-construct blocks (admonition, code-group, table-with-spans).
- Lossless HTML ↔ Carve round-trip editing.