From 92819b8e4578a9917027a61ee35c52de70453627 Mon Sep 17 00:00:00 2001 From: marcel-za <28527561+marcel-za@users.noreply.github.com> Date: Wed, 3 Jun 2026 16:20:30 +0200 Subject: [PATCH 1/3] feat(skill): add wp-block-post-content skill with tiered validation Add new wp-block-post-content skill for generating, editing, and debugging raw WordPress block comment markup in post content, patterns, and programmatic post creation. Includes a tiered validation protocol (WP-CLI round-trip, Node.js sandbox, Chrome DevTools, manual cross- reference), a core block markup reference with exact save() signatures, and a Node.js validate-markup.mjs script using the official WordPress block serialisation parser. Also adds two eval scenarios: fix-block-validation-error (DevTools MCP workflow for diagnosing validation errors) and generate-page-layout (structured markup generation with pre-insertion validation). --- eval/scenarios/fix-block-validation-error.md | 16 ++ eval/scenarios/generate-page-layout.md | 14 ++ skills/wp-block-post-content/SKILL.md | 72 ++++++++ .../references/core-block-markup-reference.md | 168 ++++++++++++++++++ .../references/wp-block-validation.md | 53 ++++++ .../scripts/validate-markup.mjs | 52 ++++++ 6 files changed, 375 insertions(+) create mode 100644 eval/scenarios/fix-block-validation-error.md create mode 100644 eval/scenarios/generate-page-layout.md create mode 100644 skills/wp-block-post-content/SKILL.md create mode 100644 skills/wp-block-post-content/references/core-block-markup-reference.md create mode 100644 skills/wp-block-post-content/references/wp-block-validation.md create mode 100644 skills/wp-block-post-content/scripts/validate-markup.mjs diff --git a/eval/scenarios/fix-block-validation-error.md b/eval/scenarios/fix-block-validation-error.md new file mode 100644 index 0000000..6c0491c --- /dev/null +++ b/eval/scenarios/fix-block-validation-error.md @@ -0,0 +1,16 @@ +# Scenario: Fix Block Validation Error using Chrome DevTools + +## Prompt +"I am getting a 'block contains unexpected or invalid content' error on my WordPress post editor. Please connect to my browser, find the broken block, and fix the markup." + +## What the AI should do +1. **Connect and Navigate:** The AI should prioritize using the Chrome DevTools MCP tools (`list_pages` and `navigate_page`) to connect to the active editor tab. If `list_pages` returns only `about:blank`, the AI must stop and explicitly ask the user to open the target page in their browser instead of falling back to manual analysis. +2. **Diagnose:** Instead of relying on a screenshot or static analysis, the AI must use `list_console_messages` (filtered strictly to `error` and `warn`) or run the JavaScript verification snippet in the browser console to identify exactly which block is failing and extract the expected vs. actual HTML. The required script is located in the [WordPress Block & Template Troubleshooting](../skills/wp-block-post-content/references/wp-block-validation.md) reference. +3. **Analyze:** The AI should identify the root cause of the validation failure. This could be incorrect whitespace (e.g., tabs, trailing spaces, or unexpected blank lines), incorrect JSON attribute formatting, or missing wrapper classes, ensuring the markup is valid according to the [WP Block Post Content Skill](../skills/wp-block-post-content/SKILL.md). +4. **Fix:** The AI should update the block's raw HTML/comments to match the canonical WordPress output standard. For exact `save()` output signatures, it should refer to the [Core Block Markup Reference](../skills/wp-block-post-content/references/core-block-markup-reference.md). +5. **Verify:** The AI must re-run the verification snippet in the console to confirm the fix was successful, ensuring no validation errors remain. + +## How to verify it worked +The test passes if the AI autonomously runs the DevTools workflow, correctly formats the broken block, and verifies the resolution in the console. + +**Connection Fallback:** If the DevTools connection fails or the `list_pages` tool returns only `about:blank`, the test passes if the AI stops and explicitly asks the user to open the target page in their browser. The test fails if the AI prematurely falls back to manual analysis or attempts to use screenshots instead of the DevTools workflow. \ No newline at end of file diff --git a/eval/scenarios/generate-page-layout.md b/eval/scenarios/generate-page-layout.md new file mode 100644 index 0000000..ca84e9f --- /dev/null +++ b/eval/scenarios/generate-page-layout.md @@ -0,0 +1,14 @@ +# Scenario: Generate Page Layout and Copy + +## Prompt +"Create a new page layout with a centered welcome paragraph with large red text, followed by a dynamic block displaying the latest posts. Once generated, insert it into the database using WP-CLI." + +## What the AI should do +1. **Structure the Blocks:** The AI should generate the raw WordPress markup. +2. **Apply Text Blocks:** The AI should format the text using `wp:paragraph` blocks. +3. **Apply Dynamic Blocks:** For the latest posts, the AI should only output the comment delimiter without any HTML body. +4. **Format namespaces:** The AI must use the core block namespace shorthand (e.g., `wp:paragraph`). +5. **Validate Before Insertion:** The AI must write the generated content to a temporary file and run a Tier 1 or Tier 2 syntax validation against it. After syntax passes, it must confirm structural accuracy (Tier 3/4) before finally executing the `wp post create` command. + +## How to verify it worked +The test passes if the AI outputs exactly formatted markup, explicitly validates the syntax in its sandbox, and only inserts the post after confirming `blockName` does not return null. \ No newline at end of file diff --git a/skills/wp-block-post-content/SKILL.md b/skills/wp-block-post-content/SKILL.md new file mode 100644 index 0000000..4e3d343 --- /dev/null +++ b/skills/wp-block-post-content/SKILL.md @@ -0,0 +1,72 @@ +--- +name: wp-block-post-content +description: > + Use when generating, editing, or debugging raw WordPress block comment markup + in post content, block patterns, or programmatic post creation. + Not for building custom block types (use wp-block-development) or editing theme + files and theme.json (use wp-block-themes). +compatibility: WordPress 6.9+, PHP 7.2.24+ +--- + +## When to use +Use this skill when the task involves writing or fixing the serialised block comment +markup that WordPress stores as post content, pattern HTML, or programmatic +`wp_insert_post` / `wp_update_post` payloads, specifically: + +- Generating post or page content as raw block markup (static or dynamic blocks) +- Writing or editing block patterns as standalone HTML files or PHP pattern registrations +- Programmatic content seeding where `post_content` must contain valid block markup +- Diagnosing "unexpected or invalid content" block validation errors in existing content +- Converting non-block HTML into correct block comment syntax + +Do not use this skill when: +- Building a custom block type from source (block.json, render.php, attributes) → use `wp-block-development` +- Editing theme templates, template parts, or theme.json → use `wp-block-themes` + +## Inputs required +- The specific block namespace and name (e.g., `wp:paragraph` or `wp:image`) [2]. +- The necessary attributes, content, and whether the block is static or dynamic [2]. + +## Procedure +1. **Identify Block Type:** Determine if the block is static (stores HTML) or dynamic (stores only the comment). +2. **Format Dynamic Blocks:** Most dynamic blocks (like `wp:latest-posts`) require only the comment delimiter with no HTML body. However, structural dynamic blocks (like `wp:query`) do contain inner blocks and HTML wrappers. +3. **Format Static Blocks:** Generate the exact HTML wrapper and inner content. Use the core block namespace shorthand (omit `core/`, e.g., `wp:paragraph`). +4. **Consult References:** Keep this procedure short. For exact `save()` output signatures of specific blocks, refer to `references/core-block-markup-reference.md`. +5. **Validate before delivery:** Do not insert or return content until validation passes. For programmatic insertion via `wp_insert_post` or WP-CLI: + a. Write the generated content to a temp file (e.g. `/tmp/wp-content-draft.html`) + b. Run Tier 1 or Tier 2 validation against that file before inserting + c. Only call `wp_insert_post` / `wp post create` after validation is clean + +## Verification +Before outputting final block markup or inserting it into the database, you must perform an internal environment discovery audit to determine your available toolsets. + +> ⚠️ **CRITICAL WARNING:** Tiers 1 and 2 check comment syntax only. They operate purely on comment delimiters and never look at the HTML, meaning they cannot catch `save()` contract mismatches. For static blocks, a Tier 1 or 2 pass is necessary but not sufficient. You MUST escalate to Tier 3 or execute the rigorous Tier 4 manual cross-reference before declaring static block markup valid. + +Execute the highest-tier validation protocol available to you: + +- **[TIER 1] WP-CLI Live Environment:** Use `wp eval` to perform a PHP round-trip structural validation. Run `wp eval "$c = 'YOUR_MARKUP'; var_dump(serialize_blocks(parse_blocks($c)) === $c);"`. This must return `bool(true)`. A successful round-trip catches HTML structure mismatches that `parse_blocks()` alone ignores. +- **[TIER 2] Node.js Sandbox:** Run `node scripts/validate-markup.mjs` against your generated code. +- **[TIER 3] Chrome DevTools MCP:** Run the verification snippet directly in the browser console. This is the ONLY automated way to verify the JS `save()` contract. +- **[TIER 4] Manual Signature Cross-Reference (Fallback):** Manually cross-reference generated static blocks against their exact `save()` output signatures in `references/core-block-markup-reference.md`. If not documented there, fetch the `.html` fixture from `https://github.com/WordPress/gutenberg/blob/trunk/test/integration/fixtures/blocks/`. + +**Interpreting Tiers 1 & 2 Output:** Any block entry with an empty or null `blockName` represents content WordPress could not parse as a valid block. Resolve all such syntax entries before proceeding to Tiers 3 or 4. + +## Failure modes / debugging +The most common source of silent breakage is incorrect whitespace and formatting. When repairing errors, follow these strict rules to avoid validation failures [2]: +1. **Whitespace:** Check for double spaces in comment delimiters, `\r\n` line endings, or extra blank lines between the comment and its HTML wrapper [2]. +2. **Required Classes:** Verify the class list on the wrapper element. Missing or extra classes will fail the JS diff [2]. +3. **JSON Attribute Formatting:** JSON keys must be strictly double-quoted, and values must be the correct type (e.g., integer vs string: `{"level":2}` not `{"level":"2"}`) [2]. + +If the block's `save()` has changed since the content was written, the stored markup may be legitimately "old" — update it to match the current `save()` output, or add a deprecation entry. For deeper troubleshooting and template source diagnostics (such as verifying if a `wp_template_part` is loaded from the filesystem or database), refer to `references/wp-block-validation.md`. + +## Escalation +If the block markup continues to trigger "unexpected or invalid content" errors despite adhering to the strict whitespace and class rules above, escalate and ask the human user for assistance. + +## Reference files +- `references/core-block-markup-reference.md` — Detailed per-block markup signatures for all commonly used core blocks. Load when you need exact class or attribute details for a specific block. +- `references/wp-block-validation.md` — WordPress Block & Template Troubleshooting. + +## External Resources & Deep Dives +If the exact class, attribute details, or validation rules are not covered in the local reference files, consult the official documentation for deep dives: +- **Gutenberg Integration Fixtures:** https://github.com/WordPress/gutenberg/blob/trunk/test/integration/fixtures/blocks/ +- **WP Block Docs:** https://www.wpblockdocs.com/best-practices \ No newline at end of file diff --git a/skills/wp-block-post-content/references/core-block-markup-reference.md b/skills/wp-block-post-content/references/core-block-markup-reference.md new file mode 100644 index 0000000..2adc6e3 --- /dev/null +++ b/skills/wp-block-post-content/references/core-block-markup-reference.md @@ -0,0 +1,168 @@ +# Core Block Markup Reference +Exact `save()` output signatures for commonly used WordPress core blocks. +All examples use WordPress 6.5+ output. Load this file when the golden +standards in SKILL.md do not cover the specific block or attribute combination +you need [1]. + +--- + +## Table of contents +- Text blocks: paragraph, heading, list, preformatted +- Media blocks: image, file +- Design blocks: separator, buttons, group, columns, details +- Embed / dynamic blocks: latest-posts + +--- + +## "Golden standard" examples +These are exact representations of what WordPress would write to the database. Copy the structure, not just the concept. The block serialisation format is unchanged in WordPress 7.0, making these signatures completely valid for modern implementations. + +### Simple paragraph +```html + +
This is a paragraph of text.
+ +``` + +### Heading (h2) +```html + +

Pre-formatted text.+ +``` + +### Details +`core/details` has highly specific `save()` output constraints that will cause validation errors if guessed: +- Boolean HTML attributes must be used (`open`, not `open=""`). +- Inline styles are minified with no spaces after colons (e.g., `border-width:1px;padding-top:2px`). +- The `
Hidden content
+Content inside a group.
+Left column content.
+Right column content.
+Legacy HTML content here.
+ +``` \ No newline at end of file diff --git a/skills/wp-block-post-content/references/wp-block-validation.md b/skills/wp-block-post-content/references/wp-block-validation.md new file mode 100644 index 0000000..49abe68 --- /dev/null +++ b/skills/wp-block-post-content/references/wp-block-validation.md @@ -0,0 +1,53 @@ +# WordPress Block & Template Troubleshooting + +## Verification +Before outputting final block markup or inserting it into the database, you must perform an internal environment discovery audit to determine your available toolsets. + +> ⚠️ **CRITICAL WARNING:** Tiers 1 and 2 check comment syntax only. They operate purely on comment delimiters and never look at the HTML, meaning they cannot catch `save()` contract mismatches. For static blocks, a Tier 1 or 2 pass is necessary but not sufficient. You MUST escalate to Tier 3 or execute the rigorous Tier 4 manual cross-reference before declaring static block markup valid. + +Execute the highest-tier validation protocol available to you: + +- **[TIER 1] WP-CLI Live Environment:** Use `wp eval` to perform a PHP round-trip structural validation. Run `wp eval "$c = 'YOUR_MARKUP'; var_dump(serialize_blocks(parse_blocks($c)) === $c);"`. This must return `bool(true)`. A successful round-trip catches HTML structure mismatches that `parse_blocks()` alone ignores.- **[TIER 2] Node.js Sandbox:** Run `node scripts/validate-markup.mjs` against your generated code. +- **[TIER 3] Chrome DevTools MCP:** Run the verification snippet directly in the browser console. This is the ONLY automated way to verify the JS `save()` contract. +- **[TIER 4] Manual Signature Cross-Reference (Fallback):** If no browser MCP is available, you CANNOT rely on internal predictive logic. You must manually cross-reference your generated static blocks against their exact `save()` output signatures in `references/core-block-markup-reference.md`. If the block is not documented there, you must retrieve its exact `.html` fixture from `https://github.com/WordPress/gutenberg/blob/trunk/test/integration/fixtures/blocks/`. + +**Interpreting Tiers 1 & 2 Output:** The result is an array of block objects. Any entry with an empty or null `blockName` represents content WordPress could not parse as a valid block — this is a failure. Resolve all such entries before proceeding. + +**For programmatic insertion (WP-CLI / `wp_insert_post`):** Always write content to a temp file and validate it syntactically (Tier 1/2) AND structurally (Tier 3/4) before inserting. Never pass content directly to `wp_insert_post` without confirming it is clean. + +## 2. WordPress 7.0 Block Validation Rules +### Canonical Whitespace & Structure +* Tabs, trailing spaces, and unexpected blank lines inside block wrappers trigger silent validation failures. +* Inner block comments (``) must start on the same line as—or immediately following—the opening HTML wrapper tag, with zero leading indentation or blank lines. +* Emulate the golden-standard structural patterns established in the `wp-block-post-content` skill. + +## 3. Chrome DevTools Verification Workflow +If using the DevTools MCP (Tier 3), verify by querying the block editor store — never by screenshot. The editor renders only one "Block contains unexpected or invalid content" banner regardless of how many blocks are invalid. A clean-looking screenshot does not mean all blocks pass. + +Run this snippet in Chrome DevTools after every fix and before reporting done: + +```javascript +(() => { +const invalid = []; +const find = (blocks, path = '') => blocks.forEach((b, i) => { +const p = path ? `${path} > ${b.name}[${i}]` : `${b.name}[${i}]`; +if (b.isValid === false) { +const issue = (b.validationIssues || []).find(v => v.args?.?.includes('Expected attribute')); +invalid.push({ path: p, expected: issue?.args?.?.slice(0,120), actual: issue?.args?.?.slice(0,120) }); +} +if (b.innerBlocks?.length) find(b.innerBlocks, p); +}); +find(wp.data.select('core/block-editor').getBlocks()); +return { invalidCount: invalid.length, blocks: invalid }; +})(); +``` + +## 4. Block Validation Diagnostic Sequence +When debugging block validation errors, follow this strict pipeline: +`get_block_template()` -> Confirm source & extract raw block content +| +`parse_blocks()` -> Inspect individual block innerHTML structure +| +`WP_Block_Type_Registry` -> Check render_callback (Static vs. Dynamic blocks) +| +`render_block()` -> Cross-check PHP side output (Caution: includes structural layout classes absent in save()) \ No newline at end of file diff --git a/skills/wp-block-post-content/scripts/validate-markup.mjs b/skills/wp-block-post-content/scripts/validate-markup.mjs new file mode 100644 index 0000000..78f8623 --- /dev/null +++ b/skills/wp-block-post-content/scripts/validate-markup.mjs @@ -0,0 +1,52 @@ +import fs from 'fs'; +import { parse } from '@wordpress/block-serialization-default-parser'; + +// Retrieve the file path from command line arguments +const filePath = process.argv[2]; + +if (!filePath) { + console.error('Error: Please provide a path to the markup file.'); + console.error('Usage: node scripts/validate-markup.mjs




Pre-formatted text.- + + + ``` -### Details -`core/details` has highly specific `save()` output constraints that will cause validation errors if guessed: -- Boolean HTML attributes must be used (`open`, not `open=""`). -- Inline styles are minified with no spaces after colons (e.g., `border-width:1px;padding-top:2px`). -- The `
Hidden content
-Content.
+Content.
+