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.
htmlAttributes - Plain object of attribute key-value pairs (for links, IDs, data attributes)
Optional:
className - Additional CSS classes. Must include the uniqueId class: e.g., "gb-element-card001 gb-element" for element blocks, "gb-element-hero001 gb-element alignfull" for full-width sections
globalClasses - Array of global CSS class slugs (e.g., ["lede"])
align - Block alignment ("full" for full-width)
CRITICAL: htmlAttributes Format
htmlAttributes MUST be a plain object, NOT an array:
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.
Rule: Text <a> blocks are leaf blocks - the link URL is managed by the editor UI. Element <a> blocks are containers - they need explicit htmlAttributes for the href.
The css attribute contains only base styles - no hover states, no transitions (the plugin generates those from the styles object)
CSS properties must be alphabetically sorted
Exceptions that go in 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:
Any extra HTML comments will break the WordPress block editor and cause parsing errors. This is non-negotiable.
Key Rules
No custom CSS classes - All styling in block attributes
Minify CSS - No line breaks in css attribute
CSS = base styles only - No hover states or transitions in css (the plugin generates those from the styles object). Exceptions: pseudo-elements, media queries, animations, parent hover targeting children
Alphabetically sort CSS - Properties in the css string must be alphabetically sorted
Duplicate styles - Put in both styles object AND css string
Test responsive - Add media queries for tablet (1024px) and mobile (768px)
Text <a> = no htmlAttributes for href - The link URL is managed by the editor UI internally
Element <a> = use htmlAttributes for href - Container links need explicit {"href":"https://full-url.com/"}
Buttons with icons - Use generateblocks/element (tagName a) wrapping generateblocks/text + generateblocks/shape blocks. Plain text buttons use generateblocks/text
Shape blocks - Use styles.svg for SVG-specific properties (fill, stroke, width, height) OR simple styles with width/height/color and inline SVG attributes. Both patterns work
Lists use core/list with .list class - Always use the native WordPress list block with className: "list" and customize styling as needed
Use --gb-container-width for inner containers - Set inner container width using the CSS variable; add align: "full" to parent section for full-width layouts
htmlAttributes as plain object - Use {"href":"https://example.com/"} NOT array format [{"attribute":"href","value":"..."}]
className must include uniqueId - Always "gb-element-{uniqueId} gb-element", never just "gb-element"
Full absolute URLs - Use https://yoursite.com/services/... not /services/... — relative paths trigger block recovery on save
No spaces in CSS functions - clamp(3rem,8vw,5rem) not clamp(3rem, 8vw, 5rem) — the block editor minifies, mismatch triggers recovery
Compact nesting - Closing tags on same line as parent: <!-- /wp:generateblocks/shape --></div> not separate lines
Simple text links use text <a> — Element <a> blocks with only text content (no inner blocks) trigger recovery errors. Use generateblocks/text with tagName: "a" for plain text links. Only use generateblocks/element with tagName: "a" when wrapping inner blocks (cards, icon buttons)
Design Inference (When CSS Not Provided)
When no CSS values are specified, infer styles based on context:
GeneratePress Defaults
Primary: #0073e6
Text: #222222
Body font: 17px, line-height 1.7
H1: 42px, H2: 35px, H3: 29px
Section padding: 60px
Container max-width: var(--gb-container-width)
Button padding: 15px 30px
yoursite.com Design System
Primary: #c0392b
Text: #0a0a0a, Muted: #5c5c5c
Background: #ffffff, Light: #f5f5f3
Headings: font-weight 900, tight letter-spacing
Section padding: 4rem
Card radius: 1rem, Button radius: 2rem
Hover lift: translateY(-6px)
Shadow: 0 20px 60px rgba(0,0,0,0.15)
Complex Layout Strategy
For large sections (50+ blocks), break into chunks:
Plan structure first - Map components before coding
Build bottom-up - Start with innermost elements
Test incrementally - Verify each component works
Use consistent IDs - Same prefix for related elements
See Troubleshooting for detailed guidance on complex layouts.