con un clic
Build layouts using GenerateBlocks V2 elements for WordPress
npx skills add https://github.com/wpgaurav/generateblocks-skills --skill generateblocks-layoutsCopia y pega este comando en Claude Code para instalar la habilidad
Build layouts using GenerateBlocks V2 elements for WordPress
npx skills add https://github.com/wpgaurav/generateblocks-skills --skill generateblocks-layoutsCopia y pega este comando en Claude Code para instalar la habilidad
Convert Elementor layouts to clean GenerateBlocks V2 format, eliminating DIVception
Convert Figma designs to GenerateBlocks V2 format for WordPress
Convert HTML/CSS layouts to GenerateBlocks V2 format with inline styles
| name | generateblocks-layouts |
| version | 2.1.0 |
| description | Build layouts using GenerateBlocks V2 elements for WordPress |
| author | Gaurav Tiwari |
| trigger | ["GenerateBlocks","GB blocks","GB layouts","HTML to GenerateBlocks","convert to GB","WordPress block layout","landing page section","blog grid","related posts","query loop with GenerateBlocks"] |
| tags | ["wordpress","generateblocks","layouts","blocks"] |
| references | ["references/_index.md","references/recovery-rules.md","references/block-types.md","references/query-block.md","references/gb-pro.md","references/css-patterns.md","references/svg-icons.md","references/responsive.md","references/troubleshooting.md"] |
| examples | ["examples/basic/","examples/compound/","examples/layouts/","examples/svg/"] |
Build professional WordPress layouts using GenerateBlocks V2's four core blocks plus the Query / Looper / Loop-Item family for dynamic content.
Before generating any markup, read these in order:
references/_index.md — task router. Tells you which other files to load.references/recovery-rules.md — every known cause of "Attempt Recovery"
errors with the exact fix. This is non-negotiable. Skip it and you will
produce broken markup._index.md.The most common task-specific files:
block-types.mdquery-block.mdgb-pro.mdThe WordPress block editor validates blocks by re-serializing the attributes and string-comparing against the markup you pasted. Any deviation — even semantically-equivalent JSON or HTML — is treated as corruption and triggers "Attempt Recovery".
This is the unifying principle. Every rule in recovery-rules.md exists to
make your output byte-identical to what the editor itself would emit.
That means matching:
block.json declarations-- < > & → \u002d\u002d \u003c \u003e \u0026) on every JSON stringIf you remember nothing else: emit what the editor emits, not what you think is correct.
ALWAYS output generated blocks to a file, never inline in the chat.
{section-name}.html (e.g., hero-section.html, services-grid.html)Why file output?
GenerateBlocks V2 uses four block types:
| Block | Class Pattern | Use For |
|---|---|---|
generateblocks/element | .gb-element-{id} | Containers (div, section, article, header, nav, footer) |
generateblocks/text | .gb-text-{id} | Text content (h1-h6, p, span, a, button) |
generateblocks/media | .gb-media-{id} | Images (static only, no dynamic features) |
generateblocks/shape | .gb-shape-{id} | SVG icons and decorative shapes |
For elements not available in GenerateBlocks or requiring advanced media features, use WordPress Core Blocks:
| Content Type | Use Core Block | Why |
|---|---|---|
| Images with captions | core/image | Built-in caption support |
| Image galleries | core/gallery | Lightbox, columns, captions |
| Videos | core/video | Native video player, controls |
| Embedded media | core/embed | YouTube, Vimeo, Twitter, etc. |
| Audio files | core/audio | Native audio player |
| File downloads | core/file | Download links with filename |
| Tables | core/table | Structured data tables |
| Lists | core/list | Semantic ul/ol with .list class |
| Quotes | core/quote | Blockquote with citation |
| Code blocks | core/code | Preformatted code display |
| Separators | core/separator | Horizontal rules |
| Buttons (grouped) | core/buttons | Multiple button layouts |
| Columns (simple) | core/columns | Quick equal-width layouts |
| Cover images | core/cover | Background images with overlays |
| Dynamic post content | core/post-* | Post title, excerpt, featured image, etc. |
| Query loops | core/query | Dynamic content from posts |
| Emojis | core/paragraph | GenerateBlocks doesn't render emojis properly |
Rule of thumb: Use GenerateBlocks for layout structure and custom styling. Use Core Blocks for specialized content types and media with built-in functionality.
<!-- wp:generateblocks/{type} {json_attributes} -->
<{tag} class="gb-{type} gb-{type}-{uniqueId}">
{content}
</{tag}>
<!-- /wp:generateblocks/{type} -->
Element blocks use "className":"gb-element" (just the base class — the plugin auto-injects the id-class). The rendered HTML class is gb-element-{id} gb-element:
<!-- wp:generateblocks/element {"uniqueId":"card001","tagName":"div","styles":{...},"css":"...","className":"gb-element"} -->
<div class="gb-element-card001 gb-element">...</div>
<!-- /wp:generateblocks/element -->
Every block needs (in this canonical key order, from block.json):
uniqueId — Unique identifier ({section}{number} like hero001, card023)tagName — HTML element type (omitted for shape, which uses html instead)content — (text block only, position 3) the rich text contentstyles — CSS properties as JSON object (camelCase). Supports responsive keys like "@media (max-width:1024px)":{...}css — Generated CSS string (kebab-case, minified, alphabetically sorted)globalClasses — Array of global CSS class slugs (optional)htmlAttributes — Plain object of attribute key-value pairs (for links, IDs, data attributes)align (element), mediaId (media), queryType, paginationType, query, inheritQuery (query), midSize (query-page-numbers), icon, iconLocation, iconOnly (text)className — always last. WordPress core attribute. Should NOT include the auto-injected gb-{type}-{uniqueId} class — the plugin adds that itself.Per-block exceptions:
content is at position 3, BEFORE styles. This is the only block that breaks the standard order.tagName. html is at position 2.queryType, paginationType, query, inheritQuery come after htmlAttributes.See references/recovery-rules.md §3.4 for the verified per-block declaration order.
The plugin auto-injects gb-{type}-{uniqueId} into the rendered HTML class
list whenever styles is non-empty. If you also put it in className, the
rendered HTML has it twice and you trigger recovery on save.
// RIGHT — let the plugin auto-inject
"className":"gb-element"
"className":"gb-element alignfull"
// WRONG — duplicates the id-class
"className":"gb-element-card001 gb-element"
The rendered HTML class list always shows the id-class once (auto-injected
at the front) followed by whatever is in className:
<div class="gb-element-card001 gb-element"> <!-- ✓ -->
<header class="gb-element-hero001 gb-element alignfull"> <!-- ✓ -->
htmlAttributes MUST be a plain object, NOT an array:
// ✅ CORRECT - Plain object
"htmlAttributes": {"href": "https://example.com/page/", "target": "_blank", "id": "section-id"}
// ❌ WRONG - Array of objects (causes block editor recovery errors)
"htmlAttributes": [
{"attribute": "href", "value": "/contact/"},
{"attribute": "target", "value": "_blank"}
]
Use full absolute URLs, not relative paths. The block editor saves links as absolute URLs; relative paths get converted on save, causing a mismatch that triggers block recovery.
// ✅ CORRECT
"htmlAttributes": {"href": "https://gauravtiwari.org/services/web-development/"}
// ❌ WRONG
"htmlAttributes": {"href": "/services/web-development/"}
There are two failure modes to avoid:
generateblocks/text with tagName:"a" strips its href on save. The
href does not survive the round trip. Don't use it for action links.generateblocks/element with tagName:"a" containing raw text triggers
recovery — element blocks expect inner blocks, not text content.The correct pattern: element <a> wrapping a text span child.
<!-- wp:generateblocks/element {"uniqueId":"link1","tagName":"a","styles":{"display":"inline-block","color":"#c0392b"},"css":".gb-element-link1{color:#c0392b;display:inline-block}","htmlAttributes":{"href":"https://example.com/page/?a=1\u0026b=2"},"className":"gb-element"} -->
<a class="gb-element-link1 gb-element" href="https://example.com/page/?a=1&b=2">
<!-- wp:generateblocks/text {"uniqueId":"link2","tagName":"span","content":"Read more →","styles":{},"css":""} -->
<span class="gb-text-link2 gb-text">Read more →</span>
<!-- /wp:generateblocks/text -->
</a>
<!-- /wp:generateblocks/element -->
This works because:
<a> has an inner block child → no "raw text" recoveryhtmlAttributes.href on the element block survives save → href preservedspan, not an a → no href stripping→ in the text — never use a CSS \2192 escape& in the JSON htmlAttributes is escaped as \u0026& in the rendered HTML href is escaped as &className is just "gb-element" (no id-class duplicate) — the plugin
auto-injects gb-element-link1 so the rendered HTML has it onceuniqueId, tagName, styles, css, htmlAttributes, className
(canonical block.json order, with className last)For inline links inside a paragraph, write the <a> directly in the rich text
content of a single generateblocks/text paragraph block — don't wrap each
inline link in its own block.
See references/recovery-rules.md §4 for the full explanation.
Always use both styles AND css attributes:
{
"uniqueId": "card001",
"tagName": "div",
"styles": {
"backgroundColor": "#ffffff",
"display": "flex",
"padding": "2rem"
},
"css": ".gb-element-card001{background-color:#ffffff;display:flex;padding:2rem}"
}
CSS rules:
css attribute contains only base styles - no hover states, no transitions (the plugin generates those from the styles object)css: pseudo-elements (::before/::after), media queries, animations, parent hover targeting children/* Base styles only (alphabetically sorted) + pseudo-elements + media queries */
.gb-element-card001{background-color:#ffffff;border-radius:1rem;display:flex;padding:2rem;position:relative}.gb-element-card001::after{content:'';position:absolute;bottom:0;left:0;width:100%;height:3px;background:#c0392b;transform:scaleX(0)}@media(max-width:768px){.gb-element-card001{padding:1rem}}
Parent hover targeting children is written in the child's css:
.gb-element-card001:hover .gb-text-title001{color:#c0392b}
Desktop-first approach with standard breakpoints:
| Breakpoint | Width | Use For |
|---|---|---|
| Desktop | 1025px+ | Default styles (no media query) |
| Tablet | 768px - 1024px | @media(max-width:1024px) |
| Mobile | < 768px | @media(max-width:768px) |
Two approaches for responsive styles:
styles object (preferred for simple overrides):{
"styles": {
"display": "grid",
"gridTemplateColumns": "minmax(0, 1fr) minmax(0, 1fr)",
"gap": "4rem",
"@media (max-width:1024px)": {
"gridTemplateColumns": "minmax(0, 1fr)"
}
}
}
css string (for complex responsive rules):.gb-element-hero001{display:grid;gap:4rem;grid-template-columns:minmax(0,1fr) minmax(0,1fr)}@media (max-width:1024px){.gb-element-hero001{grid-template-columns:minmax(0,1fr)}}
Common responsive patterns:
grid-template-columns:minmax(0,1fr) minmax(0,1fr) → grid-template-columns:minmax(0,1fr)padding:6rem 0 → padding:4rem 0 → padding:3rem 0clamp() for fluid typographyflex-direction:row → flex-direction:columngap:4rem → gap:2remtext-align:left → text-align:centerFor full-width sections with contained inner content:
<!-- wp:generateblocks/element {"uniqueId":"hero001","tagName":"section","styles":{...},"css":"...","align":"full","className":"gb-element-hero001 gb-element alignfull"} -->
<section class="gb-element-hero001 gb-element alignfull">
<!-- wp:generateblocks/element {"uniqueId":"hero002","tagName":"div","styles":{"maxWidth":"var(\u002d\u002dgb-container-width)","marginLeft":"auto","marginRight":"auto"},"css":".gb-element-hero002{margin-left:auto;margin-right:auto;max-width:var(\u002d\u002dgb-container-width)}","className":"gb-element-hero002 gb-element"} -->
<div class="gb-element-hero002 gb-element">
<!-- Inner content -->
</div>
<!-- /wp:generateblocks/element -->
</section>
<!-- /wp:generateblocks/element -->
Key:
"align":"full" + "className":"gb-element-hero001 gb-element alignfull"maxWidth: "var(\u002d\u002dgb-container-width)" (unicode-escaped --gb-container-width)Format: {section}{number}{letter}
hero, serv, card, feat, blog)a, b, c)Examples: hero001, serv023a, card014, feat007b
Start with _index.md to figure out which file you need.
See /examples/ folder for copy-paste ready blocks:
⛔ NEVER add HTML comments other than WordPress block markers.
The ONLY allowed comments are WordPress block delimiters:
<!-- wp:generateblocks/element {...} --> and <!-- /wp:generateblocks/element --><!-- wp:generateblocks/text {...} --> and <!-- /wp:generateblocks/text --><!-- wp:generateblocks/media {...} --> and <!-- /wp:generateblocks/media --><!-- wp:generateblocks/shape {...} --> and <!-- /wp:generateblocks/shape --><!-- wp:image {...} --> and <!-- /wp:image --><!-- wp:video {...} --> and <!-- /wp:video --><!-- wp:embed {...} --> and <!-- /wp:embed --><!-- wp:{namespace}/{block} --> formatWRONG - These will break the block editor:
<!-- Hero Section -->
<!-- Card container -->
<!-- Button wrapper -->
<!-- This is a heading -->
<!-- Content goes here -->
CORRECT - Only block delimiters:
<!-- wp:generateblocks/element {"uniqueId":"hero001",...,"className":"gb-element"} -->
<section class="gb-element-hero001 gb-element">
<!-- wp:generateblocks/text {"uniqueId":"hero002",...} -->
<h1 class="gb-text gb-text-hero002">Heading</h1>
<!-- /wp:generateblocks/text -->
</section>
<!-- /wp:generateblocks/element -->
Any extra HTML comments will break the WordPress block editor and cause parsing errors. This is non-negotiable.
css attribute, no spaces inside function args (repeat(3,1fr) not repeat(3, 1fr))transition declarations and no :hover rules in the css string. The plugin generates both from the styles object. Exceptions: pseudo-elements, media queries, animations, parent-hover targeting childrencss stringstyles object AND the css string-- as \u002d\u002d anywhere it appears inside JSON strings (both styles values and css strings) — literal -- in JSON triggers recovery on save. Inline style="" on rendered HTML can use literal var(--foo) because it's not JSONcss — selectors like .gb-text-x small{} or .gb-text-x .u{} get stripped and trigger recovery. Put inline style="" on the inner <small>, <code>, <strong>, <span> directly. Allowed exceptions: pseudo-elements on the block's own selector, and parent-hover targeting another GB block by its own generated class\xxxx escape sequences — write literal characters: content:'→', not content:'\2192'. Better: put arrows in the rendered text content, not in pseudo-elements<a> wrapping a text span child — text <a> strips its href on save, element <a> with raw text triggers recovery. The element-a wraps text-span pattern avoids both. See SKILL.md "The link block pattern" sectionhtmlAttributes is always a plain object — {"href":"..."} never [{"attribute":"href","value":"..."}]htmlAttributes.href — relative paths get canonicalized on save → recovery& encoding — keep literal & in JSON htmlAttributes, encode as & in the rendered HTML <a href="..."> bodyclassName must include the uniqueId class — "gb-element-{uniqueId} gb-element", never just "gb-element"csscore/image, NOT generateblocks/media. generateblocks/media is for dynamic loop images. Plain static images without captions can use either, but core/image is more reliablecore/list with className:"list"core/paragraph — GB renders emoji glyphs incorrectlyquery-block.md — use generateblocks/query + looper + loop-item for any post list, archive, or related-posts sectionstyles.svg for SVG-specific props OR simple styles with inline SVG attributes; both workvar(\u002d\u002dgb-container-width) for inner containers with align:"full" on the parent section for full-width layoutsstroke-linejoin, stroke-linecap, stroke-width, stroke, fill, viewBox, height, width. Write them in that order.For the full list of recovery causes and the exact fix for each, see
references/recovery-rules.md.
When no CSS values are specified, infer styles based on context:
#0073e6#22222217px, line-height 1.742px, H2: 35px, H3: 29px60pxvar(--gb-container-width)15px 30px#c0392b#0a0a0a, Muted: #5c5c5c#ffffff, Light: #f5f5f3900, tight letter-spacing4rem1rem, Button radius: 2remtranslateY(-6px)0 20px 60px rgba(0,0,0,0.15)For large sections (50+ blocks), break into chunks:
See Troubleshooting for detailed guidance on complex layouts.