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

Fetch Nav fallbacks and side load resulting entity into state #50126

Closed
wants to merge 12 commits into from
39 changes: 39 additions & 0 deletions lib/experimental/navigation-fallback.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
<?php
/**
* Navigation Fallback
*
* Functions required for managing Navigation fallbacks behavior.
*
* @package Gutenberg
* @since 6.3.0
*/

/**
* Expose additional fields in the embeddable links of the
* Navigation Fallback REST endpoint.
*
* The endpoint may embed the full Navigation Menu object into the
* response as the `self` link. By default the Posts Controller
* will only exposes a limited subset of fields but the editor requires
* additional fields to be available in order to utilise the menu.
*
* @param array $schema the schema for the `wp_navigation` post.
* @return array the modified schema.
*/
function gutenberg_add_fields_to_navigation_fallback_embeded_links( $schema ) {
// Expose top level fields.
$schema['properties']['status']['context'] = array_merge( $schema['properties']['status']['context'], array( 'embed' ) );
$schema['properties']['content']['context'] = array_merge( $schema['properties']['content']['context'], array( 'embed' ) );

// Expose sub properties of content field.
$schema['properties']['content']['properties']['raw']['context'] = array_merge( $schema['properties']['content']['properties']['raw']['context'], array( 'embed' ) );
$schema['properties']['content']['properties']['rendered']['context'] = array_merge( $schema['properties']['content']['properties']['rendered']['context'], array( 'embed' ) );
$schema['properties']['content']['properties']['block_version']['context'] = array_merge( $schema['properties']['content']['properties']['block_version']['context'], array( 'embed' ) );

return $schema;
}

add_filter(
'rest_wp_navigation_item_schema',
'gutenberg_add_fields_to_navigation_fallback_embeded_links'
);
2 changes: 2 additions & 0 deletions lib/load.php
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@ function gutenberg_is_experiment_enabled( $name ) {
require __DIR__ . '/experimental/navigation-theme-opt-in.php';
require __DIR__ . '/experimental/kses.php';
require __DIR__ . '/experimental/l10n.php';
require __DIR__ . '/experimental/navigation-fallback.php';

// Fonts API.
if ( ! class_exists( 'WP_Fonts' ) ) {
Expand Down Expand Up @@ -168,3 +169,4 @@ function gutenberg_is_experiment_enabled( $name ) {
require __DIR__ . '/block-supports/duotone.php';
require __DIR__ . '/block-supports/anchor.php';
require __DIR__ . '/block-supports/shadow.php';

28 changes: 20 additions & 8 deletions packages/block-library/src/navigation/edit/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,6 @@ import {
import { __, sprintf } from '@wordpress/i18n';
import { speak } from '@wordpress/a11y';
import { close, Icon } from '@wordpress/icons';
import apiFetch from '@wordpress/api-fetch';

/**
* Internal dependencies
Expand All @@ -68,6 +67,7 @@ import { detectColors } from './utils';
import ManageMenusButton from './manage-menus-button';
import MenuInspectorControls from './menu-inspector-controls';
import DeletedNavigationWarning from './deleted-navigation-warning';
import useFallback from './use-fallback';

function Navigation( {
attributes,
Expand Down Expand Up @@ -220,6 +220,12 @@ function Navigation( {
// that automatically saves the menu as an entity when changes are made to the inner blocks.
const hasUnsavedBlocks = hasUncontrolledInnerBlocks && ! isEntityAvailable;

const getNavigationFallbackId = useFallback();

// const navigationFallbackId = ! ( ref || hasUnsavedBlocks )
// ? getNavigationFallbackId()
// : null;

useEffect( () => {
// If:
// - there is an existing menu, OR
Expand All @@ -228,10 +234,9 @@ function Navigation( {
if ( ref || hasUnsavedBlocks ) {
return;
}

apiFetch( { path: '/wp-block-editor/v1/navigation-fallback' } )
.then( ( fallbackNavigationMenu ) => {
if ( ! fallbackNavigationMenu?.id ) {
getNavigationFallbackId()
.then( ( fallbackNavigationMenuId ) => {
if ( ! fallbackNavigationMenuId ) {
showNavigationMenuStatusNotice(
__( 'Unable to fetch a fallback Navigation Menu.' )
);
Expand All @@ -244,19 +249,26 @@ function Navigation( {
* nor to be undoable, hence why it is marked as non persistent
*/
__unstableMarkNextChangeAsNotPersistent();
setRef( fallbackNavigationMenu.id );
setRef( fallbackNavigationMenuId );
} )
.catch( () => {
showNavigationMenuStatusNotice(
__( 'Unable to fetch a fallback Navigation Menu.' )
);
} );

/**
* This fallback displays (both in editor and on front)
* The fallback should not request a save (entity dirty state)
* nor to be undoable, hence why it is marked as non persistent
*/
}, [
ref,
hasUnsavedBlocks,
setRef,
showNavigationMenuStatusNotice,
hasUnsavedBlocks,
getNavigationFallbackId,
__unstableMarkNextChangeAsNotPersistent,
showNavigationMenuStatusNotice,
] );

const navRef = useRef();
Expand Down
37 changes: 37 additions & 0 deletions packages/block-library/src/navigation/edit/use-fallback.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/**
* WordPress dependencies
*/
import apiFetch from '@wordpress/api-fetch';
import { useDispatch } from '@wordpress/data';
import { store as coreStore } from '@wordpress/core-data';
import { addQueryArgs } from '@wordpress/url';
import { useRef } from '@wordpress/element';

export default function useFallback() {
const isFetching = useRef( false );
const { receiveEntityRecords } = useDispatch( coreStore );

return async function () {
if ( isFetching?.current ) {
return;
}

isFetching.current = true;

const fallback = await apiFetch( {
path: addQueryArgs( '/wp-block-editor/v1/navigation-fallback', {
_embed: true,
} ),
} );

const record = fallback?._embedded?.self;

if ( record ) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added a debugger here after the receiveEntityRecords call and then switched to console and ran:

wp.data.select('core').getEntityRecord('postType', 'wp_navigation', %%THE_ID%%)

...and the record is in state.

So why - with this non-Core data approach - do we get a 2nd network request coming from:

const navigationMenu = getEntityRecord( ...args );

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider calling

dispatch.finishResolution( 'getEntityRecord', [
				'postType',
				'wp_navigation',
				fallback?.id,
			] );

receiveEntityRecords( 'postType', 'wp_navigation', record );
}

isFetching.current = false;

return fallback?.id;
};
}