diff --git a/lib/experimental/interactivity-api/directive-processing.php b/lib/experimental/interactivity-api/directive-processing.php index 41223c0815886..eae731e243891 100644 --- a/lib/experimental/interactivity-api/directive-processing.php +++ b/lib/experimental/interactivity-api/directive-processing.php @@ -8,37 +8,9 @@ */ /** - * Process directives in each block. - * - * @param string $block_content The block content. - * @param array $block The full block. - * - * @return string Filtered block content. - */ -function gutenberg_interactivity_process_directives_in_root_blocks( $block_content, $block ) { - // Don't process inner blocks or root blocks that don't contain directives. - if ( ! WP_Directive_Processor::is_root_block( $block ) || strpos( $block_content, 'data-wp-' ) === false ) { - return $block_content; - } - - // TODO: Add some directive/components registration mechanism. - $directives = array( - 'data-wp-bind' => 'gutenberg_interactivity_process_wp_bind', - 'data-wp-context' => 'gutenberg_interactivity_process_wp_context', - 'data-wp-class' => 'gutenberg_interactivity_process_wp_class', - 'data-wp-style' => 'gutenberg_interactivity_process_wp_style', - 'data-wp-text' => 'gutenberg_interactivity_process_wp_text', - ); - - $tags = new WP_Directive_Processor( $block_content ); - $tags = gutenberg_interactivity_process_directives( $tags, 'data-wp-', $directives ); - return $tags->get_updated_html(); -} -add_filter( 'render_block', 'gutenberg_interactivity_process_directives_in_root_blocks', 10, 2 ); - -/** - * Mark the inner blocks with a temporary property so we can discard them later, - * and process only the root blocks. + * Process the Interactivity API directives using the root blocks of the + * outermost rendering, ignoring the root blocks of inner blocks like Patterns, + * Template Parts or Content. * * @param array $parsed_block The parsed block. * @param array $source_block The source block. @@ -46,16 +18,56 @@ function gutenberg_interactivity_process_directives_in_root_blocks( $block_conte * * @return array The parsed block. */ -function gutenberg_interactivity_mark_inner_blocks( $parsed_block, $source_block, $parent_block ) { - if ( ! isset( $parent_block ) ) { +function gutenberg_interactivity_process_directives( $parsed_block, $source_block, $parent_block ) { + static $is_inside_root_block = false; + static $process_directives_in_root_blocks = null; + + if ( ! isset( $process_directives_in_root_blocks ) ) { + /** + * Process directives in each root block. + * + * @param string $block_content The block content. + * @param array $block The full block. + * + * @return string Filtered block content. + */ + $process_directives_in_root_blocks = static function ( $block_content, $block ) use ( &$is_inside_root_block ) { + + if ( WP_Directive_Processor::is_root_block( $block ) ) { + + $directives = array( + 'data-wp-bind' => 'gutenberg_interactivity_process_wp_bind', + 'data-wp-context' => 'gutenberg_interactivity_process_wp_context', + 'data-wp-class' => 'gutenberg_interactivity_process_wp_class', + 'data-wp-style' => 'gutenberg_interactivity_process_wp_style', + 'data-wp-text' => 'gutenberg_interactivity_process_wp_text', + ); + + $tags = new WP_Directive_Processor( $block_content ); + $tags = gutenberg_interactivity_process_rendered_html( $tags, 'data-wp-', $directives ); + $is_inside_root_block = false; + return $tags->get_updated_html(); + + } + + return $block_content; + }; + add_filter( 'render_block', $process_directives_in_root_blocks, 10, 2 ); + } + + if ( ! isset( $parent_block ) && ! $is_inside_root_block ) { WP_Directive_Processor::add_root_block( $parsed_block ); + $is_inside_root_block = true; } + return $parsed_block; } -add_filter( 'render_block_data', 'gutenberg_interactivity_mark_inner_blocks', 10, 3 ); +add_filter( 'render_block_data', 'gutenberg_interactivity_process_directives', 10, 3 ); + /** - * Process directives. + * Traverses the HTML searching for Interactivity API directives and processing + * them. * * @param WP_Directive_Processor $tags An instance of the WP_Directive_Processor. * @param string $prefix Attribute prefix. @@ -64,7 +76,7 @@ function gutenberg_interactivity_mark_inner_blocks( $parsed_block, $source_block * @return WP_Directive_Processor The modified instance of the * WP_Directive_Processor. */ -function gutenberg_interactivity_process_directives( $tags, $prefix, $directives ) { +function gutenberg_interactivity_process_rendered_html( $tags, $prefix, $directives ) { $context = new WP_Directive_Context(); $tag_stack = array(); diff --git a/packages/e2e-tests/plugins/interactive-blocks.php b/packages/e2e-tests/plugins/interactive-blocks.php index a6bd468493840..956508a11361e 100644 --- a/packages/e2e-tests/plugins/interactive-blocks.php +++ b/packages/e2e-tests/plugins/interactive-blocks.php @@ -39,8 +39,8 @@ function () { // HTML is not correct or malformed. if ( 'true' === $_GET['disable_directives_ssr'] ) { remove_filter( - 'render_block', - 'gutenberg_interactivity_process_directives_in_root_blocks' + 'render_block_data', + 'gutenberg_interactivity_process_directives' ); } } diff --git a/phpunit/experimental/interactivity-api/directive-processing-test.php b/phpunit/experimental/interactivity-api/directive-processing-test.php index 44838b4ce68d3..97dddba3c263f 100644 --- a/phpunit/experimental/interactivity-api/directive-processing-test.php +++ b/phpunit/experimental/interactivity-api/directive-processing-test.php @@ -28,10 +28,10 @@ function gutenberg_test_process_directives_helper_increment( $store ) { } /** - * Tests for the gutenberg_interactivity_process_directives function. + * Tests for the gutenberg_interactivity_process_rendered_html function. * * @group interactivity-api - * @covers gutenberg_interactivity_process_directives + * @covers gutenberg_interactivity_process_rendered_html */ class Tests_Process_Directives extends WP_UnitTestCase { public function test_correctly_call_attribute_directive_processor_on_closing_tag() { @@ -40,19 +40,19 @@ public function test_correctly_call_attribute_directive_processor_on_closing_tag $test_helper = $this->createMock( Helper_Class::class ); $test_helper->expects( $this->exactly( 2 ) ) - ->method( 'process_foo_test' ) - ->with( - $this->callback( - function ( $p ) { - return 'DIV' === $p->get_tag() && ( - // Either this is a closing tag... - $p->is_tag_closer() || - // ...or it is an open tag, and has the directive attribute set. - ( ! $p->is_tag_closer() && 'abc' === $p->get_attribute( 'foo-test' ) ) - ); - } - ) - ); + ->method( 'process_foo_test' ) + ->with( + $this->callback( + function ( $p ) { + return 'DIV' === $p->get_tag() && ( + // Either this is a closing tag... + $p->is_tag_closer() || + // ...or it is an open tag, and has the directive attribute set. + ( ! $p->is_tag_closer() && 'abc' === $p->get_attribute( 'foo-test' ) ) + ); + } + ) + ); $directives = array( 'foo-test' => array( $test_helper, 'process_foo_test' ), @@ -60,13 +60,13 @@ function ( $p ) { $markup = '
Example:
This is a test>
Here is a nested div
'; $tags = new WP_HTML_Tag_Processor( $markup ); - gutenberg_interactivity_process_directives( $tags, 'foo-', $directives ); + gutenberg_interactivity_process_rendered_html( $tags, 'foo-', $directives ); } public function test_directives_with_double_hyphen_processed_correctly() { $test_helper = $this->createMock( Helper_Class::class ); $test_helper->expects( $this->atLeastOnce() ) - ->method( 'process_foo_test' ); + ->method( 'process_foo_test' ); $directives = array( 'foo-test' => array( $test_helper, 'process_foo_test' ), @@ -74,10 +74,76 @@ public function test_directives_with_double_hyphen_processed_correctly() { $markup = '
'; $tags = new WP_HTML_Tag_Processor( $markup ); - gutenberg_interactivity_process_directives( $tags, 'foo-', $directives ); + gutenberg_interactivity_process_rendered_html( $tags, 'foo-', $directives ); + } + + public function test_interactivity_process_directives_in_root_blocks() { + $pattern_content = + '' . + '

Pattern Content Block 1

' . + '' . + '' . + '

Pattern Content Block 2

' . + ''; + register_block_pattern( + 'core/interactivity-pattern', + array( + 'title' => 'Interactivity Pattern', + 'content' => $pattern_content, + ) + ); + + $providers = $this->data_only_root_blocks_are_processed(); + foreach ( $providers as $provider ) { + do_blocks( $provider['page_content'] ); + $this->assertSame( $provider['root_blocks'], count( WP_Directive_Processor::$root_blocks ) ); + + } + } + + /** + * Data provider . + * + * @return array + **/ + public function data_only_root_blocks_are_processed() { + + return array( + array( + 'root_blocks' => 2, + 'page_content' => + '' . + '
+ ' . + '

The XYZ Doohickey Company was founded in 1971, and has been providing' . + 'quality doohickeys to the public ever since. Located in Gotham City, XYZ employs' . + 'over 2,000 people and does all kinds of awesome things for the Gotham community.

' . + ' +
' . + '' . + '' . + '
+ ' . + '

The XYZ Doohickey Company was founded in 1971, and has been providing' . + 'quality doohickeys to the public ever since. Located in Gotham City, XYZ employs' . + 'over 2,000 people and does all kinds of awesome things for the Gotham community.

' . + ' +
' . + '', + ), + array( + 'root_blocks' => 2, + 'page_content' => + '' . + '

Welcome to WordPress. This is your first post. Edit or delete it, then start writing!

' . + '' . + '', + ), + ); } } + /** * Tests for the gutenberg_interactivity_evaluate_reference function. *