Skip to main content

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

  1. WordPress content is fetched via GraphQL with block data
  2. The EditorBlockRenderer component parses block types
  3. Each block is rendered by its corresponding React component
  4. 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

BlockComponentDescription
core/paragraphParagraphBlockStandard text paragraphs
core/headingHeadingBlockH1-H6 headings
core/listListBlockOrdered and unordered lists
core/quoteQuoteBlockBlockquotes with citation
core/codeCodeBlockCode snippets with syntax highlighting
core/preformattedPreformattedBlockPreformatted text

Media Blocks

BlockComponentDescription
core/imageImageBlockOptimized images with next/image
core/galleryGalleryBlockImage galleries
core/videoVideoBlockVideo embeds
core/audioAudioBlockAudio players
core/coverCoverBlockImages/videos with text overlay
core/media-textMediaTextBlockSide-by-side media and text

Layout Blocks

BlockComponentDescription
core/columnsColumnsBlockMulti-column layouts
core/groupGroupBlockBlock grouping container
core/separatorSeparatorBlockHorizontal dividers
core/spacerSpacerBlockVertical spacing

Interactive Blocks

BlockComponentDescription
core/buttonsButtonsBlockButton groups
core/buttonButtonBlockIndividual buttons
core/tableTableBlockData 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:

  1. Add the FlatWP Hero block
  2. Configure title, subtitle, and CTA
  3. Set background image
  4. 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

  1. Use dynamic imports for large blocks:

    const HeavyBlock = lazy(() => import('./HeavyBlock'));
  2. Optimize images with next/image:

    <Image src={src} width={800} height={600} priority />
  3. Memoize expensive computations:

    const processedData = useMemo(() => processData(data), [data]);

Accessibility

  1. Use semantic HTML:

    <section aria-labelledby="section-title">
    <h2 id="section-title">{title}</h2>
    </section>
  2. Include ARIA labels for interactive elements

  3. Ensure keyboard navigation for interactive blocks

Type Safety

  1. Define TypeScript interfaces for all block attributes
  2. Use generated GraphQL types when available
  3. Validate props with Zod or similar

Troubleshooting

Block Not Rendering

Problem: Block shows nothing or raw HTML

Solutions:

  1. Verify block is registered in registry.ts
  2. Check component export (should be named export)
  3. Look for JavaScript errors in console
  4. Verify GraphQL query includes block data

Styling Not Applied

Problem: Block renders but looks unstyled

Solutions:

  1. Check Tailwind classes are valid
  2. Verify CSS is imported in layout
  3. Check for CSS specificity conflicts
  4. Inspect with browser DevTools

GraphQL Data Missing

Problem: Block attributes are null/undefined

Solutions:

  1. Check GraphQL query includes the block type
  2. Verify ACF fields are exposed in WPGraphQL
  3. Run pnpm graphql:codegen to update types
  4. Test query in GraphiQL

See Also