Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Create classic navigation menus as draft and dirty the site editor #43580

Merged
merged 16 commits into from
Sep 5, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 37 additions & 2 deletions packages/block-library/src/navigation/edit/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import {
Warning,
__experimentalUseBlockOverlayActive as useBlockOverlayActive,
} from '@wordpress/block-editor';
import { EntityProvider } from '@wordpress/core-data';
import { EntityProvider, store as coreStore } from '@wordpress/core-data';

import { useDispatch } from '@wordpress/data';
import {
Expand Down Expand Up @@ -103,6 +103,7 @@ function Navigation( {

const recursionId = `navigationMenu/${ ref }`;
const hasAlreadyRendered = useHasRecursion( recursionId );
const { editEntityRecord } = useDispatch( coreStore );

// Preload classic menus, so that they don't suddenly pop-in when viewing
// the Select Menu dropdown.
Expand All @@ -118,6 +119,11 @@ function Navigation( {
name: 'block-library/core/navigation/classic-menu-conversion',
} );

const [ showMenuAutoPublishDraftNotice, hideMenuAutoPublishDraftNotice ] =
useNavigationNotice( {
name: 'block-library/core/navigation/auto-publish-draft',
} );

const [
showNavigationMenuPermissionsNotice,
hideNavigationMenuPermissionsNotice,
Expand Down Expand Up @@ -197,6 +203,7 @@ function Navigation( {
isNavigationMenuResolved,
isNavigationMenuMissing,
navigationMenus,
navigationMenu,
canUserUpdateNavigationMenu,
hasResolvedCanUserUpdateNavigationMenu,
canUserDeleteNavigationMenu,
Expand Down Expand Up @@ -232,6 +239,12 @@ function Navigation( {
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
Expand All @@ -240,7 +253,7 @@ function Navigation( {
* nor to be undoable, hence why it is marked as non persistent
*/
__unstableMarkNextChangeAsNotPersistent();
setRef( navigationMenus[ 0 ].id );
setRef( fallbackNavigationMenus[ 0 ].id );
}, [ navigationMenus ] );

const navRef = useRef();
Expand Down Expand Up @@ -444,6 +457,28 @@ function Navigation( {
{ open: overlayMenuPreview }
);

// Prompt the user to publish the menu they have set as a draft
const isDraftNavigationMenu = navigationMenu?.status === 'draft';
useEffect( async () => {
hideMenuAutoPublishDraftNotice();
if ( ! isDraftNavigationMenu ) return;
try {
await editEntityRecord(
'postType',
'wp_navigation',
navigationMenu?.id,
{
status: 'publish',
draganescu marked this conversation as resolved.
Show resolved Hide resolved
},
{ throwOnError: true }
);
} catch {
showMenuAutoPublishDraftNotice(
__( 'Error ocurred while publishing the navigation menu.' )
);
}
}, [ isDraftNavigationMenu, navigationMenu ] );

const stylingInspectorControls = (
<InspectorControls>
{ hasSubmenuIndicatorSetting && (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,7 @@ function NavigationMenuSelector( {
</MenuGroup>
) }
{ showClassicMenus && hasClassicMenus && (
<MenuGroup label={ __( 'Classic Menus' ) }>
<MenuGroup label={ __( 'Import Classic Menus' ) }>
{ classicMenus?.map( ( menu ) => {
const label = decodeEntities( menu.name );
return (
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/**
* WordPress dependencies
*/
import { useRegistry } from '@wordpress/data';
import { useRegistry, useDispatch } from '@wordpress/data';
import { store as coreStore } from '@wordpress/core-data';
import { useState, useCallback } from '@wordpress/element';
import { __, sprintf } from '@wordpress/i18n';
Expand All @@ -18,9 +18,16 @@ export const CLASSIC_MENU_CONVERSION_PENDING = 'pending';
export const CLASSIC_MENU_CONVERSION_IDLE = 'idle';

function useConvertClassicToBlockMenu( clientId ) {
const { create: createNavigationMenu } =
useCreateNavigationMenu( clientId );
/*
* The wp_navigation post is created as a draft so the changes on the frontend and
* the site editor are not permanent without a save interaction done by the user.
*/
const { create: createNavigationMenu } = useCreateNavigationMenu(
clientId,
'draft'
);
const registry = useRegistry();
const { editEntityRecord } = useDispatch( coreStore );

const [ status, setStatus ] = useState( CLASSIC_MENU_CONVERSION_IDLE );
const [ error, setError ] = useState( null );
Expand Down Expand Up @@ -71,6 +78,23 @@ function useConvertClassicToBlockMenu( clientId ) {
menuName,
innerBlocks
);

/**
* Immediately trigger editEntityRecord to change the wp_navigation post status to 'publish'.
* This status change causes the menu to be displayed on the front of the site and sets the post state to be "dirty".
* The problem being solved is if saveEditedEntityRecord was used here, the menu would be updated on the frontend and the editor _automatically_,
* without user interaction.
* If the user abandons the site editor without saving, there would still be a wp_navigation post created as draft.
*/
await editEntityRecord(
'postType',
'wp_navigation',
navigationMenu.id,
{
status: 'publish',
},
{ throwOnError: true }
);
} catch ( err ) {
throw new Error(
sprintf(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,10 @@ 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 ) {
export default function useCreateNavigationMenu(
clientId,
postStatus = 'publish'
) {
const [ status, setStatus ] = useState( CREATE_NAVIGATION_MENU_IDLE );
const [ value, setValue ] = useState( null );
const [ error, setError ] = useState( null );
Expand Down Expand Up @@ -60,7 +63,7 @@ export default function useCreateNavigationMenu( clientId ) {
const record = {
title,
content: serialize( blocks ),
status: 'publish',
status: postStatus,
draganescu marked this conversation as resolved.
Show resolved Hide resolved
};

// Return affords ability to await on this function directly
Expand Down
32 changes: 15 additions & 17 deletions packages/block-library/src/navigation/index.php
Original file line number Diff line number Diff line change
Expand Up @@ -469,27 +469,25 @@ function render_block_core_navigation( $attributes, $content, $block ) {

// Only published posts are valid. If this is changed then a corresponding change
// must also be implemented in `use-navigation-menu.js`.
if ( 'publish' !== $navigation_post->post_status ) {
return '';
}
if ( 'publish' === $navigation_post->post_status ) {
$nav_menu_name = $navigation_post->post_title;

$nav_menu_name = $navigation_post->post_title;

if ( isset( $seen_menu_names[ $nav_menu_name ] ) ) {
++$seen_menu_names[ $nav_menu_name ];
} else {
$seen_menu_names[ $nav_menu_name ] = 1;
}
if ( isset( $seen_menu_names[ $nav_menu_name ] ) ) {
++$seen_menu_names[ $nav_menu_name ];
} else {
$seen_menu_names[ $nav_menu_name ] = 1;
}

$parsed_blocks = parse_blocks( $navigation_post->post_content );
$parsed_blocks = parse_blocks( $navigation_post->post_content );

// 'parse_blocks' includes a null block with '\n\n' as the content when
// it encounters whitespace. This code strips it.
$compacted_blocks = block_core_navigation_filter_out_empty_blocks( $parsed_blocks );
// 'parse_blocks' includes a null block with '\n\n' as the content when
// it encounters whitespace. This code strips it.
$compacted_blocks = block_core_navigation_filter_out_empty_blocks( $parsed_blocks );
cbravobernal marked this conversation as resolved.
Show resolved Hide resolved

// TODO - this uses the full navigation block attributes for the
// context which could be refined.
$inner_blocks = new WP_Block_List( $compacted_blocks, $attributes );
// TODO - this uses the full navigation block attributes for the
// context which could be refined.
$inner_blocks = new WP_Block_List( $compacted_blocks, $attributes );
}
}

// If there are no inner blocks then fallback to rendering an appropriate fallback.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,16 +36,16 @@ function resolveRecords( registry, menus ) {
dispatch.startResolution( 'getEntityRecords', [
'postType',
'wp_navigation',
{ per_page: -1, status: 'publish' },
{ per_page: -1, status: [ 'publish', 'draft' ] },
] );
dispatch.finishResolution( 'getEntityRecords', [
'postType',
'wp_navigation',
{ per_page: -1, status: 'publish' },
{ per_page: -1, status: [ 'publish', 'draft' ] },
] );
dispatch.receiveEntityRecords( 'postType', 'wp_navigation', menus, {
per_page: -1,
status: 'publish',
status: [ 'publish', 'draft' ],
} );
}

Expand Down Expand Up @@ -161,12 +161,12 @@ describe( 'useNavigationMenus', () => {
} );
} );

it( 'Should return null for the menu when menu status is "draft"', () => {
it( 'Should return the menu when menu status is "draft"', () => {
const navigationMenuDraft = { id: 4, title: 'Menu 3', status: 'draft' };
const testMenus = [ ...navigationMenus, navigationMenuDraft ];
resolveRecords( registry, testMenus );
expect( useNavigationMenu( 4 ) ).toEqual( {
navigationMenu: null,
navigationMenu: navigationMenuDraft,
navigationMenus: testMenus,
canSwitchNavigationMenu: true,
canUserCreateNavigationMenu: false,
Expand Down
17 changes: 11 additions & 6 deletions packages/block-library/src/navigation/use-navigation-menu.js
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ function selectNavigationMenus( select ) {
const args = [
'postType',
'wp_navigation',
{ per_page: -1, status: 'publish' },
{ per_page: -1, status: [ 'publish', 'draft' ] },
];
return {
navigationMenus: getEntityRecords( ...args ),
Expand Down Expand Up @@ -103,18 +103,23 @@ function selectExistingMenu( select, ref ) {
);

// Only published Navigation posts are considered valid.
// If this is changed then a corresponding change must also be made
// in the index.php file.
const isNavigationMenuPublished = editedNavigationMenu.status === 'publish';
// Draft Navigation posts are valid only on the editor,
// requiring a post update to publish to show in frontend.
// To achieve that, index.php must reflect this validation only for published.
const isNavigationMenuPublishedOrDraft =
editedNavigationMenu.status === 'publish' ||
editedNavigationMenu.status === 'draft';

return {
isNavigationMenuResolved: hasResolvedNavigationMenu,
isNavigationMenuMissing:
hasResolvedNavigationMenu &&
( ! navigationMenu || ! isNavigationMenuPublished ),
( ! navigationMenu || ! isNavigationMenuPublishedOrDraft ),

// getEditedEntityRecord will return the post regardless of status.
// Therefore if the found post is not published then we should ignore it.
navigationMenu: isNavigationMenuPublished ? editedNavigationMenu : null,
navigationMenu: isNavigationMenuPublishedOrDraft
? editedNavigationMenu
: null,
};
}