From 775355af6bf07fd8f7f708b0bd10c459d6b55e97 Mon Sep 17 00:00:00 2001 From: George Hotelling Date: Mon, 10 May 2021 13:43:08 -0400 Subject: [PATCH 01/16] Create a JS version of Page List for the editor --- packages/block-library/src/page-list/edit.js | 84 +++++++++++++++----- 1 file changed, 62 insertions(+), 22 deletions(-) diff --git a/packages/block-library/src/page-list/edit.js b/packages/block-library/src/page-list/edit.js index 5328689edcbbe2..1e1711b2a7c67e 100644 --- a/packages/block-library/src/page-list/edit.js +++ b/packages/block-library/src/page-list/edit.js @@ -12,7 +12,6 @@ import { store as blockEditorStore, getColorClassName, } from '@wordpress/block-editor'; -import ServerSideRender from '@wordpress/server-side-render'; import { ToolbarButton } from '@wordpress/components'; import { __ } from '@wordpress/i18n'; import { useEffect, useState } from '@wordpress/element'; @@ -24,11 +23,46 @@ import { addQueryArgs } from '@wordpress/url'; * Internal dependencies */ import ConvertToLinksModal from './convert-to-links-modal'; +import { ItemSubmenuIcon } from '../navigation-link/icons'; // 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 Menu = ( { pagesByParentId, parentId, depth = 0 } ) => { + return pagesByParentId.get( parentId )?.map( ( page ) => { + const hasChildren = pagesByParentId.has( page.id ); + const classes = classnames( 'wp-block-pages-list__item', { + 'has-child': hasChildren, + } ); + + return ( +
  • + + { page.title?.rendered } + + { hasChildren && ( + <> + + + + + + ) } +
  • + ); + } ); +}; + export default function PageListEdit( { context, clientId, @@ -72,6 +106,9 @@ export default function PageListEdit( { const { textColor, backgroundColor, style } = context || {}; const [ allowConvertToLinks, setAllowConvertToLinks ] = useState( false ); + const [ pagesByParentId, setPagesByParentId ] = useState( + new Map( [ [ 0, [] ] ] ) + ); const blockProps = useBlockProps( { className: classnames( { @@ -106,21 +143,28 @@ export default function PageListEdit( { }, [ context.openSubmenusOnClick, context.showSubmenuIcon ] ); useEffect( () => { - if ( isParentNavigation ) { - apiFetch( { - path: addQueryArgs( '/wp/v2/pages', { - per_page: 1, - _fields: [ 'id' ], - } ), - parse: false, - } ).then( ( res ) => { - setAllowConvertToLinks( + apiFetch( { + path: addQueryArgs( '/wp/v2/pages', { + orderby: 'menu_order', + order: 'asc', + _fields: [ 'id', 'link', 'parent', 'title' ], + } ), + } ).then( ( res ) => { + const groupedPages = res.reduce( ( parentMap, page ) => { + const { parent } = page; + if ( parentMap.has( parent ) ) { + parentMap.get( parent ).push( page ); + } else { + parentMap.set( parent, [ page ] ); + } + return parentMap; + }, new Map() ); + setPagesByParentId( groupedPages ); + setAllowConvertToLinks( + isParentNavigation && res.headers.get( 'X-WP-Total' ) <= MAX_PAGE_COUNT - ); - } ); - } else { - setAllowConvertToLinks( false ); - } + ); + } ); }, [ isParentNavigation ] ); const [ isOpen, setOpen ] = useState( false ); @@ -151,13 +195,9 @@ export default function PageListEdit( { /> ) }
    - ( - { __( 'Page List: No pages to show.' ) } - ) } - /> +
      + +
    ); From 1004b695a88b106f412281233d38165c4c600c5a Mon Sep 17 00:00:00 2001 From: Robert Anderson Date: Wed, 20 Oct 2021 16:31:26 +1100 Subject: [PATCH 02/16] Fix lint errors and remove setAttributes() calls --- packages/block-library/src/page-list/edit.js | 57 +------------------- 1 file changed, 1 insertion(+), 56 deletions(-) diff --git a/packages/block-library/src/page-list/edit.js b/packages/block-library/src/page-list/edit.js index 1e1711b2a7c67e..8ab86bc4b4d8eb 100644 --- a/packages/block-library/src/page-list/edit.js +++ b/packages/block-library/src/page-list/edit.js @@ -63,46 +63,7 @@ const Menu = ( { pagesByParentId, parentId, depth = 0 } ) => { } ); }; -export default function PageListEdit( { - context, - clientId, - attributes, - setAttributes, -} ) { - // Copy context to attributes to make it accessible in the editor's - // ServerSideRender - useEffect( () => { - const { - textColor, - customTextColor, - backgroundColor, - customBackgroundColor, - overlayTextColor, - customOverlayTextColor, - overlayBackgroundColor, - customOverlayBackgroundColor, - } = context; - setAttributes( { - textColor, - customTextColor, - backgroundColor, - customBackgroundColor, - overlayTextColor, - customOverlayTextColor, - overlayBackgroundColor, - customOverlayBackgroundColor, - } ); - }, [ - context.textColor, - context.customTextColor, - context.backgroundColor, - context.customBackgroundColor, - context.overlayTextColor, - context.customOverlayTextColor, - context.overlayBackgroundColor, - context.customOverlayBackgroundColor, - ] ); - +export default function PageListEdit( { context, clientId } ) { const { textColor, backgroundColor, style } = context || {}; const [ allowConvertToLinks, setAllowConvertToLinks ] = useState( false ); @@ -134,14 +95,6 @@ export default function PageListEdit( { [ clientId ] ); - useEffect( () => { - setAttributes( { - isNavigationChild: isParentNavigation, - openSubmenusOnClick: !! context.openSubmenusOnClick, - showSubmenuIcon: !! context.showSubmenuIcon, - } ); - }, [ context.openSubmenusOnClick, context.showSubmenuIcon ] ); - useEffect( () => { apiFetch( { path: addQueryArgs( '/wp/v2/pages', { @@ -171,14 +124,6 @@ export default function PageListEdit( { const openModal = () => setOpen( true ); const closeModal = () => setOpen( false ); - // Update parent status before component first renders. - const attributesWithParentStatus = { - ...attributes, - isNavigationChild: isParentNavigation, - openSubmenusOnClick: !! context.openSubmenusOnClick, - showSubmenuIcon: !! context.showSubmenuIcon, - }; - return ( <> { allowConvertToLinks && ( From 6759fa73c629ce27e9e1c2c70d18067b14591e42 Mon Sep 17 00:00:00 2001 From: Robert Anderson Date: Wed, 20 Oct 2021 17:00:40 +1100 Subject: [PATCH 03/16] Split page fetching into a hook --- packages/block-library/src/page-list/edit.js | 187 ++++++++++--------- 1 file changed, 98 insertions(+), 89 deletions(-) diff --git a/packages/block-library/src/page-list/edit.js b/packages/block-library/src/page-list/edit.js index 8ab86bc4b4d8eb..3d7262b4af153c 100644 --- a/packages/block-library/src/page-list/edit.js +++ b/packages/block-library/src/page-list/edit.js @@ -9,13 +9,11 @@ import classnames from 'classnames'; import { BlockControls, useBlockProps, - store as blockEditorStore, getColorClassName, } from '@wordpress/block-editor'; import { ToolbarButton } from '@wordpress/components'; import { __ } from '@wordpress/i18n'; -import { useEffect, useState } from '@wordpress/element'; -import { useSelect } from '@wordpress/data'; +import { useEffect, useState, useRef } from '@wordpress/element'; import apiFetch from '@wordpress/api-fetch'; import { addQueryArgs } from '@wordpress/url'; @@ -29,101 +27,32 @@ import { ItemSubmenuIcon } from '../navigation-link/icons'; // Performance of Navigation Links is not good past this value. const MAX_PAGE_COUNT = 100; -const Menu = ( { pagesByParentId, parentId, depth = 0 } ) => { - return pagesByParentId.get( parentId )?.map( ( page ) => { - const hasChildren = pagesByParentId.has( page.id ); - const classes = classnames( 'wp-block-pages-list__item', { - 'has-child': hasChildren, - } ); - - return ( -
  • - - { page.title?.rendered } - - { hasChildren && ( - <> - - - -
      - -
    - - ) } -
  • - ); - } ); -}; - export default function PageListEdit( { context, clientId } ) { - const { textColor, backgroundColor, style } = context || {}; + const { pagesByParentId, totalPages } = usePagesByParentId(); - const [ allowConvertToLinks, setAllowConvertToLinks ] = useState( false ); - const [ pagesByParentId, setPagesByParentId ] = useState( - new Map( [ [ 0, [] ] ] ) - ); + const isInNavigation = !! context.orientation; + const allowConvertToLinks = isInNavigation && totalPages <= MAX_PAGE_COUNT; + + const [ isOpen, setOpen ] = useState( false ); + const openModal = () => setOpen( true ); + const closeModal = () => setOpen( false ); const blockProps = useBlockProps( { className: classnames( { - 'has-text-color': !! textColor, - [ getColorClassName( 'color', textColor ) ]: !! textColor, - 'has-background': !! backgroundColor, + 'has-text-color': !! context.textColor, + [ getColorClassName( + 'color', + context.textColor + ) ]: !! context.textColor, + 'has-background': !! context.backgroundColor, [ getColorClassName( 'background-color', - backgroundColor - ) ]: !! backgroundColor, + context.backgroundColor + ) ]: !! context.backgroundColor, } ), - style: { ...style?.color }, + style: { ...context.style?.color }, } ); - const isParentNavigation = useSelect( - ( select ) => { - const { getBlockParentsByBlockName } = select( blockEditorStore ); - return ( - getBlockParentsByBlockName( clientId, 'core/navigation' ) - .length > 0 - ); - }, - [ clientId ] - ); - - useEffect( () => { - apiFetch( { - path: addQueryArgs( '/wp/v2/pages', { - orderby: 'menu_order', - order: 'asc', - _fields: [ 'id', 'link', 'parent', 'title' ], - } ), - } ).then( ( res ) => { - const groupedPages = res.reduce( ( parentMap, page ) => { - const { parent } = page; - if ( parentMap.has( parent ) ) { - parentMap.get( parent ).push( page ); - } else { - parentMap.set( parent, [ page ] ); - } - return parentMap; - }, new Map() ); - setPagesByParentId( groupedPages ); - setAllowConvertToLinks( - isParentNavigation && - res.headers.get( 'X-WP-Total' ) <= MAX_PAGE_COUNT - ); - } ); - }, [ isParentNavigation ] ); - - const [ isOpen, setOpen ] = useState( false ); - const openModal = () => setOpen( true ); - const closeModal = () => setOpen( false ); - return ( <> { allowConvertToLinks && ( @@ -141,9 +70,89 @@ export default function PageListEdit( { context, clientId } ) { ) }
      - +
    ); } + +function usePagesByParentId() { + const pagesByParentIdRef = useRef( new Map() ); + const totalPagesRef = useRef( 0 ); + + useEffect( () => { + async function performFetch() { + const response = await apiFetch( { + path: addQueryArgs( '/wp/v2/pages', { + orderby: 'menu_order', + order: 'asc', + _fields: [ 'id', 'link', 'parent', 'title' ], + } ), + parse: false, + } ); + + const pages = await response.json(); + pagesByParentIdRef.current = pages.reduce( + ( pagesByParentId, page ) => { + const { parent } = page; + if ( pagesByParentId.has( parent ) ) { + pagesByParentId.get( parent ).push( page ); + } else { + pagesByParentId.set( parent, [ page ] ); + } + return pagesByParentId; + }, + new Map() + ); + + totalPagesRef.current = response.headers.get( 'X-WP-Total' ); + } + performFetch(); + }, [] ); + + return { + pagesByParentId: pagesByParentIdRef.current, + totalPages: totalPagesRef.current, + }; +} + +function PageItems( { pagesByParentId, parentId = 0, depth = 0 } ) { + const pages = pagesByParentId.get( parentId ); + + if ( ! pages?.length ) { + return []; + } + + return pages.map( ( page ) => { + const hasChildren = pagesByParentId.has( page.id ); + const classes = classnames( 'wp-block-pages-list__item', { + 'has-child': hasChildren, + } ); + + return ( +
  • + + { page.title?.rendered } + + { hasChildren && ( + <> + + + +
      + +
    + + ) } +
  • + ); + } ); +} From 9c95ab42abc08027f2d7dc1fc48fae9b2cb5ba3d Mon Sep 17 00:00:00 2001 From: Robert Anderson Date: Wed, 20 Oct 2021 17:44:01 +1100 Subject: [PATCH 04/16] Add navigation submenu markup --- packages/block-library/src/page-list/edit.js | 91 ++++++++++++++------ 1 file changed, 67 insertions(+), 24 deletions(-) diff --git a/packages/block-library/src/page-list/edit.js b/packages/block-library/src/page-list/edit.js index 3d7262b4af153c..0668a8ab4802e4 100644 --- a/packages/block-library/src/page-list/edit.js +++ b/packages/block-library/src/page-list/edit.js @@ -30,15 +30,17 @@ const MAX_PAGE_COUNT = 100; export default function PageListEdit( { context, clientId } ) { const { pagesByParentId, totalPages } = usePagesByParentId(); - const isInNavigation = !! context.orientation; - const allowConvertToLinks = isInNavigation && totalPages <= MAX_PAGE_COUNT; + const isNavigationChild = 'showSubmenuIcon' in context; + const allowConvertToLinks = + isNavigationChild && totalPages <= MAX_PAGE_COUNT; const [ isOpen, setOpen ] = useState( false ); const openModal = () => setOpen( true ); const closeModal = () => setOpen( false ); const blockProps = useBlockProps( { - className: classnames( { + // TODO: Test that this behaviour matches index.php. + className: classnames( 'wp-block-page-list', { 'has-text-color': !! context.textColor, [ getColorClassName( 'color', @@ -68,11 +70,12 @@ export default function PageListEdit( { context, clientId } ) { clientId={ clientId } /> ) } -
    -
      - -
    -
    +
      + +
    ); } @@ -117,7 +120,7 @@ function usePagesByParentId() { }; } -function PageItems( { pagesByParentId, parentId = 0, depth = 0 } ) { +function PageItems( { context, pagesByParentId, parentId = 0, depth = 0 } ) { const pages = pagesByParentId.get( parentId ); if ( ! pages?.length ) { @@ -126,25 +129,51 @@ function PageItems( { pagesByParentId, parentId = 0, depth = 0 } ) { return pages.map( ( page ) => { const hasChildren = pagesByParentId.has( page.id ); - const classes = classnames( 'wp-block-pages-list__item', { - 'has-child': hasChildren, - } ); - + const isNavigationChild = 'showSubmenuIcon' in context; return ( -
  • - - { page.title?.rendered } - +
  • + { hasChildren && + isNavigationChild && + context.openSubmenusOnClick ? ( + + ) : ( + + { page.title?.rendered } + + ) } { hasChildren && ( <> - - - -