diff --git a/docs/reference-guides/core-blocks.md b/docs/reference-guides/core-blocks.md index 09e48ebda0f65e..7e359ae4bc7476 100644 --- a/docs/reference-guides/core-blocks.md +++ b/docs/reference-guides/core-blocks.md @@ -431,6 +431,15 @@ Display a list of all pages. ([Source](https://github.com/WordPress/gutenberg/tr - **Supports:** ~~html~~, ~~reusable~~ - **Attributes:** parentPageID +## Page List Item + +Displays a page inside a list of all pages. ([Source](https://github.com/WordPress/gutenberg/tree/trunk/packages/block-library/src/page-list-item)) + +- **Name:** core/page-list-item +- **Category:** widgets +- **Supports:** ~~html~~, ~~inserter~~, ~~lock~~, ~~reusable~~ +- **Attributes:** hasChildren, id, label, link, title + ## Paragraph Start with the basic building block of all narrative. ([Source](https://github.com/WordPress/gutenberg/tree/trunk/packages/block-library/src/paragraph)) diff --git a/packages/block-library/src/index.js b/packages/block-library/src/index.js index 88d2c26f02403a..34ba9fd5a2c8f1 100644 --- a/packages/block-library/src/index.js +++ b/packages/block-library/src/index.js @@ -67,6 +67,7 @@ import * as navigationSubmenu from './navigation-submenu'; import * as nextpage from './nextpage'; import * as pattern from './pattern'; import * as pageList from './page-list'; +import * as pageListItem from './page-list-item'; import * as paragraph from './paragraph'; import * as postAuthor from './post-author'; import * as postAuthorName from './post-author-name'; @@ -155,6 +156,7 @@ const getAllBlocks = () => more, nextpage, pageList, + pageListItem, pattern, preformatted, pullquote, diff --git a/packages/block-library/src/page-list-item/block.json b/packages/block-library/src/page-list-item/block.json new file mode 100644 index 00000000000000..97c312d1b7960e --- /dev/null +++ b/packages/block-library/src/page-list-item/block.json @@ -0,0 +1,51 @@ +{ + "$schema": "https://schemas.wp.org/trunk/block.json", + "apiVersion": 2, + "name": "core/page-list-item", + "title": "Page List Item", + "category": "widgets", + "parent": [ "core/page-list" ], + "description": "Displays a page inside a list of all pages.", + "keywords": [ "page", "menu", "navigation" ], + "textdomain": "default", + "attributes": { + "id": { + "type": "number" + }, + "label": { + "type": "string" + }, + "title": { + "type": "string" + }, + "link": { + "type": "string" + }, + "hasChildren": { + "type": "boolean" + } + }, + "usesContext": [ + "textColor", + "customTextColor", + "backgroundColor", + "customBackgroundColor", + "overlayTextColor", + "customOverlayTextColor", + "overlayBackgroundColor", + "customOverlayBackgroundColor", + "fontSize", + "customFontSize", + "showSubmenuIcon", + "style", + "openSubmenusOnClick" + ], + "supports": { + "reusable": false, + "html": false, + "lock": false, + "inserter": false + }, + "editorStyle": "wp-block-page-list-editor", + "style": "wp-block-page-list" +} diff --git a/packages/block-library/src/page-list-item/edit.js b/packages/block-library/src/page-list-item/edit.js new file mode 100644 index 00000000000000..db8e0a5c173736 --- /dev/null +++ b/packages/block-library/src/page-list-item/edit.js @@ -0,0 +1,94 @@ +/** + * External dependencies + */ +import classnames from 'classnames'; + +/** + * WordPress dependencies + */ +import { InnerBlocks } from '@wordpress/block-editor'; +import { useSelect } from '@wordpress/data'; +import { store as coreStore } from '@wordpress/core-data'; + +/** + * Internal dependencies + */ +import { ItemSubmenuIcon } from '../navigation-link/icons'; + +function useFrontPageId() { + return useSelect( ( select ) => { + const canReadSettings = select( coreStore ).canUser( + 'read', + 'settings' + ); + if ( ! canReadSettings ) { + return undefined; + } + + const site = select( coreStore ).getEntityRecord( 'root', 'site' ); + return site?.show_on_front === 'page' && site?.page_on_front; + }, [] ); +} + +export default function PageListItemEdit( { context, attributes } ) { + const { id, label, link, hasChildren } = attributes; + const isNavigationChild = 'showSubmenuIcon' in context; + const frontPageId = useFrontPageId(); + return ( +
  • + { hasChildren && context.openSubmenusOnClick ? ( + <> + + + + + + ) : ( + + { label } + + ) } + { hasChildren && ( + <> + { ! context.openSubmenusOnClick && + context.showSubmenuIcon && ( + + ) } + + + ) } +
  • + ); +} diff --git a/packages/block-library/src/page-list-item/index.js b/packages/block-library/src/page-list-item/index.js new file mode 100644 index 00000000000000..18b7fe2e40e9ea --- /dev/null +++ b/packages/block-library/src/page-list-item/index.js @@ -0,0 +1,24 @@ +/** + * WordPress dependencies + */ +import { pages as icon } from '@wordpress/icons'; + +/** + * Internal dependencies + */ +import initBlock from '../utils/init-block'; +import metadata from './block.json'; +import edit from './edit.js'; + +const { name } = metadata; + +export { metadata, name }; + +export const settings = { + __experimentalLabel: ( { label } ) => label, + icon, + example: {}, + edit, +}; + +export const init = () => initBlock( { name, metadata, settings } ); diff --git a/packages/block-library/src/page-list-item/init.js b/packages/block-library/src/page-list-item/init.js new file mode 100644 index 00000000000000..79f0492c2cb2f8 --- /dev/null +++ b/packages/block-library/src/page-list-item/init.js @@ -0,0 +1,6 @@ +/** + * Internal dependencies + */ +import { init } from './'; + +export default init(); diff --git a/packages/block-library/src/page-list/edit.js b/packages/block-library/src/page-list/edit.js index ac7ed6162cf975..d9e541305b6976 100644 --- a/packages/block-library/src/page-list/edit.js +++ b/packages/block-library/src/page-list/edit.js @@ -10,6 +10,7 @@ import { InspectorControls, BlockControls, useBlockProps, + useInnerBlocksProps, getColorClassName, } from '@wordpress/block-editor'; import { @@ -20,15 +21,13 @@ import { ComboboxControl, } from '@wordpress/components'; import { __ } from '@wordpress/i18n'; -import { useMemo, useState, memo } from '@wordpress/element'; -import { useSelect } from '@wordpress/data'; -import { store as coreStore, useEntityRecords } from '@wordpress/core-data'; +import { useMemo, useState } from '@wordpress/element'; +import { useEntityRecords } from '@wordpress/core-data'; /** * 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. @@ -65,6 +64,39 @@ export default function PageListEdit( { style: { ...context.style?.color }, } ); + const makeBlockTemplate = ( parentId = 0 ) => { + const pages = pagesByParentId.get( parentId ); + + if ( ! pages?.length ) { + return []; + } + + return pages.reduce( ( template, page ) => { + const hasChildren = pagesByParentId.has( page.id ); + const pageProps = { + id: page.id, + label: page.title?.rendered, + title: page.title?.rendered, + link: page.url, + hasChildren, + }; + let item = null; + const children = makeBlockTemplate( page.id ); + item = [ 'core/page-list-item', pageProps, children ]; + + template.push( item ); + + return template; + }, [] ); + }; + + const pagesTemplate = useMemo( makeBlockTemplate, [ pagesByParentId ] ); + + const innerBlocksProps = useInnerBlocksProps( blockProps, { + template: pagesTemplate, + templateLock: 'all', + } ); + const getBlockContent = () => { if ( ! hasResolvedPages ) { return ( @@ -95,15 +127,7 @@ export default function PageListEdit( { } if ( totalPages > 0 ) { - return ( - - ); + return ; } }; @@ -155,21 +179,6 @@ export default function PageListEdit( { ); } -function useFrontPageId() { - return useSelect( ( select ) => { - const canReadSettings = select( coreStore ).canUser( - 'read', - 'settings' - ); - if ( ! canReadSettings ) { - return undefined; - } - - const site = select( coreStore ).getEntityRecord( 'root', 'site' ); - return site?.show_on_front === 'page' && site?.page_on_front; - }, [] ); -} - function useGetPages() { const { records: pages, hasResolved: hasResolvedPages } = useEntityRecords( 'postType', @@ -221,92 +230,3 @@ function usePageData( pageId = 0 ) { }; }, [ pageId, pages, hasResolvedPages ] ); } - -const PageItems = memo( function PageItems( { - context, - pagesByParentId, - parentId = 0, - depth = 0, -} ) { - const parentPage = usePageData( parentId ); - const pages = pagesByParentId.get( parentId ) - ? pagesByParentId.get( parentId ) - : [ parentPage ]; - const frontPageId = useFrontPageId(); - - if ( ! pages?.length ) { - return []; - } - - return pages.map( ( page ) => { - const hasChildren = pagesByParentId.has( page.id ); - const isNavigationChild = 'showSubmenuIcon' in context; - return ( -
  • - { hasChildren && context.openSubmenusOnClick ? ( - <> - - - - - - ) : ( - - { page.title?.rendered } - - ) } - { hasChildren && ( - <> - { ! context.openSubmenusOnClick && - context.showSubmenuIcon && ( - - ) } - - - ) } -
  • - ); - } ); -} ); diff --git a/test/integration/fixtures/blocks/core__page-list-item.html b/test/integration/fixtures/blocks/core__page-list-item.html new file mode 100644 index 00000000000000..2b1b33d71231cf --- /dev/null +++ b/test/integration/fixtures/blocks/core__page-list-item.html @@ -0,0 +1 @@ + diff --git a/test/integration/fixtures/blocks/core__page-list-item.json b/test/integration/fixtures/blocks/core__page-list-item.json new file mode 100644 index 00000000000000..5e6f09eb971eb7 --- /dev/null +++ b/test/integration/fixtures/blocks/core__page-list-item.json @@ -0,0 +1,11 @@ +[ + { + "name": "core/page-list-item", + "isValid": true, + "attributes": { + "label": "Page", + "link": "https://example.com" + }, + "innerBlocks": [] + } +] diff --git a/test/integration/fixtures/blocks/core__page-list-item.parsed.json b/test/integration/fixtures/blocks/core__page-list-item.parsed.json new file mode 100644 index 00000000000000..e93cff97dd385e --- /dev/null +++ b/test/integration/fixtures/blocks/core__page-list-item.parsed.json @@ -0,0 +1,14 @@ +[ + { + "blockName": "core/page-list-item", + "attrs": { + "id": "1", + "label": "Page", + "link": "https://example.com", + "hasChildren": "false" + }, + "innerBlocks": [], + "innerHTML": "", + "innerContent": [] + } +] diff --git a/test/integration/fixtures/blocks/core__page-list-item.serialized.html b/test/integration/fixtures/blocks/core__page-list-item.serialized.html new file mode 100644 index 00000000000000..d61659fe1899a9 --- /dev/null +++ b/test/integration/fixtures/blocks/core__page-list-item.serialized.html @@ -0,0 +1 @@ +