diff --git a/wp-includes/blocks.php b/wp-includes/blocks.php index fdd9de9afff..efdd9b1b1aa 100644 --- a/wp-includes/blocks.php +++ b/wp-includes/blocks.php @@ -1518,6 +1518,83 @@ function traverse_and_serialize_block( $block, $pre_callback = null, $post_callb ); } +/** + * Replaces patterns in a block tree with their content. + * + * @since 6.6.0 + * + * @param array $blocks An array blocks. + * + * @return array An array of blocks with patterns replaced by their content. + */ +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( $pattern['content'] ); + $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; +} + /** * Given an array of parsed block trees, applies callbacks before and after serializing them and * returns their concatenated output. diff --git a/wp-includes/rest-api/endpoints/class-wp-rest-block-patterns-controller.php b/wp-includes/rest-api/endpoints/class-wp-rest-block-patterns-controller.php index d8f083924e0..c98b2a7c57c 100644 --- a/wp-includes/rest-api/endpoints/class-wp-rest-block-patterns-controller.php +++ b/wp-includes/rest-api/endpoints/class-wp-rest-block-patterns-controller.php @@ -162,6 +162,12 @@ protected function migrate_pattern_categories( $pattern ) { * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure. */ public function prepare_item_for_response( $item, $request ) { + // Resolve pattern blocks so they don't need to be resolved client-side + // in the editor, improving performance. + $blocks = parse_blocks( $item['content'] ); + $blocks = resolve_pattern_blocks( $blocks ); + $item['content'] = serialize_blocks( $blocks ); + $fields = $this->get_fields_for_response( $request ); $keys = array( 'name' => 'name', diff --git a/wp-includes/rest-api/endpoints/class-wp-rest-templates-controller.php b/wp-includes/rest-api/endpoints/class-wp-rest-templates-controller.php index 0ac6c7de5a2..cbf0ee040a9 100644 --- a/wp-includes/rest-api/endpoints/class-wp-rest-templates-controller.php +++ b/wp-includes/rest-api/endpoints/class-wp-rest-templates-controller.php @@ -668,6 +668,12 @@ protected function prepare_item_for_database( $request ) { * @return WP_REST_Response Response object. */ public function prepare_item_for_response( $item, $request ) { + // Resolve pattern blocks so they don't need to be resolved client-side + // in the editor, improving performance. + $blocks = parse_blocks( $item->content ); + $blocks = resolve_pattern_blocks( $blocks ); + $item->content = serialize_blocks( $blocks ); + // Restores the more descriptive, specific name for use within this method. $template = $item; diff --git a/wp-includes/version.php b/wp-includes/version.php index 8855bd235df..afe1e0d261b 100644 --- a/wp-includes/version.php +++ b/wp-includes/version.php @@ -16,7 +16,7 @@ * * @global string $wp_version */ -$wp_version = '6.6-alpha-58299'; +$wp_version = '6.6-alpha-58303'; /** * Holds the WordPress DB revision, increments when changes are made to the WordPress DB schema.