Picture a client with a big content site, hundreds of thousands of posts, many of them using complex Gutenberg layouts. They come to you frustrated. They need a custom report, a migration script, maybe some bulk edits to the content. They tried running parse_blocks() on a few of the largest posts and the server ran out of memory and fell over.
This is not a one-off. The parse_blocks() function works, but it has a real problem with anything large. It parses the entire post content into one big nested array: every bit of HTML and every JSON attribute, copied and held in memory. It is like asking a library to pile every book on your desk so you can find one sentence. I have watched a single large post turn a few megabytes of content into gigabytes of memory use. On a busy server that is enough to take it down.
You have probably written block-counting logic like this, straight out of the parse_blocks() playbook:
<?php
$blocks = parse_blocks( $post_content );
$counts = array();
while ( null !== ( $block = array_pop( $blocks ) ) ) {
$type = $block['blockName'];
$counts[ $type ] = 1 + ( $counts[ $type ] ?? 0 );
foreach ( $block['innerBlocks'] as $block ) {
$blocks[] = $block;
}
}
?>
That is a brute-force approach. It is slow, and on large content sets it becomes very hard to work with unless you spend a lot of time optimizing around it.
A streaming approach to block parsing
This is where WordPress 6.9 and the new WP_Block_Processor class come in. It changes how you work with block content on the server. Think of it as a streaming parser: instead of loading the whole library, it reads through book by book and only stops to analyze what you ask it to. For performance and memory use, that is a big difference.
Here is how that same block-counting logic looks with the WP_Block_Processor:
<?php
$processor = new WP_Block_Processor( $post_content );
$counts = array();
while ( $processor->next_block() ) {
$type = $processor->get_block_type();
$counts[ $type ] = 1 + ( $counts[ $type ] ?? 0 );
}
// Example: Only count blocks within the first 10 blocks (bbioon-specific utility)
function bbioon_count_first_ten_blocks( $html ) {
$processor = new WP_Block_Processor( $html );
$remaining = 10;
$counts = array();
while ( $processor->next_block() && --$remaining >= 0 ) {
$type = $processor->get_block_type();
$counts[ $type ] = 1 + ( $counts[ $type ] ?? 0 );
}
return $counts;
}
?>
The difference is the approach. There is no recursion and no huge array. The processor walks through the document in a single forward pass, in order. It does not build nested arrays, does not duplicate the HTML, and does not parse JSON attributes until you ask for them with allocate_and_return_parsed_attributes(). That is lazy parsing: it only does the work you actually need.
The streaming model also lets you do things that were awkward or impossible before. Want to look at only the first ten blocks, or the blocks in the first kilobyte of content? Now you can. Paired with the HTML API (worth its own post), the WP_Block_Processor gives you targeted control over block content without the memory cost that used to come with it.
Why block processing efficiency matters
For small sites with simple content, parse_blocks() is still fine. But once you are working at scale, or a client needs real content analysis or transformations, the WP_Block_Processor stops being optional. It gives you precise control over block content without the heavy memory overhead.
This landed in WordPress 6.9, and it answers a problem developers have run into for years. You can build custom tools that actually perform without hitting memory limits or writing brittle regex to pick apart HTML. There is more detail in the Make WordPress Core dev notes, which cover the feature well.
Picking the right tool for block work
The point is simple: use the right tool for the job. If you are only rendering blocks, render_block() and do_blocks() are fine. But if you are inspecting, counting, or modifying blocks in code, especially at scale, reach for the WP_Block_Processor. It uses less memory and keeps the code simpler.
This stuff gets complicated fast. If you are tired of debugging someone else’s mess and just want your site to work, drop my team a line. We have probably seen it before.