From 33995bc4385539db61af66b4ac64aa3aeb2af1d5 Mon Sep 17 00:00:00 2001 From: Dave Smith Date: Mon, 22 Nov 2021 16:22:38 +0000 Subject: [PATCH 01/16] Use non-empty Nav post as fallback --- .../block-library/src/navigation/index.php | 34 ++++++++++++++++--- 1 file changed, 30 insertions(+), 4 deletions(-) diff --git a/packages/block-library/src/navigation/index.php b/packages/block-library/src/navigation/index.php index 6db226fe960fe..f096dd9763fde 100644 --- a/packages/block-library/src/navigation/index.php +++ b/packages/block-library/src/navigation/index.php @@ -221,12 +221,38 @@ function( $block ) { $is_fallback = true; // indicate we are rendering the fallback. $attributes['__unstableMaxPages'] = 4; // set value to be passed as context to Page List block. - $page_list_block = array( - 'blockName' => 'core/page-list', - 'attrs' => array(), + $navigation_posts = get_posts( + array( + 'post_type' => 'wp_navigation', + ) ); - $inner_blocks = new WP_Block_List( array( $page_list_block ), $attributes ); + $navigation_post = null; + + // Pick first non-empty Navigation. + foreach ( $navigation_posts as $navigation_maybe ) { + if ( ! empty( $navigation_maybe->post_content ) ) { + $navigation_post = $navigation_maybe; + break; + } + } + + // Use non-empty Navigation if available. + if ( $navigation_post ) { + $fallback_blocks = parse_blocks( $navigation_post->post_content ); + } else { + $attributes['__unstableMaxPages'] = 4; // set value to be passed as context to Page List block. + + // Requires wrapping array. + $fallback_blocks = array( + array( + 'blockName' => 'core/page-list', + 'attrs' => array(), + ), + ); + } + + $inner_blocks = new WP_Block_List( $fallback_blocks, $attributes ); } // Restore legacy classnames for submenu positioning. From 3a4e549ef9f510ef1981c0d3680231942cc613e0 Mon Sep 17 00:00:00 2001 From: Dave Smith Date: Tue, 23 Nov 2021 10:46:10 +0000 Subject: [PATCH 02/16] Remove code duplication Addresses https://github.com/WordPress/gutenberg/pull/36740#discussion_r754867803 --- packages/block-library/src/navigation/index.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/block-library/src/navigation/index.php b/packages/block-library/src/navigation/index.php index f096dd9763fde..3c557f265b730 100644 --- a/packages/block-library/src/navigation/index.php +++ b/packages/block-library/src/navigation/index.php @@ -218,8 +218,7 @@ function( $block ) { // If there are no inner blocks then fallback to rendering the Page List block. if ( empty( $inner_blocks ) ) { - $is_fallback = true; // indicate we are rendering the fallback. - $attributes['__unstableMaxPages'] = 4; // set value to be passed as context to Page List block. + $is_fallback = true; // indicate we are rendering the fallback. $navigation_posts = get_posts( array( From 098f453390df402f5280713459f17a76e1257975 Mon Sep 17 00:00:00 2001 From: Dave Smith Date: Tue, 23 Nov 2021 10:50:41 +0000 Subject: [PATCH 03/16] Extract finding non empty nav block to function --- .../block-library/src/navigation/index.php | 42 ++++++++++++------- 1 file changed, 27 insertions(+), 15 deletions(-) diff --git a/packages/block-library/src/navigation/index.php b/packages/block-library/src/navigation/index.php index 3c557f265b730..2d2e194306ac9 100644 --- a/packages/block-library/src/navigation/index.php +++ b/packages/block-library/src/navigation/index.php @@ -132,6 +132,32 @@ function block_core_navigation_render_submenu_icon() { return ''; } + +/** + * Finds the first non-empty `wp_navigation` Post. + * + * @return WP_Post|null the first non-empty Navigation or null. + */ +function get_non_empty_navigation_post() { + $navigation_posts = get_posts( + array( + 'post_type' => 'wp_navigation', + ) + ); + + $navigation_post = null; + + // Pick first non-empty Navigation. + foreach ( $navigation_posts as $navigation_maybe ) { + if ( ! empty( $navigation_maybe->post_content ) ) { + $navigation_post = $navigation_maybe; + break; + } + } + + return $navigation_post; +} + /** * Renders the `core/navigation` block on server. * @@ -220,21 +246,7 @@ function( $block ) { if ( empty( $inner_blocks ) ) { $is_fallback = true; // indicate we are rendering the fallback. - $navigation_posts = get_posts( - array( - 'post_type' => 'wp_navigation', - ) - ); - - $navigation_post = null; - - // Pick first non-empty Navigation. - foreach ( $navigation_posts as $navigation_maybe ) { - if ( ! empty( $navigation_maybe->post_content ) ) { - $navigation_post = $navigation_maybe; - break; - } - } + $navigation_post = get_non_empty_navigation_post(); // Use non-empty Navigation if available. if ( $navigation_post ) { From d466c2be0f662daf388d41d0d51f393952f03cf5 Mon Sep 17 00:00:00 2001 From: Dave Smith Date: Tue, 23 Nov 2021 10:57:59 +0000 Subject: [PATCH 04/16] Extract process of getting fallback to dedicated function --- .../block-library/src/navigation/index.php | 50 ++++++++++++------- 1 file changed, 32 insertions(+), 18 deletions(-) diff --git a/packages/block-library/src/navigation/index.php b/packages/block-library/src/navigation/index.php index 2d2e194306ac9..bf07b5bbd72df 100644 --- a/packages/block-library/src/navigation/index.php +++ b/packages/block-library/src/navigation/index.php @@ -158,6 +158,34 @@ function get_non_empty_navigation_post() { return $navigation_post; } +/** + * Retrieves the appropriate fallback to be used on the front of the + * site when there is no menu assigned to the Nav block. + * + * This aims to mirror how the fallback mechanic for wp_nav_menu works. + * See https://developer.wordpress.org/reference/functions/wp_nav_menu/#more-information. + * + * @return array the array of blocks to be used as a fallback. + */ +function get_fallback() { + $navigation_post = get_non_empty_navigation_post(); + + // Use non-empty Navigation if available. + if ( $navigation_post ) { + $fallback_blocks = parse_blocks( $navigation_post->post_content ); + } else { + // Requires wrapping array. + $fallback_blocks = array( + array( + 'blockName' => 'core/page-list', + 'attrs' => array(), + ), + ); + } + + return $fallback_blocks; +} + /** * Renders the `core/navigation` block on server. * @@ -242,26 +270,12 @@ function( $block ) { $inner_blocks = new WP_Block_List( $compacted_blocks, $attributes ); } - // If there are no inner blocks then fallback to rendering the Page List block. + // If there are no inner blocks then fallback to rendering an appropriate fallback. if ( empty( $inner_blocks ) ) { - $is_fallback = true; // indicate we are rendering the fallback. + $is_fallback = true; // indicate we are rendering the fallback. + $attributes['__unstableMaxPages'] = 4; // set value to be passed as context to Page List block. - $navigation_post = get_non_empty_navigation_post(); - - // Use non-empty Navigation if available. - if ( $navigation_post ) { - $fallback_blocks = parse_blocks( $navigation_post->post_content ); - } else { - $attributes['__unstableMaxPages'] = 4; // set value to be passed as context to Page List block. - - // Requires wrapping array. - $fallback_blocks = array( - array( - 'blockName' => 'core/page-list', - 'attrs' => array(), - ), - ); - } + $fallback_blocks = get_fallback(); $inner_blocks = new WP_Block_List( $fallback_blocks, $attributes ); } From 5e75bb567e0b739061dbe76c12b812e4cc6d5238 Mon Sep 17 00:00:00 2001 From: Dave Smith Date: Tue, 23 Nov 2021 10:59:28 +0000 Subject: [PATCH 05/16] Apply block prefix to functions --- packages/block-library/src/navigation/index.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/block-library/src/navigation/index.php b/packages/block-library/src/navigation/index.php index bf07b5bbd72df..9e1db85d539c0 100644 --- a/packages/block-library/src/navigation/index.php +++ b/packages/block-library/src/navigation/index.php @@ -138,7 +138,7 @@ function block_core_navigation_render_submenu_icon() { * * @return WP_Post|null the first non-empty Navigation or null. */ -function get_non_empty_navigation_post() { +function block_core_navigation_get_non_empty_navigation() { $navigation_posts = get_posts( array( 'post_type' => 'wp_navigation', @@ -167,8 +167,8 @@ function get_non_empty_navigation_post() { * * @return array the array of blocks to be used as a fallback. */ -function get_fallback() { - $navigation_post = get_non_empty_navigation_post(); +function block_core_navigation_get_fallback() { + $navigation_post = block_core_navigation_get_non_empty_navigation(); // Use non-empty Navigation if available. if ( $navigation_post ) { @@ -275,7 +275,7 @@ function( $block ) { $is_fallback = true; // indicate we are rendering the fallback. $attributes['__unstableMaxPages'] = 4; // set value to be passed as context to Page List block. - $fallback_blocks = get_fallback(); + $fallback_blocks = block_core_navigation_get_fallback(); $inner_blocks = new WP_Block_List( $fallback_blocks, $attributes ); } From d952588b3f3083040cd1b53fc56ee31f56301cf2 Mon Sep 17 00:00:00 2001 From: Dave Smith Date: Tue, 23 Nov 2021 11:10:24 +0000 Subject: [PATCH 06/16] Add additional safety check around parsing Nav blocks --- .../block-library/src/navigation/index.php | 26 ++++++++++++------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/packages/block-library/src/navigation/index.php b/packages/block-library/src/navigation/index.php index 9e1db85d539c0..3d2f8d750576d 100644 --- a/packages/block-library/src/navigation/index.php +++ b/packages/block-library/src/navigation/index.php @@ -168,19 +168,25 @@ function block_core_navigation_get_non_empty_navigation() { * @return array the array of blocks to be used as a fallback. */ function block_core_navigation_get_fallback() { + + // Default to a list of Pages. + $fallback_blocks = array( + array( + 'blockName' => 'core/page-list', + 'attrs' => array(), + ), + ); + $navigation_post = block_core_navigation_get_non_empty_navigation(); - // Use non-empty Navigation if available. + // Prefer using the first non-empty Navigation as fallback if available. if ( $navigation_post ) { - $fallback_blocks = parse_blocks( $navigation_post->post_content ); - } else { - // Requires wrapping array. - $fallback_blocks = array( - array( - 'blockName' => 'core/page-list', - 'attrs' => array(), - ), - ); + $maybe_fallback = parse_blocks( $navigation_post->post_content ); + + // If block is unable to be parsed the parser fallsback to a null blockname. This can happen if the block + // in the content is not registered or is invalid. + // Add additional safety check to avoid invalid block being treated as valid fallback. + $fallback_blocks = ! empty( $maybe_fallback[0] ) && null !== $maybe_fallback[0]['blockName'] ? $maybe_fallback : $fallback_blocks; } return $fallback_blocks; From d15df9311010c40722380e853be769dde3aa1a87 Mon Sep 17 00:00:00 2001 From: Dave Smith Date: Tue, 23 Nov 2021 11:41:56 +0000 Subject: [PATCH 07/16] Extract function for removing null blocks and apply --- .../block-library/src/navigation/index.php | 33 ++++++++++++------- 1 file changed, 21 insertions(+), 12 deletions(-) diff --git a/packages/block-library/src/navigation/index.php b/packages/block-library/src/navigation/index.php index 3d2f8d750576d..3425841bce205 100644 --- a/packages/block-library/src/navigation/index.php +++ b/packages/block-library/src/navigation/index.php @@ -158,6 +158,25 @@ function block_core_navigation_get_non_empty_navigation() { return $navigation_post; } +/** + * 'parse_blocks' includes a null block with '\n\n' as the content when + * it encounters whitespace. This code strips it. + * + * @param array $parsed_blocks the parsed blocks to be normalized. + * @return array the normalized parsed blocks. + */ +function block_core_navigation_normalize_parsed_blocks( $parsed_blocks ) { + $filtered = array_filter( + $parsed_blocks, + function( $block ) { + return isset( $block['blockName'] ); + } + ); + + // Reset keys. + return array_values( $filtered ); +} + /** * Retrieves the appropriate fallback to be used on the front of the * site when there is no menu assigned to the Nav block. @@ -181,12 +200,7 @@ function block_core_navigation_get_fallback() { // Prefer using the first non-empty Navigation as fallback if available. if ( $navigation_post ) { - $maybe_fallback = parse_blocks( $navigation_post->post_content ); - - // If block is unable to be parsed the parser fallsback to a null blockname. This can happen if the block - // in the content is not registered or is invalid. - // Add additional safety check to avoid invalid block being treated as valid fallback. - $fallback_blocks = ! empty( $maybe_fallback[0] ) && null !== $maybe_fallback[0]['blockName'] ? $maybe_fallback : $fallback_blocks; + $fallback_blocks = block_core_navigation_normalize_parsed_blocks( parse_blocks( $navigation_post->post_content ) ); } return $fallback_blocks; @@ -264,12 +278,7 @@ function render_block_core_navigation( $attributes, $content, $block ) { // 'parse_blocks' includes a null block with '\n\n' as the content when // it encounters whitespace. This code strips it. - $compacted_blocks = array_filter( - $parsed_blocks, - function( $block ) { - return isset( $block['blockName'] ); - } - ); + $compacted_blocks = block_core_navigation_normalize_parsed_blocks( $parsed_blocks ); // TODO - this uses the full navigation block attributes for the // context which could be refined. From cdaaf5e60e992d1a206b3deab057087ddcdb33b1 Mon Sep 17 00:00:00 2001 From: Dave Smith Date: Tue, 23 Nov 2021 11:45:13 +0000 Subject: [PATCH 08/16] Check for empty parsed Nav blocks --- packages/block-library/src/navigation/index.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/block-library/src/navigation/index.php b/packages/block-library/src/navigation/index.php index 3425841bce205..cd10b8549e510 100644 --- a/packages/block-library/src/navigation/index.php +++ b/packages/block-library/src/navigation/index.php @@ -200,7 +200,11 @@ function block_core_navigation_get_fallback() { // Prefer using the first non-empty Navigation as fallback if available. if ( $navigation_post ) { - $fallback_blocks = block_core_navigation_normalize_parsed_blocks( parse_blocks( $navigation_post->post_content ) ); + $maybe_fallback = block_core_navigation_normalize_parsed_blocks( parse_blocks( $navigation_post->post_content ) ); + + // Normalizing blocks may result in an empty array of blocks if they were all `null` blocks. + // In this case default to the (Page List) fallback. + $fallback_blocks = ! empty( $maybe_fallback ) ? $maybe_fallback : $fallback_blocks; } return $fallback_blocks; From d6d1e257a23ef78dc7dcd217c54df51892a63b6a Mon Sep 17 00:00:00 2001 From: Dave Smith Date: Tue, 23 Nov 2021 14:14:42 +0000 Subject: [PATCH 09/16] Improve function comment Addresses https://github.com/WordPress/gutenberg/pull/36740#discussion_r755055265 --- packages/block-library/src/navigation/index.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/block-library/src/navigation/index.php b/packages/block-library/src/navigation/index.php index cd10b8549e510..ea8fbd43df055 100644 --- a/packages/block-library/src/navigation/index.php +++ b/packages/block-library/src/navigation/index.php @@ -142,6 +142,7 @@ function block_core_navigation_get_non_empty_navigation() { $navigation_posts = get_posts( array( 'post_type' => 'wp_navigation', + 'order' => 'DESC', ) ); @@ -159,8 +160,10 @@ function block_core_navigation_get_non_empty_navigation() { } /** + * Filter out empty "null" blocks from the block list. * 'parse_blocks' includes a null block with '\n\n' as the content when - * it encounters whitespace. This code strips it. + * it encounters whitespace. This is not a bug but rather how the parser + * is designed. * * @param array $parsed_blocks the parsed blocks to be normalized. * @return array the normalized parsed blocks. From 2831ff35cf6373a75fac2a983e0e7b1a8ba35f23 Mon Sep 17 00:00:00 2001 From: Dave Smith Date: Tue, 23 Nov 2021 14:26:09 +0000 Subject: [PATCH 10/16] Amend ordering params to approximate current wp_nav_menus behaviour --- packages/block-library/src/navigation/index.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/packages/block-library/src/navigation/index.php b/packages/block-library/src/navigation/index.php index ea8fbd43df055..e421aef4ab02d 100644 --- a/packages/block-library/src/navigation/index.php +++ b/packages/block-library/src/navigation/index.php @@ -139,10 +139,15 @@ function block_core_navigation_render_submenu_icon() { * @return WP_Post|null the first non-empty Navigation or null. */ function block_core_navigation_get_non_empty_navigation() { + // Order and orderby args set to mirror those in `wp_get_nav_menus` + // see: + // - https://github.com/WordPress/wordpress-develop/blob/ba943e113d3b31b121f77a2d30aebe14b047c69d/src/wp-includes/nav-menu.php#L613-L619. + // - https://developer.wordpress.org/reference/classes/wp_query/#order-orderby-parameters. $navigation_posts = get_posts( array( 'post_type' => 'wp_navigation', - 'order' => 'DESC', + 'order' => 'ASC', + 'orderby' => 'name', ) ); From 5f8263b1bf67c8675ed7a3315f0e1cd93014d068 Mon Sep 17 00:00:00 2001 From: Dave Smith Date: Wed, 24 Nov 2021 09:35:25 +0000 Subject: [PATCH 11/16] Fetch Nav posts in query rather than filtering in memory Implements suggestion from https://github.com/WordPress/gutenberg/pull/36740#discussion_r755647511 --- .../block-library/src/navigation/index.php | 20 ++++++------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/packages/block-library/src/navigation/index.php b/packages/block-library/src/navigation/index.php index e421aef4ab02d..1ca125fac1061 100644 --- a/packages/block-library/src/navigation/index.php +++ b/packages/block-library/src/navigation/index.php @@ -145,23 +145,15 @@ function block_core_navigation_get_non_empty_navigation() { // - https://developer.wordpress.org/reference/classes/wp_query/#order-orderby-parameters. $navigation_posts = get_posts( array( - 'post_type' => 'wp_navigation', - 'order' => 'ASC', - 'orderby' => 'name', + 'post_type' => 'wp_navigation', + 'order' => 'ASC', + 'orderby' => 'name', + 'posts_per_page' => -1, // include all posts. + 's' => '