Skip to content

Commit

Permalink
Merge pull request #1244 from WordPress/update/do-blocks-parsing-and-…
Browse files Browse the repository at this point in the history
…autop

Fix parsing in do_blocks() and rendering of blocks on frontend in the_content
  • Loading branch information
westonruter authored Jun 20, 2017
2 parents aaae523 + 6a68752 commit 5eceb50
Show file tree
Hide file tree
Showing 2 changed files with 68 additions and 21 deletions.
46 changes: 32 additions & 14 deletions lib/blocks.php
Original file line number Diff line number Diff line change
Expand Up @@ -102,28 +102,46 @@ function do_blocks( $content ) {
global $wp_registered_blocks;

// Extract the blocks from the post content.
$matcher = '/<!--\s*wp:([a-z](?:[a-z0-9\/]+)*)\s+((?:(?!-->).)*)\s*\/?-->(?:.*?<!--\s*\/wp:\g1\s+-->)?/s';
$matcher = '#' . join( '', array(
'(?P<opener><!--\s*',
'wp:(?P<block_name>[a-z](?:[a-z0-9/]+)*)\s+',
'(?P<attributes>(?:(?!-->).)*)',
'\s*/?-->\n?)',
'(?:',
'(?P<content>.*?)',
'(?P<closer><!--\s*/wp:\g{block_name}\s+-->\n?)',
')?',
) ) . '#s';
preg_match_all( $matcher, $content, $matches, PREG_OFFSET_CAPTURE );

$new_content = $content;
$offset_differential = 0;
foreach ( $matches[0] as $index => $block_match ) {
$block_name = $matches[1][ $index ][0];
// do nothing if the block is not registered.
if ( ! isset( $wp_registered_blocks[ $block_name ] ) ) {
continue;
}
$block_name = $matches['block_name'][ $index ][0];

$output = '';
if ( isset( $wp_registered_blocks[ $block_name ] ) ) {
$block_attributes_string = $matches['attributes'][ $index ][0];
$block_attributes = parse_block_attributes( $block_attributes_string );

$block_markup = $block_match[0];
$block_attributes_string = $matches[2][ $index ][0];
$block_attributes = parse_block_attributes( $block_attributes_string );
// Call the block's render function to generate the dynamic output.
$output = call_user_func( $wp_registered_blocks[ $block_name ]['render'], $block_attributes );
} elseif ( isset( $matches['content'][ $index ][0] ) ) {
$output = $matches['content'][ $index ][0];
}

// Call the block's render function to generate the dynamic output.
$output = call_user_func( $wp_registered_blocks[ $block_name ]['render'], $block_attributes );
// Replace the matched block with the static or dynamic output.
$new_content = substr_replace(
$new_content,
$output,
$block_match[1] - $offset_differential,
strlen( $block_match[0] )
);

// Replace the matched block with the dynamic output.
$new_content = str_replace( $block_markup, $output, $new_content );
// Update offset for the next replacement.
$offset_differential += strlen( $block_match[0] ) - strlen( $output );
}

return $new_content;
}
add_filter( 'the_content', 'do_blocks', 10 ); // BEFORE do_shortcode().
add_filter( 'the_content', 'do_blocks', 9 ); // BEFORE do_shortcode() and wpautop().
43 changes: 36 additions & 7 deletions phpunit/class-dynamic-blocks-render-test.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,14 @@
* Test do_blocks
*/
class Dynamic_Blocks_Render_Test extends WP_UnitTestCase {

/**
* Dummy block instance number.
*
* @var int
*/
protected $dummy_block_instance_number = 0;

/**
* Dummy block rendering function.
*
Expand All @@ -17,13 +25,23 @@ class Dynamic_Blocks_Render_Test extends WP_UnitTestCase {
* @return string Block output.
*/
function render_dummy_block( $attributes ) {
return $attributes['value'];
$this->dummy_block_instance_number += 1;
return $this->dummy_block_instance_number . ':' . $attributes['value'];
}

/**
* Tear down.
*/
function tearDown() {
$this->dummy_block_instance_number = 0;
$GLOBALS['wp_registered_blocks'] = array();
}

/**
* Test dynamic blocks that lack content, including void blocks.
*
* @covers do_blocks
*/
function test_dynamic_block_rendering() {
$settings = array(
'render' => array(
Expand All @@ -32,23 +50,34 @@ function test_dynamic_block_rendering() {
),
);
register_block_type( 'core/dummy', $settings );

// The duplicated dynamic blocks below are there to ensure that do_blocks() replaces each one-by-one.
$post_content =
'before' .
'<!-- wp:core/dummy value="b1" --><!-- /wp:core/dummy -->' .
'<!-- wp:core/dummy value="b1" --><!-- /wp:core/dummy -->' .
'between' .
'<!-- wp:core/dummy value="b2" --><!-- /wp:core/dummy -->' .
'<!-- wp:core/dummy value="b2" /-->' .
'<!-- wp:core/dummy value="b2" /-->' .
'after';

$updated_post_content = do_blocks( $post_content );
$this->assertEquals( $updated_post_content,
'before' .
'b1' .
'1:b1' .
'2:b1' .
'between' .
'b2' .
'3:b2' .
'4:b2' .
'after'
);
}

/**
* Test dynamic blocks that contain content.
*
* @covers do_blocks
*/
function test_dynamic_block_rendering_with_content() {
$settings = array(
'render' => array(
Expand All @@ -59,17 +88,17 @@ function test_dynamic_block_rendering_with_content() {
register_block_type( 'core/dummy', $settings );
$post_content =
'before' .
'<!-- wp:core/dummy value="b1" -->this should be ignored<!-- /wp:core/dummy -->' .
"<!-- wp:core/dummy value=\"b1\" -->this\nshould\n\nbe\nignored<!-- /wp:core/dummy -->" .
'between' .
'<!-- wp:core/dummy value="b2" -->this should also be ignored<!-- /wp:core/dummy -->' .
'after';

$updated_post_content = do_blocks( $post_content );
$this->assertEquals( $updated_post_content,
'before' .
'b1' .
'1:b1' .
'between' .
'b2' .
'2:b2' .
'after'
);
}
Expand Down

0 comments on commit 5eceb50

Please sign in to comment.