From 6c47daf72c8c375e09ffe8dd671c895b72562bf2 Mon Sep 17 00:00:00 2001 From: Weston Ruter Date: Mon, 19 Jun 2017 03:11:09 +0200 Subject: [PATCH 1/6] Add do_blocks filter for the_content to run before wpautop --- lib/blocks.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/blocks.php b/lib/blocks.php index b1861fc281f9a7..99ca26415cb51b 100644 --- a/lib/blocks.php +++ b/lib/blocks.php @@ -126,4 +126,4 @@ function do_blocks( $content ) { 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(). From f8f67c2f1f9265a7d0ead8a1546890ad941e0521 Mon Sep 17 00:00:00 2001 From: Weston Ruter Date: Mon, 19 Jun 2017 03:12:10 +0200 Subject: [PATCH 2/6] Fix regex to match block contents; process unregistered and registered blocks alike --- lib/blocks.php | 37 ++++++++++++++++++++++++------------- 1 file changed, 24 insertions(+), 13 deletions(-) diff --git a/lib/blocks.php b/lib/blocks.php index 99ca26415cb51b..cae1c1573c7203 100644 --- a/lib/blocks.php +++ b/lib/blocks.php @@ -102,26 +102,37 @@ function do_blocks( $content ) { global $wp_registered_blocks; // Extract the blocks from the post content. - $matcher = '/).)*)\s*\/?-->(?:.*?)?/s'; + $matcher = '#' . join( '', array( + '(?P).)*)', + '\s*/?-->\n?)', + '(?:', + '(?P.*?)', + '(?P\n?)', + ')?', + ) ) . '#s'; preg_match_all( $matcher, $content, $matches, PREG_OFFSET_CAPTURE ); $new_content = $content; foreach ( $matches[0] as $index => $block_match ) { - $block_name = $matches[1][ $index ][0]; - // do nothing if the block is not registered. + $block_name = $matches['block_name'][ $index ][0]; + + $output = ''; if ( ! isset( $wp_registered_blocks[ $block_name ] ) ) { - continue; + if ( isset( $matches['content'][ $index ][0] ) ) { + $output = $matches['content'][ $index ][0]; + } + } else { + $block_attributes_string = $matches['attributes'][ $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 ); } - $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 ); - - // Replace the matched block with the dynamic output. - $new_content = str_replace( $block_markup, $output, $new_content ); + // Replace the matched block with the static or dynamic output. + $new_content = str_replace( $block_match[0], $output, $new_content ); } return $new_content; From 0b78c64712081b77b16d5fd2206a752b8153ff7c Mon Sep 17 00:00:00 2001 From: Weston Ruter Date: Mon, 19 Jun 2017 03:47:30 +0200 Subject: [PATCH 3/6] Replace specific matched block instead of replacing all blocks --- lib/blocks.php | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/lib/blocks.php b/lib/blocks.php index cae1c1573c7203..060ec25082a9bd 100644 --- a/lib/blocks.php +++ b/lib/blocks.php @@ -115,6 +115,7 @@ function do_blocks( $content ) { 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['block_name'][ $index ][0]; @@ -132,7 +133,15 @@ function do_blocks( $content ) { } // Replace the matched block with the static or dynamic output. - $new_content = str_replace( $block_match[0], $output, $new_content ); + $new_content = substr_replace( + $new_content, + $output, + $block_match[1] - $offset_differential, + strlen( $block_match[0] ) + ); + + // Update offset for the next replacement. + $offset_differential += strlen( $block_match[0] ) - strlen( $output ); } return $new_content; From 08bcffa35d1d81dcb973e805ae5b3fa6766f44e0 Mon Sep 17 00:00:00 2001 From: Weston Ruter Date: Mon, 19 Jun 2017 04:27:20 +0200 Subject: [PATCH 4/6] Add tests to ensure that dynamic blocks are replaced one-by-one --- phpunit/class-dynamic-blocks-render-test.php | 41 +++++++++++++++++--- 1 file changed, 35 insertions(+), 6 deletions(-) diff --git a/phpunit/class-dynamic-blocks-render-test.php b/phpunit/class-dynamic-blocks-render-test.php index 60b6de3d729e61..cc2adc4b50dd21 100644 --- a/phpunit/class-dynamic-blocks-render-test.php +++ b/phpunit/class-dynamic-blocks-render-test.php @@ -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. * @@ -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( @@ -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' . '' . + '' . 'between' . - '' . + '' . + '' . '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( @@ -67,9 +96,9 @@ function test_dynamic_block_rendering_with_content() { $updated_post_content = do_blocks( $post_content ); $this->assertEquals( $updated_post_content, 'before' . - 'b1' . + '1:b1' . 'between' . - 'b2' . + '2:b2' . 'after' ); } From 7817f8a4ba2f3e47f106a662d52d651008802611 Mon Sep 17 00:00:00 2001 From: Weston Ruter Date: Mon, 19 Jun 2017 05:25:01 +0200 Subject: [PATCH 5/6] Add test to ensure that multi-line blocks get matched in PHP --- phpunit/class-dynamic-blocks-render-test.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/phpunit/class-dynamic-blocks-render-test.php b/phpunit/class-dynamic-blocks-render-test.php index cc2adc4b50dd21..7e557ed73986d5 100644 --- a/phpunit/class-dynamic-blocks-render-test.php +++ b/phpunit/class-dynamic-blocks-render-test.php @@ -88,7 +88,7 @@ function test_dynamic_block_rendering_with_content() { register_block_type( 'core/dummy', $settings ); $post_content = 'before' . - 'this should be ignored' . + "this\nshould\n\nbe\nignored" . 'between' . 'this should also be ignored' . 'after'; From 6a6875210e9f7560ae07dd96a40f908b6187b4e4 Mon Sep 17 00:00:00 2001 From: Weston Ruter Date: Tue, 20 Jun 2017 12:18:06 -0700 Subject: [PATCH 6/6] Refactor if/else conditional in do_blocks() --- lib/blocks.php | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/lib/blocks.php b/lib/blocks.php index 060ec25082a9bd..5190dac4689583 100644 --- a/lib/blocks.php +++ b/lib/blocks.php @@ -120,16 +120,14 @@ function do_blocks( $content ) { $block_name = $matches['block_name'][ $index ][0]; $output = ''; - if ( ! isset( $wp_registered_blocks[ $block_name ] ) ) { - if ( isset( $matches['content'][ $index ][0] ) ) { - $output = $matches['content'][ $index ][0]; - } - } else { + if ( isset( $wp_registered_blocks[ $block_name ] ) ) { $block_attributes_string = $matches['attributes'][ $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]; } // Replace the matched block with the static or dynamic output.