Blocks are the fundamental element of the WordPress Block Editor. They are the primary way plugins and themes register functionality and extend the editor’s capabilities.
What is a Block?
A block is a discrete unit of content or functionality in the WordPress editor. Each block encapsulates its own:
Data structure (attributes)
User interface (edit component)
Saved output (save function or render callback)
Behavior (transforms, variations, styles)
Block Registration Methods
You can register blocks using two approaches:
1. JavaScript-only Registration
import { registerBlockType } from '@wordpress/blocks' ;
registerBlockType ( 'my-plugin/book' , {
title: __ ( 'Book' ),
edit : () => < div > { __ ( 'Hello from the editor!' ) } </ div > ,
save : () => < div > Hello from the saved content! </ div > ,
} );
The recommended approach is to use a block.json file that defines your block’s metadata:
{
"$schema" : "https://schemas.wp.org/trunk/block.json" ,
"apiVersion" : 3 ,
"name" : "core/paragraph" ,
"title" : "Paragraph" ,
"category" : "text" ,
"description" : "Start with the basic building block of all narrative." ,
"keywords" : [ "text" ],
"textdomain" : "default" ,
"attributes" : {
"content" : {
"type" : "rich-text" ,
"source" : "rich-text" ,
"selector" : "p" ,
"role" : "content"
}
},
"supports" : {
"anchor" : true ,
"color" : {
"gradients" : true ,
"link" : true
},
"typography" : {
"fontSize" : true ,
"lineHeight" : true
}
}
}
Then register it in JavaScript:
import { registerBlockType } from '@wordpress/blocks' ;
import metadata from './block.json' ;
import edit from './edit' ;
import save from './save' ;
registerBlockType ( metadata , {
edit ,
save ,
} );
Core Block API Concepts
Attributes Define the data structure and how it’s stored in post content
Supports Enable editor features like colors, spacing, and typography
Patterns Create reusable block layouts for common designs
Inner Blocks Build container blocks that can nest other blocks
Block Naming Convention
Block names must follow the pattern namespace/block-name and can only contain lowercase alphanumeric characters, dashes, and must start with a letter.
// ✅ Good examples
registerBlockType ( 'my-company-blocks/hero' , {} );
registerBlockType ( 'awesome-gallery-plugin/slideshow' , {} );
// ❌ Bad examples
registerBlockType ( 'create-block/example' , {} ); // Too generic
registerBlockType ( 'block/content' , {} ); // Too generic
registerBlockType ( 'MyPlugin/Block' , {} ); // Contains uppercase
The block name is stored in post content with every post using that block. Changing it later requires database migration.
Block Types
Static Blocks
Blocks that render entirely in JavaScript and save static HTML:
export default function save () {
const blockProps = useBlockProps . save ();
return (
< div { ... blockProps } >
< p > This HTML is saved to the database </ p >
</ div >
);
}
Dynamic Blocks
Blocks that render on the server using PHP:
register_block_type ( 'my-plugin/server-block' , array (
'render_callback' => function ( $attributes ) {
$wrapper_attributes = get_block_wrapper_attributes ();
return sprintf (
'<div %1$s>%2$s</div>' ,
$wrapper_attributes ,
'Server-rendered content'
);
},
) );
Block API Version
The apiVersion field determines which version of the Block API your block uses:
Version 1 : Original API (deprecated)
Version 2 : Introduces automatic wrapper element handling
Version 3 : Current version with enhanced features and performance
{
"apiVersion" : 3 ,
"name" : "my-plugin/my-block"
}
TypeScript Support
Gutenberg provides TypeScript type definitions for the Block API:
import type { BlockEditProps } from '@wordpress/blocks' ;
interface MyBlockAttributes {
content : string ;
alignment : 'left' | 'center' | 'right' ;
}
export default function Edit ( { attributes , setAttributes } : BlockEditProps < MyBlockAttributes > ) {
return (
< div >
< p >{ attributes. content } </ p >
</ div >
);
}
Block Data Flow
Understanding how data flows through a block:
Parsing
WordPress parses post content and extracts block data based on comment delimiters: <!-- wp:paragraph {"align":"center"} -->
< p class = "has-text-align-center" > Hello World </ p >
<!-- /wp:paragraph -->
Hydration
Block attributes are extracted using the attribute sources defined in block.json
Editing
The edit component renders with current attributes and provides controls to modify them
Saving
The save function (or PHP render callback) generates the final HTML output
Block Collections
Group related blocks together in the inserter:
import { registerBlockCollection } from '@wordpress/blocks' ;
registerBlockCollection ( 'my-plugin' , {
title: __ ( 'My Plugin Blocks' ),
icon: 'admin-plugins' ,
} );
Best Practices
Use block.json for registration
Always use block.json metadata files. They enable better performance, automatic translations, and server-side registration.
Follow naming conventions
Use a unique, descriptive namespace that represents your plugin or theme. This prevents conflicts with other blocks.
Use the supports API instead of building custom controls for common features like colors, spacing, and typography.
Consider dynamic rendering
For blocks with server-side data or complex logic, use dynamic blocks with PHP render callbacks.
Next Steps
Register Your First Block Learn the complete registration process
Define Block Attributes Understand how to structure block data