@10up/block-renderer
v0.1.10
Published
Generate valid WordPress block markup from JSON - AI-friendly block generation
Readme
@10up/block-renderer
Main package for Block Renderer - generate valid WordPress block markup from AI-friendly JSON structures.
Installation
npm install @10up/block-renderer
# or
pnpm add @10up/block-rendererOverview
This is the unified package that:
- Provides a CLI - Start MCP servers and generate prompts
- Re-exports all sub-packages - Use any functionality with a single import
- Includes debug commands - Generate documentation of your WordPress setup
The Problem
When AI generates WordPress block markup directly, it often produces invalid output:
- Incorrect HTML comment syntax
- Malformed JSON in attributes
- Missing closing tags
- Invalid nesting
The Solution
AI generates a constrained JSON structure, and this package renders it to valid WordPress markup using native @wordpress/blocks serialization.
{
"root": "para-1",
"elements": {
"para-1": {
"key": "para-1",
"type": "core/paragraph",
"props": { "content": "Hello world" }
}
}
}Becomes:
<!-- wp:paragraph -->
<p>Hello world</p>
<!-- /wp:paragraph -->CLI Usage
Start MCP Server
For AI assistant integration (Claude, Cursor, etc.):
# Basic server
block-renderer mcp-server
# With theme (recommended)
block-renderer mcp-server --theme /path/to/theme
# With preferences
block-renderer mcp-server --theme /path/to/theme --preferences ./prefs.jsonGenerate AI System Prompt
Generate a system prompt for AI assistants:
# Generate prompt
block-renderer generate-prompt --theme /path/to/theme
# Compact mode for smaller context
block-renderer generate-prompt --theme /path/to/theme --compact
# With preferences
block-renderer generate-prompt --theme /path/to/theme -p ./prefs.jsonDebug Commands
Generate markdown documentation of your WordPress setup:
# First, create a config file in your theme
# .block-renderer/config.json
# { "themePath": "../" }
# Then run from theme directory:
block-renderer debug:tokens # Lists color, spacing, typography tokens
block-renderer debug:blocks # Lists all blocks with attributes
block-renderer debug:patterns # Lists available patterns
block-renderer debug:css-variables # Lists CSS custom propertiesOutput files are written to .block-renderer/ directory.
CLI Options
Options:
-t, --theme <path> Path to WordPress theme directory
-p, --preferences <path> Path to preferences file
-c, --compact Use compact output format
-h, --help Show help
-v, --version Show versionProgrammatic Usage
Render Blocks
import {
setupBrowserEnvironment,
registerCoreBlocks,
renderBlockTree
} from '@10up/block-renderer';
// Setup environment (required once)
setupBrowserEnvironment();
await registerCoreBlocks();
// Render a block tree
const tree = {
root: 'group-1',
elements: {
'group-1': {
key: 'group-1',
type: 'core/group',
props: { layout: { type: 'constrained' } },
children: ['heading-1', 'para-1']
},
'heading-1': {
key: 'heading-1',
type: 'core/heading',
props: { content: 'Welcome', level: 2 },
parentKey: 'group-1'
},
'para-1': {
key: 'para-1',
type: 'core/paragraph',
props: { content: 'Hello world!' },
parentKey: 'group-1'
}
}
};
const markup = renderBlockTree(tree);Validate Trees
import { validateTree, parseTheme, loadPatterns } from '@10up/block-renderer';
const theme = parseTheme('/path/to/theme');
const patterns = loadPatterns('/path/to/theme');
const result = validateTree(tree, {
tokens: theme.tokens,
patterns
});
if (!result.valid) {
console.log('Errors:', result.errors);
}Parse Theme
import { parseTheme } from '@10up/block-renderer';
const theme = parseTheme('/path/to/theme');
console.log(theme.tokens.colors.palette);
console.log(theme.tokens.typography.fontSizes);
console.log(theme.tokens.spacing.spacingSizes);Load Patterns
import { loadPatterns } from '@10up/block-renderer';
const patterns = loadPatterns('/path/to/theme');
for (const [slug, pattern] of patterns) {
console.log(slug, pattern.title);
}Generate Prompts
import { generateSystemPrompt, parseTheme, loadPatterns } from '@10up/block-renderer';
const theme = parseTheme('/path/to/theme');
const patterns = loadPatterns('/path/to/theme');
const prompt = generateSystemPrompt({
tokens: theme.tokens,
patterns,
compact: true
});Load Preferences
import { loadPreferences, formatPreferencesForPrompt } from '@10up/block-renderer';
const prefs = loadPreferences('/path/to/project');
const promptSection = formatPreferencesForPrompt(prefs);MCP Server Integration
The recommended approach is per-project configuration.
Setup (Recommended)
- Create workspace config in your project root at
.block-renderer/config.json:
{
"themePath": "./wp-content/themes/your-theme",
"ignite": true,
"prettyPrint": true
}- Create MCP client config for your IDE:
Cursor IDE
Create .cursor/mcp.json in project root:
{
"mcpServers": {
"block-renderer": {
"command": "npx",
"args": ["@10up/block-renderer-mcp-server"]
}
}
}Claude Code
Create .claude/settings.json in project root:
{
"mcpServers": {
"block-renderer": {
"command": "npx",
"args": ["@10up/block-renderer-mcp-server"]
}
}
}Claude Desktop
Add to global config (~/Library/Application Support/Claude/claude_desktop_config.json on macOS):
{
"mcpServers": {
"block-renderer": {
"command": "npx",
"args": [
"@10up/block-renderer-mcp-server",
"--config",
"/absolute/path/to/your/project"
]
}
}
}The server automatically watches for file changes and reloads theme tokens, patterns, and blocks.
Re-exports
This package re-exports from all sub-packages:
| Package | Exports |
|---------|---------|
| @10up/block-renderer-core | Types: BlockTree, BlockElement, BlockDefinition, etc. |
| @10up/block-renderer-block-schemas | generateBlockDefinition |
| @10up/block-renderer-theme-json | parseTheme, parseThemeJson |
| @10up/block-renderer-patterns | loadPatterns, scanPatterns |
| @10up/block-renderer-serializer | setupBrowserEnvironment, renderBlockTree, registerCoreBlocks, etc. |
| @10up/block-renderer-validator | validateTree, createTreeValidator, etc. |
| @10up/block-renderer-preferences | loadPreferences, formatPreferencesForPrompt |
| @10up/block-renderer-prompt-generator | generateSystemPrompt, generateMinimalPrompt |
Block Tree Format
The JSON format uses a flat structure with key references:
interface BlockTree {
root: string; // Key of root element
elements: Record<string, BlockElement>; // Map of key -> element
}
interface BlockElement {
key: string; // Unique identifier
type: string; // Block name, e.g., "core/paragraph"
props: Record<string, unknown>; // Block attributes
children?: string[]; // Keys of child elements
parentKey?: string; // Key of parent element
}Why Flat Structure?
- Easier for AI to generate - No deep nesting means fewer bracket-matching errors
- Easier to validate - Each element can be validated independently
- Easier to reference - Elements can reference siblings without knowing the full tree
Design Tokens
Use WordPress design token syntax for theme-aware values:
{
"type": "core/group",
"props": {
"backgroundColor": "primary",
"style": {
"color": { "text": "var:preset|color|contrast" },
"spacing": { "padding": { "top": "var:preset|spacing|50" } }
}
}
}Token Formats
| Format | Example | Use Case |
|--------|---------|----------|
| Slug only | "primary" | Direct attributes like backgroundColor |
| CSS var reference | "var:preset\|color\|primary" | Inside style object |
Common Block Examples
Paragraph with Styling
{
"root": "para",
"elements": {
"para": {
"key": "para",
"type": "core/paragraph",
"props": {
"content": "Styled paragraph text",
"fontSize": "large",
"textColor": "primary"
}
}
}
}Columns Layout
{
"root": "cols",
"elements": {
"cols": {
"key": "cols",
"type": "core/columns",
"children": ["col1", "col2"]
},
"col1": {
"key": "col1",
"type": "core/column",
"props": { "width": "66.66%" },
"children": ["content"],
"parentKey": "cols"
},
"col2": {
"key": "col2",
"type": "core/column",
"props": { "width": "33.33%" },
"children": ["sidebar"],
"parentKey": "cols"
},
"content": {
"key": "content",
"type": "core/paragraph",
"props": { "content": "Main content" },
"parentKey": "col1"
},
"sidebar": {
"key": "sidebar",
"type": "core/paragraph",
"props": { "content": "Sidebar" },
"parentKey": "col2"
}
}
}Using a Pattern
{
"root": "pattern",
"elements": {
"pattern": {
"key": "pattern",
"type": "core/pattern",
"props": { "slug": "theme/hero-section" }
}
}
}License
MIT
