WordPress Blocks
FlatWP provides full support for WordPress Core Gutenberg blocks and includes a library of custom blocks designed for modern marketing websites.
Block Architecture
FlatWP uses a modular block rendering system that maps WordPress blocks to React components.
How It Works
- WordPress content is fetched via GraphQL with block data
- The
EditorBlockRenderercomponent parses block types - Each block is rendered by its corresponding React component
- Components are dynamically imported for code splitting
Block Data Structure
Each block from WordPress contains:
interface Block {
name: string; // e.g., "core/paragraph"
attributes: object; // Block-specific attributes
innerBlocks: Block[]; // Nested blocks
renderedHtml: string; // Server-rendered HTML (fallback)
}
Core Gutenberg Blocks
FlatWP includes React components for all major WordPress core blocks.
Text Blocks
| Block | Component | Description |
|---|---|---|
core/paragraph | ParagraphBlock | Standard text paragraphs |
core/heading | HeadingBlock | H1-H6 headings |
core/list | ListBlock | Ordered and unordered lists |
core/quote | QuoteBlock | Blockquotes with citation |
core/code | CodeBlock | Code snippets with syntax highlighting |
core/preformatted | PreformattedBlock | Preformatted text |
Media Blocks
| Block | Component | Description |
|---|---|---|
core/image | ImageBlock | Optimized images with next/image |
core/gallery | GalleryBlock | Image galleries |
core/video | VideoBlock | Video embeds |
core/audio | AudioBlock | Audio players |
core/cover | CoverBlock | Images/videos with text overlay |
core/media-text | MediaTextBlock | Side-by-side media and text |
Layout Blocks
| Block | Component | Description |
|---|---|---|
core/columns | ColumnsBlock | Multi-column layouts |
core/group | GroupBlock | Block grouping container |
core/separator | SeparatorBlock | Horizontal dividers |
core/spacer | SpacerBlock | Vertical spacing |
Interactive Blocks
| Block | Component | Description |
|---|---|---|
core/buttons | ButtonsBlock | Button groups |
core/button | ButtonBlock | Individual buttons |
core/table | TableBlock | Data tables |
FlatWP Custom Blocks
FlatWP includes pre-built blocks for common marketing website sections.
Hero Block
Full-width hero sections with customizable content.
Block Name: flatwp/hero
Features:
- Background image or gradient
- Title and subtitle
- CTA buttons
- Text alignment options
- Overlay opacity control
Usage in WordPress:
- Add the FlatWP Hero block
- Configure title, subtitle, and CTA
- Set background image
- Adjust overlay and alignment
Attributes:
interface HeroBlockAttributes {
title: string;
subtitle: string;
backgroundImage?: string;
overlayOpacity: number;
alignment: 'left' | 'center' | 'right';
ctaText?: string;
ctaUrl?: string;
ctaStyle: 'primary' | 'secondary' | 'outline';
}
Features Block
Grid layout for showcasing features or services.
Block Name: flatwp/features
Features:
- Configurable grid columns (2-4)
- Icon support (Lucide icons)
- Title and description per feature
- Responsive layout
Attributes:
interface FeaturesBlockAttributes {
features: Array<{
icon: string;
title: string;
description: string;
link?: string;
}>;
columns: 2 | 3 | 4;
alignment: 'left' | 'center';
}
CTA Block
Call-to-action sections with flexible layouts.
Block Name: flatwp/cta
Features:
- Full-width or contained
- Background color options
- Primary and secondary buttons
- Image or icon support
Testimonials Block
Customer testimonials with various display options.
Block Name: flatwp/testimonials
Features:
- Carousel or grid layout
- Avatar images
- Company/role display
- Star ratings
- Quote styling
Pricing Block
Pricing table layouts for products or services.
Block Name: flatwp/pricing
Features:
- Multiple pricing tiers
- Feature comparison
- Highlighted/recommended tier
- Annual/monthly toggle
- Custom CTA per tier
FAQ Block
Expandable FAQ sections.
Block Name: flatwp/faq
Features:
- Accordion-style expansion
- Schema.org FAQ markup
- Customizable styling
- Search functionality (optional)
Creating Custom Blocks
Add your own blocks to extend FlatWP.
Step 1: Create the Component
Create a new file in components/blocks/flatwp/:
// components/blocks/flatwp/MyCustomBlock.tsx
import { cn } from '@/lib/utils';
interface MyCustomBlockProps {
attributes: {
title: string;
content: string;
variant: 'default' | 'highlighted';
};
}
export function MyCustomBlock({ attributes }: MyCustomBlockProps) {
const { title, content, variant } = attributes;
return (
<section
className={cn(
'py-12 px-4',
variant === 'highlighted' && 'bg-primary/5'
)}
>
<div className="container mx-auto max-w-4xl">
<h2 className="text-3xl font-bold mb-4">{title}</h2>
<div className="prose">{content}</div>
</div>
</section>
);
}
Step 2: Register in Block Registry
Update the block registry to include your component:
// lib/blocks/registry.ts
import { lazy } from 'react';
export const blockRegistry = {
// ... existing blocks
'flatwp/my-custom-block': lazy(
() => import('@/components/blocks/flatwp/MyCustomBlock')
),
};
Step 3: Create WordPress Block (Optional)
For full WordPress editor integration, create a WordPress block:
// In WordPress plugin or theme
registerBlockType('flatwp/my-custom-block', {
title: 'My Custom Block',
category: 'flatwp',
attributes: {
title: { type: 'string', default: '' },
content: { type: 'string', default: '' },
variant: { type: 'string', default: 'default' },
},
edit: EditComponent,
save: () => null, // Render on frontend only
});
Step 4: Add GraphQL Fields
If your block uses ACF fields, ensure they're exposed in GraphQL:
query GetPageWithCustomBlock {
page(id: "123") {
editorBlocks {
name
... on FlatwpMyCustomBlock {
attributes {
title
content
variant
}
}
}
}
}
Block Rendering
EditorBlockRenderer
The main component for rendering blocks:
import { EditorBlockRenderer } from '@/components/blocks/EditorBlockRenderer';
export default function Page({ page }) {
return (
<main>
<EditorBlockRenderer blocks={page.editorBlocks} />
</main>
);
}
Fallback Rendering
For unknown blocks, FlatWP falls back to server-rendered HTML:
// Automatic fallback for unregistered blocks
<div
dangerouslySetInnerHTML={{ __html: block.renderedHtml }}
/>
Block Props
All block components receive standard props:
interface BlockComponentProps {
attributes: Record<string, unknown>;
innerBlocks?: Block[];
className?: string;
}
Styling Blocks
TailwindCSS Classes
Blocks use Tailwind for styling:
<div className="py-12 px-4 bg-background">
<h2 className="text-3xl font-bold text-foreground">
{title}
</h2>
</div>
Block-Specific Styles
Add custom styles per block:
/* globals.css */
.wp-block-flatwp-hero {
min-height: 60vh;
display: flex;
align-items: center;
}
Theme Integration
Blocks use CSS variables for theming:
:root {
--block-padding: 3rem;
--block-max-width: 1200px;
}
[data-theme='dark'] {
--block-bg: hsl(var(--background));
}
Best Practices
Performance
-
Use dynamic imports for large blocks:
const HeavyBlock = lazy(() => import('./HeavyBlock')); -
Optimize images with next/image:
<Image src={src} width={800} height={600} priority /> -
Memoize expensive computations:
const processedData = useMemo(() => processData(data), [data]);
Accessibility
-
Use semantic HTML:
<section aria-labelledby="section-title">
<h2 id="section-title">{title}</h2>
</section> -
Include ARIA labels for interactive elements
-
Ensure keyboard navigation for interactive blocks
Type Safety
- Define TypeScript interfaces for all block attributes
- Use generated GraphQL types when available
- Validate props with Zod or similar
Troubleshooting
Block Not Rendering
Problem: Block shows nothing or raw HTML
Solutions:
- Verify block is registered in
registry.ts - Check component export (should be named export)
- Look for JavaScript errors in console
- Verify GraphQL query includes block data
Styling Not Applied
Problem: Block renders but looks unstyled
Solutions:
- Check Tailwind classes are valid
- Verify CSS is imported in layout
- Check for CSS specificity conflicts
- Inspect with browser DevTools
GraphQL Data Missing
Problem: Block attributes are null/undefined
Solutions:
- Check GraphQL query includes the block type
- Verify ACF fields are exposed in WPGraphQL
- Run
pnpm graphql:codegento update types - Test query in GraphiQL
See Also
- ACF Setup - Configure Advanced Custom Fields
- GraphQL API - Query blocks via GraphQL
- Styling Guide - Customize block appearance
- Developer Guide - Advanced customization