-
-
- {
- // Some attributes are stored in an escaped form. It's a legacy issue.
- // Ideally they would be stored in a raw, unescaped form.
- // Unescape is used here to "recover" the escaped characters
- // so they display without encoding.
- // See `updateAttributes` for more details.
- `${ decodeEntities( label ) } ${
- isInvalid || isDraft
- ? placeholderText
- : ''
- }`.trim()
- }
-
-
+
+
+ {
+ // Some attributes are stored in an escaped form. It's a legacy issue.
+ // Ideally they would be stored in a raw, unescaped form.
+ // Unescape is used here to "recover" the escaped characters
+ // so they display without encoding.
+ // See `updateAttributes` for more details.
+ `${ decodeEntities( label ) } ${
+ isInvalid || isDraft
+ ? placeholderText
+ : ''
+ }`.trim()
+ }
+
) }
>
diff --git a/packages/block-library/src/navigation-link/editor.scss b/packages/block-library/src/navigation-link/editor.scss
index 84cd6f6d4ee363..b27c4520921fd4 100644
--- a/packages/block-library/src/navigation-link/editor.scss
+++ b/packages/block-library/src/navigation-link/editor.scss
@@ -80,24 +80,33 @@
background-image: none !important;
// Draw a wavy underline.
- .wp-block-navigation-link__placeholder-text span {
- $blur: 10%;
- $width: 6%;
- $stop1: 30%;
- $stop2: 64%;
-
- --wp-underline-color: var(--wp-admin-theme-color);
-
- background-image:
- linear-gradient(45deg, transparent ($stop1 - $blur), var(--wp-underline-color) $stop1, var(--wp-underline-color) ($stop1 + $width), transparent ($stop1 + $width + $blur)),
- linear-gradient(135deg, transparent ($stop2 - $blur), var(--wp-underline-color) $stop2, var(--wp-underline-color) ($stop2 + $width), transparent ($stop2 + $width + $blur));
- background-position: 0 100%;
- background-size: 6px 3px;
- background-repeat: repeat-x;
-
- // Since applied to a span, it doesn't change the footprint of the item,
- // but it does vertically shift the underline to better align.
- padding-bottom: 0.1em;
+ .wp-block-navigation-link__placeholder-text {
+ span {
+ $blur: 10%;
+ $width: 6%;
+ $stop1: 30%;
+ $stop2: 64%;
+
+ --wp-underline-color: var(--wp-admin-theme-color);
+
+ background-image:
+ linear-gradient(45deg, transparent ($stop1 - $blur), var(--wp-underline-color) $stop1, var(--wp-underline-color) ($stop1 + $width), transparent ($stop1 + $width + $blur)),
+ linear-gradient(135deg, transparent ($stop2 - $blur), var(--wp-underline-color) $stop2, var(--wp-underline-color) ($stop2 + $width), transparent ($stop2 + $width + $blur));
+ background-position: 0 100%;
+ background-size: 6px 3px;
+ background-repeat: repeat-x;
+
+ // Since applied to a span, it doesn't change the footprint of the item,
+ // but it does vertically shift the underline to better align.
+ padding-bottom: 0.1em;
+ }
+
+ &.is-invalid,
+ &.is-draft {
+ span {
+ --wp-underline-color: #{$alert-red};
+ }
+ }
}
// This needs extra specificity.
diff --git a/packages/block-library/src/navigation-submenu/index.js b/packages/block-library/src/navigation-submenu/index.js
index 69e97fb85325a5..f5eb1e2346d76e 100644
--- a/packages/block-library/src/navigation-submenu/index.js
+++ b/packages/block-library/src/navigation-submenu/index.js
@@ -2,6 +2,7 @@
* WordPress dependencies
*/
import { page, addSubmenu } from '@wordpress/icons';
+import { _x } from '@wordpress/i18n';
/**
* Internal dependencies
@@ -37,6 +38,12 @@ export const settings = {
return label;
},
edit,
+ example: {
+ attributes: {
+ label: _x( 'About', 'Example link text for Navigation Submenu' ),
+ type: 'page',
+ },
+ },
save,
transforms,
};
diff --git a/packages/block-library/src/navigation-submenu/index.php b/packages/block-library/src/navigation-submenu/index.php
index 0f560e2849fac2..016e708c3256e6 100644
--- a/packages/block-library/src/navigation-submenu/index.php
+++ b/packages/block-library/src/navigation-submenu/index.php
@@ -82,7 +82,6 @@ function render_block_core_navigation_submenu( $attributes, $content, $block ) {
$font_sizes = block_core_navigation_submenu_build_css_font_sizes( $block->context );
$style_attribute = $font_sizes['inline_styles'];
- $css_classes = trim( implode( ' ', $font_sizes['css_classes'] ) );
$has_submenu = count( $block->inner_blocks ) > 0;
$kind = empty( $attributes['kind'] ) ? 'post_type' : str_replace( '-', '_', $attributes['kind'] );
$is_active = ! empty( $attributes['id'] ) && get_queried_object_id() === (int) $attributes['id'] && ! empty( get_queried_object()->$kind );
@@ -99,11 +98,29 @@ function render_block_core_navigation_submenu( $attributes, $content, $block ) {
$open_on_hover_and_click = isset( $block->context['openSubmenusOnClick'] ) && ! $block->context['openSubmenusOnClick'] &&
$show_submenu_indicators;
+ $classes = array(
+ 'wp-block-navigation-item',
+ );
+ $classes = array_merge(
+ $classes,
+ $font_sizes['css_classes']
+ );
+ if ( $has_submenu ) {
+ $classes[] = 'has-child';
+ }
+ if ( $open_on_click ) {
+ $classes[] = 'open-on-click';
+ }
+ if ( $open_on_hover_and_click ) {
+ $classes[] = 'open-on-hover-click';
+ }
+ if ( $is_active ) {
+ $classes[] = 'current-menu-item';
+ }
+
$wrapper_attributes = get_block_wrapper_attributes(
array(
- 'class' => $css_classes . ' wp-block-navigation-item' . ( $has_submenu ? ' has-child' : '' ) .
- ( $open_on_click ? ' open-on-click' : '' ) . ( $open_on_hover_and_click ? ' open-on-hover-click' : '' ) .
- ( $is_active ? ' current-menu-item' : '' ),
+ 'class' => implode( ' ', $classes ),
'style' => $style_attribute,
)
);
diff --git a/packages/block-library/src/navigation/edit/use-convert-classic-menu-to-block-menu.js b/packages/block-library/src/navigation/edit/use-convert-classic-menu-to-block-menu.js
index 300672fa91e8ad..0984f601959a05 100644
--- a/packages/block-library/src/navigation/edit/use-convert-classic-menu-to-block-menu.js
+++ b/packages/block-library/src/navigation/edit/use-convert-classic-menu-to-block-menu.js
@@ -47,7 +47,7 @@ function useConvertClassicToBlockMenu(
} catch ( err ) {
throw new Error(
sprintf(
- // translators: %s: the name of a menu (e.g. Header navigation).
+ // translators: %s: The name of a menu (e.g. Header menu).
__( `Unable to fetch classic menu "%s" from API.` ),
menuName
),
@@ -61,7 +61,7 @@ function useConvertClassicToBlockMenu(
if ( classicMenuItems === null ) {
throw new Error(
sprintf(
- // translators: %s: the name of a menu (e.g. Header navigation).
+ // translators: %s: The name of a menu (e.g. Header menu).
__( `Unable to fetch classic menu "%s" from API.` ),
menuName
)
@@ -98,7 +98,7 @@ function useConvertClassicToBlockMenu(
} catch ( err ) {
throw new Error(
sprintf(
- // translators: %s: the name of a menu (e.g. Header navigation).
+ // translators: %s: The name of a menu (e.g. Header menu).
__( `Unable to create Navigation Menu "%s".` ),
menuName
),
@@ -155,7 +155,7 @@ function useConvertClassicToBlockMenu(
if ( throwOnError ) {
throw new Error(
sprintf(
- // translators: %s: the name of a menu (e.g. Header navigation).
+ // translators: %s: The name of a menu (e.g. Header menu).
__( `Unable to create Navigation Menu "%s".` ),
menuName
),
diff --git a/packages/block-library/src/navigation/edit/use-generate-default-navigation-title.js b/packages/block-library/src/navigation/edit/use-generate-default-navigation-title.js
index 0a134a256e6646..9784a5fd75a6b4 100644
--- a/packages/block-library/src/navigation/edit/use-generate-default-navigation-title.js
+++ b/packages/block-library/src/navigation/edit/use-generate-default-navigation-title.js
@@ -50,12 +50,12 @@ export default function useGenerateDefaultNavigationTitle( clientId ) {
const title = area
? sprintf(
- // translators: %s: the name of a menu (e.g. Header navigation).
- __( '%s navigation' ),
+ // translators: %s: the name of a menu (e.g. Header menu).
+ __( '%s menu' ),
area
)
- : // translators: 'navigation' as in website navigation.
- __( 'Navigation' );
+ : // translators: 'menu' as in website navigation menu.
+ __( 'Menu' );
// Determine how many menus start with the automatic title.
const matchingMenuTitleCount = [
diff --git a/packages/block-library/src/navigation/index.php b/packages/block-library/src/navigation/index.php
index 43ca8331534275..d52b67b7e1958c 100644
--- a/packages/block-library/src/navigation/index.php
+++ b/packages/block-library/src/navigation/index.php
@@ -241,11 +241,12 @@ private static function get_inner_blocks_from_navigation_post( $attributes ) {
// it encounters whitespace. This code strips it.
$blocks = block_core_navigation_filter_out_empty_blocks( $parsed_blocks );
- // Run Block Hooks algorithm to inject hooked blocks.
- $markup = block_core_navigation_insert_hooked_blocks( $blocks, $navigation_post );
- $root_nav_block = parse_blocks( $markup )[0];
-
- $blocks = isset( $root_nav_block['innerBlocks'] ) ? $root_nav_block['innerBlocks'] : $blocks;
+ // Re-serialize, and run Block Hooks algorithm to inject hooked blocks.
+ // TODO: See if we can move the apply_block_hooks_to_content_from_post_object() call
+ // before the parse_blocks() call further above, to avoid the extra serialization/parsing.
+ $markup = serialize_blocks( $blocks );
+ $markup = apply_block_hooks_to_content_from_post_object( $markup, $navigation_post );
+ $blocks = parse_blocks( $markup );
// TODO - this uses the full navigation block attributes for the
// context which could be refined.
@@ -1077,12 +1078,11 @@ function block_core_navigation_get_fallback_blocks() {
// Run Block Hooks algorithm to inject hooked blocks.
// We have to run it here because we need the post ID of the Navigation block to track ignored hooked blocks.
- $markup = block_core_navigation_insert_hooked_blocks( $fallback_blocks, $navigation_post );
- $blocks = parse_blocks( $markup );
-
- if ( isset( $blocks[0]['innerBlocks'] ) ) {
- $fallback_blocks = $blocks[0]['innerBlocks'];
- }
+ // TODO: See if we can move the apply_block_hooks_to_content_from_post_object() call
+ // before the parse_blocks() call further above, to avoid the extra serialization/parsing.
+ $markup = serialize_blocks( $fallback_blocks );
+ $markup = apply_block_hooks_to_content_from_post_object( $markup, $navigation_post );
+ $fallback_blocks = parse_blocks( $markup );
}
/**
@@ -1436,61 +1436,3 @@ function block_core_navigation_get_most_recently_published_navigation() {
return null;
}
-
-/**
- * Mock a parsed block for the Navigation block given its inner blocks and the `wp_navigation` post object.
- * The `wp_navigation` post's `_wp_ignored_hooked_blocks` meta is queried to add the `metadata.ignoredHookedBlocks` attribute.
- *
- * @since 6.5.0
- *
- * @param array $inner_blocks Parsed inner blocks of a Navigation block.
- * @param WP_Post $post `wp_navigation` post object corresponding to the block.
- *
- * @return array the normalized parsed blocks.
- */
-function block_core_navigation_mock_parsed_block( $inner_blocks, $post ) {
- $attributes = array();
-
- if ( isset( $post->ID ) ) {
- $ignored_hooked_blocks = get_post_meta( $post->ID, '_wp_ignored_hooked_blocks', true );
- if ( ! empty( $ignored_hooked_blocks ) ) {
- $ignored_hooked_blocks = json_decode( $ignored_hooked_blocks, true );
- $attributes['metadata'] = array(
- 'ignoredHookedBlocks' => $ignored_hooked_blocks,
- );
- }
- }
-
- $mock_anchor_parent_block = array(
- 'blockName' => 'core/navigation',
- 'attrs' => $attributes,
- 'innerBlocks' => $inner_blocks,
- 'innerContent' => array_fill( 0, count( $inner_blocks ), null ),
- );
-
- return $mock_anchor_parent_block;
-}
-
-/**
- * Insert hooked blocks into a Navigation block.
- *
- * Given a Navigation block's inner blocks and its corresponding `wp_navigation` post object,
- * this function inserts hooked blocks into it, and returns the serialized inner blocks in a
- * mock Navigation block wrapper.
- *
- * If there are any hooked blocks that need to be inserted as the Navigation block's first or last
- * children, the `wp_navigation` post's `_wp_ignored_hooked_blocks` meta is checked to see if any
- * of those hooked blocks should be exempted from insertion.
- *
- * @since 6.5.0
- *
- * @param array $inner_blocks Parsed inner blocks of a Navigation block.
- * @param WP_Post $post `wp_navigation` post object corresponding to the block.
- * @return string Serialized inner blocks in mock Navigation block wrapper, with hooked blocks inserted, if any.
- */
-function block_core_navigation_insert_hooked_blocks( $inner_blocks, $post ) {
- $mock_navigation_block = block_core_navigation_mock_parsed_block( $inner_blocks, $post );
-
- $mock_navigation_block_markup = serialize_block( $mock_navigation_block );
- return apply_block_hooks_to_content( $mock_navigation_block_markup, $post, 'insert_hooked_blocks' );
-}
diff --git a/packages/block-library/src/page-list/edit.js b/packages/block-library/src/page-list/edit.js
index 8f1409f864f9b9..458b8075749e5d 100644
--- a/packages/block-library/src/page-list/edit.js
+++ b/packages/block-library/src/page-list/edit.js
@@ -322,58 +322,60 @@ export default function PageListEdit( {
return (
<>
-
- {
- setAttributes( { parentPageID: 0 } );
- } }
- dropdownMenuProps={ dropdownMenuProps }
- >
- { pagesTree.length > 0 && (
- parentPageID !== 0 }
- onDeselect={ () =>
- setAttributes( { parentPageID: 0 } )
- }
- isShownByDefault
- >
-
- setAttributes( {
- parentPageID: value ?? 0,
- } )
+ { ( pagesTree.length > 0 || allowConvertToLinks ) && (
+
+ {
+ setAttributes( { parentPageID: 0 } );
+ } }
+ dropdownMenuProps={ dropdownMenuProps }
+ >
+ { pagesTree.length > 0 && (
+ parentPageID !== 0 }
+ onDeselect={ () =>
+ setAttributes( { parentPageID: 0 } )
}
- help={ __(
- 'Choose a page to show only its subpages.'
- ) }
- />
-
- ) }
-
- { allowConvertToLinks && (
-
-
{ convertDescription }
-
- { __( 'Edit' ) }
-
-
- ) }
-
-
+
+ setAttributes( {
+ parentPageID: value ?? 0,
+ } )
+ }
+ help={ __(
+ 'Choose a page to show only its subpages.'
+ ) }
+ />
+
+ ) }
+
+ { allowConvertToLinks && (
+