From 132a1c0723be158d699796074b6b4ede343d55d0 Mon Sep 17 00:00:00 2001 From: Ben Dwyer Date: Wed, 14 Sep 2022 23:07:04 +0100 Subject: [PATCH 01/33] Navigation: Fallback to a classic menu if one is availiable --- .../src/navigation/edit/index.js | 72 ++++++++++++------- .../block-library/src/navigation/index.php | 60 ++++++++++++++++ 2 files changed, 105 insertions(+), 27 deletions(-) diff --git a/packages/block-library/src/navigation/edit/index.js b/packages/block-library/src/navigation/edit/index.js index 6cb773e60107bd..bac6c0e10e56e9 100644 --- a/packages/block-library/src/navigation/edit/index.js +++ b/packages/block-library/src/navigation/edit/index.js @@ -107,7 +107,7 @@ function Navigation( { // Preload classic menus, so that they don't suddenly pop-in when viewing // the Select Menu dropdown. - useNavigationEntities(); + const { menus: classicMenus } = useNavigationEntities(); const [ showNavigationMenuStatusNotice, hideNavigationMenuStatusNotice ] = useNavigationNotice( { @@ -224,36 +224,54 @@ function Navigation( { // than 1 exists then use the most recent. // The aim is for the block to "just work" from a user perspective using existing data. useEffect( () => { - if ( - hasUncontrolledInnerBlocks || - isCreatingNavigationMenu || - ref || - ! navigationMenus?.length - ) { + // Only autofallback to published menus. + const fallbackNavigationMenus = navigationMenus?.filter( + ( menu ) => menu.status === 'publish' + ); + + if ( hasUncontrolledInnerBlocks || isCreatingNavigationMenu || ref ) { return; } - navigationMenus.sort( ( menuA, menuB ) => { - const menuADate = new Date( menuA.date ); - const menuBDate = new Date( menuB.date ); - return menuADate.getTime() < menuBDate.getTime(); - } ); + // See if we have any navigation menus + if ( fallbackNavigationMenus?.length ) { + navigationMenus.sort( ( menuA, menuB ) => { + const menuADate = new Date( menuA.date ); + const menuBDate = new Date( menuB.date ); + return menuADate.getTime() < menuBDate.getTime(); + } ); - // Only autofallback to published menus. - const fallbackNavigationMenus = navigationMenus.filter( - ( menu ) => menu.status === 'publish' - ); - if ( fallbackNavigationMenus.length === 0 ) return; - - /** - * This fallback displays (both in editor and on front) - * a list of pages only if no menu (user assigned or - * automatically picked) is available. - * The fallback should not request a save (entity dirty state) - * nor to be undoable, hence why it is marked as non persistent - */ - __unstableMarkNextChangeAsNotPersistent(); - setRef( fallbackNavigationMenus[ 0 ].id ); + /** + * This fallback displays (both in editor and on front) + * a list of pages only if no menu (user assigned or + * automatically picked) is available. + * The fallback should not request a save (entity dirty state) + * nor to be undoable, hence why it is marked as non persistent + */ + __unstableMarkNextChangeAsNotPersistent(); + setRef( fallbackNavigationMenus[ 0 ].id ); + } else if ( classicMenus?.length ) { + // Use a classic menu fallback + + // We should get the primary one. + + // We should probably create this not as a draft... + + // This is duplicated several times. + const onSelectClassicMenu = async ( classicMenu ) => { + const navMenu = await convertClassicMenu( + classicMenu.id, + classicMenu.name + ); + if ( navMenu ) { + handleUpdateMenu( navMenu.id, { + focusNavigationBlock: true, + } ); + } + }; + + onSelectClassicMenu( classicMenus[ 0 ] ); + } }, [ navigationMenus ] ); const navRef = useRef(); diff --git a/packages/block-library/src/navigation/index.php b/packages/block-library/src/navigation/index.php index 5173f96040b4d0..0da81b890e2521 100644 --- a/packages/block-library/src/navigation/index.php +++ b/packages/block-library/src/navigation/index.php @@ -248,6 +248,62 @@ function block_core_navigation_render_submenu_icon() { return ''; } +function block_core_navigation_get_classic_menu_fallback() { + $classic_nav_menus = wp_get_nav_menus(); + + // If menus exist. + if ( $classic_nav_menus && ! is_wp_error( $classic_nav_menus ) ) { + // Get the primary one + // Should this be the one at the primary location? + $primary_nav_menu = array_filter( $classic_nav_menus, function( $classic_menu ) { + return $classic_menu->slug === 'primary'; + } ); + + if ( isset( $primary_nav_menu ) && count( $primary_nav_menu ) > 0 ) { + return current( $primary_nav_menu ); + } + + // If there's no primary one then just use the newest. + return $classic_nav_menus[ 0 ]; + } +} + +/** + * Finds the most classic navigation fallback to use. + * + * @return WP_Post|null the classic navigation post. + */ +function block_core_navigation_get_classic_menu_fallback_blocks() { + $classic_nav_menu = block_core_navigation_get_classic_menu_fallback(); + + $menu_items = wp_get_nav_menu_items( $classic_nav_menu->term_id, array( 'update_post_term_cache' => false ) ); + + // Set up the $menu_item variables. + _wp_menu_item_classes_by_context( $menu_items ); + + $sorted_menu_items = array(); + foreach ( (array) $menu_items as $menu_item ) { + $sorted_menu_items[ $menu_item->menu_order ] = $menu_item; + } + + unset( $menu_items, $menu_item ); + + // END: Code that already exists in wp_nav_menu(). + + $menu_items_by_parent_id = array(); + foreach ( $sorted_menu_items as $menu_item ) { + $menu_items_by_parent_id[ $menu_item->menu_item_parent ][] = $menu_item; + } + + $inner_blocks = gutenberg_convert_menu_items_to_blocks( + isset( $menu_items_by_parent_id[0] ) + ? $menu_items_by_parent_id[0] + : array(), + $menu_items_by_parent_id + ); + + return $inner_blocks; +} /** * Finds the most recently published `wp_navigation` Post. @@ -255,6 +311,7 @@ function block_core_navigation_render_submenu_icon() { * @return WP_Post|null the first non-empty Navigation or null. */ function block_core_navigation_get_most_recently_published_navigation() { + // We default to the most recently created menu. $parsed_args = array( 'post_type' => 'wp_navigation', @@ -329,6 +386,9 @@ function block_core_navigation_get_fallback_blocks() { // 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; + } else { + // See if we have any classic menus + $fallback_blocks = block_core_navigation_get_classic_menu_fallback_blocks(); } /** From 858795fb77013c947e66fff5dd76690e735eefa2 Mon Sep 17 00:00:00 2001 From: Ben Dwyer Date: Thu, 15 Sep 2022 13:32:01 +0100 Subject: [PATCH 02/33] only use classic menus if there is one --- .../block-library/src/navigation/index.php | 32 ++++++++----------- 1 file changed, 14 insertions(+), 18 deletions(-) diff --git a/packages/block-library/src/navigation/index.php b/packages/block-library/src/navigation/index.php index 0da81b890e2521..540e9dc40fc88a 100644 --- a/packages/block-library/src/navigation/index.php +++ b/packages/block-library/src/navigation/index.php @@ -248,34 +248,27 @@ function block_core_navigation_render_submenu_icon() { return ''; } +/** + * Get the classic navigation menu to use as a fallback. + * + * @return object WP_Term The classic navigation. + */ function block_core_navigation_get_classic_menu_fallback() { $classic_nav_menus = wp_get_nav_menus(); // If menus exist. - if ( $classic_nav_menus && ! is_wp_error( $classic_nav_menus ) ) { - // Get the primary one - // Should this be the one at the primary location? - $primary_nav_menu = array_filter( $classic_nav_menus, function( $classic_menu ) { - return $classic_menu->slug === 'primary'; - } ); - - if ( isset( $primary_nav_menu ) && count( $primary_nav_menu ) > 0 ) { - return current( $primary_nav_menu ); - } - - // If there's no primary one then just use the newest. + if ( $classic_nav_menus && ! is_wp_error( $classic_nav_menus ) && count( $classic_nav_menus ) === 1 ) { + // If there's only one classic menu then use it. return $classic_nav_menus[ 0 ]; } } /** - * Finds the most classic navigation fallback to use. + * Finds the classic navigation fallback to use. * - * @return WP_Post|null the classic navigation post. + * @return array the normalized parsed blocks. */ -function block_core_navigation_get_classic_menu_fallback_blocks() { - $classic_nav_menu = block_core_navigation_get_classic_menu_fallback(); - +function block_core_navigation_get_classic_menu_fallback_blocks( $classic_nav_menu ) { $menu_items = wp_get_nav_menu_items( $classic_nav_menu->term_id, array( 'update_post_term_cache' => false ) ); // Set up the $menu_item variables. @@ -388,7 +381,10 @@ function block_core_navigation_get_fallback_blocks() { $fallback_blocks = ! empty( $maybe_fallback ) ? $maybe_fallback : $fallback_blocks; } else { // See if we have any classic menus - $fallback_blocks = block_core_navigation_get_classic_menu_fallback_blocks(); + $classic_nav_menu = block_core_navigation_get_classic_menu_fallback(); + if ( $classic_nav_menu ) { + $fallback_blocks = block_core_navigation_get_classic_menu_fallback_blocks( $classic_nav_menu ); + } } /** From 75955e05ac4329567136acce55a59848fb1bc5ba Mon Sep 17 00:00:00 2001 From: Ben Dwyer Date: Thu, 15 Sep 2022 17:20:04 +0100 Subject: [PATCH 03/33] only import classic menus if there's only one of them --- .../src/navigation/edit/index.js | 45 ++++++++++--------- .../use-convert-classic-menu-to-block-menu.js | 16 +++++-- .../block-library/src/navigation/index.php | 29 +++++++++--- 3 files changed, 58 insertions(+), 32 deletions(-) diff --git a/packages/block-library/src/navigation/edit/index.js b/packages/block-library/src/navigation/edit/index.js index bac6c0e10e56e9..7d6017af1b1596 100644 --- a/packages/block-library/src/navigation/edit/index.js +++ b/packages/block-library/src/navigation/edit/index.js @@ -233,6 +233,27 @@ function Navigation( { return; } + if ( ! fallbackNavigationMenus?.length && classicMenus?.length === 1 ) { + // If there's only one classic menu + // then create a new navigation menu based on it. + + // This is duplicated several times. + const onSelectClassicMenu = async ( classicMenu ) => { + const navMenu = await convertClassicMenu( + classicMenu.id, + classicMenu.name, + 'publish' + ); + if ( navMenu ) { + handleUpdateMenu( navMenu.id, { + focusNavigationBlock: true, + } ); + } + }; + + onSelectClassicMenu( classicMenus[ 0 ] ); + } + // See if we have any navigation menus if ( fallbackNavigationMenus?.length ) { navigationMenus.sort( ( menuA, menuB ) => { @@ -250,27 +271,6 @@ function Navigation( { */ __unstableMarkNextChangeAsNotPersistent(); setRef( fallbackNavigationMenus[ 0 ].id ); - } else if ( classicMenus?.length ) { - // Use a classic menu fallback - - // We should get the primary one. - - // We should probably create this not as a draft... - - // This is duplicated several times. - const onSelectClassicMenu = async ( classicMenu ) => { - const navMenu = await convertClassicMenu( - classicMenu.id, - classicMenu.name - ); - if ( navMenu ) { - handleUpdateMenu( navMenu.id, { - focusNavigationBlock: true, - } ); - } - }; - - onSelectClassicMenu( classicMenus[ 0 ] ); } }, [ navigationMenus ] ); @@ -660,7 +660,8 @@ function Navigation( { onSelectClassicMenu={ async ( classicMenu ) => { const navMenu = await convertClassicMenu( classicMenu.id, - classicMenu.name + classicMenu.name, + 'draft' ); if ( navMenu ) { handleUpdateMenu( navMenu.id, { 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 3f0d73b263624f..26707a87db5194 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 @@ -32,7 +32,11 @@ function useConvertClassicToBlockMenu( clientId ) { const [ status, setStatus ] = useState( CLASSIC_MENU_CONVERSION_IDLE ); const [ error, setError ] = useState( null ); - async function convertClassicMenuToBlockMenu( menuId, menuName ) { + async function convertClassicMenuToBlockMenu( + menuId, + menuName, + postStatus = 'publish' + ) { let navigationMenu; let classicMenuItems; @@ -91,7 +95,7 @@ function useConvertClassicToBlockMenu( clientId ) { 'wp_navigation', navigationMenu.id, { - status: 'publish', + status: postStatus, }, { throwOnError: true } ); @@ -111,7 +115,7 @@ function useConvertClassicToBlockMenu( clientId ) { return navigationMenu; } - const convert = useCallback( async ( menuId, menuName ) => { + const convert = useCallback( async ( menuId, menuName, postStatus ) => { if ( ! menuId || ! menuName ) { setError( 'Unable to convert menu. Missing menu details.' ); setStatus( CLASSIC_MENU_CONVERSION_ERROR ); @@ -121,7 +125,11 @@ function useConvertClassicToBlockMenu( clientId ) { setStatus( CLASSIC_MENU_CONVERSION_PENDING ); setError( null ); - return await convertClassicMenuToBlockMenu( menuId, menuName ) + return await convertClassicMenuToBlockMenu( + menuId, + menuName, + postStatus + ) .then( ( navigationMenu ) => { setStatus( CLASSIC_MENU_CONVERSION_SUCCESS ); return navigationMenu; diff --git a/packages/block-library/src/navigation/index.php b/packages/block-library/src/navigation/index.php index 540e9dc40fc88a..b56f8386d4bfea 100644 --- a/packages/block-library/src/navigation/index.php +++ b/packages/block-library/src/navigation/index.php @@ -372,6 +372,29 @@ function block_core_navigation_get_fallback_blocks() { $navigation_post = block_core_navigation_get_most_recently_published_navigation(); + // If there are no navigation posts then try to find a classic menu. + if ( ! $navigation_post ) { + // See if we have a classic menu + $classic_nav_menu = block_core_navigation_get_classic_menu_fallback(); + + // If we have a classic menu then convert it to blocks. + if ( $classic_nav_menu ) { + $classic_nav_menu_blocks = block_core_navigation_get_classic_menu_fallback_blocks( $classic_nav_menu ); + $classic_nav_menu_blocks_serialized = serialize_blocks( $classic_nav_menu_blocks ); + + // Create a new navigation menu from the classic menu. + wp_insert_post( array( + 'post_content' => $classic_nav_menu_blocks_serialized, + 'post_title' => $classic_nav_menu->slug, + 'post_status' => 'publish', + 'post_type' => 'wp_navigation' + ) ); + + // Fetch the navigation menus again + $navigation_post = block_core_navigation_get_most_recently_published_navigation(); + } + } + // Prefer using the first non-empty Navigation as fallback if available. if ( $navigation_post ) { $maybe_fallback = block_core_navigation_filter_out_empty_blocks( parse_blocks( $navigation_post->post_content ) ); @@ -379,12 +402,6 @@ function block_core_navigation_get_fallback_blocks() { // 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; - } else { - // See if we have any classic menus - $classic_nav_menu = block_core_navigation_get_classic_menu_fallback(); - if ( $classic_nav_menu ) { - $fallback_blocks = block_core_navigation_get_classic_menu_fallback_blocks( $classic_nav_menu ); - } } /** From 49237462718a7a356762a792c34f8315e4a4ee81 Mon Sep 17 00:00:00 2001 From: Ben Dwyer Date: Fri, 16 Sep 2022 15:39:45 +0100 Subject: [PATCH 04/33] fix gutenberg_convert_menu_items_to_blocks --- lib/experimental/navigation-theme-opt-in.php | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/lib/experimental/navigation-theme-opt-in.php b/lib/experimental/navigation-theme-opt-in.php index 7efed9794d0ccc..08506f991515d6 100644 --- a/lib/experimental/navigation-theme-opt-in.php +++ b/lib/experimental/navigation-theme-opt-in.php @@ -214,13 +214,17 @@ function gutenberg_convert_menu_items_to_blocks( ); } - $block['innerBlocks'] = gutenberg_convert_menu_items_to_blocks( - isset( $menu_items_by_parent_id[ $menu_item->ID ] ) - ? $menu_items_by_parent_id[ $menu_item->ID ] + $menu_item_id = (int) $menu_item->ID; + + $block['innerContent'] = gutenberg_convert_menu_items_to_blocks( + isset( $menu_items_by_parent_id[ $menu_item_id ] ) + ? $menu_items_by_parent_id[ $menu_item_id ] : array(), $menu_items_by_parent_id ); + $block['innerBlocks'] = $block['innerContent'] ; + $blocks[] = $block; } From 33e65ca6153f9bd4fed06360cc633c037b6d48dc Mon Sep 17 00:00:00 2001 From: Ben Dwyer Date: Fri, 16 Sep 2022 15:57:33 +0100 Subject: [PATCH 05/33] refactor --- .../block-library/src/navigation/index.php | 47 +++++++++++-------- 1 file changed, 28 insertions(+), 19 deletions(-) diff --git a/packages/block-library/src/navigation/index.php b/packages/block-library/src/navigation/index.php index b56f8386d4bfea..21199a48caae9d 100644 --- a/packages/block-library/src/navigation/index.php +++ b/packages/block-library/src/navigation/index.php @@ -298,6 +298,33 @@ function block_core_navigation_get_classic_menu_fallback_blocks( $classic_nav_me return $inner_blocks; } +/** + * If there's a the classic menu then use it as a fallback. + * + * @return array the normalized parsed blocks. + */ +function block_core_navigation_maybe_use_classic_menu_fallback() { + // See if we have a classic menu + $classic_nav_menu = block_core_navigation_get_classic_menu_fallback(); + + // If we have a classic menu then convert it to blocks. + if ( $classic_nav_menu ) { + $classic_nav_menu_blocks = block_core_navigation_get_classic_menu_fallback_blocks( $classic_nav_menu ); + $classic_nav_menu_blocks_serialized = serialize_blocks( $classic_nav_menu_blocks ); + + // Create a new navigation menu from the classic menu. + wp_insert_post( array( + 'post_content' => $classic_nav_menu_blocks_serialized, + 'post_title' => $classic_nav_menu->slug, + 'post_status' => 'publish', + 'post_type' => 'wp_navigation' + ) ); + + // Fetch the most recently published navigation which will be the classic one created above. + return block_core_navigation_get_most_recently_published_navigation(); + } +} + /** * Finds the most recently published `wp_navigation` Post. * @@ -374,25 +401,7 @@ function block_core_navigation_get_fallback_blocks() { // If there are no navigation posts then try to find a classic menu. if ( ! $navigation_post ) { - // See if we have a classic menu - $classic_nav_menu = block_core_navigation_get_classic_menu_fallback(); - - // If we have a classic menu then convert it to blocks. - if ( $classic_nav_menu ) { - $classic_nav_menu_blocks = block_core_navigation_get_classic_menu_fallback_blocks( $classic_nav_menu ); - $classic_nav_menu_blocks_serialized = serialize_blocks( $classic_nav_menu_blocks ); - - // Create a new navigation menu from the classic menu. - wp_insert_post( array( - 'post_content' => $classic_nav_menu_blocks_serialized, - 'post_title' => $classic_nav_menu->slug, - 'post_status' => 'publish', - 'post_type' => 'wp_navigation' - ) ); - - // Fetch the navigation menus again - $navigation_post = block_core_navigation_get_most_recently_published_navigation(); - } + $navigation_post = block_core_navigation_maybe_use_classic_menu_fallback(); } // Prefer using the first non-empty Navigation as fallback if available. From 5657427c1a52b1d82378cbcf3181bb80f5ce7ccc Mon Sep 17 00:00:00 2001 From: Ben Dwyer Date: Fri, 16 Sep 2022 17:13:12 +0100 Subject: [PATCH 06/33] only create navigation once, and create it published --- .../src/navigation/edit/index.js | 51 +++++++++++-------- .../use-convert-classic-menu-to-block-menu.js | 3 +- .../edit/use-create-navigation-menu.js | 7 +-- 3 files changed, 34 insertions(+), 27 deletions(-) diff --git a/packages/block-library/src/navigation/edit/index.js b/packages/block-library/src/navigation/edit/index.js index 7d6017af1b1596..f51f9b834dbdca 100644 --- a/packages/block-library/src/navigation/edit/index.js +++ b/packages/block-library/src/navigation/edit/index.js @@ -233,25 +233,30 @@ function Navigation( { return; } + // If there's non fallback navigation menus and + // only one classic menu then create a new navigation menu based on it. if ( ! fallbackNavigationMenus?.length && classicMenus?.length === 1 ) { - // If there's only one classic menu - // then create a new navigation menu based on it. - - // This is duplicated several times. - const onSelectClassicMenu = async ( classicMenu ) => { - const navMenu = await convertClassicMenu( - classicMenu.id, - classicMenu.name, - 'publish' - ); - if ( navMenu ) { - handleUpdateMenu( navMenu.id, { - focusNavigationBlock: true, - } ); - } - }; - - onSelectClassicMenu( classicMenus[ 0 ] ); + // Only create classic menus once. + if ( ! convertingClassicMenu ) { + // This is duplicated several times. + const onSelectClassicMenu = async ( classicMenu ) => { + setConvertingClassicMenu( true ); + const navMenu = await convertClassicMenu( + classicMenu.id, + classicMenu.name, + 'publish' + ); + if ( navMenu ) { + handleUpdateMenu( navMenu.id, { + focusNavigationBlock: true, + } ); + } + }; + + onSelectClassicMenu( classicMenus[ 0 ] ); + } + + return; } // See if we have any navigation menus @@ -359,6 +364,7 @@ function Navigation( { // Turn on contrast checker for web only since it's not supported on mobile yet. const enableContrastChecking = Platform.OS === 'web'; + const [ convertingClassicMenu, setConvertingClassicMenu ] = useState(); const [ detectedBackgroundColor, setDetectedBackgroundColor ] = useState(); const [ detectedColor, setDetectedColor ] = useState(); const [ @@ -742,7 +748,8 @@ function Navigation( { onSelectClassicMenu={ async ( classicMenu ) => { const navMenu = await convertClassicMenu( classicMenu.id, - classicMenu.name + classicMenu.name, + 'draft' ); if ( navMenu ) { handleUpdateMenu( navMenu.id, { @@ -827,7 +834,8 @@ function Navigation( { onSelectClassicMenu={ async ( classicMenu ) => { const navMenu = await convertClassicMenu( classicMenu.id, - classicMenu.name + classicMenu.name, + 'draft' ); if ( navMenu ) { handleUpdateMenu( navMenu.id, { @@ -855,7 +863,8 @@ function Navigation( { onSelectClassicMenu={ async ( classicMenu ) => { const navMenu = await convertClassicMenu( classicMenu.id, - classicMenu.name + classicMenu.name, + 'draft' ); if ( navMenu ) { handleUpdateMenu( navMenu.id, { 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 26707a87db5194..664c5c807e47ba 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 @@ -80,7 +80,8 @@ function useConvertClassicToBlockMenu( clientId ) { try { navigationMenu = await createNavigationMenu( menuName, - innerBlocks + innerBlocks, + postStatus ); /** diff --git a/packages/block-library/src/navigation/edit/use-create-navigation-menu.js b/packages/block-library/src/navigation/edit/use-create-navigation-menu.js index 6b0fda71489bdc..2a2249842b9557 100644 --- a/packages/block-library/src/navigation/edit/use-create-navigation-menu.js +++ b/packages/block-library/src/navigation/edit/use-create-navigation-menu.js @@ -16,10 +16,7 @@ export const CREATE_NAVIGATION_MENU_ERROR = 'error'; export const CREATE_NAVIGATION_MENU_PENDING = 'pending'; export const CREATE_NAVIGATION_MENU_IDLE = 'idle'; -export default function useCreateNavigationMenu( - clientId, - postStatus = 'publish' -) { +export default function useCreateNavigationMenu( clientId ) { const [ status, setStatus ] = useState( CREATE_NAVIGATION_MENU_IDLE ); const [ value, setValue ] = useState( null ); const [ error, setError ] = useState( null ); @@ -30,7 +27,7 @@ export default function useCreateNavigationMenu( // This callback uses data from the two placeholder steps and only creates // a new navigation menu when the user completes the final step. const create = useCallback( - async ( title = null, blocks = [] ) => { + async ( title = null, blocks = [], postStatus ) => { // Guard against creating Navigations without a title. // Note you can pass no title, but if one is passed it must be // a string otherwise the title may end up being empty. From 567b8c64235039c587b5b73d692325228eabbeac Mon Sep 17 00:00:00 2001 From: Ben Dwyer Date: Fri, 16 Sep 2022 17:16:31 +0100 Subject: [PATCH 07/33] remove the code that makes the block dirty --- packages/block-library/src/navigation/edit/index.js | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/packages/block-library/src/navigation/edit/index.js b/packages/block-library/src/navigation/edit/index.js index f51f9b834dbdca..425323f84e9512 100644 --- a/packages/block-library/src/navigation/edit/index.js +++ b/packages/block-library/src/navigation/edit/index.js @@ -241,16 +241,11 @@ function Navigation( { // This is duplicated several times. const onSelectClassicMenu = async ( classicMenu ) => { setConvertingClassicMenu( true ); - const navMenu = await convertClassicMenu( + await convertClassicMenu( classicMenu.id, classicMenu.name, 'publish' ); - if ( navMenu ) { - handleUpdateMenu( navMenu.id, { - focusNavigationBlock: true, - } ); - } }; onSelectClassicMenu( classicMenus[ 0 ] ); From 3d0df38e7a5ce30f1e9311b20c8d1e3a2305332d Mon Sep 17 00:00:00 2001 From: Ben Dwyer Date: Mon, 19 Sep 2022 12:21:31 +0100 Subject: [PATCH 08/33] convert navigation with submenu items correctly --- lib/experimental/navigation-theme-opt-in.php | 53 +++++++++----------- 1 file changed, 23 insertions(+), 30 deletions(-) diff --git a/lib/experimental/navigation-theme-opt-in.php b/lib/experimental/navigation-theme-opt-in.php index 08506f991515d6..aec937f6a57216 100644 --- a/lib/experimental/navigation-theme-opt-in.php +++ b/lib/experimental/navigation-theme-opt-in.php @@ -191,40 +191,33 @@ function gutenberg_convert_menu_items_to_blocks( $blocks = array(); foreach ( $menu_items as $menu_item ) { - if ( 'block' === $menu_item->type ) { - $parsed_blocks = parse_blocks( $menu_item->content ); - - if ( count( $parsed_blocks ) ) { - $block = $parsed_blocks[0]; - } else { - $block = array( - 'blockName' => 'core/freeform', - 'attrs' => array( - 'originalContent' => $menu_item->content, - ), - ); - } - } else { - $block = array( - 'blockName' => 'core/navigation-link', - 'attrs' => array( - 'label' => $menu_item->title, - 'url' => $menu_item->url, - ), - ); - } - $menu_item_id = (int) $menu_item->ID; - $block['innerContent'] = gutenberg_convert_menu_items_to_blocks( - isset( $menu_items_by_parent_id[ $menu_item_id ] ) - ? $menu_items_by_parent_id[ $menu_item_id ] - : array(), - $menu_items_by_parent_id - ); + $has_children = isset( $menu_items_by_parent_id[ $menu_item_id ] ); - $block['innerBlocks'] = $block['innerContent'] ; + if ( $has_children ) { + $submenu_items = $menu_items_by_parent_id[ $menu_item_id ]; + $block_name = 'core/navigation-submenu'; + } else { + $submenu_items = array(); + $block_name = 'core/navigation-link'; + } + $block = array( + 'blockName' => $block_name, + 'attrs' => array( + 'label' => $menu_item->title, + 'url' => $menu_item->url, + ), + ); + $block_content = gutenberg_convert_menu_items_to_blocks( + $submenu_items, + $menu_items_by_parent_id, + ); + if ( ! empty( $block_content ) ) { + $block['innerContent'] = $block_content; + $block['innerBlocks'] = $block_content; + } $blocks[] = $block; } From 2a50c49847c0a2285d27b0337786fff8e6d26cb9 Mon Sep 17 00:00:00 2001 From: Ben Dwyer Date: Mon, 19 Sep 2022 14:28:03 +0100 Subject: [PATCH 09/33] php lint --- lib/experimental/navigation-theme-opt-in.php | 13 +++++++---- .../block-library/src/navigation/index.php | 23 +++++++++++-------- 2 files changed, 22 insertions(+), 14 deletions(-) diff --git a/lib/experimental/navigation-theme-opt-in.php b/lib/experimental/navigation-theme-opt-in.php index aec937f6a57216..30ed17d291a9bf 100644 --- a/lib/experimental/navigation-theme-opt-in.php +++ b/lib/experimental/navigation-theme-opt-in.php @@ -197,12 +197,13 @@ function gutenberg_convert_menu_items_to_blocks( if ( $has_children ) { $submenu_items = $menu_items_by_parent_id[ $menu_item_id ]; - $block_name = 'core/navigation-submenu'; + $block_name = 'core/navigation-submenu'; } else { $submenu_items = array(); - $block_name = 'core/navigation-link'; + $block_name = 'core/navigation-link'; } + // Create a child block. $block = array( 'blockName' => $block_name, 'attrs' => array( @@ -210,14 +211,18 @@ function gutenberg_convert_menu_items_to_blocks( 'url' => $menu_item->url, ), ); + + // Create the content of the block. $block_content = gutenberg_convert_menu_items_to_blocks( $submenu_items, - $menu_items_by_parent_id, + $menu_items_by_parent_id ); + if ( ! empty( $block_content ) ) { $block['innerContent'] = $block_content; - $block['innerBlocks'] = $block_content; + $block['innerBlocks'] = $block_content; } + $blocks[] = $block; } diff --git a/packages/block-library/src/navigation/index.php b/packages/block-library/src/navigation/index.php index 21199a48caae9d..154b001e360fdf 100644 --- a/packages/block-library/src/navigation/index.php +++ b/packages/block-library/src/navigation/index.php @@ -259,13 +259,14 @@ function block_core_navigation_get_classic_menu_fallback() { // If menus exist. if ( $classic_nav_menus && ! is_wp_error( $classic_nav_menus ) && count( $classic_nav_menus ) === 1 ) { // If there's only one classic menu then use it. - return $classic_nav_menus[ 0 ]; + return $classic_nav_menus[0]; } } /** - * Finds the classic navigation fallback to use. + * Converts a classic navigation to blocks. * + * @param object WP_Term The classic navigation object to convert. * @return array the normalized parsed blocks. */ function block_core_navigation_get_classic_menu_fallback_blocks( $classic_nav_menu ) { @@ -304,21 +305,23 @@ function block_core_navigation_get_classic_menu_fallback_blocks( $classic_nav_me * @return array the normalized parsed blocks. */ function block_core_navigation_maybe_use_classic_menu_fallback() { - // See if we have a classic menu + // See if we have a classic menu. $classic_nav_menu = block_core_navigation_get_classic_menu_fallback(); // If we have a classic menu then convert it to blocks. if ( $classic_nav_menu ) { - $classic_nav_menu_blocks = block_core_navigation_get_classic_menu_fallback_blocks( $classic_nav_menu ); + $classic_nav_menu_blocks = block_core_navigation_get_classic_menu_fallback_blocks( $classic_nav_menu ); $classic_nav_menu_blocks_serialized = serialize_blocks( $classic_nav_menu_blocks ); // Create a new navigation menu from the classic menu. - wp_insert_post( array( - 'post_content' => $classic_nav_menu_blocks_serialized, - 'post_title' => $classic_nav_menu->slug, - 'post_status' => 'publish', - 'post_type' => 'wp_navigation' - ) ); + wp_insert_post( + array( + 'post_content' => $classic_nav_menu_blocks_serialized, + 'post_title' => $classic_nav_menu->slug, + 'post_status' => 'publish', + 'post_type' => 'wp_navigation' + ) + ); // Fetch the most recently published navigation which will be the classic one created above. return block_core_navigation_get_most_recently_published_navigation(); From 8e085c1079f8cf5103be89a0c004721e6e6dc45f Mon Sep 17 00:00:00 2001 From: Ben Dwyer Date: Tue, 20 Sep 2022 14:00:19 +0100 Subject: [PATCH 10/33] use a different function to convert classic menus to blocks --- packages/block-library/src/navigation/index.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/block-library/src/navigation/index.php b/packages/block-library/src/navigation/index.php index 154b001e360fdf..c4c1c1d8a1770b 100644 --- a/packages/block-library/src/navigation/index.php +++ b/packages/block-library/src/navigation/index.php @@ -289,7 +289,7 @@ function block_core_navigation_get_classic_menu_fallback_blocks( $classic_nav_me $menu_items_by_parent_id[ $menu_item->menu_item_parent ][] = $menu_item; } - $inner_blocks = gutenberg_convert_menu_items_to_blocks( + $inner_blocks = block_core_navigation_parse_blocks_from_menu_items( isset( $menu_items_by_parent_id[0] ) ? $menu_items_by_parent_id[0] : array(), From cdb473a7d1e3ae0f419468c8e88251e5c0a338f5 Mon Sep 17 00:00:00 2001 From: Ben Dwyer Date: Tue, 20 Sep 2022 14:07:15 +0100 Subject: [PATCH 11/33] add error handling --- 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 c4c1c1d8a1770b..daba7b7c4d9ef0 100644 --- a/packages/block-library/src/navigation/index.php +++ b/packages/block-library/src/navigation/index.php @@ -314,7 +314,7 @@ function block_core_navigation_maybe_use_classic_menu_fallback() { $classic_nav_menu_blocks_serialized = serialize_blocks( $classic_nav_menu_blocks ); // Create a new navigation menu from the classic menu. - wp_insert_post( + $wp_insert_post_result = wp_insert_post( array( 'post_content' => $classic_nav_menu_blocks_serialized, 'post_title' => $classic_nav_menu->slug, @@ -323,6 +323,10 @@ function block_core_navigation_maybe_use_classic_menu_fallback() { ) ); + if ( is_wp_error( $wp_insert_post_result ) ) { + return; + } + // Fetch the most recently published navigation which will be the classic one created above. return block_core_navigation_get_most_recently_published_navigation(); } From 13945bcaeea6866dc691a8c45f26cd4e988d57bf Mon Sep 17 00:00:00 2001 From: Ben Dwyer Date: Tue, 20 Sep 2022 11:39:39 +0100 Subject: [PATCH 12/33] Update packages/block-library/src/navigation/index.php Co-authored-by: Dave Smith --- packages/block-library/src/navigation/index.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/block-library/src/navigation/index.php b/packages/block-library/src/navigation/index.php index daba7b7c4d9ef0..0f838c49076fb9 100644 --- a/packages/block-library/src/navigation/index.php +++ b/packages/block-library/src/navigation/index.php @@ -258,7 +258,9 @@ function block_core_navigation_get_classic_menu_fallback() { // If menus exist. if ( $classic_nav_menus && ! is_wp_error( $classic_nav_menus ) && count( $classic_nav_menus ) === 1 ) { - // If there's only one classic menu then use it. + // Use the first classic menu only. Handles simple use case where user has a single + // classic menu and switches to a block theme. In future this maybe expanded to + // determine the most appropriate classic menu to be used based on location. return $classic_nav_menus[0]; } } From 30df68a4c078ae03f0aadf746ee43eb3ee5c0526 Mon Sep 17 00:00:00 2001 From: Ben Dwyer Date: Tue, 20 Sep 2022 11:40:04 +0100 Subject: [PATCH 13/33] Update packages/block-library/src/navigation/index.php Co-authored-by: Dave Smith --- packages/block-library/src/navigation/index.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/block-library/src/navigation/index.php b/packages/block-library/src/navigation/index.php index 0f838c49076fb9..a4b98f61d2cf66 100644 --- a/packages/block-library/src/navigation/index.php +++ b/packages/block-library/src/navigation/index.php @@ -341,7 +341,7 @@ function block_core_navigation_maybe_use_classic_menu_fallback() { */ function block_core_navigation_get_most_recently_published_navigation() { - // We default to the most recently created menu. + // Default to the most recently created menu. $parsed_args = array( 'post_type' => 'wp_navigation', 'no_found_rows' => true, From 73061c64cf314db8d17fba5ee328da5f9b369249 Mon Sep 17 00:00:00 2001 From: Ben Dwyer Date: Tue, 20 Sep 2022 14:04:15 +0100 Subject: [PATCH 14/33] Update packages/block-library/src/navigation/index.php Co-authored-by: Jonny Harris --- packages/block-library/src/navigation/index.php | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/block-library/src/navigation/index.php b/packages/block-library/src/navigation/index.php index a4b98f61d2cf66..3fb05048e578f2 100644 --- a/packages/block-library/src/navigation/index.php +++ b/packages/block-library/src/navigation/index.php @@ -320,6 +320,7 @@ function block_core_navigation_maybe_use_classic_menu_fallback() { array( 'post_content' => $classic_nav_menu_blocks_serialized, 'post_title' => $classic_nav_menu->slug, + 'post_name' => $classic_nav_menu->slug, 'post_status' => 'publish', 'post_type' => 'wp_navigation' ) From 93d5a94032d5c131b68cf1570aa3ca7d0e627c43 Mon Sep 17 00:00:00 2001 From: Ben Dwyer Date: Tue, 20 Sep 2022 15:41:23 +0100 Subject: [PATCH 15/33] pass second param as true --- packages/block-library/src/navigation/index.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/block-library/src/navigation/index.php b/packages/block-library/src/navigation/index.php index 3fb05048e578f2..5a9557bd7a5571 100644 --- a/packages/block-library/src/navigation/index.php +++ b/packages/block-library/src/navigation/index.php @@ -323,7 +323,8 @@ function block_core_navigation_maybe_use_classic_menu_fallback() { 'post_name' => $classic_nav_menu->slug, 'post_status' => 'publish', 'post_type' => 'wp_navigation' - ) + ), + true // So that we can check whether the result is an error. ); if ( is_wp_error( $wp_insert_post_result ) ) { From 27582847a2dfc0f86b6e9af561ba0efd88843fe7 Mon Sep 17 00:00:00 2001 From: Dave Smith Date: Wed, 21 Sep 2022 09:42:52 +0100 Subject: [PATCH 16/33] Use existing classic menu conversion state --- .../src/navigation/edit/index.js | 22 +++++++++---------- 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/packages/block-library/src/navigation/edit/index.js b/packages/block-library/src/navigation/edit/index.js index 425323f84e9512..ec8eb90114ca42 100644 --- a/packages/block-library/src/navigation/edit/index.js +++ b/packages/block-library/src/navigation/edit/index.js @@ -216,6 +216,15 @@ function Navigation( { const navMenuResolvedButMissing = hasResolvedNavigationMenus && isNavigationMenuMissing; + const { + convert: convertClassicMenu, + status: classicMenuConversionStatus, + error: classicMenuConversionError, + } = useConvertClassicToBlockMenu( clientId ); + + const isConvertingClassicMenu = + classicMenuConversionStatus === CLASSIC_MENU_CONVERSION_PENDING; + // Attempt to retrieve and prioritize any existing navigation menu unless: // - the are uncontrolled inner blocks already present in the block. // - the user is creating a new menu. @@ -237,10 +246,9 @@ function Navigation( { // only one classic menu then create a new navigation menu based on it. if ( ! fallbackNavigationMenus?.length && classicMenus?.length === 1 ) { // Only create classic menus once. - if ( ! convertingClassicMenu ) { + if ( ! isConvertingClassicMenu ) { // This is duplicated several times. const onSelectClassicMenu = async ( classicMenu ) => { - setConvertingClassicMenu( true ); await convertClassicMenu( classicMenu.id, classicMenu.name, @@ -276,15 +284,6 @@ function Navigation( { const navRef = useRef(); - const { - convert: convertClassicMenu, - status: classicMenuConversionStatus, - error: classicMenuConversionError, - } = useConvertClassicToBlockMenu( clientId ); - - const isConvertingClassicMenu = - classicMenuConversionStatus === CLASSIC_MENU_CONVERSION_PENDING; - // The standard HTML5 tag for the block wrapper. const TagName = 'nav'; @@ -359,7 +358,6 @@ function Navigation( { // Turn on contrast checker for web only since it's not supported on mobile yet. const enableContrastChecking = Platform.OS === 'web'; - const [ convertingClassicMenu, setConvertingClassicMenu ] = useState(); const [ detectedBackgroundColor, setDetectedBackgroundColor ] = useState(); const [ detectedColor, setDetectedColor ] = useState(); const [ From 6c22417a69aed0a200ecd6e798c3b3301073fa60 Mon Sep 17 00:00:00 2001 From: Ben Dwyer Date: Wed, 21 Sep 2022 09:43:56 +0100 Subject: [PATCH 17/33] Update packages/block-library/src/navigation/edit/index.js Co-authored-by: Dave Smith --- packages/block-library/src/navigation/edit/index.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/block-library/src/navigation/edit/index.js b/packages/block-library/src/navigation/edit/index.js index ec8eb90114ca42..b3fa5a21853886 100644 --- a/packages/block-library/src/navigation/edit/index.js +++ b/packages/block-library/src/navigation/edit/index.js @@ -233,15 +233,15 @@ function Navigation( { // than 1 exists then use the most recent. // The aim is for the block to "just work" from a user perspective using existing data. useEffect( () => { + if ( hasUncontrolledInnerBlocks || isCreatingNavigationMenu || ref ) { + return; + } + // Only autofallback to published menus. const fallbackNavigationMenus = navigationMenus?.filter( ( menu ) => menu.status === 'publish' ); - if ( hasUncontrolledInnerBlocks || isCreatingNavigationMenu || ref ) { - return; - } - // If there's non fallback navigation menus and // only one classic menu then create a new navigation menu based on it. if ( ! fallbackNavigationMenus?.length && classicMenus?.length === 1 ) { From 7910757ee95d0469051ada79ab003a8a6d3c20c9 Mon Sep 17 00:00:00 2001 From: Ben Dwyer Date: Wed, 21 Sep 2022 10:05:18 +0100 Subject: [PATCH 18/33] rename function --- packages/block-library/src/navigation/edit/index.js | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/packages/block-library/src/navigation/edit/index.js b/packages/block-library/src/navigation/edit/index.js index b3fa5a21853886..ef93bd23a74ec8 100644 --- a/packages/block-library/src/navigation/edit/index.js +++ b/packages/block-library/src/navigation/edit/index.js @@ -236,7 +236,7 @@ function Navigation( { if ( hasUncontrolledInnerBlocks || isCreatingNavigationMenu || ref ) { return; } - + // Only autofallback to published menus. const fallbackNavigationMenus = navigationMenus?.filter( ( menu ) => menu.status === 'publish' @@ -247,8 +247,7 @@ function Navigation( { if ( ! fallbackNavigationMenus?.length && classicMenus?.length === 1 ) { // Only create classic menus once. if ( ! isConvertingClassicMenu ) { - // This is duplicated several times. - const onSelectClassicMenu = async ( classicMenu ) => { + const onConvertClassicMenu = async ( classicMenu ) => { await convertClassicMenu( classicMenu.id, classicMenu.name, @@ -256,7 +255,7 @@ function Navigation( { ); }; - onSelectClassicMenu( classicMenus[ 0 ] ); + onConvertClassicMenu( classicMenus[ 0 ] ); } return; From 225b7fd9752b04ddf0c622c1e0ab82f31260298f Mon Sep 17 00:00:00 2001 From: Andrei Draganescu Date: Wed, 21 Sep 2022 15:03:41 +0300 Subject: [PATCH 19/33] Fixes multiple menu creation on import. Also: - refactores the effects for block menu fallback and classic menu fallback Co-authored-by: Dave Smith <444434+getdave@users.noreply.github.com> Co-authored-by: Ben Dwyer <275961+scruffian@users.noreply.github.com> --- .../src/navigation/edit/index.js | 85 ++++++++++--------- 1 file changed, 44 insertions(+), 41 deletions(-) diff --git a/packages/block-library/src/navigation/edit/index.js b/packages/block-library/src/navigation/edit/index.js index ef93bd23a74ec8..0f2fa0b0cd78fe 100644 --- a/packages/block-library/src/navigation/edit/index.js +++ b/packages/block-library/src/navigation/edit/index.js @@ -225,6 +225,11 @@ function Navigation( { const isConvertingClassicMenu = classicMenuConversionStatus === CLASSIC_MENU_CONVERSION_PENDING; + // Only autofallback to published menus. + const fallbackNavigationMenus = navigationMenus?.filter( + ( menu ) => menu.status === 'publish' + ); + // Attempt to retrieve and prioritize any existing navigation menu unless: // - the are uncontrolled inner blocks already present in the block. // - the user is creating a new menu. @@ -233,53 +238,50 @@ function Navigation( { // than 1 exists then use the most recent. // The aim is for the block to "just work" from a user perspective using existing data. useEffect( () => { - if ( hasUncontrolledInnerBlocks || isCreatingNavigationMenu || ref ) { + if ( + hasUncontrolledInnerBlocks || + isCreatingNavigationMenu || + ref || + ! fallbackNavigationMenus?.length + ) { return; } - // Only autofallback to published menus. - const fallbackNavigationMenus = navigationMenus?.filter( - ( menu ) => menu.status === 'publish' - ); + fallbackNavigationMenus.sort( ( menuA, menuB ) => { + const menuADate = new Date( menuA.date ); + const menuBDate = new Date( menuB.date ); + return menuADate.getTime() < menuBDate.getTime(); + } ); - // If there's non fallback navigation menus and - // only one classic menu then create a new navigation menu based on it. - if ( ! fallbackNavigationMenus?.length && classicMenus?.length === 1 ) { - // Only create classic menus once. - if ( ! isConvertingClassicMenu ) { - const onConvertClassicMenu = async ( classicMenu ) => { - await convertClassicMenu( - classicMenu.id, - classicMenu.name, - 'publish' - ); - }; - - onConvertClassicMenu( classicMenus[ 0 ] ); - } + /** + * This fallback displays (both in editor and on front) + * a list of pages only if no menu (user assigned or + * automatically picked) is available. + * The fallback should not request a save (entity dirty state) + * nor to be undoable, hence why it is marked as non persistent + */ + __unstableMarkNextChangeAsNotPersistent(); + setRef( fallbackNavigationMenus[ 0 ].id ); + }, [ navigationMenus ] ); - return; + useEffect( async () => { + if ( + ! hasResolvedNavigationMenus || + isConvertingClassicMenu || + fallbackNavigationMenus?.length > 0 || + classicMenus?.length !== 1 + ) { + return false; } - // See if we have any navigation menus - if ( fallbackNavigationMenus?.length ) { - navigationMenus.sort( ( menuA, menuB ) => { - const menuADate = new Date( menuA.date ); - const menuBDate = new Date( menuB.date ); - return menuADate.getTime() < menuBDate.getTime(); - } ); - - /** - * This fallback displays (both in editor and on front) - * a list of pages only if no menu (user assigned or - * automatically picked) is available. - * The fallback should not request a save (entity dirty state) - * nor to be undoable, hence why it is marked as non persistent - */ - __unstableMarkNextChangeAsNotPersistent(); - setRef( fallbackNavigationMenus[ 0 ].id ); - } - }, [ navigationMenus ] ); + // If there's non fallback navigation menus and + // only one classic menu then create a new navigation menu based on it. + await convertClassicMenu( + classicMenus[ 0 ].id, + classicMenus[ 0 ].name, + 'publish' + ); + }, [ hasResolvedNavigationMenus ] ); const navRef = useRef(); @@ -296,10 +298,11 @@ function Navigation( { ! isCreatingNavigationMenu && ! isConvertingClassicMenu && hasResolvedNavigationMenus && + classicMenus?.length === 0 && ! hasUncontrolledInnerBlocks; useEffect( () => { - if ( isPlaceholder && ! ref ) { + if ( isPlaceholder ) { /** * this fallback only displays (both in editor and on front) * the list of pages block if no menu is available as a fallback. From fcb2111483cfbfb2c7fedfe3e532067a405d6e4b Mon Sep 17 00:00:00 2001 From: Ben Dwyer Date: Thu, 22 Sep 2022 10:50:37 +0100 Subject: [PATCH 20/33] return early when we won't continue --- .../block-library/src/navigation/index.php | 46 +++++++++++-------- 1 file changed, 26 insertions(+), 20 deletions(-) diff --git a/packages/block-library/src/navigation/index.php b/packages/block-library/src/navigation/index.php index 5a9557bd7a5571..d01e7f253a5e4c 100644 --- a/packages/block-library/src/navigation/index.php +++ b/packages/block-library/src/navigation/index.php @@ -310,30 +310,36 @@ function block_core_navigation_maybe_use_classic_menu_fallback() { // See if we have a classic menu. $classic_nav_menu = block_core_navigation_get_classic_menu_fallback(); + if ( ! $classic_nav_menu ) { + return; + } + // If we have a classic menu then convert it to blocks. - if ( $classic_nav_menu ) { - $classic_nav_menu_blocks = block_core_navigation_get_classic_menu_fallback_blocks( $classic_nav_menu ); - $classic_nav_menu_blocks_serialized = serialize_blocks( $classic_nav_menu_blocks ); - - // Create a new navigation menu from the classic menu. - $wp_insert_post_result = wp_insert_post( - array( - 'post_content' => $classic_nav_menu_blocks_serialized, - 'post_title' => $classic_nav_menu->slug, - 'post_name' => $classic_nav_menu->slug, - 'post_status' => 'publish', - 'post_type' => 'wp_navigation' - ), - true // So that we can check whether the result is an error. - ); + $classic_nav_menu_blocks = block_core_navigation_get_classic_menu_fallback_blocks( $classic_nav_menu ); + $classic_nav_menu_blocks_serialized = serialize_blocks( $classic_nav_menu_blocks ); - if ( is_wp_error( $wp_insert_post_result ) ) { - return; - } + if ( empty( $classic_nav_menu_blocks_serialized ) ) { + return; + } + + // Create a new navigation menu from the classic menu. + $wp_insert_post_result = wp_insert_post( + array( + 'post_content' => $classic_nav_menu_blocks_serialized, + 'post_title' => $classic_nav_menu->slug, + 'post_name' => $classic_nav_menu->slug, + 'post_status' => 'publish', + 'post_type' => 'wp_navigation' + ), + true // So that we can check whether the result is an error. + ); - // Fetch the most recently published navigation which will be the classic one created above. - return block_core_navigation_get_most_recently_published_navigation(); + if ( is_wp_error( $wp_insert_post_result ) ) { + return; } + + // Fetch the most recently published navigation which will be the classic one created above. + return block_core_navigation_get_most_recently_published_navigation(); } /** From 2ad500bf2f6472b9266b30c85362d4322741d287 Mon Sep 17 00:00:00 2001 From: Ben Dwyer Date: Thu, 22 Sep 2022 10:54:16 +0100 Subject: [PATCH 21/33] a comment about where the duplicated code starts --- packages/block-library/src/navigation/index.php | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/block-library/src/navigation/index.php b/packages/block-library/src/navigation/index.php index d01e7f253a5e4c..fbd9635fb857e6 100644 --- a/packages/block-library/src/navigation/index.php +++ b/packages/block-library/src/navigation/index.php @@ -272,6 +272,7 @@ function block_core_navigation_get_classic_menu_fallback() { * @return array the normalized parsed blocks. */ function block_core_navigation_get_classic_menu_fallback_blocks( $classic_nav_menu ) { + // BEGIN: Code that already exists in wp_nav_menu(). $menu_items = wp_get_nav_menu_items( $classic_nav_menu->term_id, array( 'update_post_term_cache' => false ) ); // Set up the $menu_item variables. From a9196682462634fff4a262a1e1362996427034b7 Mon Sep 17 00:00:00 2001 From: Ben Dwyer Date: Wed, 21 Sep 2022 17:27:57 +0100 Subject: [PATCH 22/33] Update packages/block-library/src/navigation/index.php Co-authored-by: Dave Smith --- packages/block-library/src/navigation/index.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/block-library/src/navigation/index.php b/packages/block-library/src/navigation/index.php index fbd9635fb857e6..87c7c0c73ff484 100644 --- a/packages/block-library/src/navigation/index.php +++ b/packages/block-library/src/navigation/index.php @@ -422,7 +422,7 @@ function block_core_navigation_get_fallback_blocks() { $navigation_post = block_core_navigation_maybe_use_classic_menu_fallback(); } - // Prefer using the first non-empty Navigation as fallback if available. + // Use the first non-empty Navigation as fallback if available. if ( $navigation_post ) { $maybe_fallback = block_core_navigation_filter_out_empty_blocks( parse_blocks( $navigation_post->post_content ) ); From 92b861c1217dcc715636b04245501bdc822676f9 Mon Sep 17 00:00:00 2001 From: Ben Dwyer Date: Wed, 21 Sep 2022 17:28:04 +0100 Subject: [PATCH 23/33] Update packages/block-library/src/navigation/index.php Co-authored-by: Dave Smith --- packages/block-library/src/navigation/index.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/block-library/src/navigation/index.php b/packages/block-library/src/navigation/index.php index 87c7c0c73ff484..a9925b35c91b7c 100644 --- a/packages/block-library/src/navigation/index.php +++ b/packages/block-library/src/navigation/index.php @@ -417,7 +417,8 @@ function block_core_navigation_get_fallback_blocks() { $navigation_post = block_core_navigation_get_most_recently_published_navigation(); - // If there are no navigation posts then try to find a classic menu. + // If there are no navigation posts then try to find a classic menu + // and convert it into a block based navigation menu. if ( ! $navigation_post ) { $navigation_post = block_core_navigation_maybe_use_classic_menu_fallback(); } From eba030ce943c7d5335e2adeb7504f5b558987a4a Mon Sep 17 00:00:00 2001 From: Ben Dwyer Date: Thu, 22 Sep 2022 10:59:09 +0100 Subject: [PATCH 24/33] make the callback from the useEffect return a function not a promise --- .../src/navigation/edit/index.js | 34 ++++++++++--------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/packages/block-library/src/navigation/edit/index.js b/packages/block-library/src/navigation/edit/index.js index 0f2fa0b0cd78fe..a02713f91f33b0 100644 --- a/packages/block-library/src/navigation/edit/index.js +++ b/packages/block-library/src/navigation/edit/index.js @@ -264,23 +264,25 @@ function Navigation( { setRef( fallbackNavigationMenus[ 0 ].id ); }, [ navigationMenus ] ); - useEffect( async () => { - if ( - ! hasResolvedNavigationMenus || - isConvertingClassicMenu || - fallbackNavigationMenus?.length > 0 || - classicMenus?.length !== 1 - ) { - return false; - } + useEffect( () => { + ( async () => { + if ( + ! hasResolvedNavigationMenus || + isConvertingClassicMenu || + fallbackNavigationMenus?.length > 0 || + classicMenus?.length !== 1 + ) { + return false; + } - // If there's non fallback navigation menus and - // only one classic menu then create a new navigation menu based on it. - await convertClassicMenu( - classicMenus[ 0 ].id, - classicMenus[ 0 ].name, - 'publish' - ); + // If there's non fallback navigation menus and + // only one classic menu then create a new navigation menu based on it. + await convertClassicMenu( + classicMenus[ 0 ].id, + classicMenus[ 0 ].name, + 'publish' + ); + } )(); }, [ hasResolvedNavigationMenus ] ); const navRef = useRef(); From 6249285fc0c1025107b26420356615c4cd99acfa Mon Sep 17 00:00:00 2001 From: Ben Dwyer Date: Thu, 22 Sep 2022 14:13:07 +0100 Subject: [PATCH 25/33] remove await as this doesn't need to be async --- .../src/navigation/edit/index.js | 32 +++++++++---------- 1 file changed, 15 insertions(+), 17 deletions(-) diff --git a/packages/block-library/src/navigation/edit/index.js b/packages/block-library/src/navigation/edit/index.js index a02713f91f33b0..eac560559b5b80 100644 --- a/packages/block-library/src/navigation/edit/index.js +++ b/packages/block-library/src/navigation/edit/index.js @@ -265,24 +265,22 @@ function Navigation( { }, [ navigationMenus ] ); useEffect( () => { - ( async () => { - if ( - ! hasResolvedNavigationMenus || - isConvertingClassicMenu || - fallbackNavigationMenus?.length > 0 || - classicMenus?.length !== 1 - ) { - return false; - } + if ( + ! hasResolvedNavigationMenus || + isConvertingClassicMenu || + fallbackNavigationMenus?.length > 0 || + classicMenus?.length !== 1 + ) { + return false; + } - // If there's non fallback navigation menus and - // only one classic menu then create a new navigation menu based on it. - await convertClassicMenu( - classicMenus[ 0 ].id, - classicMenus[ 0 ].name, - 'publish' - ); - } )(); + // If there's non fallback navigation menus and + // only one classic menu then create a new navigation menu based on it. + convertClassicMenu( + classicMenus[ 0 ].id, + classicMenus[ 0 ].name, + 'publish' + ); }, [ hasResolvedNavigationMenus ] ); const navRef = useRef(); From ff6e9da62e8dcb978d57a7d60c0e9fcafc3d1994 Mon Sep 17 00:00:00 2001 From: Ben Dwyer Date: Wed, 5 Oct 2022 11:26:54 +0100 Subject: [PATCH 26/33] Prevent classic menus from importing twice' --- .../use-convert-classic-menu-to-block-menu.js | 15 +++++++++++++++ 1 file changed, 15 insertions(+) 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 664c5c807e47ba..1db62c3cfcc9dc 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 @@ -17,6 +17,10 @@ export const CLASSIC_MENU_CONVERSION_ERROR = 'error'; export const CLASSIC_MENU_CONVERSION_PENDING = 'pending'; export const CLASSIC_MENU_CONVERSION_IDLE = 'idle'; +// This is needed to ensure that multiple components using this hook +// do not import the same classic menu twice. +let isConvertingClassicMenu = null; + function useConvertClassicToBlockMenu( clientId ) { /* * The wp_navigation post is created as a draft so the changes on the frontend and @@ -117,6 +121,14 @@ function useConvertClassicToBlockMenu( clientId ) { } const convert = useCallback( async ( menuId, menuName, postStatus ) => { + // Check whether this classic menu is being imported already. + if ( isConvertingClassicMenu === menuId ) { + return; + } + + // Set the ID for the currently importing classic menu. + isConvertingClassicMenu = menuId; + if ( ! menuId || ! menuName ) { setError( 'Unable to convert menu. Missing menu details.' ); setStatus( CLASSIC_MENU_CONVERSION_ERROR ); @@ -133,10 +145,13 @@ function useConvertClassicToBlockMenu( clientId ) { ) .then( ( navigationMenu ) => { setStatus( CLASSIC_MENU_CONVERSION_SUCCESS ); + // Reset the ID for the currently importing classic menu. + isConvertingClassicMenu = null; return navigationMenu; } ) .catch( ( err ) => { setError( err?.message ); + // Reset the ID for the currently importing classic menu. setStatus( CLASSIC_MENU_CONVERSION_ERROR ); // Rethrow error for debugging. From 98bb748754ca19335a7de8b2adc326068ff6201a Mon Sep 17 00:00:00 2001 From: Ben Dwyer Date: Wed, 5 Oct 2022 13:14:42 +0100 Subject: [PATCH 27/33] revert unnecessary changes --- lib/experimental/navigation-theme-opt-in.php | 50 ++++++++++---------- 1 file changed, 24 insertions(+), 26 deletions(-) diff --git a/lib/experimental/navigation-theme-opt-in.php b/lib/experimental/navigation-theme-opt-in.php index 30ed17d291a9bf..7efed9794d0ccc 100644 --- a/lib/experimental/navigation-theme-opt-in.php +++ b/lib/experimental/navigation-theme-opt-in.php @@ -191,38 +191,36 @@ function gutenberg_convert_menu_items_to_blocks( $blocks = array(); foreach ( $menu_items as $menu_item ) { - $menu_item_id = (int) $menu_item->ID; - - $has_children = isset( $menu_items_by_parent_id[ $menu_item_id ] ); - - if ( $has_children ) { - $submenu_items = $menu_items_by_parent_id[ $menu_item_id ]; - $block_name = 'core/navigation-submenu'; + if ( 'block' === $menu_item->type ) { + $parsed_blocks = parse_blocks( $menu_item->content ); + + if ( count( $parsed_blocks ) ) { + $block = $parsed_blocks[0]; + } else { + $block = array( + 'blockName' => 'core/freeform', + 'attrs' => array( + 'originalContent' => $menu_item->content, + ), + ); + } } else { - $submenu_items = array(); - $block_name = 'core/navigation-link'; + $block = array( + 'blockName' => 'core/navigation-link', + 'attrs' => array( + 'label' => $menu_item->title, + 'url' => $menu_item->url, + ), + ); } - // Create a child block. - $block = array( - 'blockName' => $block_name, - 'attrs' => array( - 'label' => $menu_item->title, - 'url' => $menu_item->url, - ), - ); - - // Create the content of the block. - $block_content = gutenberg_convert_menu_items_to_blocks( - $submenu_items, + $block['innerBlocks'] = gutenberg_convert_menu_items_to_blocks( + isset( $menu_items_by_parent_id[ $menu_item->ID ] ) + ? $menu_items_by_parent_id[ $menu_item->ID ] + : array(), $menu_items_by_parent_id ); - if ( ! empty( $block_content ) ) { - $block['innerContent'] = $block_content; - $block['innerBlocks'] = $block_content; - } - $blocks[] = $block; } From 20a418b2bf7f64ab0f076b2399adf728eebcba60 Mon Sep 17 00:00:00 2001 From: Ben Dwyer Date: Wed, 5 Oct 2022 13:34:23 +0100 Subject: [PATCH 28/33] lint fix --- packages/block-library/src/navigation/index.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/block-library/src/navigation/index.php b/packages/block-library/src/navigation/index.php index a9925b35c91b7c..d0503d584f73a4 100644 --- a/packages/block-library/src/navigation/index.php +++ b/packages/block-library/src/navigation/index.php @@ -268,7 +268,7 @@ function block_core_navigation_get_classic_menu_fallback() { /** * Converts a classic navigation to blocks. * - * @param object WP_Term The classic navigation object to convert. + * @param object $classic_nav_menu WP_Term The classic navigation object to convert. * @return array the normalized parsed blocks. */ function block_core_navigation_get_classic_menu_fallback_blocks( $classic_nav_menu ) { @@ -328,9 +328,9 @@ function block_core_navigation_maybe_use_classic_menu_fallback() { array( 'post_content' => $classic_nav_menu_blocks_serialized, 'post_title' => $classic_nav_menu->slug, - 'post_name' => $classic_nav_menu->slug, + 'post_name' => $classic_nav_menu->slug, 'post_status' => 'publish', - 'post_type' => 'wp_navigation' + 'post_type' => 'wp_navigation', ), true // So that we can check whether the result is an error. ); From 2a40f96124bcedffe5be6b6c1c3975763bb5c4af Mon Sep 17 00:00:00 2001 From: Dave Smith Date: Wed, 5 Oct 2022 15:53:22 +0100 Subject: [PATCH 29/33] Rename variable for clarity --- .../navigation/edit/use-convert-classic-menu-to-block-menu.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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 1db62c3cfcc9dc..9c4635727499eb 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 @@ -19,7 +19,7 @@ export const CLASSIC_MENU_CONVERSION_IDLE = 'idle'; // This is needed to ensure that multiple components using this hook // do not import the same classic menu twice. -let isConvertingClassicMenu = null; +let classicMenuBeingConvertedId = null; function useConvertClassicToBlockMenu( clientId ) { /* @@ -122,7 +122,7 @@ function useConvertClassicToBlockMenu( clientId ) { const convert = useCallback( async ( menuId, menuName, postStatus ) => { // Check whether this classic menu is being imported already. - if ( isConvertingClassicMenu === menuId ) { + if ( classicMenuBeingConvertedId === menuId ) { return; } From 1989a628ffb22b859fa5913825363a43cfd465c0 Mon Sep 17 00:00:00 2001 From: Dave Smith Date: Wed, 5 Oct 2022 15:59:37 +0100 Subject: [PATCH 30/33] Fix var rename --- .../navigation/edit/use-convert-classic-menu-to-block-menu.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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 9c4635727499eb..ee4a3b2f954e62 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 @@ -127,7 +127,7 @@ function useConvertClassicToBlockMenu( clientId ) { } // Set the ID for the currently importing classic menu. - isConvertingClassicMenu = menuId; + classicMenuBeingConvertedId = menuId; if ( ! menuId || ! menuName ) { setError( 'Unable to convert menu. Missing menu details.' ); @@ -146,7 +146,7 @@ function useConvertClassicToBlockMenu( clientId ) { .then( ( navigationMenu ) => { setStatus( CLASSIC_MENU_CONVERSION_SUCCESS ); // Reset the ID for the currently importing classic menu. - isConvertingClassicMenu = null; + classicMenuBeingConvertedId = null; return navigationMenu; } ) .catch( ( err ) => { From f38b19a89cc8c4023db965f508457d340342c9de Mon Sep 17 00:00:00 2001 From: Dave Smith Date: Wed, 5 Oct 2022 16:06:35 +0100 Subject: [PATCH 31/33] Reset the menu id on error --- .../edit/use-convert-classic-menu-to-block-menu.js | 5 +++++ 1 file changed, 5 insertions(+) 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 ee4a3b2f954e62..68c12f4796c9e9 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 @@ -66,6 +66,8 @@ function useConvertClassicToBlockMenu( clientId ) { ); } + classicMenuItems = null; + // Handle offline response which resolves to `null`. if ( classicMenuItems === null ) { throw new Error( @@ -154,6 +156,9 @@ function useConvertClassicToBlockMenu( clientId ) { // Reset the ID for the currently importing classic menu. setStatus( CLASSIC_MENU_CONVERSION_ERROR ); + // Reset the ID for the currently importing classic menu. + classicMenuBeingConvertedId = null; + // Rethrow error for debugging. throw new Error( sprintf( From a98cfc96e0db7998d2c55676d80788b52d600197 Mon Sep 17 00:00:00 2001 From: Dave Smith Date: Wed, 5 Oct 2022 16:07:04 +0100 Subject: [PATCH 32/33] Revert testing code --- .../navigation/edit/use-convert-classic-menu-to-block-menu.js | 2 -- 1 file changed, 2 deletions(-) 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 68c12f4796c9e9..01eea8d0261aa7 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 @@ -66,8 +66,6 @@ function useConvertClassicToBlockMenu( clientId ) { ); } - classicMenuItems = null; - // Handle offline response which resolves to `null`. if ( classicMenuItems === null ) { throw new Error( From 27107c741febc35e3c2d4a22e897a986dadc79c2 Mon Sep 17 00:00:00 2001 From: Ben Dwyer Date: Thu, 6 Oct 2022 11:22:52 +0100 Subject: [PATCH 33/33] serialize blocks in the function that gets the classic menu --- packages/block-library/src/navigation/index.php | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/packages/block-library/src/navigation/index.php b/packages/block-library/src/navigation/index.php index d0503d584f73a4..dadde9891d1d61 100644 --- a/packages/block-library/src/navigation/index.php +++ b/packages/block-library/src/navigation/index.php @@ -299,7 +299,7 @@ function block_core_navigation_get_classic_menu_fallback_blocks( $classic_nav_me $menu_items_by_parent_id ); - return $inner_blocks; + return serialize_blocks( $inner_blocks ); } /** @@ -316,17 +316,16 @@ function block_core_navigation_maybe_use_classic_menu_fallback() { } // If we have a classic menu then convert it to blocks. - $classic_nav_menu_blocks = block_core_navigation_get_classic_menu_fallback_blocks( $classic_nav_menu ); - $classic_nav_menu_blocks_serialized = serialize_blocks( $classic_nav_menu_blocks ); + $classic_nav_menu_blocks = block_core_navigation_get_classic_menu_fallback_blocks( $classic_nav_menu ); - if ( empty( $classic_nav_menu_blocks_serialized ) ) { + if ( empty( $classic_nav_menu_blocks ) ) { return; } // Create a new navigation menu from the classic menu. $wp_insert_post_result = wp_insert_post( array( - 'post_content' => $classic_nav_menu_blocks_serialized, + 'post_content' => $classic_nav_menu_blocks, 'post_title' => $classic_nav_menu->slug, 'post_name' => $classic_nav_menu->slug, 'post_status' => 'publish',