From c60c176f05358a80ac14e39c02a2344cccf1bdce Mon Sep 17 00:00:00 2001 From: Marcus Kazmierczak Date: Tue, 4 May 2021 10:16:10 -0700 Subject: [PATCH 1/6] Update Page List with toggle to show child pages - Adds a showOnlyChildPages attribute to Edit - Update render to use attribute and only pull in children - Do not show on post pages which will not have a parent - Allow showing on wp_template pages Fixes #31063 --- package-lock.json | 1 + packages/block-library/package.json | 1 + .../block-library/src/page-list/block.json | 5 +- packages/block-library/src/page-list/edit.js | 115 ++++++++++++------ .../block-library/src/page-list/index.php | 35 +++++- 5 files changed, 112 insertions(+), 45 deletions(-) diff --git a/package-lock.json b/package-lock.json index dc95bcdb05e2f6..f0e5ba3b04e462 100644 --- a/package-lock.json +++ b/package-lock.json @@ -18769,6 +18769,7 @@ "@wordpress/date": "file:packages/date", "@wordpress/deprecated": "file:packages/deprecated", "@wordpress/dom": "file:packages/dom", + "@wordpress/editor": "file:packages/editor", "@wordpress/element": "file:packages/element", "@wordpress/escape-html": "file:packages/escape-html", "@wordpress/hooks": "file:packages/hooks", diff --git a/packages/block-library/package.json b/packages/block-library/package.json index ef95510c01421f..16b2afa6d99203 100644 --- a/packages/block-library/package.json +++ b/packages/block-library/package.json @@ -46,6 +46,7 @@ "@wordpress/date": "file:../date", "@wordpress/deprecated": "file:../deprecated", "@wordpress/dom": "file:../dom", + "@wordpress/editor": "file:../editor", "@wordpress/element": "file:../element", "@wordpress/escape-html": "file:../escape-html", "@wordpress/hooks": "file:../hooks", diff --git a/packages/block-library/src/page-list/block.json b/packages/block-library/src/page-list/block.json index 146f236fca84f8..f654922dcb4afb 100644 --- a/packages/block-library/src/page-list/block.json +++ b/packages/block-library/src/page-list/block.json @@ -3,10 +3,13 @@ "name": "core/page-list", "title": "Page List", "category": "widgets", - "description": "Display a list of all pages.", + "description": "Display a list of pages.", "keywords": [ "menu", "navigation" ], "textdomain": "default", "attributes": { + "showOnlyChildPages": { + "type": "boolean" + } }, "usesContext": [ "textColor", diff --git a/packages/block-library/src/page-list/edit.js b/packages/block-library/src/page-list/edit.js index 7d44a376ce0429..1b66ef9ad7247d 100644 --- a/packages/block-library/src/page-list/edit.js +++ b/packages/block-library/src/page-list/edit.js @@ -11,8 +11,10 @@ import { BlockControls, useBlockProps, getColorClassName, + InspectorControls, } from '@wordpress/block-editor'; import { ToolbarButton, Placeholder, Spinner } from '@wordpress/components'; +import { PanelBody, ToggleControl, ToolbarButton } from '@wordpress/components'; import { __ } from '@wordpress/i18n'; import { useEffect, useState, memo } from '@wordpress/element'; import apiFetch from '@wordpress/api-fetch'; @@ -31,32 +33,80 @@ const MAX_PAGE_COUNT = 100; export default function PageListEdit( { context, clientId } ) { const { pagesByParentId, totalPages } = usePagesByParentId(); - const isNavigationChild = 'showSubmenuIcon' in context; - const allowConvertToLinks = - isNavigationChild && totalPages <= MAX_PAGE_COUNT; + const isParentBlockNavigation = useSelect( + ( select ) => { + const { getBlockParentsByBlockName } = select( blockEditorStore ); + return ( + getBlockParentsByBlockName( clientId, 'core/navigation' ) + .length > 0 + ); + }, + [ clientId ] + ); + + const showChildPageToggle = useSelect( ( select ) => { + const { getCurrentPostType } = select( editorStore ); + const currentPostType = getCurrentPostType(); + const allowedTypes = [ 'page', 'wp_template' ]; + return allowedTypes.includes( currentPostType ); + } ); + + useEffect( () => { + setAttributes( { + isNavigationChild: isParentBlockNavigation, + openSubmenusOnClick: !! context.openSubmenusOnClick, + showSubmenuIcon: !! context.showSubmenuIcon, + } ); + }, [ context.openSubmenusOnClick, context.showSubmenuIcon ] ); + + useEffect( () => { + if ( isParentBlockNavigation ) { + apiFetch( { + path: addQueryArgs( '/wp/v2/pages', { + per_page: 1, + _fields: [ 'id' ], + } ), + parse: false, + } ).then( ( res ) => { + setAllowConvertToLinks( + res.headers.get( 'X-WP-Total' ) <= MAX_PAGE_COUNT + ); + } ); + } else { + setAllowConvertToLinks( false ); + } + }, [ isParentBlockNavigation ] ); const [ isOpen, setOpen ] = useState( false ); const openModal = () => setOpen( true ); const closeModal = () => setOpen( false ); - const blockProps = useBlockProps( { - className: classnames( 'wp-block-page-list', { - 'has-text-color': !! context.textColor, - [ getColorClassName( - 'color', - context.textColor - ) ]: !! context.textColor, - 'has-background': !! context.backgroundColor, - [ getColorClassName( - 'background-color', - context.backgroundColor - ) ]: !! context.backgroundColor, - } ), - style: { ...context.style?.color }, - } ); + // Update parent status before component first renders. + const attributesWithParentBlockStatus = { + ...attributes, + isNavigationChild: isParentBlockNavigation, + openSubmenusOnClick: !! context.openSubmenusOnClick, + showSubmenuIcon: !! context.showSubmenuIcon, + }; return ( <> + + { showChildPageToggle && ( + + + setAttributes( { + showOnlyChildPages: ! attributes.showOnlyChildPages, + } ) + } + help={ __( 'Uses parent to list child pages.' ) } + /> + + ) } + { allowConvertToLinks && ( @@ -70,26 +120,15 @@ export default function PageListEdit( { context, clientId } ) { clientId={ clientId } /> ) } - { totalPages === null && ( -
- - - -
- ) } - { totalPages === 0 && ( -
- { __( 'Page List: No pages to show.' ) } -
- ) } - { totalPages > 0 && ( -
    - -
- ) } +
+ ( + { __( 'Page List: No pages to show.' ) } + ) } + /> +
); } diff --git a/packages/block-library/src/page-list/index.php b/packages/block-library/src/page-list/index.php index 733d2e0e4354ee..34b001be901119 100644 --- a/packages/block-library/src/page-list/index.php +++ b/packages/block-library/src/page-list/index.php @@ -236,16 +236,30 @@ function block_core_page_list_nest_pages( $current_level, $children ) { * @return string Returns the page list markup. */ function render_block_core_page_list( $attributes, $content, $block ) { + global $post; static $block_id = 0; $block_id++; - $all_pages = get_pages( - array( - 'sort_column' => 'menu_order,post_title', - 'order' => 'asc', - ) + $only_child_pages = isset( $attributes['showOnlyChildPages'] ) && $attributes['showOnlyChildPages']; + // The pages will be siblings (same parent) or set parent id equal to self if no children. + $parent_id = ( $post->post_parent ) ? $post->post_parent : $post->ID; + + // TODO: When https://core.trac.wordpress.org/ticket/39037 REST API support for multiple orderby values is resolved, + // update 'sort_column' to 'menu_order, post_title'. Sorting by both menu_order and post_title ensures a stable sort. + // Otherwise with pages that have the same menu_order value, we can see different ordering depending on how DB + // queries are constructed internally. For example we might see a different order when a limit is set to <499 + // versus >= 500. + $query_args = array( + 'sort_column' => 'menu_order', + 'order' => 'asc', ); + if ( $only_child_pages && $parent_id ) { + $query_args['child_of'] = $parent_id; + } + + $all_pages = get_pages( $query_args ); + // If thare are no pages, there is nothing to show. if ( empty( $all_pages ) ) { return; @@ -264,7 +278,16 @@ function render_block_core_page_list( $attributes, $content, $block ) { $active_page_ancestor_ids = get_post_ancestors( $page->ID ); } - if ( $page->post_parent ) { + // When showing only child pages of parent, set the pages to top level + // since there is no other top level page. + if ( $only_child_pages ) { + $top_level_pages[ $page->ID ] = array( + 'page_id' => $page->ID, + 'title' => $page->post_title, + 'link' => get_permalink( $page->ID ), + 'is_active' => $is_active, + ); + } else if ( $page->post_parent ) { $pages_with_children[ $page->post_parent ][ $page->ID ] = array( 'page_id' => $page->ID, 'title' => $page->post_title, From 56a3fa875c7b77a9e38243fef76471fe0c06f0bd Mon Sep 17 00:00:00 2001 From: Marcus Kazmierczak Date: Wed, 29 Sep 2021 08:50:38 -0700 Subject: [PATCH 2/6] Update verbiage explaining control --- packages/block-library/src/page-list/edit.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/block-library/src/page-list/edit.js b/packages/block-library/src/page-list/edit.js index 1b66ef9ad7247d..14cb22724793d7 100644 --- a/packages/block-library/src/page-list/edit.js +++ b/packages/block-library/src/page-list/edit.js @@ -95,14 +95,16 @@ export default function PageListEdit( { context, clientId } ) { { showChildPageToggle && ( setAttributes( { showOnlyChildPages: ! attributes.showOnlyChildPages, } ) } - help={ __( 'Uses parent to list child pages.' ) } + help={ __( + 'When enabled, the block lists only child pages of the current page.' + ) } /> ) } From 984be2c50e4dcda49ab9d7ddb6946070c857212b Mon Sep 17 00:00:00 2001 From: Marcus Kazmierczak Date: Wed, 29 Sep 2021 08:58:09 -0700 Subject: [PATCH 3/6] Simplify if-else for setting top/child pages, makes linter happier --- packages/block-library/src/page-list/index.php | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/packages/block-library/src/page-list/index.php b/packages/block-library/src/page-list/index.php index 34b001be901119..9a203fe5718aed 100644 --- a/packages/block-library/src/page-list/index.php +++ b/packages/block-library/src/page-list/index.php @@ -278,16 +278,9 @@ function render_block_core_page_list( $attributes, $content, $block ) { $active_page_ancestor_ids = get_post_ancestors( $page->ID ); } - // When showing only child pages of parent, set the pages to top level - // since there is no other top level page. - if ( $only_child_pages ) { - $top_level_pages[ $page->ID ] = array( - 'page_id' => $page->ID, - 'title' => $page->post_title, - 'link' => get_permalink( $page->ID ), - 'is_active' => $is_active, - ); - } else if ( $page->post_parent ) { + // Only set pages with children when only child pages is not set, since + // when set we want child pages to be top-level. + if ( $page->post_parent && ! $only_child_pages ) { $pages_with_children[ $page->post_parent ][ $page->ID ] = array( 'page_id' => $page->ID, 'title' => $page->post_title, From 4622e8005a37cec690f2fef70d9815542dfc5584 Mon Sep 17 00:00:00 2001 From: Marcus Kazmierczak Date: Mon, 11 Oct 2021 09:24:00 -0700 Subject: [PATCH 4/6] Reverse logic on when to display toggle The toggle was set to show explictly on certain posts types but it is easier to hide on post types so it will show on others such was templates, template parts, or menus. --- packages/block-library/src/page-list/edit.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/block-library/src/page-list/edit.js b/packages/block-library/src/page-list/edit.js index 14cb22724793d7..669caffa51b434 100644 --- a/packages/block-library/src/page-list/edit.js +++ b/packages/block-library/src/page-list/edit.js @@ -47,8 +47,8 @@ export default function PageListEdit( { context, clientId } ) { const showChildPageToggle = useSelect( ( select ) => { const { getCurrentPostType } = select( editorStore ); const currentPostType = getCurrentPostType(); - const allowedTypes = [ 'page', 'wp_template' ]; - return allowedTypes.includes( currentPostType ); + const hideToggleFrom = [ 'post' ]; + return ! hideToggleFrom.includes( currentPostType ); } ); useEffect( () => { From ac19e71a135f5540891424fb7927b2386a43d48f Mon Sep 17 00:00:00 2001 From: Marcus Kazmierczak Date: Mon, 11 Oct 2021 17:58:03 -0700 Subject: [PATCH 5/6] Update logic for checking top-level and child pages Moves check for top level and child checks to its own function so it came be a little more clear what it is doing and why. When the only_child_pages flag is set, we need to treat direct child pages to the parent as top level so they show. And treat grand children pages as child pages so they nest. --- .../block-library/src/page-list/index.php | 30 +++++++++++++++++-- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/packages/block-library/src/page-list/index.php b/packages/block-library/src/page-list/index.php index 9a203fe5718aed..3b39e48e19aa8d 100644 --- a/packages/block-library/src/page-list/index.php +++ b/packages/block-library/src/page-list/index.php @@ -226,6 +226,31 @@ function block_core_page_list_nest_pages( $current_level, $children ) { return $current_level; } +/** + * Determines if page should be classified as top-level or child page. Broken + * out to this function to explain instead of a complex if statement. + * When only_child_pages is true, force child pages to be considered top level. + * Thy are top level since the parent is not shown (only child pages). + * + * @param int $page_parent_id Parent id of the page being tested. + * @param boolean $only_child_pages Only showing child pages. + * @param int $parent_id Top level parent id for child pages, needed so we can nest grand children. + * @return boolean True if page should be considered a child page. + */ +function block_core_page_list_treat_as_child( $page_parent_id, $only_child_pages, $parent_id ) { + if ( ! $page_parent_id ) { + return false; + } + + // Check only child pages, and id matches parent, then it is top level and + // should not be treated like a child page. + if ( $only_child_pages && ( $page_parent_id === $parent_id ) ) { + return false; + } + + return true; +} + /** * Renders the `core/page-list` block on server. * @@ -278,9 +303,8 @@ function render_block_core_page_list( $attributes, $content, $block ) { $active_page_ancestor_ids = get_post_ancestors( $page->ID ); } - // Only set pages with children when only child pages is not set, since - // when set we want child pages to be top-level. - if ( $page->post_parent && ! $only_child_pages ) { + // See function for logic when pages are treated like child pages. + if ( block_core_page_list_treat_as_child( $page->post_parent, $only_child_pages, $parent_id ) ) { $pages_with_children[ $page->post_parent ][ $page->ID ] = array( 'page_id' => $page->ID, 'title' => $page->post_title, From 83ef45cbc2b949d945a3c546da50b7df0659e51c Mon Sep 17 00:00:00 2001 From: Marcus Kazmierczak Date: Sat, 30 Oct 2021 10:18:13 -0700 Subject: [PATCH 6/6] Fix rebasing issues --- packages/block-library/src/page-list/edit.js | 118 +++++++++---------- 1 file changed, 58 insertions(+), 60 deletions(-) diff --git a/packages/block-library/src/page-list/edit.js b/packages/block-library/src/page-list/edit.js index 669caffa51b434..49ea5580e64c54 100644 --- a/packages/block-library/src/page-list/edit.js +++ b/packages/block-library/src/page-list/edit.js @@ -13,10 +13,17 @@ import { getColorClassName, InspectorControls, } from '@wordpress/block-editor'; -import { ToolbarButton, Placeholder, Spinner } from '@wordpress/components'; -import { PanelBody, ToggleControl, ToolbarButton } from '@wordpress/components'; +import { + PanelBody, + Placeholder, + Spinner, + ToggleControl, + ToolbarButton, +} from '@wordpress/components'; +import { useSelect } from '@wordpress/data'; +import { store as editorStore } from '@wordpress/editor'; import { __ } from '@wordpress/i18n'; -import { useEffect, useState, memo } from '@wordpress/element'; +import { memo, useEffect, useState } from '@wordpress/element'; import apiFetch from '@wordpress/api-fetch'; import { addQueryArgs } from '@wordpress/url'; @@ -30,19 +37,21 @@ import { ItemSubmenuIcon } from '../navigation-link/icons'; // Performance of Navigation Links is not good past this value. const MAX_PAGE_COUNT = 100; -export default function PageListEdit( { context, clientId } ) { +export default function PageListEdit( { + attributes, + clientId, + context, + setAttributes, +} ) { const { pagesByParentId, totalPages } = usePagesByParentId(); - const isParentBlockNavigation = useSelect( - ( select ) => { - const { getBlockParentsByBlockName } = select( blockEditorStore ); - return ( - getBlockParentsByBlockName( clientId, 'core/navigation' ) - .length > 0 - ); - }, - [ clientId ] - ); + 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 showChildPageToggle = useSelect( ( select ) => { const { getCurrentPostType } = select( editorStore ); @@ -51,43 +60,21 @@ export default function PageListEdit( { context, clientId } ) { return ! hideToggleFrom.includes( currentPostType ); } ); - useEffect( () => { - setAttributes( { - isNavigationChild: isParentBlockNavigation, - openSubmenusOnClick: !! context.openSubmenusOnClick, - showSubmenuIcon: !! context.showSubmenuIcon, - } ); - }, [ context.openSubmenusOnClick, context.showSubmenuIcon ] ); - - useEffect( () => { - if ( isParentBlockNavigation ) { - apiFetch( { - path: addQueryArgs( '/wp/v2/pages', { - per_page: 1, - _fields: [ 'id' ], - } ), - parse: false, - } ).then( ( res ) => { - setAllowConvertToLinks( - res.headers.get( 'X-WP-Total' ) <= MAX_PAGE_COUNT - ); - } ); - } else { - setAllowConvertToLinks( false ); - } - }, [ isParentBlockNavigation ] ); - - const [ isOpen, setOpen ] = useState( false ); - const openModal = () => setOpen( true ); - const closeModal = () => setOpen( false ); - - // Update parent status before component first renders. - const attributesWithParentBlockStatus = { - ...attributes, - isNavigationChild: isParentBlockNavigation, - openSubmenusOnClick: !! context.openSubmenusOnClick, - showSubmenuIcon: !! context.showSubmenuIcon, - }; + const blockProps = useBlockProps( { + className: classnames( 'wp-block-page-list', { + 'has-text-color': !! context.textColor, + [ getColorClassName( + 'color', + context.textColor + ) ]: !! context.textColor, + 'has-background': !! context.backgroundColor, + [ getColorClassName( + 'background-color', + context.backgroundColor + ) ]: !! context.backgroundColor, + } ), + style: { ...context.style?.color }, + } ); return ( <> @@ -122,15 +109,26 @@ export default function PageListEdit( { context, clientId } ) { clientId={ clientId } /> ) } -
- ( - { __( 'Page List: No pages to show.' ) } - ) } - /> -
+ { totalPages === null && ( +
+ + + +
+ ) } + { totalPages === 0 && ( +
+ { __( 'Page List: No pages to show.' ) } +
+ ) } + { totalPages > 0 && ( +
    + +
+ ) } ); }