Block Architecture

Key Concepts

Block Paradigm

The Block Editor, also known as Gutenberg, is built around the concept that everything in the editor is a block. This modular approach allows for a highly flexible and customizable content creation experience. Each piece of content, whether it’s a paragraph, image, or video, is treated as a block, making it easy to manipulate and arrange content.

Block Types

There are several types of blocks:

Static Blocks: These blocks have content that doesn’t change dynamically. Examples include paragraphs and headings.
A static block stores all of its code in the content. For example, all the markup for this pull quote is contained in the content:

<!-- wp:pullquote -->
<figure class="wp-block-pullquote"><blockquote><p>quotie quote quote</p><cite>citronen</cite></blockquote></figure>
<!-- /wp:pullquote -->

Dynamic Blocks: These blocks can change based on certain conditions or data. For instance, the latest posts block that updates with new posts. In the below example, the data needed to render the frontend markup is stored, but the actual markup and data processing is done when the page is viewed:

<!-- wp:theme-slug/example-dynamic {"title":"The title!","excerpt":"we are excerpting"} /-->

Reusable Blocks: These are blocks that can be saved and reused across different posts and pages, ensuring consistency and saving time.

Block Registration

Blocks are registered using JavaScript and PHP. The registration process involves defining the block’s attributes, settings, and rendering functions. This allows developers to create custom blocks tailored to their specific needs.

The registerBlockType function is used within the block’s index.js file. Below is an example:

/**
 * Every block starts by registering a new block type definition.
 *
 * @see https://developer.wordpress.org/block-editor/reference-guides/block-api/block-registration/
 */
registerBlockType( metadata.name, {
	attributes: {
		title: {
			type: 'string',
		},
		excerpt: {
			type: 'string',
		},
	},
	/**
	 * @see ./edit.js
	 */
	edit: Edit,
	save: ( { attributes } ) => null,
	icon: { src: reactIcon, foreground: '#cc0000' },
} );

On the PHP side of things, register_block_type or register_block_type_from_metadata can be used. Both can accept the block.json file – basically, the former is shorter to type than the latter. Also, register_block_type can also ingest a WP_Block_Type instance.

The child theme has an auto-ingest function that will search the theme’s build/blocks directory for a block.json file and register the block.

Block Attributes

Attributes are used to store data for blocks. They define the properties of a block, such as its content, alignment, and other settings. Attributes are defined in the block’s registration and can be accessed and modified through the block’s controls.

The block’s registerBlockType function in the index.js file uses the attributes field to create the fields and their properties.

attributes: {
		title: {
			type: 'string',
		},
		excerpt: {
			type: 'string',
		},
	},

Further Reading: WordPress Developer Resource – Attributes

Block Patterns

Block patterns are used to group blocks in a pre-determined order. This is used to speed up the layout of a page.

Further Reading: Block Patterns

Block Variations

Block variations are predefined sets of attributes for a block type, enabling multiple configurations from a single block. This API allows for the creation of different interfaces and presets, making it easier to customize blocks according to specific needs. Variations can appear as new blocks in the library or as presets when inserting a new block.

Further Reading: Block Variations

Block Styles

Styles, formerly known as Global Styles, are configurations managed through a theme.json file. This file consolidates various settings and tools, simplifying the communication with the editor. Styles coordinate the design aspects coming from WordPress, the active theme, and the user, ensuring a cohesive look and feel across the site.

Further Reading: Block Styles

Block Controls

Block controls are the user interface elements that allow users to interact with and configure blocks. These controls can include text fields, dropdowns, sliders, and more. They provide a way for users to customize the appearance and behavior of blocks.

The controls reside in two locations.

Screenshot of the paragraph block quick controls.

One is “attached” to the block. For example, this paragraph block has the following controls:

Screenshot of the paragraph block sidebar controls.

There are also more advanced controls on the sidebar:

Block Rendering

Blocks are rendered both in the editor and on the front end of the site. The rendering process involves converting the block’s attributes and content into HTML. This ensures that the content looks consistent in both the editor and the published page.

Summarized from Key Concepts on WordPress.org

Data Flow and Format

Diagram of how a block page is parsed.

The Format

A block editor post is an internal, in-memory representation of a post in WordPress during editing. It is made up of blocks, which are semantically meaningful units of content (e.g., paragraphs, images, headings). This representation is different from the final output of the post, which is stored in post_content and rendered for the user.

The block editor’s format consists of an array of block objects, like this:

const value = [ block1, block2, block3 ];

Each block object contains:

  • clientId: A unique string identifier for the block.
  • type: The type of block (e.g., ‘core/paragraph’, ‘core/image’).
  • attributes: A set of key-value pairs that represent the properties or content of the block.
  • innerBlocks: An array of child blocks or sub-blocks within the block.

Serialization and Parsing

The block editor works with an in-memory tree of blocks, but this structure needs to be transformed into a format suitable for storage and rendering. This is done through serialization.

Serialization transforms the block tree into HTML using HTML comments as delimiters. These comments store block attributes in a non-HTML form, ensuring that the structure of the blocks can be preserved when the post is saved. This approach maintains compatibility with legacy systems that expect HTML content, while also enabling block-based editing in newer systems.

The serialized blocks are stored as HTML, and the HTML is used as the single source of truth for the post content. For example:

<!-- wp:paragraph -->
<p>This is the <strong>content</strong> of the paragraph block</p>
<!-- /wp:paragraph -->

This structure ensures that the post content can be rendered in older systems that don’t recognize the block-based editor.

When a post is reloaded for editing, a parsing grammar is used to interpret the serialized HTML and reconstruct the in-memory block tree. This allows the block editor to restore the original block structure.

The Anatomy of a Block

When a block is serialized, its attributes (like block type and content) are stored in an HTML comment, as described above. For example, an image block might be serialized as:

<!-- wp:image -->
<figure class="wp-block-image"><img src="source.jpg" alt="" /></figure>
<!-- /wp:image -->

A dynamic block (like one that fetches the latest posts from the server) could be represented with a self-closing tag:

<!-- wp:latest-posts {"postsToShow":4,"displayPostDate":true} /-->

Further Reading: Anatomy of a Block

The Data Lifecycle

The block editor workflow follows a data lifecycle:

  1. Parsing: The saved HTML content is parsed into an in-memory tree of blocks using delimiters (HTML comments).
  2. Editing: During editing, the block tree is manipulated (blocks are added, removed, or modified).
  3. Serialization: When the post is saved, the block tree is serialized back into HTML with the same delimiters and structure, and stored in the post_content field.

This lifecycle ensures the consistency of content during the editing process and that data can be easily serialized for storage or transmission.

In addition to the core editor functions, plugins or external data sources could hypothetically be used to modify or extend the block data structure, making it flexible for a variety of use cases.

Summarized from Data Flow and Data Format