diff --git a/src/wp-includes/blocks.php b/src/wp-includes/blocks.php index a53092e04e4d7..0655692010ffc 100644 --- a/src/wp-includes/blocks.php +++ b/src/wp-includes/blocks.php @@ -916,6 +916,29 @@ function insert_hooked_blocks( &$parsed_anchor_block, $relative_position, $hooke $markup = ''; foreach ( $hooked_block_types as $hooked_block_type ) { + $hooked_block_type_definition = WP_Block_Type_Registry::get_instance()->get_registered( $hooked_block_type ); + if ( ! $hooked_block_type_definition ) { + continue; + } + if ( false === block_has_support( $hooked_block_type_definition, 'multiple', true ) ) { + if ( $context instanceof WP_Block_Template ) { + // Template or template part. + $content = $context->content; + } elseif ( $context instanceof WP_Post ) { + // wp_navigation post. + $content = $context->post_content; + } elseif ( is_array( $context ) && isset( $context['content'] ) ) { + // Pattern. + $content = $context['content']; + } else { + $content = ''; + } + + if ( ! empty( $content ) && has_block( $hooked_block_type, $content ) ) { + continue; + } + } + $parsed_hooked_block = array( 'blockName' => $hooked_block_type, 'attrs' => array(), diff --git a/tests/phpunit/tests/blocks/insertHookedBlocks.php b/tests/phpunit/tests/blocks/insertHookedBlocks.php index cf99b213e518c..3849b82784f04 100644 --- a/tests/phpunit/tests/blocks/insertHookedBlocks.php +++ b/tests/phpunit/tests/blocks/insertHookedBlocks.php @@ -15,12 +15,45 @@ class Tests_Blocks_InsertHookedBlocks extends WP_UnitTestCase { const HOOKED_BLOCK_TYPE = 'tests/hooked-block'; const OTHER_HOOKED_BLOCK_TYPE = 'tests/other-hooked-block'; - const HOOKED_BLOCKS = array( - self::ANCHOR_BLOCK_TYPE => array( - 'after' => array( self::HOOKED_BLOCK_TYPE ), - 'before' => array( self::OTHER_HOOKED_BLOCK_TYPE ), - ), - ); + /** + * Set up. + * + * @ticket 61902. + */ + public static function wpSetUpBeforeClass() { + register_block_type( + self::HOOKED_BLOCK_TYPE, + array( + 'block_hooks' => array( + self::ANCHOR_BLOCK_TYPE => 'after', + ), + ) + ); + + register_block_type( + self::OTHER_HOOKED_BLOCK_TYPE, + array( + 'block_hooks' => array( + self::ANCHOR_BLOCK_TYPE => 'before', + ), + 'supports' => array( + 'multiple' => false, + ), + ) + ); + } + + /** + * Tear down. + * + * @ticket 61902. + */ + public static function wpTearDownAfterClass() { + $registry = WP_Block_Type_Registry::get_instance(); + + $registry->unregister( self::HOOKED_BLOCK_TYPE ); + $registry->unregister( self::OTHER_HOOKED_BLOCK_TYPE ); + } /** * @ticket 59572 @@ -34,7 +67,7 @@ public function test_insert_hooked_blocks_returns_correct_markup() { 'blockName' => self::ANCHOR_BLOCK_TYPE, ); - $actual = insert_hooked_blocks( $anchor_block, 'after', self::HOOKED_BLOCKS, array() ); + $actual = insert_hooked_blocks( $anchor_block, 'after', get_hooked_blocks(), array() ); $this->assertSame( '', $actual, @@ -59,7 +92,7 @@ public function test_insert_hooked_blocks_if_block_is_ignored() { ), ); - $actual = insert_hooked_blocks( $anchor_block, 'after', self::HOOKED_BLOCKS, array() ); + $actual = insert_hooked_blocks( $anchor_block, 'after', get_hooked_blocks(), array() ); $this->assertSame( '', $actual, @@ -84,7 +117,7 @@ public function test_insert_hooked_blocks_if_other_block_is_ignored() { ), ); - $actual = insert_hooked_blocks( $anchor_block, 'before', self::HOOKED_BLOCKS, array() ); + $actual = insert_hooked_blocks( $anchor_block, 'before', get_hooked_blocks(), array() ); $this->assertSame( '', $actual, @@ -92,6 +125,64 @@ public function test_insert_hooked_blocks_if_other_block_is_ignored() { ); } + /** + * @ticket 61902 + * + * @covers ::insert_hooked_blocks + */ + public function test_insert_hooked_blocks_if_block_has_multiple_false_and_is_already_present() { + $anchor_block = array( + 'blockName' => 'tests/anchor-block', + ); + + $context = new WP_Block_Template(); + $context->content = ''; + $context->content .= ''; + + $actual = insert_hooked_blocks( $anchor_block, 'before', get_hooked_blocks(), $context ); + $this->assertSame( + '', + $actual, + 'Hooked block with "multiple": false should not be inserted if another instance is already present.' + ); + $actual = insert_hooked_blocks( $anchor_block, 'before', get_hooked_blocks(), $context ); + $this->assertSame( + '', + $actual, + 'Hooked block with "multiple": false should not be inserted if another instance is already present.' + ); + } + + /** + * @ticket 61902 + * + * @covers ::insert_hooked_blocks + */ + public function test_insert_hooked_blocks_if_block_has_multiple_false_but_is_not_yet_present() { + $anchor_block = array( + 'blockName' => 'tests/anchor-block', + ); + + $context = new WP_Block_Template(); + $context->content = ''; + + $expected = ''; + $actual = insert_hooked_blocks( $anchor_block, 'before', get_hooked_blocks(), $context ); + $this->assertSame( + $expected, + $actual, + 'Hooked block with "multiple": false should be inserted if another instance is not present.' + ); + + $context->content = $expected . $context->content; // Simulate result of first insertion. + $actual = insert_hooked_blocks( $anchor_block, 'before', get_hooked_blocks(), $context ); + $this->assertSame( + '', + $actual, + 'Hooked block with "multiple": false should not be inserted if another instance is already present.' + ); + } + /** * @ticket 59572 * @ticket 60126 @@ -125,7 +216,7 @@ public function test_insert_hooked_blocks_filter_can_set_attributes() { return $parsed_hooked_block; }; add_filter( 'hooked_block_' . self::HOOKED_BLOCK_TYPE, $filter, 10, 4 ); - $actual = insert_hooked_blocks( $anchor_block, 'after', self::HOOKED_BLOCKS, array() ); + $actual = insert_hooked_blocks( $anchor_block, 'after', get_hooked_blocks(), array() ); remove_filter( 'hooked_block_' . self::HOOKED_BLOCK_TYPE, $filter ); $this->assertSame( @@ -171,7 +262,7 @@ public function test_insert_hooked_blocks_filter_can_wrap_block() { ); }; add_filter( 'hooked_block_' . self::HOOKED_BLOCK_TYPE, $filter, 10, 3 ); - $actual = insert_hooked_blocks( $anchor_block, 'after', self::HOOKED_BLOCKS, array() ); + $actual = insert_hooked_blocks( $anchor_block, 'after', get_hooked_blocks(), array() ); remove_filter( 'hooked_block_' . self::HOOKED_BLOCK_TYPE, $filter ); $this->assertSame( @@ -213,7 +304,7 @@ public function test_insert_hooked_blocks_filter_can_suppress_hooked_block() { return $parsed_hooked_block; }; add_filter( 'hooked_block_' . self::HOOKED_BLOCK_TYPE, $filter, 10, 4 ); - $actual = insert_hooked_blocks( $anchor_block, 'after', self::HOOKED_BLOCKS, array() ); + $actual = insert_hooked_blocks( $anchor_block, 'after', get_hooked_blocks(), array() ); remove_filter( 'hooked_block_' . self::HOOKED_BLOCK_TYPE, $filter ); $this->assertSame( '', $actual, "No markup should've been generated for hooked block suppressed by filter." ); diff --git a/tests/phpunit/tests/blocks/insertHookedBlocksAndSetIgnoredHookedBlocksMetadata.php b/tests/phpunit/tests/blocks/insertHookedBlocksAndSetIgnoredHookedBlocksMetadata.php index 8e88719fee262..cc56f38738cc7 100644 --- a/tests/phpunit/tests/blocks/insertHookedBlocksAndSetIgnoredHookedBlocksMetadata.php +++ b/tests/phpunit/tests/blocks/insertHookedBlocksAndSetIgnoredHookedBlocksMetadata.php @@ -16,12 +16,47 @@ class Tests_Blocks_InsertHookedBlocksAndSetIgnoredHookedBlocksMetadata extends W const HOOKED_BLOCK_TYPE = 'tests/hooked-block'; const OTHER_HOOKED_BLOCK_TYPE = 'tests/other-hooked-block'; - const HOOKED_BLOCKS = array( - self::ANCHOR_BLOCK_TYPE => array( - 'after' => array( self::HOOKED_BLOCK_TYPE ), - 'before' => array( self::OTHER_HOOKED_BLOCK_TYPE ), - ), - ); + /** + * Set up. + * + * @ticket 61902. + */ + public static function wpSetUpBeforeClass() { + register_block_type( + self::HOOKED_BLOCK_TYPE, + array( + 'block_hooks' => array( + self::ANCHOR_BLOCK_TYPE => 'after', + ), + ) + ); + + register_block_type( + self::OTHER_HOOKED_BLOCK_TYPE, + array( + 'block_hooks' => array( + self::ANCHOR_BLOCK_TYPE => 'before', + ), + ) + ); + + register_block_type( 'tests/hooked-block-added-by-filter' ); + register_block_type( 'tests/hooked-block-suppressed-by-filter' ); + } + + /** + * Tear down. + * + * @ticket 61902. + */ + public static function wpTearDownAfterClass() { + $registry = WP_Block_Type_Registry::get_instance(); + + $registry->unregister( self::HOOKED_BLOCK_TYPE ); + $registry->unregister( self::OTHER_HOOKED_BLOCK_TYPE ); + $registry->unregister( 'tests/hooked-block-added-by-filter' ); + $registry->unregister( 'tests/hooked-block-suppressed-by-filter' ); + } /** * @ticket 59574 @@ -47,7 +82,7 @@ public function test_insert_hooked_blocks_and_set_ignored_hooked_blocks_metadata 'blockName' => self::ANCHOR_BLOCK_TYPE, ); - $actual = insert_hooked_blocks_and_set_ignored_hooked_blocks_metadata( $anchor_block, 'after', self::HOOKED_BLOCKS, array() ); + $actual = insert_hooked_blocks_and_set_ignored_hooked_blocks_metadata( $anchor_block, 'after', get_hooked_blocks(), array() ); $this->assertSame( '', $actual, @@ -73,7 +108,7 @@ public function test_insert_hooked_blocks_and_set_ignored_hooked_blocks_metadata ), ); - $actual = insert_hooked_blocks_and_set_ignored_hooked_blocks_metadata( $anchor_block, 'after', self::HOOKED_BLOCKS, array() ); + $actual = insert_hooked_blocks_and_set_ignored_hooked_blocks_metadata( $anchor_block, 'after', get_hooked_blocks(), array() ); $this->assertSame( '', $actual, @@ -147,7 +182,7 @@ public function test_insert_hooked_blocks_and_set_ignored_hooked_blocks_metadata return $parsed_hooked_block; }; add_filter( 'hooked_block_' . self::HOOKED_BLOCK_TYPE, $filter, 10, 4 ); - $actual = insert_hooked_blocks_and_set_ignored_hooked_blocks_metadata( $anchor_block, 'after', self::HOOKED_BLOCKS, array() ); + $actual = insert_hooked_blocks_and_set_ignored_hooked_blocks_metadata( $anchor_block, 'after', get_hooked_blocks(), array() ); remove_filter( 'hooked_block_' . self::HOOKED_BLOCK_TYPE, $filter ); $this->assertSame( '', $actual, "No markup should've been generated for hooked block suppressed by filter." );