diff --git a/packages/block-library/src/page-list/constants.js b/packages/block-library/src/page-list/constants.js
deleted file mode 100644
index 9322fa345321c4..00000000000000
--- a/packages/block-library/src/page-list/constants.js
+++ /dev/null
@@ -1,8 +0,0 @@
-/**
- * WordPress dependencies
- */
-import { __ } from '@wordpress/i18n';
-
-export const convertDescription = __(
- 'This menu is automatically kept in sync with pages on your site. You can manage the menu yourself by clicking customize below.'
-);
diff --git a/packages/block-library/src/page-list/convert-to-links-modal.js b/packages/block-library/src/page-list/convert-to-links-modal.js
deleted file mode 100644
index dbc76fc77cdb1e..00000000000000
--- a/packages/block-library/src/page-list/convert-to-links-modal.js
+++ /dev/null
@@ -1,70 +0,0 @@
-/**
- * WordPress dependencies
- */
-import { Button, Modal } from '@wordpress/components';
-import { __ } from '@wordpress/i18n';
-import { useDispatch } from '@wordpress/data';
-import { useEntityRecords } from '@wordpress/core-data';
-import { store as blockEditorStore } from '@wordpress/block-editor';
-/**
- * Internal dependencies
- */
-import { convertToNavigationLinks } from './convert-to-navigation-links';
-
-/**
- * Internal dependencies
- */
-import { convertDescription } from './constants';
-
-const PAGE_FIELDS = [ 'id', 'title', 'link', 'type', 'parent' ];
-const MAX_PAGE_COUNT = 100;
-
-export default function ConvertToLinksModal( { onClose, clientId } ) {
- const { records: pages, hasResolved: pagesFinished } = useEntityRecords(
- 'postType',
- 'page',
- {
- per_page: MAX_PAGE_COUNT,
- _fields: PAGE_FIELDS,
- // TODO: When https://core.trac.wordpress.org/ticket/39037 REST API support for multiple orderby
- // values is resolved, update 'orderby' to [ 'menu_order', 'post_title' ] to provide a consistent
- // sort.
- orderby: 'menu_order',
- order: 'asc',
- }
- );
-
- const { replaceBlock } = useDispatch( blockEditorStore );
-
- return (
-
-
- { convertDescription }
-
-
-
-
-
-
- );
-}
diff --git a/packages/block-library/src/page-list/edit.js b/packages/block-library/src/page-list/edit.js
index 219822ed87944f..8a18b79ce58507 100644
--- a/packages/block-library/src/page-list/edit.js
+++ b/packages/block-library/src/page-list/edit.js
@@ -23,24 +23,128 @@ import {
Notice,
ComboboxControl,
Button,
+ Modal,
} from '@wordpress/components';
import { __, sprintf } from '@wordpress/i18n';
import { useMemo, useState, useEffect } from '@wordpress/element';
import { useEntityRecords } from '@wordpress/core-data';
-import { useSelect, useDispatch } from '@wordpress/data';
+import { useSelect } from '@wordpress/data';
/**
* Internal dependencies
*/
-import ConvertToLinksModal from './convert-to-links-modal';
-import { convertToNavigationLinks } from './convert-to-navigation-links';
-import { convertDescription } from './constants';
+import { useConvertToNavigationLinks } from './use-convert-to-navigation-links';
// We only show the edit option when page count is <= MAX_PAGE_COUNT
// Performance of Navigation Links is not good past this value.
const MAX_PAGE_COUNT = 100;
const NOOP = () => {};
+const convertDescription = __(
+ 'This menu is automatically kept in sync with pages on your site. You can manage the menu yourself by clicking customize below.'
+);
+
+function BlockContent( {
+ blockProps,
+ innerBlocksProps,
+ hasResolvedPages,
+ blockList,
+ pages,
+ parentPageID,
+} ) {
+ if ( ! hasResolvedPages ) {
+ return (
+
+
+
+ );
+ }
+
+ if ( pages === null ) {
+ return (
+
+
+ { __( 'Page List: Cannot retrieve Pages.' ) }
+
+
+ );
+ }
+
+ if ( pages.length === 0 ) {
+ return (
+
+
+ { __( 'Page List: Cannot retrieve Pages.' ) }
+
+
+ );
+ }
+
+ if ( blockList.length === 0 ) {
+ const parentPageDetails = pages.find(
+ ( page ) => page.id === parentPageID
+ );
+ return (
+
+
+ { sprintf(
+ // translators: %s: Page title.
+ __( '"%s" page has no children.' ),
+ parentPageDetails.title.rendered
+ ) }
+
+
+ );
+ }
+
+ if ( pages.length > 0 ) {
+ return ;
+ }
+}
+
+function ConvertToLinksModal( { onClick, disabled } ) {
+ const [ isOpen, setOpen ] = useState( false );
+ const openModal = () => setOpen( true );
+ const closeModal = () => setOpen( false );
+
+ return (
+ <>
+
+
+ { __( 'Edit' ) }
+
+
+ { isOpen && (
+
+
+ { convertDescription }
+
+
+
+
+
+
+ ) }
+ >
+ );
+}
+
export default function PageListEdit( {
context,
clientId,
@@ -48,16 +152,56 @@ export default function PageListEdit( {
setAttributes,
} ) {
const { parentPageID } = attributes;
- const [ pages ] = useGetPages();
- const { pagesByParentId, totalPages, hasResolvedPages } = usePageData();
- const isNavigationChild = 'showSubmenuIcon' in context;
+ const { records: pages, hasResolved: hasResolvedPages } = useEntityRecords(
+ 'postType',
+ 'page',
+ {
+ per_page: MAX_PAGE_COUNT,
+ _fields: [ 'id', 'link', 'menu_order', 'parent', 'title', 'type' ],
+ // TODO: When https://core.trac.wordpress.org/ticket/39037 REST API support for multiple orderby
+ // values is resolved, update 'orderby' to [ 'menu_order', 'post_title' ] to provide a consistent
+ // sort.
+ orderby: 'menu_order',
+ order: 'asc',
+ }
+ );
+
const allowConvertToLinks =
- isNavigationChild && totalPages <= MAX_PAGE_COUNT;
+ 'showSubmenuIcon' in context &&
+ pages?.length > 0 &&
+ pages?.length <= MAX_PAGE_COUNT;
- const [ isOpen, setOpen ] = useState( false );
- const openModal = () => setOpen( true );
- const closeModal = () => setOpen( false );
+ const convertToNavigationLinks = useConvertToNavigationLinks( {
+ clientId,
+ pages,
+ } );
+
+ const pagesByParentId = useMemo( () => {
+ if ( pages === null ) {
+ return new Map();
+ }
+
+ // TODO: Once the REST API supports passing multiple values to
+ // 'orderby', this can be removed.
+ // https://core.trac.wordpress.org/ticket/39037
+ const sortedPages = pages.sort( ( a, b ) => {
+ if ( a.menu_order === b.menu_order ) {
+ return a.title.rendered.localeCompare( b.title.rendered );
+ }
+ return a.menu_order - b.menu_order;
+ } );
+
+ return sortedPages.reduce( ( accumulator, page ) => {
+ const { parent } = page;
+ if ( accumulator.has( parent ) ) {
+ accumulator.get( parent ).push( page );
+ } else {
+ accumulator.set( parent, [ page ] );
+ }
+ return accumulator;
+ }, new Map() );
+ }, [ pages ] );
const blockProps = useBlockProps( {
className: classnames( 'wp-block-page-list', {
@@ -137,77 +281,16 @@ export default function PageListEdit( {
value: blockList,
} );
- const getBlockContent = () => {
- if ( ! hasResolvedPages ) {
- return (
-
-
-
- );
- }
-
- if ( totalPages === null ) {
- return (
-
-
- { __( 'Page List: Cannot retrieve Pages.' ) }
-
-
- );
- }
-
- if ( totalPages === 0 ) {
- return (
-
-
- { __( 'Page List: Cannot retrieve Pages.' ) }
-
-
- );
- }
-
- if ( blockList.length === 0 ) {
- const parentPageDetails =
- pages && pages.find( ( page ) => page.id === parentPageID );
- return (
-
-
- { sprintf(
- // translators: %s: Page title.
- __( '"%s" page has no children.' ),
- parentPageDetails.title.rendered
- ) }
-
-
- );
- }
-
- if ( totalPages > 0 ) {
- return ;
- }
- };
-
- const { replaceBlock, selectBlock } = useDispatch( blockEditorStore );
-
- const { parentNavBlockClientId, isNested } = useSelect(
+ const { isNested } = useSelect(
( select ) => {
- const { getSelectedBlockClientId, getBlockParentsByBlockName } =
- select( blockEditorStore );
-
- const _selectedBlockClientId = getSelectedBlockClientId();
-
+ const { getBlockParentsByBlockName } = select( blockEditorStore );
+ const blockParents = getBlockParentsByBlockName(
+ clientId,
+ 'core/navigation-submenu',
+ true
+ );
return {
- parentNavBlockClientId: getBlockParentsByBlockName(
- _selectedBlockClientId,
- 'core/navigation',
- true
- )[ 0 ],
- isNested:
- getBlockParentsByBlockName(
- clientId,
- 'core/navigation-submenu',
- true
- ).length > 0,
+ isNested: blockParents.length > 0,
};
},
[ clientId ]
@@ -220,22 +303,13 @@ export default function PageListEdit( {
return (
<>
- { isNavigationChild && pages?.length > 0 && (
+ { allowConvertToLinks && (
{ convertDescription }
@@ -258,69 +332,20 @@ export default function PageListEdit( {
) }
- { allowConvertToLinks && totalPages > 0 && (
-
-
- { __( 'Edit' ) }
-
-
- ) }
- { allowConvertToLinks && isOpen && (
+ { allowConvertToLinks && (
) }
-
- { getBlockContent() }
+
>
);
}
-
-function useGetPages() {
- const { records: pages, hasResolved: hasResolvedPages } = useEntityRecords(
- 'postType',
- 'page',
- {
- orderby: 'menu_order',
- order: 'asc',
- _fields: [ 'id', 'link', 'parent', 'title', 'menu_order' ],
- per_page: -1,
- context: 'view',
- }
- );
-
- return [ pages, hasResolvedPages ];
-}
-
-function usePageData( pageId = 0 ) {
- const [ pages, hasResolvedPages ] = useGetPages();
-
- return useMemo( () => {
- // TODO: Once the REST API supports passing multiple values to
- // 'orderby', this can be removed.
- // https://core.trac.wordpress.org/ticket/39037
-
- const sortedPages = [ ...( pages ?? [] ) ].sort( ( a, b ) => {
- if ( a.menu_order === b.menu_order ) {
- return a.title.rendered.localeCompare( b.title.rendered );
- }
- return a.menu_order - b.menu_order;
- } );
- const pagesByParentId = sortedPages.reduce( ( accumulator, page ) => {
- const { parent } = page;
- if ( accumulator.has( parent ) ) {
- accumulator.get( parent ).push( page );
- } else {
- accumulator.set( parent, [ page ] );
- }
- return accumulator;
- }, new Map() );
-
- return {
- pagesByParentId,
- hasResolvedPages,
- totalPages: pages?.length ?? null,
- };
- }, [ pageId, pages, hasResolvedPages ] );
-}
diff --git a/packages/block-library/src/page-list/test/convert-to-links-modal.js b/packages/block-library/src/page-list/test/convert-to-links-modal.js
index 4c83b64f9bb9f9..d7907cbf2e4d4a 100644
--- a/packages/block-library/src/page-list/test/convert-to-links-modal.js
+++ b/packages/block-library/src/page-list/test/convert-to-links-modal.js
@@ -2,7 +2,7 @@
* Internal dependencies
*/
-import { convertToNavigationLinks } from '../convert-to-navigation-links';
+import { convertToNavigationLinks } from '../use-convert-to-navigation-links';
// Mock createBlock to avoid creating the blocks in test environment
// as convertToNavigationLinks calls this method internally.
diff --git a/packages/block-library/src/page-list/convert-to-navigation-links.js b/packages/block-library/src/page-list/use-convert-to-navigation-links.js
similarity index 59%
rename from packages/block-library/src/page-list/convert-to-navigation-links.js
rename to packages/block-library/src/page-list/use-convert-to-navigation-links.js
index 64b1dbf1c7d4d6..929fb706e01bab 100644
--- a/packages/block-library/src/page-list/convert-to-navigation-links.js
+++ b/packages/block-library/src/page-list/use-convert-to-navigation-links.js
@@ -2,12 +2,10 @@
* WordPress dependencies
*/
import { createBlock } from '@wordpress/blocks';
+import { useSelect, useDispatch } from '@wordpress/data';
+import { store as blockEditorStore } from '@wordpress/block-editor';
-export const convertToNavigationLinks = ( pages ) => {
- if ( ! pages ) {
- return;
- }
-
+export function convertToNavigationLinks( pages = [] ) {
const linkMap = {};
const navigationLinks = [];
pages.forEach( ( { id, title, link: url, type, parent } ) => {
@@ -57,4 +55,36 @@ export const convertToNavigationLinks = ( pages ) => {
transformSubmenus( navigationLinks );
return navigationLinks;
-};
+}
+
+export function useConvertToNavigationLinks( { clientId, pages } ) {
+ const { replaceBlock, selectBlock } = useDispatch( blockEditorStore );
+
+ const { parentNavBlockClientId } = useSelect(
+ ( select ) => {
+ const { getSelectedBlockClientId, getBlockParentsByBlockName } =
+ select( blockEditorStore );
+
+ const _selectedBlockClientId = getSelectedBlockClientId();
+
+ return {
+ parentNavBlockClientId: getBlockParentsByBlockName(
+ _selectedBlockClientId,
+ 'core/navigation',
+ true
+ )[ 0 ],
+ };
+ },
+ [ clientId ]
+ );
+
+ return () => {
+ const navigationLinks = convertToNavigationLinks( pages );
+
+ // Replace the Page List block with the Navigation Links.
+ replaceBlock( clientId, navigationLinks );
+
+ // Select the Navigation block to reveal the changes.
+ selectBlock( parentNavBlockClientId );
+ };
+}