Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 24 additions & 6 deletions packages/block-library/src/navigation/index.php
Original file line number Diff line number Diff line change
Expand Up @@ -697,14 +697,10 @@ private static function get_responsive_container_markup( $attributes, $inner_blo
if ( ! empty( $attributes['overlay'] ) ) {
// Get blocks from the overlay template part.
$overlay_blocks = static::get_overlay_blocks_from_template_part( $attributes['overlay'], $attributes );
// Check if overlay contains a navigation-overlay-close block.
$has_custom_overlay_close_block = block_core_navigation_block_tree_has_block_type(
$overlay_blocks,
'core/navigation-overlay-close',
array( 'core/navigation' ) // Skip navigation blocks, as they cannot contain an overlay close block
);
// Render template part blocks directly without navigation container wrapper.
$overlay_blocks_html = static::get_template_part_blocks_html( $overlay_blocks );
// Check if overlay contains a navigation-overlay-close block (detect in rendered HTML so it works with patterns).
$has_custom_overlay_close_block = block_core_navigation_overlay_html_has_close_block( $overlay_blocks_html );
// Add Interactivity API directives to the overlay close block if present.
if ( $has_custom_overlay_close_block && $is_interactive ) {
$tags = new WP_HTML_Tag_Processor( $overlay_blocks_html );
Expand Down Expand Up @@ -1094,6 +1090,28 @@ function block_core_navigation_get_inner_blocks_from_unstable_location( $attribu
}
}

/**
* Checks if the overlay HTML contains a navigation-overlay-close block.
*
* Uses WP_HTML_Tag_Processor to detect the close button in rendered output,
* so it works when the overlay uses patterns (pattern content is rendered at
* output time, not in the block tree).
*
* @since 7.0.0
*
* @param string $html The rendered overlay HTML.
* @return bool True if a close button element is found.
*/
function block_core_navigation_overlay_html_has_close_block( $html ) {
$tags = new WP_HTML_Tag_Processor( $html );
return $tags->next_tag(
array(
'tag_name' => 'BUTTON',
'class_name' => 'wp-block-navigation-overlay-close',
)
);
}

/**
* Add Interactivity API directives to the navigation-overlay-close block
* markup using the Tag Processor.
Expand Down
92 changes: 92 additions & 0 deletions phpunit/blocks/class-wp-navigation-block-renderer-test.php
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,98 @@ public function test_gutenberg_block_core_navigation_block_tree_has_block_type_r
$this->assertFalse( $result );
}

/**
* Test that gutenberg_block_core_navigation_overlay_html_has_close_block returns true when HTML contains the close button element.
*
* @group navigation-renderer
*
* @covers ::gutenberg_block_core_navigation_overlay_html_has_close_block
*/
public function test_gutenberg_block_core_navigation_overlay_html_has_close_block_returns_true_when_close_button_present() {
$html = '<div class="wp-block-group"><button class="wp-block-navigation-overlay-close" type="button">Close</button></div>';
$result = gutenberg_block_core_navigation_overlay_html_has_close_block( $html );
$this->assertTrue( $result );
}

/**
* Test that gutenberg_block_core_navigation_overlay_html_has_close_block returns false when HTML does not contain the close button.
*
* @group navigation-renderer
*
* @covers ::gutenberg_block_core_navigation_overlay_html_has_close_block
*/
public function test_gutenberg_block_core_navigation_overlay_html_has_close_block_returns_false_when_absent() {
$html = '<div class="wp-block-group"><p>No close button here</p></div>';
$result = gutenberg_block_core_navigation_overlay_html_has_close_block( $html );
$this->assertFalse( $result );
}

/**
* Test that gutenberg_block_core_navigation_overlay_html_has_close_block returns false when class string appears only in text content.
*
* @group navigation-renderer
*
* @covers ::gutenberg_block_core_navigation_overlay_html_has_close_block
*/
public function test_gutenberg_block_core_navigation_overlay_html_has_close_block_returns_false_when_class_in_text_only() {
$html = '<p>Use the wp-block-navigation-overlay-close button to close</p>';
$result = gutenberg_block_core_navigation_overlay_html_has_close_block( $html );
$this->assertFalse( $result );
}

/**
* Test that gutenberg_block_core_navigation_overlay_html_has_close_block finds nested close button.
*
* @group navigation-renderer
*
* @covers ::gutenberg_block_core_navigation_overlay_html_has_close_block
*/
public function test_block_core_navigation_overlay_html_has_close_block_finds_nested_close_button() {
$html = '<div class="wp-block-group"><div class="wp-block-group"><button class="wp-block-navigation-overlay-close" type="button" aria-label="Close"><svg>...</svg></button></div></div>';
$result = gutenberg_block_core_navigation_overlay_html_has_close_block( $html );
$this->assertTrue( $result );
}

/**
* Test that gutenberg_block_core_navigation_overlay_html_has_close_block detects close block when overlay content is a pattern.
*
* Simulates the bug scenario: template part contains wp:pattern, pattern renders its content including the close block.
*
* @group navigation-renderer
*
* @covers ::gutenberg_block_core_navigation_overlay_html_has_close_block
*/
public function test_block_core_navigation_overlay_html_has_close_block_detects_close_in_pattern_output() {
register_block_pattern(
'test/navigation-overlay-pattern',
array(
'title' => 'Navigation Overlay Pattern',
'content' => '<!-- wp:group --><div class="wp-block-group"><!-- wp:navigation-overlay-close /--></div><!-- /wp:group -->',
'description' => 'Pattern containing navigation-overlay-close (simulates overlay template part using pattern).',
'categories' => array( 'navigation' ),
)
);

try {
// Simulate overlay template part content: just a pattern block (unresolved in block tree).
$parsed_blocks = parse_blocks( '<!-- wp:pattern {"slug":"test/navigation-overlay-pattern"} /-->' );
$blocks = new WP_Block_List( $parsed_blocks, array() );

// Render blocks (pattern block's render_callback outputs pattern content).
$html = '';
foreach ( $blocks as $block ) {
$html .= $block->render();
}

$this->assertTrue(
gutenberg_block_core_navigation_overlay_html_has_close_block( $html ),
'Close block should be detected in rendered pattern output (fixes #76567).'
);
} finally {
unregister_block_pattern( 'test/navigation-overlay-pattern' );
}
}

/**
* Test that gutenberg_block_core_navigation_block_tree_has_block_type skips searching inside specified block types.
*
Expand Down
Loading