elementor-to-generateblocks
Convert Elementor layouts to clean GenerateBlocks V2 format, eliminating DIVception
Elementor to GenerateBlocks Converter
Convert bloated Elementor layouts to clean, semantic GenerateBlocks V2 blocks.
Read first
Before converting, read these files in the sibling generateblocks-layouts skill:
../generateblocks-layouts/references/_index.md— task router../generateblocks-layouts/references/recovery-rules.md— every cause of "Attempt Recovery" errors with the exact fix../generateblocks-layouts/references/block-types.md— attribute specs
For Elementor Posts/Loop widgets, build the GB equivalent with the V2 Query
block family — see ../generateblocks-layouts/references/query-block.md.
For Elementor widgets that map to Pro features (accordion, tabs, carousel,
sticky header), see ../generateblocks-layouts/references/gb-pro.md.
Output Requirements
ALWAYS output converted blocks to a file, never inline in the chat.
- Output filename:
{section-name}-converted.html(e.g.,hero-converted.html) - For full page conversions: Split into multiple files by section
- Include a brief summary in chat describing what was converted
Why file output?
- Converted block code is often 100+ lines
- Easier to copy/paste into WordPress
- Prevents truncation and formatting issues
- Allows comparison with original Elementor output
The DIVception Problem
Elementor wraps everything in excessive nested divs with utility classes:
<!-- Elementor's typical output -->
<section class="elementor-section elementor-top-section elementor-element elementor-element-abc123 elementor-section-boxed elementor-section-height-default elementor-section-height-default">
<div class="elementor-container elementor-column-gap-default">
<div class="elementor-column elementor-col-50 elementor-top-column elementor-element elementor-element-def456">
<div class="elementor-widget-wrap elementor-element-populated">
<div class="elementor-element elementor-element-ghi789 elementor-widget elementor-widget-heading">
<div class="elementor-widget-container">
<h2 class="elementor-heading-title elementor-size-default">Hello World</h2>
</div>
</div>
</div>
</div>
</div>
</section>
Result: 7 nested divs for a simple heading.
GenerateBlocks Solution
Same content, cleaner structure:
<!-- wp:generateblocks/element {"uniqueId":"sect001","tagName":"section","styles":{"paddingBottom":"4rem","paddingTop":"4rem"},"css":".gb-element-sect001{padding-bottom:4rem;padding-top:4rem}","className":"gb-element-sect001 gb-element"} -->
<section class="gb-element-sect001 gb-element">
<!-- wp:generateblocks/element {"uniqueId":"sect001a","tagName":"div","styles":{"marginLeft":"auto","marginRight":"auto","maxWidth":"var(--gb-container-width)","paddingLeft":"1rem","paddingRight":"1rem"},"css":".gb-element-sect001a{margin-left:auto;margin-right:auto;max-width:var(--gb-container-width);padding-left:1rem;padding-right:1rem}","className":"gb-element-sect001a gb-element"} -->
<div class="gb-element-sect001a gb-element">
<!-- wp:generateblocks/text {"uniqueId":"sect001b","tagName":"h2","styles":{"color":"#0a0a0a","fontSize":"2rem","fontWeight":"700"},"css":".gb-text-sect001b{color:#0a0a0a;font-size:2rem;font-weight:700}"} -->
<h2 class="gb-text gb-text-sect001b">Hello World</h2>
<!-- /wp:generateblocks/text -->
</div>
<!-- /wp:generateblocks/element -->
</section>
<!-- /wp:generateblocks/element -->
Result: 3 semantic elements. Clean, maintainable, fast.
Conversion Rules
1. Flatten the Structure
| Elementor Pattern | GenerateBlocks Equivalent |
|---|---|
elementor-section > elementor-container | Single section + inner div |
elementor-column > elementor-widget-wrap | Single div with flex/grid |
elementor-widget > elementor-widget-container | Direct content block |
| Multiple wrapper divs | Remove all unnecessary wrappers |
2. Map Elementor Classes to Inline Styles
| Elementor Class | CSS Property |
|---|---|
elementor-section-boxed | max-width: var(--gb-container-width); margin: auto |
elementor-section-full_width | max-width: 100% |
elementor-column-gap-default | gap: 1rem |
elementor-column-gap-extended | gap: 2rem |
elementor-col-50 | flex: 0 0 50% or grid column |
elementor-col-33 | flex: 0 0 33.333% or grid column |
elementor-hidden-desktop | @media(min-width:1025px){display:none} |
elementor-hidden-tablet | @media(max-width:1024px){display:none} |
elementor-hidden-mobile | @media(max-width:767px){display:none} |
3. Widget to Block Mapping
| Elementor Widget | GenerateBlocks Block |
|---|---|
elementor-widget-heading | generateblocks/text with h1-h6 |
elementor-widget-text-editor | generateblocks/text with p/div |
elementor-widget-button (text only) | generateblocks/text with tagName="a" (no htmlAttributes for href) |
elementor-widget-button (with icon) | generateblocks/element with tagName="a" wrapping text + shape blocks |
elementor-widget-image | generateblocks/media (or core/image if caption needed) |
elementor-widget-icon | generateblocks/shape with inline SVG |
elementor-widget-icon-box | generateblocks/element container with shape + text blocks |
elementor-widget-image-box | generateblocks/element container |
elementor-widget-spacer | Remove (use margins/padding instead) |
elementor-widget-divider | generateblocks/element with border (or core/separator) |
| Clickable card (with inner blocks) | generateblocks/element with tagName="a" + htmlAttributes: {"href":"https://example.com/"} |
4. Widgets Requiring Core Blocks
Some Elementor widgets should convert to Core Blocks instead of GenerateBlocks:
| Elementor Widget | Use Core Block | Reason |
|---|---|---|
elementor-widget-video | core/video or core/embed | Native player, embed support |
elementor-widget-image-gallery | core/gallery | Lightbox, columns, captions |
elementor-widget-image-carousel | core/gallery + CSS or third-party | Slider functionality |
elementor-widget-audio | core/audio | Native audio player |
elementor-widget-table | core/table | Semantic table structure |
elementor-widget-blockquote | core/quote | Semantic quote with citation |
elementor-widget-code-highlight | core/code | Preformatted code display |
elementor-widget-text-path | Keep as SVG | No Core equivalent |
elementor-widget-lottie | Keep as custom | No Core equivalent |
elementor-widget-image (with caption) | core/image | Built-in caption support |
elementor-widget-tabs | core/details or custom | Accordion/tabs functionality |
elementor-widget-accordion | core/details | Native disclosure widget |
elementor-widget-toggle | core/details | Native disclosure widget |
| Text with emojis | core/paragraph | GenerateBlocks doesn't render emojis properly |
Rule: Use GenerateBlocks for layout and styling. Use Core Blocks for specialized functionality (media players, embeds, tables, interactive elements).
4. Column Layouts
Elementor 2-column:
<div class="elementor-container">
<div class="elementor-column elementor-col-50">...</div>
<div class="elementor-column elementor-col-50">...</div>
</div>
GenerateBlocks equivalent:
<!-- wp:generateblocks/element {"uniqueId":"col001","tagName":"div","styles":{"display":"grid","gap":"2rem","gridTemplateColumns":"repeat(2, minmax(0, 1fr))","@media (max-width:768px)":{"gridTemplateColumns":"1fr"}},"css":".gb-element-col001{display:grid;gap:2rem;grid-template-columns:repeat(2, minmax(0, 1fr))}@media(max-width:768px){.gb-element-col001{grid-template-columns:1fr}}","className":"gb-element-col001 gb-element"} -->
<div class="gb-element-col001 gb-element">
<!-- Column 1 content -->
<!-- Column 2 content -->
</div>
<!-- /wp:generateblocks/element -->
5. Common Elementor Patterns
Hero with background:
<!-- wp:generateblocks/element {"uniqueId":"hero001","tagName":"section","styles":{"alignItems":"center","backgroundImage":"url(image.jpg)","backgroundPosition":"center","backgroundSize":"cover","display":"flex","justifyContent":"center","minHeight":"80vh"},"css":".gb-element-hero001{align-items:center;background-image:url(image.jpg);background-position:center;background-size:cover;display:flex;justify-content:center;min-height:80vh}.gb-element-hero001::before{background:rgba(0,0,0,0.5);content:'';inset:0;position:absolute}","className":"gb-element-hero001 gb-element"} -->
<section class="gb-element-hero001 gb-element">
<!-- Hero content -->
</section>
<!-- /wp:generateblocks/element -->
Card grid:
<!-- wp:generateblocks/element {"uniqueId":"cards001","tagName":"div","styles":{"display":"grid","gap":"2rem","gridTemplateColumns":"repeat(3, minmax(0, 1fr))","@media (max-width:1024px)":{"gridTemplateColumns":"repeat(2, minmax(0, 1fr))"},"@media (max-width:768px)":{"gridTemplateColumns":"1fr"}},"css":".gb-element-cards001{display:grid;gap:2rem;grid-template-columns:repeat(3, minmax(0, 1fr))}@media(max-width:1024px){.gb-element-cards001{grid-template-columns:repeat(2, minmax(0, 1fr))}}@media(max-width:768px){.gb-element-cards001{grid-template-columns:1fr}}","className":"gb-element-cards001 gb-element"} -->
<div class="gb-element-cards001 gb-element">
<!-- Card blocks -->
</div>
<!-- /wp:generateblocks/element -->
Design Inference (When CSS Not Provided)
When converting Elementor without CSS values, infer styles based on context:
Default GeneratePress Design System
Use these defaults when no specific styles are provided:
Colors:
- Primary:
#0073e6(GeneratePress default accent) - Text:
#222222 - Muted text:
#757575 - Background:
#ffffff - Light background:
#f7f8f9 - Border:
#e0e0e0
Typography:
- Body:
17px, line-height1.7 - H1:
42px, font-weight600 - H2:
35px, font-weight600 - H3:
29px, font-weight600 - H4:
24px, font-weight600
Spacing:
- Section padding:
60pxtop/bottom - Container max-width:
var(--gb-container-width) - Content padding:
20px - Gap between elements:
20px
Buttons:
- Padding:
15px 30px - Border-radius:
4px - Background: primary color
- Hover: darken 10%
Site-Specific Inference
When the target site is known, extract design tokens from:
- Theme's style.css - Primary colors, fonts, base sizes
- theme.json (block themes) - Color palette, typography presets
- Existing pages - Match the established visual language
Example inference for gauravtiwari.org:
{
"colors": {
"primary": "#c0392b",
"text": "#0a0a0a",
"muted": "#5c5c5c",
"background": "#ffffff",
"lightBg": "#f5f5f3",
"border": "#e5e5e5"
},
"typography": {
"body": "1rem",
"h1": "clamp(2rem, 5vw, 3.5rem)",
"h2": "clamp(1.5rem, 3vw, 2.5rem)",
"fontWeight": "900 for headings"
},
"spacing": {
"sectionPadding": "4rem",
"containerMax": "var(--gb-container-width)",
"gap": "1rem to 2rem"
},
"effects": {
"borderRadius": "1rem for cards, 2rem for buttons",
"hoverLift": "translateY(-6px)",
"shadow": "0 20px 60px rgba(0,0,0,0.15)"
}
}
CRITICAL: No Extra HTML Comments
⛔ 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:gallery {...} -->and<!-- /wp:gallery -->- Any other
<!-- wp:{namespace}/{block} -->format
WRONG - These will break the block editor:
<!-- This is a card -->
<!-- Hero section -->
<!-- Converted from Elementor -->
CORRECT - Only block delimiters:
<!-- wp:generateblocks/element {"uniqueId":"sect001",...} -->
<section class="gb-element-sect001 gb-element">
<!-- wp:generateblocks/text {"uniqueId":"sect001a",...} -->
<h2 class="gb-text-sect001a gb-text">Hello World</h2>
<!-- /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.
Critical Rules
1. htmlAttributes MUST Use Object Format
htmlAttributes MUST be a plain object, NOT an array of objects:
// ✅ CORRECT - Plain object
"htmlAttributes": {"href": "https://example.com/contact/", "target": "_blank", "id": "section-id"}
// ❌ WRONG - Array of objects (causes block editor recovery errors)
"htmlAttributes": [
{"attribute": "href", "value": "/contact/"},
{"attribute": "target", "value": "_blank"},
{"attribute": "id", "value": "section-id"}
]
Note: linkHtmlAttributes for media blocks may use a different format.
2. Always Include Both styles and css
Every block needs:
stylesobject with camelCase properties (supports responsive keys like"@media (max-width:1024px)":{...})cssstring with minified CSS (kebab-case, alphabetically sorted, base styles only)- The
cssattribute must NOT contain hover states or transitions (the plugin generates those from thestylesobject) - Exceptions that go in
css: pseudo-elements (::before/::after), media queries, animations, parent hover targeting children
3. Element Blocks Need className
Add "className":"gb-element-{id} gb-element" to all element block attributes (className MUST include the uniqueId). HTML class order: gb-element-{id} gb-element:
<!-- wp:generateblocks/element {"uniqueId":"card001",...,"className":"gb-element-card001 gb-element"} -->
<div class="gb-element-card001 gb-element">...</div>
<!-- /wp:generateblocks/element -->
4. Text <a> vs Element <a> Links
| Block Type | htmlAttributes for href | Use Case |
|---|---|---|
generateblocks/text with tagName: "a" | No - plugin manages link internally | Plain text buttons/links (no inner blocks) |
generateblocks/element with tagName: "a" | Yes - {"href":"https://example.com/"} | Containers wrapping inner blocks (cards, icon buttons) |
5. SVG Icons Use Shape Blocks
Convert Elementor icons to generateblocks/shape (not generateblocks/element with raw SVG):
<!-- wp:generateblocks/shape {"uniqueId":"icon001","styles":{"alignItems":"center","backgroundColor":"#f5f5f3","borderRadius":"0.75rem","color":"#c0392b","display":"flex","height":"3rem","justifyContent":"center","width":"3rem","svg":{"fill":"currentColor","height":"1.5rem","width":"1.5rem"}},"css":".gb-shape-icon001{align-items:center;background-color:#f5f5f3;border-radius:0.75rem;color:#c0392b;display:flex;height:3rem;justify-content:center;width:3rem}.gb-shape-icon001 svg{fill:currentColor;height:1.5rem;width:1.5rem}"} -->
<span class="gb-shape gb-shape-icon001"><svg viewBox="0 0 24 24" fill="currentColor"><path d="..."/></svg></span>
<!-- /wp:generateblocks/shape -->
6. Lists Use core/list with .list Class
Convert Elementor list widgets to native WordPress list block:
<!-- wp:list {"className":"list"} -->
<ul class="wp-block-list list">...</ul>
<!-- /wp:list -->
7. Container Width with CSS Variable
Use --gb-container-width for inner container width and align: "full" on parent section:
{"align": "full", "styles": {"maxWidth": "var(\u002d\u002dgb-container-width)"}}
8. Use Semantic HTML
Replace Elementor's generic divs with proper tags:
| Content Type | Tag |
|---|---|
| Page section | section |
| Header area | header |
| Footer area | footer |
| Navigation | nav |
| Main content | article |
| Sidebar | aside |
| Card wrapper | div or a (if clickable) |
9. Remove Spacers
Never convert elementor-widget-spacer to a block. Use:
marginBottomon preceding elementmarginTopon following elementgapon parent container
10. Flatten Icon Boxes
Elementor icon box (simplified):
<div class="elementor-icon-box">
<div class="elementor-icon-box-icon">
<span class="elementor-icon"><i class="fab fa-wordpress"></i></span>
</div>
<div class="elementor-icon-box-content">
<h3>Title</h3>
<p>Description</p>
</div>
</div>
GenerateBlocks:
<!-- wp:generateblocks/element {"uniqueId":"ibox001","tagName":"div","styles":{"alignItems":"flex-start","display":"flex","gap":"1rem"},"css":".gb-element-ibox001{align-items:flex-start;display:flex;gap:1rem}","className":"gb-element-ibox001 gb-element"} -->
<div class="gb-element-ibox001 gb-element">
<!-- wp:generateblocks/shape {"uniqueId":"ibox001a","styles":{"alignItems":"center","backgroundColor":"#f5f5f3","borderRadius":"0.75rem","color":"#c0392b","display":"flex","flexShrink":"0","height":"3rem","justifyContent":"center","width":"3rem","svg":{"fill":"currentColor","height":"1.5rem","width":"1.5rem"}},"css":".gb-shape-ibox001a{align-items:center;background-color:#f5f5f3;border-radius:0.75rem;color:#c0392b;display:flex;flex-shrink:0;height:3rem;justify-content:center;width:3rem}.gb-shape-ibox001a svg{fill:currentColor;height:1.5rem;width:1.5rem}"} -->
<span class="gb-shape gb-shape-ibox001a"><svg viewBox="0 0 24 24" fill="currentColor"><path d="..."/></svg></span>
<!-- /wp:generateblocks/shape -->
<!-- wp:generateblocks/element {"uniqueId":"ibox001b","tagName":"div","styles":{"flex":"1"},"css":".gb-element-ibox001b{flex:1}","className":"gb-element-ibox001b gb-element"} -->
<div class="gb-element-ibox001b gb-element">
<!-- wp:generateblocks/text {"uniqueId":"ibox001c","tagName":"h3","styles":{"fontSize":"1.125rem","fontWeight":"700","marginBottom":"0.5rem"},"css":".gb-text-ibox001c{font-size:1.125rem;font-weight:700;margin-bottom:0.5rem}"} -->
<h3 class="gb-text gb-text-ibox001c">Title</h3>
<!-- /wp:generateblocks/text -->
<!-- wp:generateblocks/text {"uniqueId":"ibox001d","tagName":"p","styles":{"color":"#5c5c5c","lineHeight":"1.6"},"css":".gb-text-ibox001d{color:#5c5c5c;line-height:1.6}"} -->
<p class="gb-text gb-text-ibox001d">Description</p>
<!-- /wp:generateblocks/text -->
</div>
<!-- /wp:generateblocks/element -->
</div>
<!-- /wp:generateblocks/element -->
11. Full Absolute URLs
Always use full absolute URLs in htmlAttributes, never relative paths:
// ✅ CORRECT
"htmlAttributes": {"href": "https://example.com/contact/"}
// ❌ WRONG
"htmlAttributes": {"href": "/contact/"}
12. No Spaces in CSS Functions
The block editor minifies CSS, so spaces in functions like clamp() cause mismatches:
/* ✅ CORRECT */
font-size:clamp(2rem,5vw,3rem)
/* ❌ WRONG */
font-size:clamp(2rem, 5vw, 3rem)
13. SVG Attribute Order in HTML
SVG elements must follow this attribute order: viewBox first, then fill, then aria-hidden:
<!-- ✅ CORRECT -->
<svg viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><path d="..."/></svg>
<!-- ❌ WRONG -->
<svg fill="currentColor" viewBox="0 0 24 24"><path d="..."/></svg>
14. Compact Nesting
Closing tags must be on the same line as their parent's closing comment. No blank lines between closing tags:
<!-- ✅ CORRECT -->
</div>
<!-- /wp:generateblocks/element -->
</section>
<!-- /wp:generateblocks/element -->
<!-- ❌ WRONG -->
</div>
<!-- /wp:generateblocks/element -->
</section>
<!-- /wp:generateblocks/element -->
Conversion Workflow
- Analyze Elementor HTML - Identify sections, columns, widgets
- Extract content - Isolate actual text, images, links
- Determine layout - Map column structure to grid/flex
- Apply design tokens - Use provided CSS or infer from site
- Build blocks - Create GenerateBlocks with inline styles
- Test responsive - Add media queries for breakpoints
- Validate - Ensure no HTML comments except block markers
Performance Benefits
| Metric | Elementor | GenerateBlocks |
|---|---|---|
| DOM nodes | 50-100+ per section | 5-15 per section |
| CSS file size | 200KB+ | 0 (inline) |
| Render blocking | Multiple CSS files | None |
| First paint | Delayed | Fast |
| CLS issues | Common | Rare |
Font Awesome to SVG
Replace Elementor's Font Awesome icons with inline SVGs:
<!-- Instead of <i class="fab fa-twitter"></i> -->
<svg viewBox="0 0 24 24" fill="currentColor" aria-hidden="true">
<path d="M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-5.214-6.817L4.99 21.75H1.68l7.73-8.835L1.254 2.25H8.08l4.713 6.231zm-1.161 17.52h1.833L7.084 4.126H5.117z"/>
</svg>
See SVG Icons Reference for common icons.