From data-liberation
Converts a page's raw HTML into WordPress block-editor markup using design tokens and a screenshot. Call per-page after extraction to produce `post_content` that renders with the theme's tokens and patterns.
How this skill is triggered — by the user, by Claude, or both
Slash command
/data-liberation:compose-page-blocksThis skill is limited to the following tools:
The summary Claude sees in its skill listing — used to decide when to auto-load this skill
You compose **one page's** WordPress block markup from its source HTML and, when supplied, a screenshot, using the site's design foundation. The streaming watch loop calls you per-URL; you produce a block-markup string and hand it to the runner via `liberate_block_compose` before the post is inserted.
You compose one page's WordPress block markup from its source HTML and, when supplied, a screenshot, using the site's design foundation. The streaming watch loop calls you per-URL; you produce a block-markup string and hand it to the runner via liberate_block_compose before the post is inserted.
You are NOT generating a theme. That's the replicate-with-blocks skill's job. Your output is post_content for one specific post — not template parts, not patterns the theme registers, just the inner content of one page.
The calling loop hands you, per invocation:
| Field | Type | Description |
|---|---|---|
url | string | Source URL (used for traceability + media-URL rewriting downstream) |
htmlPath | string | Absolute path to the sanitized rendered HTML file. Source HTML went through html-sanitize.ts upstream — script/iframe/object/embed tags, HTML comments, and on*= event handlers are already stripped. |
screenshotPath | string | Absolute path to the desktop screenshot (and .scrolled.png if present at the sibling path), or an explicit skipped-screenshot instruction when the active archetype template already captures the visual treatment |
designFoundationPath | string | Absolute path to the run's design-foundation.json |
archetype | enum | 'page' | 'post' | 'product' | 'gallery' | 'event' |
outputPath | string | Where to write the block-markup string |
Every non-skipped file is required. If an input file is missing or empty, return an error and do not write outputPath.
A single text file at outputPath containing valid WP block markup. The file must:
parse_blocks() — every <!-- wp:foo --> opens has a matching <!-- /wp:foo --> close (or is self-closed <!-- wp:foo /-->).output-verify.ts) checks every text node against the source's plain text. Any hallucinated phrase (rewriting "Foo Industries" as "Bar Inc.", inventing a tagline, generating fake testimonials) gets the entire output discarded.core/paragraph, core/heading, core/list, core/list-item, core/image, core/gallery, core/cover, core/columns, core/column, core/group, core/buttons, core/button, core/separator, core/spacer, core/quote, core/details, core/embed. Do not emit core/html, wp:html, or Custom HTML blocks. Avoid emitting any other block type unless the active replica theme has already registered a purpose-built custom block for this exact component.className. Every section that maps to a foundation role (e.g. accent surfaces, raised surfaces, inverse surfaces) carries the matching style slug (is-style-accent-primary, is-style-soft-card, etc.) in className. The list of registered styles is documented in references/post-content-conventions.md.You MUST NOT:
#0f4d7a directly. Use native slug attributes (backgroundColor, textColor) when the block exposes them; otherwise use a registered className style and let the theme define CSS in style.css or theme.json/block styles.<!-- wp:template-part {"slug":"header"} /-->). Template parts don't render inside post_content; they're a Site Editor concept. If a section "looks like" header/footer chrome in the screenshot, skip it — it's the theme's job, not yours.<script>, no raw <iframe> outside a core/embed block. The pre-skill sanitizer already removed these from input; do not reintroduce them.post_content.core/html / wp:html as an escape hatch for layout, CSS, forms, embeds, icons, or missing block types.<style> tags or inline style attributes to recreate a source section. CSS belongs in the active theme's style.css or theme.json/block styles. Use className hooks and foundation style slugs instead....). Reordering a clause, swapping a word, or writing a "punchier" version is paraphrase and is forbidden. If you can't find the supporting text in the source HTML for a slot, omit the slot or emit a clearly-marked [copy not captured] placeholder — NEVER "fill in plausible words." This applies to body copy just as strictly as to review/testimonial quotes; an earlier getsnooz build paraphrased section body copy ("Real fan-powered sound — no loops…") while the real line was in the captured HTML. Body-copy paraphrase HARD-FAILS the liberate_validate_artifacts provenance gate (body text must be substantially contained in the captured source) — do not bypass it.You MUST:
wp:cover for hero sections — large headline + subtext + optional CTA over a background. Pull url from any <img> directly inside the source's hero region; if no hero image, omit the cover and use wp:group with align: full instead.wp:columns + wp:column for multi-column layouts. Preserve the column count from the source. When a row holds 4 cards in the screenshot, emit 4 wp:column children. The verticalAlignment attribute should match the visual alignment in the screenshot.wp:group (with align: "full" or "wide") for full-bleed sections. Apply foundation surface tokens via backgroundColor slug.wp:gallery for image grids of 3+ images (e.g. portfolio, product gallery teaser). Use wp:image for single images.wp:details for FAQ/accordion patterns — the question is the <summary>, the answer is the children.wp:buttons + wp:button for CTAs. Use native block color slug attributes such as backgroundColor / textColor or a registered className style; do not add ad hoc inline CSS.design-foundation.json to know which slugs are available. Specifically: color.surface.*, color.accent.*, typography.families.*. You will reference these by slug, not by hex.wp:group with a heading + subtext is safer than a wp:cover whose image you couldn't ground.className to the corresponding style slug.wp:image (or wp:gallery for multiple) with the source URL. The downstream media-url-rewrite step swaps these to local upload URLs after compose.outputPath. Do not include any wrapping tags (no <html>, no <body>) — just block markup.{
"url": "https://example.com/about",
"blocksCount": 7,
"sectionsMapped": ["hero", "overview", "features", "cta"],
"foundationsUsed": ["accent-primary", "surface-raised"],
"warnings": []
}
The streaming loop calls a deterministic heuristic-blocks.ts BEFORE invoking you. If the page is "all paragraphs + h2/h3" or "single image followed by paragraphs" or "one section with heading + text," the heuristic emits markup directly and you are skipped. If you ARE invoked, the page has at least one non-trivial structural element — a hero, a multi-column layout, a gallery, an interactive section. Spend your effort there.
<div class="container"> could be a hero, a footer band, or just an alignment wrapper. Use the screenshot to disambiguate.design-foundation.json doesn't list a slug you want (e.g. you imagine a "muted cyan" surface), do not invent it. Pick the closest existing slug or omit the visual treatment.wp:html. Custom HTML blocks are rejected. Always prefer the right semantic block, or ask for a custom block/theme CSS change when the source component cannot be represented with core blocks.core/html to recreate a missing block type. When a layout needs something outside the allow-list above, omit the section and add a warning.references/blocks-reference.md — concrete markup examples for cover, columns, group, heading, image, buttons, gallery, details. Read when you need the exact JSON-attribute shape for a block.references/post-content-conventions.md — what's legal in post_content, what's not. Read before composing.skills/replicate-with-blocks/styling-priority.md — the preset→patch→instance→variation→layout→CSS cascade, the structured-props cheat sheet, and the hard bans (no raw style="" attrs, no invented className CSS hooks). Applies to native block output; core/html islands exempt.evals/evals.json enumerates representative pages from existing fixtures (biostratamarketing rich blog post, getsnooz about page, dopplepress product page). Each eval supplies the inputs your invocation receives plus a brief intent description. Assertions land after the first iteration of grading.
npx claudepluginhub automattic/data-liberation-agent --plugin data-liberationGenerates or edits WordPress Gutenberg blocks for the Greenshift/GreenLight plugin and converts data or vanilla HTML+CSS+JS to WordPress blocks.
Rebuilds a single divergent section into canonical WordPress core blocks from source HTML, screenshots, spec, and design tokens after earlier stages fail to reach visual parity.
Converts WPBakery Page Builder pages to native Gutenberg blocks, parsing shortcodes and mapping to core blocks.