| @@ -278,10 +278,16 @@ | ||
| 278 | 278 | $is_list_open = false; |
| 279 | 279 | |
| 280 | 280 | foreach ( $inner_blocks as $inner_block ) { |
| 281 | 281 | $inner_block_markup = static::get_markup_for_inner_block( $inner_block ); |
| 282 | - $p = new WP_HTML_Tag_Processor( $inner_block_markup ); | |
| 283 | - $is_list_item = $p->next_tag( 'LI' ); | |
| 282 | + // Skip hidden blocks (e.g. hidden via block visibility) that render | |
| 283 | + // as an empty string. Without this check, empty markup is mistaken | |
| 284 | + // for a non-list-item and incorrectly closes the open <ul>. | |
| 285 | + if ( '' === $inner_block_markup ) { | |
| 286 | + continue; | |
| 287 | + } | |
| 288 | + $p = new WP_HTML_Tag_Processor( $inner_block_markup ); | |
| 289 | + $is_list_item = $p->next_tag( 'LI' ); | |
| 284 | 290 | |
| 285 | 291 | if ( $is_list_item && ! $is_list_open ) { |
| 286 | 292 | $is_list_open = true; |
| 287 | 293 | $inner_blocks_html .= sprintf( |
| @@ -410,9 +416,9 @@ | ||
| 410 | 416 | * |
| 411 | 417 | * @since 6.5.0 |
| 412 | 418 | * |
| 413 | 419 | * @param string $overlay_template_part_id The overlay template part ID in format "theme//slug". |
| 414 | - * @param array $attributes The block attributes. | |
| 420 | + * @param array $attributes The block attributes. | |
| 415 | 421 | * @return WP_Block_List Returns the inner blocks for the overlay template part. |
| 416 | 422 | */ |
| 417 | 423 | private static function get_overlay_blocks_from_template_part( $overlay_template_part_id, $attributes ) { |
| 418 | 424 | if ( empty( $overlay_template_part_id ) || ! is_string( $overlay_template_part_id ) ) { |
| @@ -511,9 +517,9 @@ | ||
| 511 | 517 | * |
| 512 | 518 | * @since 6.5.0 |
| 513 | 519 | * |
| 514 | 520 | * @param array $attributes The block attributes. |
| 515 | - * @param WP_Block $block The parsed block. | |
| 521 | + * @param WP_Block $block The parsed block. | |
| 516 | 522 | * @return WP_Block_List Returns the inner blocks for the navigation block. |
| 517 | 523 | */ |
| 518 | 524 | private static function get_inner_blocks( $attributes, $block ) { |
| 519 | 525 | $inner_blocks = $block->inner_blocks; |
| @@ -614,14 +620,15 @@ | ||
| 614 | 620 | 'center' => 'items-justified-center', |
| 615 | 621 | 'space-between' => 'items-justified-space-between', |
| 616 | 622 | ); |
| 617 | 623 | |
| 618 | - $layout_class = ''; | |
| 624 | + $layout_class = ''; | |
| 625 | + $nav_justify_content = $attributes['layout']['justifyContent'] ?? null; | |
| 619 | 626 | if ( |
| 620 | - isset( $attributes['layout']['justifyContent'] ) && | |
| 621 | - isset( $layout_justification[ $attributes['layout']['justifyContent'] ] ) | |
| 627 | + is_string( $nav_justify_content ) && | |
| 628 | + isset( $layout_justification[ $nav_justify_content ] ) | |
| 622 | 629 | ) { |
| 623 | - $layout_class .= $layout_justification[ $attributes['layout']['justifyContent'] ]; | |
| 630 | + $layout_class .= $layout_justification[ $nav_justify_content ]; | |
| 624 | 631 | } |
| 625 | 632 | if ( isset( $attributes['layout']['orientation'] ) && 'vertical' === $attributes['layout']['orientation'] ) { |
| 626 | 633 | $layout_class .= ' is-vertical'; |
| 627 | 634 | } |
| @@ -681,11 +688,16 @@ | ||
| 681 | 688 | * |
| 682 | 689 | * @since 7.0.0 |
| 683 | 690 | * |
| 684 | 691 | * @param bool $is_hidden_by_default Whether the responsive menu is hidden by default. |
| 685 | - * @param bool $has_custom_overlay Whether a custom overlay is used. | |
| 686 | - * @param array $colors The colors array. | |
| 692 | + * @param bool $has_custom_overlay Whether a custom overlay is used. | |
| 693 | + * @param array $colors The colors array. | |
| 687 | 694 | * @return array Returns the responsive container classes. |
| 695 | + * | |
| 696 | + * @phpstan-param array{ | |
| 697 | + * overlay_css_classes: list<string>, | |
| 698 | + * ... | |
| 699 | + * } $colors | |
| 688 | 700 | */ |
| 689 | 701 | private static function get_responsive_container_classes( $is_hidden_by_default, $has_custom_overlay, $colors ) { |
| 690 | 702 | $responsive_container_classes = array( 'wp-block-navigation__responsive-container' ); |
| 691 | 703 | |
| @@ -708,10 +720,16 @@ | ||
| 708 | 720 | * Get overlay inline styles for the navigation block. |
| 709 | 721 | * |
| 710 | 722 | * @since 7.0.0 |
| 711 | 723 | * |
| 712 | - * @param array $colors The colors array. | |
| 724 | + * @param bool $has_custom_overlay Whether a custom overlay is used. | |
| 725 | + * @param array $colors The colors array. | |
| 713 | 726 | * @return string Returns the overlay inline styles. |
| 727 | + * | |
| 728 | + * @phpstan-param array{ | |
| 729 | + * overlay_inline_styles: string, | |
| 730 | + * ... | |
| 731 | + * } $colors | |
| 714 | 732 | */ |
| 715 | 733 | private static function get_overlay_inline_styles( $has_custom_overlay, $colors ) { |
| 716 | 734 | $overlay_inline_styles = $has_custom_overlay ? '' : esc_attr( safecss_filter_attr( $colors['overlay_inline_styles'] ) ); |
| 717 | 735 | return ( ! empty( $overlay_inline_styles ) ) ? "style=\"$overlay_inline_styles\"" : ''; |
| @@ -721,10 +739,10 @@ | ||
| 721 | 739 | * Get the responsive container markup |
| 722 | 740 | * |
| 723 | 741 | * @since 6.5.0 |
| 724 | 742 | * |
| 725 | - * @param array $attributes The block attributes. | |
| 726 | - * @param WP_Block_List $inner_blocks The list of inner blocks. | |
| 743 | + * @param array $attributes The block attributes. | |
| 744 | + * @param WP_Block_List $inner_blocks The list of inner blocks. | |
| 727 | 745 | * @param string $inner_blocks_html The markup for the inner blocks. |
| 728 | 746 | * @return string Returns the container markup. |
| 729 | 747 | */ |
| 730 | 748 | private static function get_responsive_container_markup( $attributes, $inner_blocks, $inner_blocks_html ) { |
| @@ -813,8 +831,16 @@ | ||
| 813 | 831 | '; |
| 814 | 832 | $responsive_container_content_directives = ' |
| 815 | 833 | data-wp-watch="callbacks.focusFirstElement" |
| 816 | 834 | '; |
| 835 | + | |
| 836 | + // The default overlay displays every submenu it contains; a custom overlay | |
| 837 | + // opts out through the `disable-default-overlay` class on this container. | |
| 838 | + // Submenus inherit this flag to tell the two apart, derived from the same | |
| 839 | + // value as that class so the markup and the styles cannot disagree. | |
| 840 | + if ( $has_custom_overlay ) { | |
| 841 | + $responsive_container_directives .= ' ' . wp_interactivity_data_wp_context( array( 'hasCustomOverlay' => true ) ); | |
| 842 | + } | |
| 817 | 843 | } |
| 818 | 844 | |
| 819 | 845 | // Don't apply overlay inline styles if using a custom overlay template part. |
| 820 | 846 | // The custom overlay is responsible for its own styling. |
| @@ -873,10 +899,10 @@ | ||
| 873 | 899 | * Get the wrapper attributes |
| 874 | 900 | * |
| 875 | 901 | * @since 6.5.0 |
| 876 | 902 | * |
| 877 | - * @param array $attributes The block attributes. | |
| 878 | - * @param WP_Block_List $inner_blocks A list of inner blocks. | |
| 903 | + * @param array $attributes The block attributes. | |
| 904 | + * @param WP_Block_List $inner_blocks A list of inner blocks. | |
| 879 | 905 | * @return string Returns the navigation block markup. |
| 880 | 906 | */ |
| 881 | 907 | private static function get_nav_attributes( $attributes, $inner_blocks ) { |
| 882 | 908 | $is_interactive = static::is_interactive( $attributes, $inner_blocks ); |
| @@ -960,9 +986,9 @@ | ||
| 960 | 986 | * Returns the markup for the navigation block. |
| 961 | 987 | * |
| 962 | 988 | * @since 6.5.0 |
| 963 | 989 | * |
| 964 | - * @param array $attributes The block attributes. | |
| 990 | + * @param array $attributes The block attributes. | |
| 965 | 991 | * @param WP_Block_List $inner_blocks The list of inner blocks. |
| 966 | 992 | * @return string Returns the navigation wrapper markup. |
| 967 | 993 | */ |
| 968 | 994 | private static function get_inner_block_markup( $attributes, $inner_blocks ) { |
| @@ -1029,8 +1055,12 @@ | ||
| 1029 | 1055 | } |
| 1030 | 1056 | |
| 1031 | 1057 | unset( $attributes['rgbTextColor'], $attributes['rgbBackgroundColor'] ); |
| 1032 | 1058 | |
| 1059 | + // Submenu detection is memoized while a navigation block renders. Reset it so | |
| 1060 | + // the result of a previously rendered navigation block is not reused for this one. | |
| 1061 | + static::$has_submenus = false; | |
| 1062 | + | |
| 1033 | 1063 | $inner_blocks = static::get_inner_blocks( $attributes, $block ); |
| 1034 | 1064 | // Prevent navigation blocks referencing themselves from rendering. |
| 1035 | 1065 | if ( gutenberg_block_core_navigation_block_tree_has_block_type( |
| 1036 | 1066 | $inner_blocks, |
| @@ -1249,9 +1279,9 @@ | ||
| 1249 | 1279 | 'class_name' => 'wp-block-navigation-submenu__toggle', |
| 1250 | 1280 | ) |
| 1251 | 1281 | ) ) { |
| 1252 | 1282 | $tags->set_attribute( 'data-wp-on--click', 'actions.toggleMenuOnClick' ); |
| 1253 | - $tags->set_attribute( 'data-wp-bind--aria-expanded', 'state.isMenuOpen' ); | |
| 1283 | + $tags->set_attribute( 'data-wp-bind--aria-expanded', 'state.isSubmenuOpen' ); | |
| 1254 | 1284 | // The `aria-expanded` attribute for SSR is already added in the submenu block. |
| 1255 | 1285 | } |
| 1256 | 1286 | // Add directives to the submenu. |
| 1257 | 1287 | if ( $tags->next_tag( |
| @@ -1767,14 +1797,14 @@ | ||
| 1767 | 1797 | * @since 5.9.0 |
| 1768 | 1798 | * |
| 1769 | 1799 | * @deprecated 6.3.0 Use WP_Navigation_Fallback::parse_blocks_from_menu_items() instead. |
| 1770 | 1800 | * |
| 1771 | - * @param array $menu_items An array of menu items that represent | |
| 1772 | - * an individual level of a menu. | |
| 1773 | - * @param array $menu_items_by_parent_id An array keyed by the id of the | |
| 1774 | - * parent menu where each element is an | |
| 1775 | - * array of menu items that belong to | |
| 1776 | - * that parent. | |
| 1801 | + * @param array $menu_items An array of menu items that represent | |
| 1802 | + * an individual level of a menu. | |
| 1803 | + * @param array $menu_items_by_parent_id An array keyed by the id of the | |
| 1804 | + * parent menu where each element is an | |
| 1805 | + * array of menu items that belong to | |
| 1806 | + * that parent. | |
| 1777 | 1807 | * @return array An array of parsed block data. |
| 1778 | 1808 | */ |
| 1779 | 1809 | function gutenberg_block_core_navigation_parse_blocks_from_menu_items( $menu_items, $menu_items_by_parent_id ) { |
| 1780 | 1810 | |
| @@ -1872,9 +1902,9 @@ | ||
| 1872 | 1902 | * @since 6.2.0 |
| 1873 | 1903 | * |
| 1874 | 1904 | * @deprecated 6.3.0 Use WP_Navigation_Fallback::get_classic_menu_fallback_blocks() instead. |
| 1875 | 1905 | * |
| 1876 | - * @param object $classic_nav_menu WP_Term The classic navigation object to convert. | |
| 1906 | + * @param object $classic_nav_menu WP_Term The classic navigation object to convert. | |
| 1877 | 1907 | * @return array the normalized parsed blocks. |
| 1878 | 1908 | */ |
| 1879 | 1909 | function gutenberg_block_core_navigation_get_classic_menu_fallback_blocks( $classic_nav_menu ) { |
| 1880 | 1910 | |