mirror of
git://develop.git.wordpress.org/
synced 2025-04-11 15:42:03 +02:00
Editor: resolve patterns server side.
See https://github.com/WordPress/gutenberg/pull/60349. See https://github.com/WordPress/gutenberg/pull/61757. See https://github.com/WordPress/wordpress-develop/pull/6673. Fixes #61228. Props ellatrix, antonvlasenko. git-svn-id: https://develop.svn.wordpress.org/trunk@58303 602fd350-edb4-49c9-b593-d223f7449a82
This commit is contained in:
parent
94a0485a5e
commit
06914f5ca6
@ -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.
|
||||
|
@ -162,6 +162,12 @@ class WP_REST_Block_Patterns_Controller extends WP_REST_Controller {
|
||||
* @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',
|
||||
|
@ -668,6 +668,12 @@ class WP_REST_Templates_Controller extends WP_REST_Controller {
|
||||
* @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;
|
||||
|
||||
|
72
tests/phpunit/tests/blocks/resolvePatternBlocks.php
Normal file
72
tests/phpunit/tests/blocks/resolvePatternBlocks.php
Normal file
@ -0,0 +1,72 @@
|
||||
<?php
|
||||
/**
|
||||
* Tests for resolve_pattern_blocks.
|
||||
*
|
||||
* @package WordPress
|
||||
* @subpackage Blocks
|
||||
*
|
||||
* @since 6.6.0
|
||||
*
|
||||
* @group blocks
|
||||
* @covers resolve_pattern_blocks
|
||||
*/
|
||||
class Tests_Blocks_ResolvePatternBlocks extends WP_UnitTestCase {
|
||||
public function set_up() {
|
||||
parent::set_up();
|
||||
|
||||
register_block_pattern(
|
||||
'core/test',
|
||||
array(
|
||||
'title' => 'Test',
|
||||
'content' => '<!-- wp:paragraph -->Hello<!-- /wp:paragraph --><!-- wp:paragraph -->World<!-- /wp:paragraph -->',
|
||||
'description' => 'Test pattern.',
|
||||
)
|
||||
);
|
||||
register_block_pattern(
|
||||
'core/recursive',
|
||||
array(
|
||||
'title' => 'Recursive',
|
||||
'content' => '<!-- wp:paragraph -->Recursive<!-- /wp:paragraph --><!-- wp:pattern {"slug":"core/recursive"} /-->',
|
||||
'description' => 'Recursive pattern.',
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
public function tear_down() {
|
||||
unregister_block_pattern( 'core/test' );
|
||||
unregister_block_pattern( 'core/recursive' );
|
||||
|
||||
parent::tear_down();
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider data_should_resolve_pattern_blocks_as_expected
|
||||
*
|
||||
* @ticket 61228
|
||||
*
|
||||
* @param string $blocks A string representing blocks that need resolving.
|
||||
* @param string $expected Expected result.
|
||||
*/
|
||||
public function test_should_resolve_pattern_blocks_as_expected( $blocks, $expected ) {
|
||||
$actual = resolve_pattern_blocks( parse_blocks( $blocks ) );
|
||||
$this->assertSame( $expected, serialize_blocks( $actual ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Data provider.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function data_should_resolve_pattern_blocks_as_expected() {
|
||||
return array(
|
||||
// Works without attributes, leaves the block as is.
|
||||
'pattern with no slug attribute' => array( '<!-- wp:pattern /-->', '<!-- wp:pattern /-->' ),
|
||||
// Resolves the pattern.
|
||||
'test pattern' => array( '<!-- wp:pattern {"slug":"core/test"} /-->', '<!-- wp:paragraph -->Hello<!-- /wp:paragraph --><!-- wp:paragraph -->World<!-- /wp:paragraph -->' ),
|
||||
// Skips recursive patterns.
|
||||
'recursive pattern' => array( '<!-- wp:pattern {"slug":"core/recursive"} /-->', '<!-- wp:paragraph -->Recursive<!-- /wp:paragraph -->' ),
|
||||
// Resolves the pattern within a block.
|
||||
'pattern within a block' => array( '<!-- wp:group --><!-- wp:paragraph -->Before<!-- /wp:paragraph --><!-- wp:pattern {"slug":"core/test"} /--><!-- wp:paragraph -->After<!-- /wp:paragraph --><!-- /wp:group -->', '<!-- wp:group --><!-- wp:paragraph -->Before<!-- /wp:paragraph --><!-- wp:paragraph -->Hello<!-- /wp:paragraph --><!-- wp:paragraph -->World<!-- /wp:paragraph --><!-- wp:paragraph -->After<!-- /wp:paragraph --><!-- /wp:group -->' ),
|
||||
);
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user