do_blocks()WP 5.0.0

Converts the specified string with Gutenberg block markup into ready HTML by sequentially parsing and rendering each block.

The function goes through the content, creates a block tree via parse_blocks(), and then outputs the HTML of each block by calling render_block(). Thus, you get the HTML of the blocks, but in any needed place — for example, when outputting data from meta-fields or REST API.

The default function hooks into the_content:

add_filter( 'the_content', 'do_blocks', 9 );

If you pass a string that does not contain comments <!-- wp:... -->, the function will return the original text unchanged.

1 time — 0.0066509 sec (very slow) | 50000 times — 30.33 sec (very slow) | PHP 8.2.25, WP 6.8.1

No Hooks.

Returns

String. Rendered HTML content.

Usage

do_blocks( $content );
$content(string) (required)
Raw content in Gutenberg block notation: <!-- wp:paragraph -->…<!-- /wp:paragraph -->.

Examples

0

#1 Demo

$block_content = do_blocks(
	<<<'HTML'
	<!-- wp:group {"layout":{"type":"constrained"}} -->
	<div class="wp-block-group">
		<!-- wp:heading {"level":2} -->
		<h2>Example of a heading</h2>
		<!-- /wp:heading -->

		<!-- wp:paragraph -->
		<p>This is a demonstration paragraph. It will be displayed just like in the editor.</p>
		<!-- /wp:paragraph -->

		<!-- wp:image {"sizeSlug":"large"} -->
		<figure class="wp-block-image size-large">
			<img src="https://via.placeholder.com/1024x512" alt="Placeholder" />
		</figure>
		<!-- /wp:image -->
	</div>
	<!-- /wp:group -->
	HTML
);

echo $block_content;

We will get:

<div class="wp-block-group">
	<div class="wp-block-group__inner-container is-layout-constrained wp-block-group-is-layout-constrained">
		<h2 class="wp-block-heading">Example of a heading</h2>

		<p>This is a demonstration paragraph. It will be displayed just like in the editor.</p>

		<figure class="wp-block-image size-large">
			<img src="https://via.placeholder.com/1024x512" alt="Placeholder"/>
		</figure>
	</div>
</div>
0

#2 Using in the REST API endpoint

Returning HTML blocks instead of raw markup.

register_rest_field( 'post', 'blocks_html', [
	'get_callback' => fn( $post_arr ) => do_blocks( $post_arr['content']['raw'] ),
] );

Changelog

Since 5.0.0 Introduced.

do_blocks() code WP 7.0

function do_blocks( $content ) {
	$blocks                = parse_blocks( $content );
	$top_level_block_count = count( $blocks );
	$output                = '';

	/**
	 * Parsed blocks consist of a list of top-level blocks. Those top-level
	 * blocks may themselves contain nested inner blocks. However, every
	 * top-level block is rendered independently, meaning there are no data
	 * dependencies between them.
	 *
	 * Ideally, therefore, the parser would only need to parse one complete
	 * top-level block at a time, render it, and move on. Unfortunately, this
	 * is not possible with {@see \parse_blocks()} because it must parse the
	 * entire given document at once.
	 *
	 * While the current implementation prevents this optimization, it’s still
	 * possible to reduce the peak memory use when calls to `render_block()`
	 * on those top-level blocks are memory-heavy (which many of them are).
	 * By setting each parsed block to `NULL` after rendering it, any memory
	 * allocated during the render will be freed and reused for the next block.
	 * Before making this change, that memory was retained and would lead to
	 * out-of-memory crashes for certain posts that now run with this change.
	 */
	for ( $i = 0; $i < $top_level_block_count; $i++ ) {
		$output      .= render_block( $blocks[ $i ] );
		$blocks[ $i ] = null;
	}

	// If there are blocks in this content, we shouldn't run wpautop() on it later.
	$priority = has_filter( 'the_content', 'wpautop' );
	if ( false !== $priority && doing_filter( 'the_content' ) && has_blocks( $content ) ) {
		remove_filter( 'the_content', 'wpautop', $priority );
		add_filter( 'the_content', '_restore_wpautop_hook', $priority + 1 );
	}

	return $output;
}