This function has no description on this page, so here's what it actually does and a few non-obvious behaviors found in the source:
resolve_pattern_blocks() walks a block tree (as returned by parse_blocks()) and replaces any 'core/pattern' block — a reference to a registered pattern by slug — with that pattern's actual block content, recursively (including inside innerBlocks).
1. UNKNOWN PATTERNS ARE LEFT ALONE. If the referenced slug isn't aregistered pattern, the 'core/pattern' block is left untouched in the tree (it won't render as content, but it stays as-is).
2. RECURSIVE PATTERNS ARE SILENTLY DELETED. If a pattern ends up referencing itself (directly, or through another pattern it includes), the SECOND occurrence isn't left in place or replaced with an error — it's spliced out of the block array entirely, with no warning. If you're debugging "why did my block disappear", check for pattern self-references.
3. STATE CAN LEAK BETWEEN CALLS IN THE SAME REQUEST. The $seen_refs and $inner_content variables are declared `static` inside the function, so they persist across separate top-level calls within the same PHP request — not just within one recursive call chain. The code always cleans up $seen_refs[$slug] after processing a pattern, but only if execution reaches that line. If something throws an exception while resolving a pattern's inner blocks (e.g. a filter hooked into parse_blocks() elsewhere), that slug's entry in $seen_refs is never removed. Every SUBSEQUENT call to resolve_pattern_blocks() in that same request will then treat that slug as "already seen" and silently strip it out — even in completely unrelated block trees. This is hard to reproduce and debug because it depends on request-wide state, not on the input you're passing in.
Practical takeaway: don't build custom exception-handling around code paths that call this function (or anything that calls parse_blocks() during pattern resolution) without being aware that a mid-resolution failure can corrupt pattern rendering for the rest of that request.
Replaces patterns in a block tree with their content.
Parameters$blocksarrayrequiredAn array blocks.
function resolve_pattern_blocks( $blocks ) {
static $inner_content;
// Keep track of seen references to avoid infinite loops.
static $seen_refs = array();
$i = 0;
while ( $i < count( $blocks ) ) {
if ( 'core/pattern' === $blocks[ $i ]['blockName'] ) {
$attrs = $blocks[ $i ]['attrs'];
if ( empty( $attrs['slug'] ) ) {
++$i;
continue;
}
$slug = $attrs['slug'];
if ( isset( $seen_refs[ $slug ] ) ) {
// Skip recursive patterns.
array_splice( $blocks, $i, 1 );
continue;
}
$registry = WP_Block_Patterns_Registry::get_instance();
$pattern = $registry->get_registered( $slug );
// Skip unknown patterns.
if ( ! $pattern ) {
++$i;
continue;
}
$blocks_to_insert = parse_blocks( trim( $pattern['content'] ) );
/*
* For single-root patterns, add the pattern name to make this a pattern instance in the editor.
* If the pattern has metadata, merge it with the existing metadata.
*/
if ( count( $blocks_to_insert ) === 1 ) {
$block_metadata = $blocks_to_insert[0]['attrs']['metadata'] ?? array();
$block_metadata['patternName'] = $slug;
/*
* Merge pattern metadata with existing block metadata.
* Pattern metadata takes precedence, but existing block metadata
* is preserved as a fallback when the pattern doesn't define that field.
* Only the defined fields (name, description, categories) are updated;
* other metadata keys are preserved.
*/
foreach ( array(
'name' => 'title', // 'title' is the field in the pattern object 'name' is the field in the block metadata.
'description' => 'description',
'categories' => 'categories',
) as $key => $pattern_key ) {
$value = $pattern[ $pattern_key ] ?? $block_metadata[ $key ] ?? null;
if ( $value ) {
$block_metadata[ $key ] = is_array( $value )
? array_map( 'sanitize_text_field', $value )
: sanitize_text_field( $value );
}
}
$blocks_to_insert[0]['attrs']['metadata'] = $block_metadata;
}
$seen_refs[ $slug ] = true;
$prev_inner_content = $inner_content;
$inner_content = null;
$blocks_to_insert = resolve_pattern_blocks( $blocks_to_insert );
$inner_content = $prev_inner_content;
unset( $seen_refs[ $slug ] );
array_splice( $blocks, $i, 1, $blocks_to_insert );
// If we have inner content, we need to insert nulls in the
// inner content array, otherwise serialize_blocks will skip
// blocks.
if ( $inner_content ) {
$null_indices = array_keys( $inner_content, null, true );
$content_index = $null_indices[ $i ];
$nulls = array_fill( 0, count( $blocks_to_insert ), null );
array_splice( $inner_content, $content_index, 1, $nulls );
}
// Skip inserted blocks.
$i += count( $blocks_to_insert );
} else {
if ( ! empty( $blocks[ $i ]['innerBlocks'] ) ) {
$prev_inner_content = $inner_content;
$inner_content = $blocks[ $i ]['innerContent'];
$blocks[ $i ]['innerBlocks'] = resolve_pattern_blocks(
$blocks[ $i ]['innerBlocks']
);
$blocks[ $i ]['innerContent'] = $inner_content;
$inner_content = $prev_inner_content;
}
++$i;
}
}
return $blocks;
}
View all references View on Trac View on GitHub
Changelog| Version | Description |
|---|---|
| 7.0.0 | Adds metadata to attributes of single-pattern container blocks. |
| 6.6.0 | Introduced. |
| # | Наименование новости | Тональность | Информативность | Дата публикации |
|---|---|---|---|---|
| 1 | Comment on WP_REST_Request::get_param() by Rodrigo Vieira Eufrasio da Silva | 0 | 12.64 | 14-08-2026 |
| 2 | Comment on load_script_textdomain_relative_path by Rodrigo Vieira Eufrasio da Silva | 0 | 8.69 | 14-08-2026 |
| 3 | Comment on load_script_module_textdomain() by Rodrigo Vieira Eufrasio da Silva | 0 | 6.98 | 14-08-2026 |
| 4 | Comment on WP_Icons_Registry by Rodrigo Vieira Eufrasio da Silva | 0 | 9.38 | 14-08-2026 |
| 5 | Comment on wp_deregister_script() by Rodrigo Vieira Eufrasio da Silva | 0 | 29.53 | 14-08-2026 |
| 6 | Comment on login_head by vee | 0 | 9.55 | 15-08-2026 |
| 7 | A treasure hunt hidden in my blog | 0 | 6.08 | 19-08-2026 |
| 8 | anyway the “nice cock jason” tiktok is playing in my head at all times on repeat indefinitely | 0 | 17.66 | 10-02-2026 |
| 9 | i’m sorry. | 0 | 27.76 | 06-06-2026 |
| 10 | Постсекулярный поворот и цифровые повествования буддийской идентичности | 0 | 12.8 | 11-07-2026 |