PluginProbe
Gutenberg / 22.7.0
Gutenberg v22.7.0
24.0.0 23.9.1 23.9.0 23.8.0 23.7.2 23.7.1 23.7.0 23.6.1 23.6.2 23.6.0 23.5.3 23.5.2 23.5.1 23.5.0 23.4.0 23.3.2 23.3.1 23.3.0 23.2.0 23.2.1 23.2.2 23.1.1 23.1.0 23.0.1 12.6.0 All 403 releases
← All changes | build/scripts/block-library/navigation.php +21 -231 23.6.2 → 22.7.0 View file →
@@ -15,9 +15,9 @@
15 15 * Backward compatibility: WordPress applies default attribute values, so submenuVisibility
16 16 * will always have a value even for legacy blocks. We check the legacy openSubmenusOnClick
17 17 * attribute first to preserve original behavior for blocks saved before the migration.
18 18 *
19 - * @since 7.0.0
19 + * @since 6.9.0
20 20 *
21 21 * @param array $attributes Block attributes containing submenuVisibility and/or openSubmenusOnClick.
22 22 * @return string The visibility mode: 'hover', 'click', or 'always'.
23 23 */
@@ -40,47 +40,8 @@
40 40 return $submenu_visibility ?? 'hover';
41 41 }
42 42
43 43 /**
44 - * Returns the custom properties used by the Navigation block for a layout.
45 - *
46 - * @since 7.1.0
47 - *
48 - * @param array $layout Layout configuration.
49 - * @return array Navigation layout custom property declarations.
50 - */
51 -function gutenberg_block_core_navigation_get_layout_custom_property_declarations( $layout ) {
52 - $justification_values = array(
53 - 'left' => 'flex-start',
54 - 'center' => 'center',
55 - 'right' => 'flex-end',
56 - 'space-between' => 'space-between',
57 - );
58 - $justify_content = is_array( $layout ) ? ( $layout['justifyContent'] ?? 'left' ) : 'left';
59 - if ( ! is_string( $justify_content ) || ! isset( $justification_values[ $justify_content ] ) ) {
60 - $justify_content = 'left';
61 - }
62 -
63 - $justification = $justification_values[ $justify_content ];
64 - $is_vertical = is_array( $layout ) && 'vertical' === ( $layout['orientation'] ?? null );
65 - $align = 'center';
66 - $justify = $justification;
67 -
68 - if ( $is_vertical ) {
69 - $align = in_array( $justify_content, array( 'center', 'right' ), true ) ? $justification : 'flex-start';
70 - $justify = 'left' === $justify_content ? 'initial' : $justification;
71 - }
72 -
73 - return array(
74 - '--navigation-layout-justification-setting' => $justification,
75 - '--navigation-layout-direction' => $is_vertical ? 'column' : 'row',
76 - '--navigation-layout-wrap' => is_array( $layout ) && 'nowrap' === ( $layout['flexWrap'] ?? null ) ? 'nowrap' : 'wrap',
77 - '--navigation-layout-justify' => $justify,
78 - '--navigation-layout-align' => $align,
79 - );
80 -}
81 -
82 -/**
83 44 * Helper functions used to render the navigation block.
84 45 *
85 46 * @since 6.5.0
86 47 */
@@ -463,13 +424,9 @@
463 424 // Construct the full template part ID for get_block_file_template.
464 425 $full_template_part_id = $theme . '//' . $slug;
465 426 $block_template = get_block_file_template( $full_template_part_id, 'wp_template_part' );
466 427 if ( isset( $block_template->content ) ) {
467 - // Expand shortcodes before parsing blocks, matching the order in
468 - // `render_block_core_template_part()`.
469 - $content = shortcode_unautop( $block_template->content );
470 - $content = do_shortcode( $content );
471 - $parsed_blocks = parse_blocks( $content );
428 + $parsed_blocks = parse_blocks( $block_template->content );
472 429 $blocks = gutenberg_block_core_navigation_filter_out_empty_blocks( $parsed_blocks );
473 430 // Disable overlay menu for any navigation blocks within the overlay to prevent nested overlays.
474 431 $blocks = static::disable_overlay_menu_for_nested_navigation_blocks( $blocks );
475 432 return new WP_Block_List( $blocks, $attributes );
@@ -491,14 +448,8 @@
491 448
492 449 // Re-serialize, and run Block Hooks algorithm to inject hooked blocks.
493 450 $markup = serialize_blocks( $blocks );
494 451 $markup = apply_block_hooks_to_content_from_post_object( $markup, $template_part_post );
495 -
496 - // Expand shortcodes before parsing blocks, matching the order in
497 - // `render_block_core_template_part()`.
498 - $markup = shortcode_unautop( $markup );
499 - $markup = do_shortcode( $markup );
500 -
501 452 $blocks = parse_blocks( $markup );
502 453
503 454 // Disable overlay menu for any navigation blocks within the overlay to prevent nested overlays.
504 455 $blocks = static::disable_overlay_menu_for_nested_navigation_blocks( $blocks );
@@ -745,23 +696,21 @@
745 696 // This needs to happen before building classes so we know if overlay blocks actually exist.
746 697 if ( ! empty( $attributes['overlay'] ) ) {
747 698 // Get blocks from the overlay template part.
748 699 $overlay_blocks = static::get_overlay_blocks_from_template_part( $attributes['overlay'], $attributes );
700 + // Check if overlay contains a navigation-overlay-close block.
701 + $has_custom_overlay_close_block = gutenberg_block_core_navigation_block_tree_has_block_type(
702 + $overlay_blocks,
703 + 'core/navigation-overlay-close',
704 + array( 'core/navigation' ) // Skip navigation blocks, as they cannot contain an overlay close block
705 + );
749 706 // Render template part blocks directly without navigation container wrapper.
750 707 $overlay_blocks_html = static::get_template_part_blocks_html( $overlay_blocks );
751 - // Check if overlay contains a navigation-overlay-close block (detect in rendered HTML so it works with patterns).
752 - $has_custom_overlay_close_block = gutenberg_block_core_navigation_overlay_html_has_close_block( $overlay_blocks_html );
753 708 // Add Interactivity API directives to the overlay close block if present.
754 709 if ( $has_custom_overlay_close_block && $is_interactive ) {
755 710 $tags = new WP_HTML_Tag_Processor( $overlay_blocks_html );
756 711 $overlay_blocks_html = gutenberg_block_core_navigation_add_directives_to_overlay_close( $tags );
757 712 }
758 - // Images in the overlay are hidden until the menu is opened. Pre-set
759 - // fetchpriority="low" so that when wp_filter_content_tags() processes the
760 - // parent template part, it sees the attribute already present and calls
761 - // wp_get_loading_optimization_attributes() with fetchpriority="low", which both prevents
762 - // fetchpriority="high" from being added and stops the LCP counter from being incremented.
763 - $overlay_blocks_html = gutenberg_block_core_navigation_set_overlay_image_fetch_priority( $overlay_blocks_html );
764 713 }
765 714
766 715 $has_custom_overlay = ! empty( $overlay_blocks_html );
767 716
@@ -1139,30 +1088,8 @@
1139 1088 }
1140 1089 }
1141 1090
1142 1091 /**
1143 - * Checks if the overlay HTML contains a navigation-overlay-close block.
1144 - *
1145 - * Uses WP_HTML_Tag_Processor to detect the close button in rendered output,
1146 - * so it works when the overlay uses patterns (pattern content is rendered at
1147 - * output time, not in the block tree).
1148 - *
1149 - * @since 7.0.0
1150 - *
1151 - * @param string $html The rendered overlay HTML.
1152 - * @return bool True if a close button element is found.
1153 - */
1154 -function gutenberg_block_core_navigation_overlay_html_has_close_block( $html ) {
1155 - $tags = new WP_HTML_Tag_Processor( $html );
1156 - return $tags->next_tag(
1157 - array(
1158 - 'tag_name' => 'BUTTON',
1159 - 'class_name' => 'wp-block-navigation-overlay-close',
1160 - )
1161 - );
1162 -}
1163 -
1164 -/**
1165 1092 * Add Interactivity API directives to the navigation-overlay-close block
1166 1093 * markup using the Tag Processor.
1167 1094 *
1168 1095 * @since 6.5.0
@@ -1184,27 +1111,8 @@
1184 1111 return $tags->get_updated_html();
1185 1112 }
1186 1113
1187 1114 /**
1188 - * Sets fetchpriority="low" on all IMG tags within the navigation overlay.
1189 - *
1190 - * Images in the overlay are hidden until the menu is opened, so they should
1191 - * not compete with any actual LCP element image on the page.
1192 - *
1193 - * @since 7.0.0
1194 - *
1195 - * @param string $overlay_blocks_html The rendered HTML of the overlay blocks.
1196 - * @return string Modified HTML with fetchpriority="low" on all IMG tags.
1197 - */
1198 -function gutenberg_block_core_navigation_set_overlay_image_fetch_priority( string $overlay_blocks_html ): string {
1199 - $tags = new WP_HTML_Tag_Processor( $overlay_blocks_html );
1200 - while ( $tags->next_tag( 'IMG' ) ) {
1201 - $tags->set_attribute( 'fetchpriority', 'low' );
1202 - }
1203 - return $tags->get_updated_html();
1204 -}
1205 -
1206 -/**
1207 1115 * Add Interactivity API directives to the navigation-submenu and page-list
1208 1116 * blocks markup using the Tag Processor.
1209 1117 *
1210 1118 * @since 6.3.0
@@ -1237,10 +1145,10 @@
1237 1145 $computed_visibility = gutenberg_block_core_navigation_get_submenu_visibility( $block_attributes );
1238 1146 $open_on_hover = 'hover' === $computed_visibility;
1239 1147
1240 1148 if ( $open_on_hover ) {
1241 - $tags->set_attribute( 'data-wp-on--pointerenter', 'actions.openMenuOnHover' );
1242 - $tags->set_attribute( 'data-wp-on--pointerleave', 'actions.closeMenuOnHover' );
1149 + $tags->set_attribute( 'data-wp-on--mouseenter', 'actions.openMenuOnHover' );
1150 + $tags->set_attribute( 'data-wp-on--mouseleave', 'actions.closeMenuOnHover' );
1243 1151 }
1244 1152
1245 1153 // Add directives to the toggle submenu button.
1246 1154 if ( $tags->next_tag(
@@ -1393,8 +1301,19 @@
1393 1301 return $font_sizes;
1394 1302 }
1395 1303
1396 1304 /**
1305 + * Returns the top-level submenu SVG chevron icon.
1306 + *
1307 + * @since 5.9.0
1308 + *
1309 + * @return string
1310 + */
1311 +function gutenberg_block_core_navigation_render_submenu_icon() {
1312 + return '<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 12 12" fill="none" aria-hidden="true" focusable="false"><path d="M1.50002 4L6.00002 8L10.5 4" stroke-width="1.5"></path></svg>';
1313 +}
1314 +
1315 +/**
1397 1316 * Filter out empty "null" blocks from the block list.
1398 1317 * 'parse_blocks' includes a null block with '\n\n' as the content when
1399 1318 * it encounters whitespace. This is not a bug but rather how the parser
1400 1319 * is designed.
@@ -1594,137 +1513,8 @@
1594 1513 );
1595 1514 }
1596 1515
1597 1516 add_action( 'init', 'gutenberg_register_block_core_navigation', 20 );
1598 -
1599 -/**
1600 - * Adds Navigation block support classes to inner list containers.
1601 - *
1602 - * State block support adds the generated `wp-states-*` class to the outer
1603 - * block wrapper. The Navigation block renders its menu items inside an inner
1604 - * `wp-block-navigation__container` list, so the same state class is also needed
1605 - * there for state styles to apply directly to the menu list.
1606 - *
1607 - * Navigation also uses layout classes on its outer wrapper to define custom
1608 - * properties consumed by its inner containers. Viewport layout styles cannot
1609 - * change those classes, so equivalent custom properties and a scoping class
1610 - * are generated for each configured viewport layout.
1611 - *
1612 - * Currently this is required as a workaround because of how difficult it is for nav
1613 - * child blocks to inherit styles through the complex responsive nav block html. The
1614 - * bug in https://github.com/WordPress/gutenberg/issues/62690 also prevents inheritance.
1615 - *
1616 - * @since 7.1.0
1617 - *
1618 - * @param string $block_content The block content.
1619 - * @param array $block The full block, including name and attributes.
1620 - * @return string The updated block content.
1621 - */
1622 -function gutenberg_block_core_navigation_add_support_classes_to_container( $block_content, $block ) {
1623 - if ( 'core/navigation' !== ( $block['blockName'] ?? null ) || empty( $block_content ) ) {
1624 - return $block_content;
1625 - }
1626 -
1627 - $attributes = is_array( $block['attrs'] ?? null ) ? $block['attrs'] : array();
1628 - $style = is_array( $attributes['style'] ?? null ) ? $attributes['style'] : array();
1629 - if (
1630 - defined( 'IS_GUTENBERG_PLUGIN' ) &&
1631 - IS_GUTENBERG_PLUGIN &&
1632 - function_exists( 'gutenberg_resolve_style_state_aliases' )
1633 - ) {
1634 - $style = gutenberg_resolve_style_state_aliases( $style, 'core/navigation' );
1635 - }
1636 -
1637 - $global_settings = gutenberg_get_global_settings();
1638 - $viewport_settings = $global_settings['viewport'] ?? null;
1639 - $responsive_media_queries = array();
1640 - if ( method_exists( 'WP_Theme_JSON_Gutenberg', 'get_viewport_media_queries' ) ) {
1641 - $responsive_media_queries = WP_Theme_JSON_Gutenberg::get_viewport_media_queries( $viewport_settings );
1642 - } elseif ( method_exists( 'WP_Theme_JSON', 'get_viewport_media_queries' ) ) {
1643 - $responsive_media_queries = WP_Theme_JSON::get_viewport_media_queries( $viewport_settings );
1644 - }
1645 -
1646 - $styles = array();
1647 - $base_layout = is_array( $attributes['layout'] ?? null ) ? $attributes['layout'] : array();
1648 - foreach ( $responsive_media_queries as $breakpoint => $media_query ) {
1649 - $viewport_style = is_array( $style[ $breakpoint ] ?? null ) ? $style[ $breakpoint ] : array();
1650 - $viewport_layout = is_array( $viewport_style['layout'] ?? null ) ? $viewport_style['layout'] : array();
1651 - if ( empty( $viewport_layout ) ) {
1652 - continue;
1653 - }
1654 -
1655 - $styles[] = array(
1656 - 'declarations' => gutenberg_block_core_navigation_get_layout_custom_property_declarations(
1657 - array_replace( $base_layout, $viewport_layout )
1658 - ),
1659 - 'rules_group' => $media_query,
1660 - );
1661 - }
1662 -
1663 - $processor = new WP_HTML_Tag_Processor( $block_content );
1664 - if ( ! $processor->next_tag() ) {
1665 - return $block_content;
1666 - }
1667 -
1668 - $class_attribute = $processor->get_attribute( 'class' );
1669 - $state_class = null;
1670 - if ( is_string( $class_attribute ) && preg_match( '/\bwp-states-[a-f0-9]{8}\b/', $class_attribute, $matches ) ) {
1671 - $state_class = $matches[0];
1672 - }
1673 -
1674 - $layout_class = null;
1675 - if ( ! empty( $styles ) ) {
1676 - $layout_class = wp_unique_id( 'wp-block-navigation-' );
1677 - // The inner selector includes both Navigation classes so it overrides the
1678 - // default layout custom properties set by `.wp-block-navigation.items-*`.
1679 - $selector = ".wp-block-navigation.{$layout_class},.wp-block-navigation.wp-block-navigation__container.{$layout_class}";
1680 - foreach ( $styles as &$style_rule ) {
1681 - $style_rule['selector'] = $selector;
1682 - }
1683 - unset( $style_rule );
1684 -
1685 - $processor->add_class( $layout_class );
1686 - gutenberg_style_engine_get_stylesheet_from_css_rules(
1687 - $styles,
1688 - array( 'context' => 'block-supports' )
1689 - );
1690 - }
1691 -
1692 - if ( null === $state_class && null === $layout_class ) {
1693 - return $block_content;
1694 - }
1695 -
1696 - while ( $processor->next_tag() ) {
1697 - // Custom overlay content can include nested Navigation blocks.
1698 - // Avoid applying the outer Navigation classes to an inner nav block.
1699 - if ( $processor->has_class( 'wp-block-navigation' ) && ! $processor->has_class( 'wp-block-navigation__container' ) ) {
1700 - break;
1701 - }
1702 -
1703 - if ( ! $processor->has_class( 'wp-block-navigation__container' ) ) {
1704 - continue;
1705 - }
1706 -
1707 - if ( null !== $layout_class ) {
1708 - $processor->add_class( $layout_class );
1709 - }
1710 -
1711 - if ( null === $state_class ) {
1712 - continue;
1713 - }
1714 -
1715 - $class_attribute = $processor->get_attribute( 'class' );
1716 - if ( is_string( $class_attribute ) && preg_match( '/\bwp-states-[a-f0-9]{8}\b/', $class_attribute ) ) {
1717 - continue;
1718 - }
1719 -
1720 - $processor->add_class( $state_class );
1721 - }
1722 -
1723 - return $processor->get_updated_html();
1724 -}
1725 -
1726 -add_filter( 'render_block', 'gutenberg_block_core_navigation_add_support_classes_to_container', 11, 2 );
1727 1517
1728 1518 /**
1729 1519 * Filter that changes the parsed attribute values of navigation blocks contain typographic presets to contain the values directly.
1730 1520 *