From 8a52cbcfacad275a092c5ff45a1d9bcc6ebe43cf Mon Sep 17 00:00:00 2001 From: ntsekouras Date: Fri, 19 Apr 2024 13:23:59 +0300 Subject: [PATCH 01/10] Editor: Update post excerpt panel with new designs --- .../components/sidebar/post-status/index.js | 38 +++++--- .../sidebar/settings-sidebar/index.js | 2 - .../page-panels/page-summary.js | 5 + .../src/components/template-actions/index.js | 42 ++++++++- .../src/components/post-actions/actions.js | 4 + .../src/components/post-actions/index.js | 1 + .../post-actions/private-actions.js | 65 +++++++++++++ .../src/components/post-card-panel/index.js | 93 ++++++++++--------- .../src/components/post-excerpt/check.js | 18 ---- .../src/components/post-excerpt/index.js | 55 ++++++++--- .../src/components/post-excerpt/panel.js | 71 +++++++++++++- packages/editor/src/private-apis.js | 2 + 12 files changed, 301 insertions(+), 95 deletions(-) create mode 100644 packages/editor/src/components/post-actions/private-actions.js diff --git a/packages/edit-post/src/components/sidebar/post-status/index.js b/packages/edit-post/src/components/sidebar/post-status/index.js index c5a2350ed04117..dab8ec2688b3a2 100644 --- a/packages/edit-post/src/components/sidebar/post-status/index.js +++ b/packages/edit-post/src/components/sidebar/post-status/index.js @@ -28,7 +28,8 @@ import PostSlug from '../post-slug'; import PostFormat from '../post-format'; import { unlock } from '../../../lock-unlock'; -const { PostStatus: PostStatusPanel } = unlock( editorPrivateApis ); +const { PostStatus: PostStatusPanel, PrivatePostExcerptPanel } = + unlock( editorPrivateApis ); /** * Module Constants @@ -36,16 +37,30 @@ const { PostStatus: PostStatusPanel } = unlock( editorPrivateApis ); const PANEL_NAME = 'post-status'; export default function PostStatus() { - const { isOpened, isRemoved } = useSelect( ( select ) => { - // We use isEditorPanelRemoved to hide the panel if it was programatically removed. We do - // not use isEditorPanelEnabled since this panel should not be disabled through the UI. - const { isEditorPanelRemoved, isEditorPanelOpened } = - select( editorStore ); - return { - isRemoved: isEditorPanelRemoved( PANEL_NAME ), - isOpened: isEditorPanelOpened( PANEL_NAME ), - }; - }, [] ); + const { isOpened, isRemoved, showPostExcerptPanel } = useSelect( + ( select ) => { + // We use isEditorPanelRemoved to hide the panel if it was programatically removed. We do + // not use isEditorPanelEnabled since this panel should not be disabled through the UI. + const { + isEditorPanelRemoved, + isEditorPanelOpened, + getCurrentPostType, + } = select( editorStore ); + const postType = getCurrentPostType(); + return { + isRemoved: isEditorPanelRemoved( PANEL_NAME ), + isOpened: isEditorPanelOpened( PANEL_NAME ), + // Post excerpt panel is rendered in different place depending on the post type. + // So we cannot make this check inside the PostExcerpt component based on the current edited entity. + showPostExcerptPanel: ! [ + 'wp_template', + 'wp_template_part', + 'wp_block', + ].includes( postType ), + }; + }, + [] + ); const { toggleEditorPanelOpened } = useDispatch( editorStore ); if ( isRemoved ) { @@ -64,6 +79,7 @@ export default function PostStatus() { <> + { showPostExcerptPanel && } diff --git a/packages/edit-post/src/components/sidebar/settings-sidebar/index.js b/packages/edit-post/src/components/sidebar/settings-sidebar/index.js index 05fb4fc91e69c2..472e08c3fac019 100644 --- a/packages/edit-post/src/components/sidebar/settings-sidebar/index.js +++ b/packages/edit-post/src/components/sidebar/settings-sidebar/index.js @@ -22,7 +22,6 @@ import { PluginDocumentSettingPanel, PluginSidebar, PostDiscussionPanel, - PostExcerptPanel, PostLastRevisionPanel, PostTaxonomiesPanel, privateApis as editorPrivateApis, @@ -130,7 +129,6 @@ const SidebarContent = ( { tabName, keyboardShortcut, isEditingTemplate } ) => { - diff --git a/packages/edit-site/src/components/sidebar-edit-mode/page-panels/page-summary.js b/packages/edit-site/src/components/sidebar-edit-mode/page-panels/page-summary.js index 5ca010e2faccba..5b8710ac3abe42 100644 --- a/packages/edit-site/src/components/sidebar-edit-mode/page-panels/page-summary.js +++ b/packages/edit-site/src/components/sidebar-edit-mode/page-panels/page-summary.js @@ -9,12 +9,16 @@ import { PostSchedulePanel, PostTemplatePanel, PostFeaturedImagePanel, + privateApis as editorPrivateApis, } from '@wordpress/editor'; /** * Internal dependencies */ import PageStatus from './page-status'; +import { unlock } from '../../../lock-unlock'; + +const { PrivatePostExcerptPanel } = unlock( editorPrivateApis ); export default function PageSummary( { status, @@ -29,6 +33,7 @@ export default function PageSummary( { { ( fills ) => ( <> + ) } + { isRevertable && ( ); } + +function EditDescriptionMenuItem() { + const [ isModalOpen, setIsModalOpen ] = useState( false ); + return ( + <> + setIsModalOpen( true ) }> + { __( 'Edit description' ) } + + { isModalOpen && ( + { + setIsModalOpen( false ); + } } + overlayClassName="editor-action-modal" + > + + { ( fills ) => ( + <> + + { fills } + + ) } + + + ) } + + ); +} diff --git a/packages/editor/src/components/post-actions/actions.js b/packages/editor/src/components/post-actions/actions.js index 7b91c2c5c96e3e..4dbbf9792776d1 100644 --- a/packages/editor/src/components/post-actions/actions.js +++ b/packages/editor/src/components/post-actions/actions.js @@ -25,6 +25,7 @@ import { TEMPLATE_ORIGINS, TEMPLATE_POST_TYPE } from '../../store/constants'; import { store as editorStore } from '../../store'; import { unlock } from '../../lock-unlock'; import isTemplateRevertable from '../../store/utils/is-template-revertable'; +import { useEditExcerptAction } from './private-actions'; function getItemTitle( item ) { if ( typeof item.title === 'string' ) { @@ -771,6 +772,7 @@ const renameTemplateAction = { export function usePostActions( onActionPerformed, actionIds = null ) { const permanentlyDeletePostAction = usePermanentlyDeletePostAction(); const restorePostAction = useRestorePostAction(); + const editPostExcerptAction = useEditExcerptAction(); return useMemo( () => { // By default, return all actions... @@ -784,6 +786,7 @@ export function usePostActions( onActionPerformed, actionIds = null ) { postRevisionsAction, renamePostAction, renameTemplateAction, + editPostExcerptAction, trashPostAction, ]; @@ -856,6 +859,7 @@ export function usePostActions( onActionPerformed, actionIds = null ) { ...( actionIds || [] ), permanentlyDeletePostAction, restorePostAction, + editPostExcerptAction, onActionPerformed, ] ); diff --git a/packages/editor/src/components/post-actions/index.js b/packages/editor/src/components/post-actions/index.js index 48d83f992e7056..748c599432ccdd 100644 --- a/packages/editor/src/components/post-actions/index.js +++ b/packages/editor/src/components/post-actions/index.js @@ -35,6 +35,7 @@ const POST_ACTIONS_WHILE_EDITING = [ 'view-post', 'view-post-revisions', 'rename-post', + 'edit-post-excerpt', 'move-to-trash', ]; diff --git a/packages/editor/src/components/post-actions/private-actions.js b/packages/editor/src/components/post-actions/private-actions.js new file mode 100644 index 00000000000000..9a4cd05afdedb5 --- /dev/null +++ b/packages/editor/src/components/post-actions/private-actions.js @@ -0,0 +1,65 @@ +/** + * WordPress dependencies + */ +import { useSelect } from '@wordpress/data'; +import { store as coreStore } from '@wordpress/core-data'; +import { __ } from '@wordpress/i18n'; +import { useMemo } from '@wordpress/element'; + +/** + * Internal dependencies + */ +import PostExcerpt from '../post-excerpt'; +import PluginPostExcerpt from '../post-excerpt/plugin'; +import { store as editorStore } from '../../store'; + +export function useEditExcerptAction() { + const { canEditExcerpt, shouldUseDescriptionLabel } = useSelect( + ( select ) => { + const { getCurrentPostType, isEditorPanelEnabled } = + select( editorStore ); + const { getPostType } = select( coreStore ); + const postType = getPostType( getCurrentPostType() ); + // TODO: When we are rendering the excerpt/description for templates, + // template parts and patterns do not abide by the `isEnabled` panel flag. + // It's not implemented here right now because the actions are to be consolidated + // and this is rendered only for the rest post types. + return { + canEditExcerpt: + isEditorPanelEnabled( 'post-excerpt' ) && + postType?.supports?.excerpt, + shouldUseDescriptionLabel: [ + 'wp_template', + 'wp_template_part', + 'wp_block', + ].includes( postType ), + }; + }, + [] + ); + const label = shouldUseDescriptionLabel + ? __( 'Edit description' ) + : __( 'Edit excerpt' ); + return useMemo( + () => ( { + id: 'edit-post-excerpt', + label, + isEligible() { + return canEditExcerpt; + }, + RenderModal: () => { + return ( + + { ( fills ) => ( + <> + + { fills } + + ) } + + ); + }, + } ), + [ canEditExcerpt, label ] + ); +} diff --git a/packages/editor/src/components/post-card-panel/index.js b/packages/editor/src/components/post-card-panel/index.js index a8419c0feb8c2f..0da08ed07e977e 100644 --- a/packages/editor/src/components/post-card-panel/index.js +++ b/packages/editor/src/components/post-card-panel/index.js @@ -28,40 +28,53 @@ import { store as editorStore } from '../../store'; import { TEMPLATE_POST_TYPE, TEMPLATE_PART_POST_TYPE, + PATTERN_POST_TYPE, } from '../../store/constants'; +import { PrivatePostExcerptPanel } from '../post-excerpt/panel'; import { unlock } from '../../lock-unlock'; import TemplateAreas from '../template-areas'; export default function PostCardPanel( { className, actions } ) { - const { modified, title, templateInfo, icon, postType, isPostsPage } = - useSelect( ( select ) => { - const { - getEditedPostAttribute, - getCurrentPostType, - getCurrentPostId, - __experimentalGetTemplateInfo, - } = select( editorStore ); - const { getEditedEntityRecord, getEntityRecord } = - select( coreStore ); - const siteSettings = getEntityRecord( 'root', 'site' ); - const _type = getCurrentPostType(); - const _id = getCurrentPostId(); - const _record = getEditedEntityRecord( 'postType', _type, _id ); - const _templateInfo = __experimentalGetTemplateInfo( _record ); - return { - title: - _templateInfo?.title || getEditedPostAttribute( 'title' ), - modified: getEditedPostAttribute( 'modified' ), - id: _id, - postType: _type, - templateInfo: _templateInfo, - icon: unlock( select( editorStore ) ).getPostIcon( _type, { - area: _record?.area, - } ), - isPostsPage: +_id === siteSettings?.page_for_posts, - }; - }, [] ); - const description = templateInfo?.description; + const { + modified, + title, + showPostExcerptPanel, + icon, + postType, + isPostsPage, + } = useSelect( ( select ) => { + const { + getEditedPostAttribute, + getCurrentPostType, + getCurrentPostId, + __experimentalGetTemplateInfo, + } = select( editorStore ); + const { getEditedEntityRecord, getEntityRecord } = select( coreStore ); + const siteSettings = getEntityRecord( 'root', 'site' ); + const _type = getCurrentPostType(); + const _id = getCurrentPostId(); + const _record = getEditedEntityRecord( 'postType', _type, _id ); + const _templateInfo = + [ TEMPLATE_POST_TYPE, TEMPLATE_PART_POST_TYPE ].includes( _type ) && + __experimentalGetTemplateInfo( _record ); + return { + title: _templateInfo?.title || getEditedPostAttribute( 'title' ), + modified: getEditedPostAttribute( 'modified' ), + id: _id, + postType: _type, + icon: unlock( select( editorStore ) ).getPostIcon( _type, { + area: _record?.area, + } ), + isPostsPage: +_id === siteSettings?.page_for_posts, + // Post excerpt panel is rendered in different place depending on the post type. + // So we cannot make this check inside the PostExcerpt component based on the current edited entity. + showPostExcerptPanel: [ + TEMPLATE_POST_TYPE, + TEMPLATE_PART_POST_TYPE, + PATTERN_POST_TYPE, + ].includes( _type ), + }; + }, [] ); const lastEditedText = modified && sprintf( @@ -98,20 +111,14 @@ export default function PostCardPanel( { className, actions } ) { { actions } - { ( description || - lastEditedText || - showPostContentInfo ) && ( - - { description && { description } } - { showPostContentInfo && } - { lastEditedText && ( - { lastEditedText } - ) } - - ) } + + { showPostExcerptPanel && } + { showPostContentInfo && } + { lastEditedText && { lastEditedText } } + { postType === TEMPLATE_POST_TYPE && } diff --git a/packages/editor/src/components/post-excerpt/check.js b/packages/editor/src/components/post-excerpt/check.js index d1d125428f58bd..77436ecfed218a 100644 --- a/packages/editor/src/components/post-excerpt/check.js +++ b/packages/editor/src/components/post-excerpt/check.js @@ -1,13 +1,7 @@ -/** - * WordPress dependencies - */ -import { useSelect } from '@wordpress/data'; - /** * Internal dependencies */ import PostTypeSupportCheck from '../post-type-support-check'; -import { store as editorStore } from '../../store'; /** * Component for checking if the post type supports the excerpt field. @@ -18,18 +12,6 @@ import { store as editorStore } from '../../store'; * @return {Component} The component to be rendered. */ function PostExcerptCheck( { children } ) { - const postType = useSelect( ( select ) => { - const { getEditedPostAttribute } = select( editorStore ); - return getEditedPostAttribute( 'type' ); - }, [] ); - - // This special case is unfortunate, but the REST API of wp_template and wp_template_part - // support the excerpt field throught the "description" field rather than "excerpt" which means - // the default ExcerptPanel won't work for these. - if ( [ 'wp_template', 'wp_template_part' ].includes( postType ) ) { - return null; - } - return ( { children } diff --git a/packages/editor/src/components/post-excerpt/index.js b/packages/editor/src/components/post-excerpt/index.js index 47a1d3bf585850..f29e346fe905fc 100644 --- a/packages/editor/src/components/post-excerpt/index.js +++ b/packages/editor/src/components/post-excerpt/index.js @@ -10,29 +10,60 @@ import { useDispatch, useSelect } from '@wordpress/data'; */ import { store as editorStore } from '../../store'; -function PostExcerpt() { - const excerpt = useSelect( - ( select ) => select( editorStore ).getEditedPostAttribute( 'excerpt' ), +function PostExcerpt( { hideLabelFromVision = false } ) { + const { excerpt, shouldUseDescriptionLabel, usedAttribute } = useSelect( + ( select ) => { + const { getCurrentPostType, getEditedPostAttribute } = + select( editorStore ); + const postType = getCurrentPostType(); + // This special case is unfortunate, but the REST API of wp_template and wp_template_part + // support the excerpt field throught the "description" field rather than "excerpt". + const _usedAttribute = [ + 'wp_template', + 'wp_template_part', + ].includes( postType ) + ? 'description' + : 'excerpt'; + return { + excerpt: getEditedPostAttribute( _usedAttribute ), + // There are special cases where we want to label the excerpt as a description. + shouldUseDescriptionLabel: [ + 'wp_template', + 'wp_template_part', + 'wp_block', + ].includes( postType ), + usedAttribute: _usedAttribute, + }; + }, [] ); const { editPost } = useDispatch( editorStore ); + const label = shouldUseDescriptionLabel + ? __( 'Write a description (optional)' ) + : __( 'Write an excerpt (optional)' ); + return (
editPost( { excerpt: value } ) } + onChange={ ( value ) => + editPost( { [ usedAttribute ]: value } ) + } value={ excerpt } /> - - { __( 'Learn more about manual excerpts' ) } - + { ! shouldUseDescriptionLabel && ( + + { __( 'Learn more about manual excerpts' ) } + + ) }
); } diff --git a/packages/editor/src/components/post-excerpt/panel.js b/packages/editor/src/components/post-excerpt/panel.js index 63149a05222385..1eef825cd3d257 100644 --- a/packages/editor/src/components/post-excerpt/panel.js +++ b/packages/editor/src/components/post-excerpt/panel.js @@ -2,7 +2,7 @@ * WordPress dependencies */ import { __ } from '@wordpress/i18n'; -import { PanelBody } from '@wordpress/components'; +import { PanelBody, __experimentalText as Text } from '@wordpress/components'; import { useDispatch, useSelect } from '@wordpress/data'; /** @@ -19,13 +19,17 @@ import { store as editorStore } from '../../store'; const PANEL_NAME = 'post-excerpt'; function ExcerptPanel() { - const { isOpened, isEnabled } = useSelect( ( select ) => { - const { isEditorPanelOpened, isEditorPanelEnabled } = - select( editorStore ); + const { isOpened, isEnabled, postType } = useSelect( ( select ) => { + const { + isEditorPanelOpened, + isEditorPanelEnabled, + getCurrentPostType, + } = select( editorStore ); return { isOpened: isEditorPanelOpened( PANEL_NAME ), isEnabled: isEditorPanelEnabled( PANEL_NAME ), + postType: getCurrentPostType(), }; }, [] ); @@ -36,9 +40,20 @@ function ExcerptPanel() { return null; } + // There are special cases where we want to label the excerpt as a description. + const shouldUseDescriptionLabel = [ + 'wp_template', + 'wp_template_part', + 'wp_block', + ].includes( postType ); + return ( @@ -61,3 +76,49 @@ export default function PostExcerptPanel() { ); } + +function PrivateExcerpt() { + const { isEnabled, excerpt } = useSelect( ( select ) => { + const { + getCurrentPostType, + getEditedPostAttribute, + isEditorPanelEnabled, + } = select( editorStore ); + const postType = getCurrentPostType(); + const shouldBeUsedAsDescription = [ + 'wp_template', + 'wp_template_part', + 'wp_block', + ].includes( postType ); + // This special case is unfortunate, but the REST API of wp_template and wp_template_part + // support the excerpt field throught the "description" field rather than "excerpt". + const _usedAttribute = [ 'wp_template', 'wp_template_part' ].includes( + postType + ) + ? 'description' + : 'excerpt'; + return { + excerpt: getEditedPostAttribute( _usedAttribute ), + // When we are rendering the excerpt/description for templates, template parts + // and patterns, do not abide by the `isEnabled` panel flag. + isEnabled: + isEditorPanelEnabled( PANEL_NAME ) || shouldBeUsedAsDescription, + }; + }, [] ); + if ( ! isEnabled ) { + return null; + } + return ( +
+ { excerpt } +
+ ); +} + +export function PrivatePostExcerptPanel() { + return ( + + + + ); +} diff --git a/packages/editor/src/private-apis.js b/packages/editor/src/private-apis.js index aae3762794b4d6..d031e1364e6a47 100644 --- a/packages/editor/src/private-apis.js +++ b/packages/editor/src/private-apis.js @@ -28,6 +28,7 @@ import PostCardPanel from './components/post-card-panel'; import PostStatus from './components/post-status'; import ToolsMoreMenuGroup from './components/more-menu/tools-more-menu-group'; import ViewMoreMenuGroup from './components/more-menu/view-more-menu-group'; +import { PrivatePostExcerptPanel } from './components/post-excerpt/panel'; const { store: interfaceStore, ...remainingInterfaceApis } = interfaceApis; @@ -52,6 +53,7 @@ lock( privateApis, { PostStatus, ToolsMoreMenuGroup, ViewMoreMenuGroup, + PrivatePostExcerptPanel, // This is a temporary private API while we're updating the site editor to use EditorProvider. useAutoSwitchEditorSidebars, From 3a07113ebeb34a302a8874e976941edc4af3c507 Mon Sep 17 00:00:00 2001 From: ntsekouras Date: Mon, 22 Apr 2024 12:21:30 +0300 Subject: [PATCH 02/10] reorder edit excerpt menu item and show only for user generated entities --- .../src/components/template-actions/index.js | 62 +++++++++++++------ 1 file changed, 44 insertions(+), 18 deletions(-) diff --git a/packages/edit-site/src/components/template-actions/index.js b/packages/edit-site/src/components/template-actions/index.js index a42e2fdacbbf7d..9e954a78d6c7a7 100644 --- a/packages/edit-site/src/components/template-actions/index.js +++ b/packages/edit-site/src/components/template-actions/index.js @@ -17,6 +17,7 @@ import { store as noticesStore } from '@wordpress/notices'; import { decodeEntities } from '@wordpress/html-entities'; import { PostExcerpt, + store as editorStore, privateApis as editorPrivateApis, } from '@wordpress/editor'; @@ -39,14 +40,39 @@ export default function TemplateActions( { toggleProps, onRemove, } ) { - const template = useSelect( - ( select ) => - select( coreStore ).getEntityRecord( 'postType', postType, postId ), + const { template, eligibleToEditExcerpt } = useSelect( + ( select ) => { + const { getCurrentPostType, isEditorPanelEnabled } = + select( editorStore ); + const { getPostType } = select( coreStore ); + const _postType = getPostType( getCurrentPostType() ); + return { + eligibleToEditExcerpt: + isEditorPanelEnabled( 'post-excerpt' ) && + _postType?.supports?.excerpt, + template: select( coreStore ).getEntityRecord( + 'postType', + postType, + postId + ), + }; + }, [ postType, postId ] ); const { removeTemplate } = useDispatch( editSiteStore ); const isRemovable = isTemplateRemovable( template ); const isRevertable = isTemplateRevertable( template ); + // Until we consolidate these actions we need to make different checks for `wp_block` + // type and template/template parts. The reason for this is that we want to allow + // editing excerpt/description for templates/template parts that are + // user generated and this shouldn't abide by the isPanelEnabled flag. + const canEditExcerpt = + isRemovable || + ( eligibleToEditExcerpt && template?.type === 'wp_block' ); + + if ( ! isRemovable && ! isRevertable && ! canEditExcerpt ) { + return null; + } return ( ( { isRemovable && ( - <> - - { - removeTemplate( template ); - onRemove?.(); - onClose(); - } } - title={ template.title.rendered } - /> - + + ) } + { canEditExcerpt && } + { isRemovable && ( + { + removeTemplate( template ); + onRemove?.(); + onClose(); + } } + title={ template.title.rendered } + /> ) } - { isRevertable && ( Date: Wed, 24 Apr 2024 12:05:26 +0300 Subject: [PATCH 03/10] remove action in ellipsis and add dialog --- .../src/components/template-actions/index.js | 96 +++-------- .../src/components/post-actions/actions.js | 4 - .../src/components/post-actions/index.js | 1 - .../post-actions/private-actions.js | 65 -------- .../src/components/post-excerpt/panel.js | 151 +++++++++++++----- .../src/components/post-excerpt/style.scss | 11 ++ 6 files changed, 142 insertions(+), 186 deletions(-) delete mode 100644 packages/editor/src/components/post-actions/private-actions.js diff --git a/packages/edit-site/src/components/template-actions/index.js b/packages/edit-site/src/components/template-actions/index.js index 9e954a78d6c7a7..06a644f79c29e0 100644 --- a/packages/edit-site/src/components/template-actions/index.js +++ b/packages/edit-site/src/components/template-actions/index.js @@ -9,17 +9,11 @@ import { DropdownMenu, MenuGroup, MenuItem, - Modal, __experimentalConfirmDialog as ConfirmDialog, } from '@wordpress/components'; import { moreVertical } from '@wordpress/icons'; import { store as noticesStore } from '@wordpress/notices'; import { decodeEntities } from '@wordpress/html-entities'; -import { - PostExcerpt, - store as editorStore, - privateApis as editorPrivateApis, -} from '@wordpress/editor'; /** * Internal dependencies @@ -29,9 +23,6 @@ import isTemplateRemovable from '../../utils/is-template-removable'; import isTemplateRevertable from '../../utils/is-template-revertable'; import RenamePostMenuItem from '../rename-post-menu-item'; import { TEMPLATE_POST_TYPE } from '../../utils/constants'; -import { unlock } from '../../lock-unlock'; - -const { PluginPostExcerpt } = unlock( editorPrivateApis ); export default function TemplateActions( { postType, @@ -40,37 +31,16 @@ export default function TemplateActions( { toggleProps, onRemove, } ) { - const { template, eligibleToEditExcerpt } = useSelect( - ( select ) => { - const { getCurrentPostType, isEditorPanelEnabled } = - select( editorStore ); - const { getPostType } = select( coreStore ); - const _postType = getPostType( getCurrentPostType() ); - return { - eligibleToEditExcerpt: - isEditorPanelEnabled( 'post-excerpt' ) && - _postType?.supports?.excerpt, - template: select( coreStore ).getEntityRecord( - 'postType', - postType, - postId - ), - }; - }, + const template = useSelect( + ( select ) => + select( coreStore ).getEntityRecord( 'postType', postType, postId ), [ postType, postId ] ); const { removeTemplate } = useDispatch( editSiteStore ); const isRemovable = isTemplateRemovable( template ); const isRevertable = isTemplateRevertable( template ); - // Until we consolidate these actions we need to make different checks for `wp_block` - // type and template/template parts. The reason for this is that we want to allow - // editing excerpt/description for templates/template parts that are - // user generated and this shouldn't abide by the isPanelEnabled flag. - const canEditExcerpt = - isRemovable || - ( eligibleToEditExcerpt && template?.type === 'wp_block' ); - if ( ! isRemovable && ! isRevertable && ! canEditExcerpt ) { + if ( ! isRemovable && ! isRevertable ) { return null; } @@ -84,21 +54,20 @@ export default function TemplateActions( { { ( { onClose } ) => ( { isRemovable && ( - - ) } - { canEditExcerpt && } - { isRemovable && ( - { - removeTemplate( template ); - onRemove?.(); - onClose(); - } } - title={ template.title.rendered } - /> + <> + + { + removeTemplate( template ); + onRemove?.(); + onClose(); + } } + title={ template.title.rendered } + /> + ) } { isRevertable && ( ); } - -function EditDescriptionMenuItem() { - const [ isModalOpen, setIsModalOpen ] = useState( false ); - return ( - <> - setIsModalOpen( true ) }> - { __( 'Edit description' ) } - - { isModalOpen && ( - { - setIsModalOpen( false ); - } } - overlayClassName="editor-action-modal" - > - - { ( fills ) => ( - <> - - { fills } - - ) } - - - ) } - - ); -} diff --git a/packages/editor/src/components/post-actions/actions.js b/packages/editor/src/components/post-actions/actions.js index 4dbbf9792776d1..7b91c2c5c96e3e 100644 --- a/packages/editor/src/components/post-actions/actions.js +++ b/packages/editor/src/components/post-actions/actions.js @@ -25,7 +25,6 @@ import { TEMPLATE_ORIGINS, TEMPLATE_POST_TYPE } from '../../store/constants'; import { store as editorStore } from '../../store'; import { unlock } from '../../lock-unlock'; import isTemplateRevertable from '../../store/utils/is-template-revertable'; -import { useEditExcerptAction } from './private-actions'; function getItemTitle( item ) { if ( typeof item.title === 'string' ) { @@ -772,7 +771,6 @@ const renameTemplateAction = { export function usePostActions( onActionPerformed, actionIds = null ) { const permanentlyDeletePostAction = usePermanentlyDeletePostAction(); const restorePostAction = useRestorePostAction(); - const editPostExcerptAction = useEditExcerptAction(); return useMemo( () => { // By default, return all actions... @@ -786,7 +784,6 @@ export function usePostActions( onActionPerformed, actionIds = null ) { postRevisionsAction, renamePostAction, renameTemplateAction, - editPostExcerptAction, trashPostAction, ]; @@ -859,7 +856,6 @@ export function usePostActions( onActionPerformed, actionIds = null ) { ...( actionIds || [] ), permanentlyDeletePostAction, restorePostAction, - editPostExcerptAction, onActionPerformed, ] ); diff --git a/packages/editor/src/components/post-actions/index.js b/packages/editor/src/components/post-actions/index.js index 748c599432ccdd..48d83f992e7056 100644 --- a/packages/editor/src/components/post-actions/index.js +++ b/packages/editor/src/components/post-actions/index.js @@ -35,7 +35,6 @@ const POST_ACTIONS_WHILE_EDITING = [ 'view-post', 'view-post-revisions', 'rename-post', - 'edit-post-excerpt', 'move-to-trash', ]; diff --git a/packages/editor/src/components/post-actions/private-actions.js b/packages/editor/src/components/post-actions/private-actions.js deleted file mode 100644 index 9a4cd05afdedb5..00000000000000 --- a/packages/editor/src/components/post-actions/private-actions.js +++ /dev/null @@ -1,65 +0,0 @@ -/** - * WordPress dependencies - */ -import { useSelect } from '@wordpress/data'; -import { store as coreStore } from '@wordpress/core-data'; -import { __ } from '@wordpress/i18n'; -import { useMemo } from '@wordpress/element'; - -/** - * Internal dependencies - */ -import PostExcerpt from '../post-excerpt'; -import PluginPostExcerpt from '../post-excerpt/plugin'; -import { store as editorStore } from '../../store'; - -export function useEditExcerptAction() { - const { canEditExcerpt, shouldUseDescriptionLabel } = useSelect( - ( select ) => { - const { getCurrentPostType, isEditorPanelEnabled } = - select( editorStore ); - const { getPostType } = select( coreStore ); - const postType = getPostType( getCurrentPostType() ); - // TODO: When we are rendering the excerpt/description for templates, - // template parts and patterns do not abide by the `isEnabled` panel flag. - // It's not implemented here right now because the actions are to be consolidated - // and this is rendered only for the rest post types. - return { - canEditExcerpt: - isEditorPanelEnabled( 'post-excerpt' ) && - postType?.supports?.excerpt, - shouldUseDescriptionLabel: [ - 'wp_template', - 'wp_template_part', - 'wp_block', - ].includes( postType ), - }; - }, - [] - ); - const label = shouldUseDescriptionLabel - ? __( 'Edit description' ) - : __( 'Edit excerpt' ); - return useMemo( - () => ( { - id: 'edit-post-excerpt', - label, - isEligible() { - return canEditExcerpt; - }, - RenderModal: () => { - return ( - - { ( fills ) => ( - <> - - { fills } - - ) } - - ); - }, - } ), - [ canEditExcerpt, label ] - ); -} diff --git a/packages/editor/src/components/post-excerpt/panel.js b/packages/editor/src/components/post-excerpt/panel.js index 1eef825cd3d257..adf6ba4041aec0 100644 --- a/packages/editor/src/components/post-excerpt/panel.js +++ b/packages/editor/src/components/post-excerpt/panel.js @@ -2,8 +2,16 @@ * WordPress dependencies */ import { __ } from '@wordpress/i18n'; -import { PanelBody, __experimentalText as Text } from '@wordpress/components'; +import { + PanelBody, + __experimentalText as Text, + Dropdown, + Button, + __experimentalVStack as VStack, +} from '@wordpress/components'; import { useDispatch, useSelect } from '@wordpress/data'; +import { useMemo, useState } from '@wordpress/element'; +import { __experimentalInspectorPopoverHeader as InspectorPopoverHeader } from '@wordpress/block-editor'; /** * Internal dependencies @@ -77,48 +85,115 @@ export default function PostExcerptPanel() { ); } +export function PrivatePostExcerptPanel() { + return ( + + + + ); +} + function PrivateExcerpt() { - const { isEnabled, excerpt } = useSelect( ( select ) => { - const { - getCurrentPostType, - getEditedPostAttribute, - isEditorPanelEnabled, - } = select( editorStore ); - const postType = getCurrentPostType(); - const shouldBeUsedAsDescription = [ - 'wp_template', - 'wp_template_part', - 'wp_block', - ].includes( postType ); - // This special case is unfortunate, but the REST API of wp_template and wp_template_part - // support the excerpt field throught the "description" field rather than "excerpt". - const _usedAttribute = [ 'wp_template', 'wp_template_part' ].includes( - postType - ) - ? 'description' - : 'excerpt'; - return { - excerpt: getEditedPostAttribute( _usedAttribute ), - // When we are rendering the excerpt/description for templates, template parts - // and patterns, do not abide by the `isEnabled` panel flag. - isEnabled: - isEditorPanelEnabled( PANEL_NAME ) || shouldBeUsedAsDescription, - }; - }, [] ); + const { isEnabled, excerpt, shouldBeUsedAsDescription } = useSelect( + ( select ) => { + const { + getCurrentPostType, + getEditedPostAttribute, + isEditorPanelEnabled, + } = select( editorStore ); + const postType = getCurrentPostType(); + const _shouldBeUsedAsDescription = [ + 'wp_template', + 'wp_template_part', + 'wp_block', + ].includes( postType ); + // This special case is unfortunate, but the REST API of wp_template and wp_template_part + // support the excerpt field throught the "description" field rather than "excerpt". + const _usedAttribute = [ + 'wp_template', + 'wp_template_part', + ].includes( postType ) + ? 'description' + : 'excerpt'; + return { + excerpt: getEditedPostAttribute( _usedAttribute ), + // When we are rendering the excerpt/description for templates, template parts + // and patterns, do not abide by the `isEnabled` panel flag. + isEnabled: + isEditorPanelEnabled( PANEL_NAME ) || + _shouldBeUsedAsDescription, + shouldBeUsedAsDescription: _shouldBeUsedAsDescription, + }; + }, + [] + ); + const [ popoverAnchor, setPopoverAnchor ] = useState( null ); + const label = shouldBeUsedAsDescription + ? __( 'Description' ) + : __( 'Excerpt' ); + // Memoize popoverProps to avoid returning a new object every time. + const popoverProps = useMemo( + () => ( { + // Anchor the popover to the middle of the entire row so that it doesn't + // move around when the label changes. + anchor: popoverAnchor, + 'aria-label': label, + headerTitle: label, + placement: 'left-start', + offset: 36, + shift: true, + } ), + [ popoverAnchor, label ] + ); + if ( ! isEnabled ) { return null; } - return ( -
- { excerpt } -
- ); -} -export function PrivatePostExcerptPanel() { + // TODO: if not editable show just text.. + + // TODO: if empty should have placeholder... + // we need to make different checks for `wp_block` + // type and template/template parts. The reason for this is that we want to allow + // editing excerpt/description for templates/template parts that are + // user generated and this shouldn't abide by the isPanelEnabled flag. + // const canEditExcerpt = + // isRemovable || + // ( eligibleToEditExcerpt && template?.type === 'wp_block' ); + return ( - - - + ( + + ) } + renderContent={ ( { onClose } ) => ( + <> + + + + + { ( fills ) => ( + <> + + { fills } + + ) } + + + + ) } + /> ); } diff --git a/packages/editor/src/components/post-excerpt/style.scss b/packages/editor/src/components/post-excerpt/style.scss index 056d81ad36c731..2959781fc17dd4 100644 --- a/packages/editor/src/components/post-excerpt/style.scss +++ b/packages/editor/src/components/post-excerpt/style.scss @@ -2,3 +2,14 @@ width: 100%; margin-bottom: 10px; } + +.editor-post-excerpt__dropdown__trigger { + height: auto; +} + +.editor-post-excerpt__dropdown__content { + .components-popover__content { + min-width: 320px; + padding: $grid-unit-20; + } +} From 2cac5342437f472eeca92835cd23df2638e6e605 Mon Sep 17 00:00:00 2001 From: ntsekouras Date: Wed, 24 Apr 2024 16:17:39 +0300 Subject: [PATCH 04/10] handle if we should render the panel and if is editable --- .../src/components/sidebar-edit-mode/index.js | 2 - .../src/components/post-excerpt/panel.js | 91 ++++++++++++------- 2 files changed, 56 insertions(+), 37 deletions(-) diff --git a/packages/edit-site/src/components/sidebar-edit-mode/index.js b/packages/edit-site/src/components/sidebar-edit-mode/index.js index 7ac2098a00c1be..8541f952abbf41 100644 --- a/packages/edit-site/src/components/sidebar-edit-mode/index.js +++ b/packages/edit-site/src/components/sidebar-edit-mode/index.js @@ -14,7 +14,6 @@ import { store as coreStore } from '@wordpress/core-data'; import { PageAttributesPanel, PostDiscussionPanel, - PostExcerptPanel, PostLastRevisionPanel, PostTaxonomiesPanel, privateApis as editorPrivateApis, @@ -100,7 +99,6 @@ const FillContents = ( { tabName, isEditingPage, supportsGlobalStyles } ) => { { isEditingPage ? : } - diff --git a/packages/editor/src/components/post-excerpt/panel.js b/packages/editor/src/components/post-excerpt/panel.js index adf6ba4041aec0..bd537acf362707 100644 --- a/packages/editor/src/components/post-excerpt/panel.js +++ b/packages/editor/src/components/post-excerpt/panel.js @@ -12,6 +12,7 @@ import { import { useDispatch, useSelect } from '@wordpress/data'; import { useMemo, useState } from '@wordpress/element'; import { __experimentalInspectorPopoverHeader as InspectorPopoverHeader } from '@wordpress/block-editor'; +import { store as coreStore } from '@wordpress/core-data'; /** * Internal dependencies @@ -19,6 +20,7 @@ import { __experimentalInspectorPopoverHeader as InspectorPopoverHeader } from ' import PostExcerptForm from './index'; import PostExcerptCheck from './check'; import PluginPostExcerpt from './plugin'; +import { TEMPLATE_ORIGINS } from '../../store/constants'; import { store as editorStore } from '../../store'; /** @@ -94,39 +96,55 @@ export function PrivatePostExcerptPanel() { } function PrivateExcerpt() { - const { isEnabled, excerpt, shouldBeUsedAsDescription } = useSelect( - ( select ) => { + const { shouldRender, excerpt, shouldBeUsedAsDescription, allowEditing } = + useSelect( ( select ) => { const { getCurrentPostType, + getCurrentPostId, getEditedPostAttribute, isEditorPanelEnabled, } = select( editorStore ); const postType = getCurrentPostType(); - const _shouldBeUsedAsDescription = [ + const isTemplateOrTemplatePart = [ 'wp_template', 'wp_template_part', - 'wp_block', ].includes( postType ); - // This special case is unfortunate, but the REST API of wp_template and wp_template_part - // support the excerpt field throught the "description" field rather than "excerpt". - const _usedAttribute = [ - 'wp_template', - 'wp_template_part', - ].includes( postType ) + const isPattern = postType === 'wp_block'; + // These post types use the `excerpt` field as a description semantically, so we need to + // handle proper labeling and some flows where we should always render them as text. + const _shouldBeUsedAsDescription = + isTemplateOrTemplatePart || isPattern; + const _usedAttribute = isTemplateOrTemplatePart ? 'description' : 'excerpt'; + // We need to fetch the entity in this case to check if we'll allow editing. + const template = + isTemplateOrTemplatePart && + select( coreStore ).getEntityRecord( + 'postType', + postType, + getCurrentPostId() + ); + // For post types that use excerpt as description, we do not abide + // by the `isEnabled` panel flag in order to render them as text. + const _shouldRender = + isEditorPanelEnabled( PANEL_NAME ) || + _shouldBeUsedAsDescription; return { excerpt: getEditedPostAttribute( _usedAttribute ), - // When we are rendering the excerpt/description for templates, template parts - // and patterns, do not abide by the `isEnabled` panel flag. - isEnabled: - isEditorPanelEnabled( PANEL_NAME ) || - _shouldBeUsedAsDescription, + shouldRender: _shouldRender, shouldBeUsedAsDescription: _shouldBeUsedAsDescription, + // If we should render, allow editing for all post types that are not used as description. + // For the rest allow editing only for user generated entities. + allowEditing: + _shouldRender && + ( ! _shouldBeUsedAsDescription || + isPattern || + ( template && + template.source === TEMPLATE_ORIGINS.custom && + ! template.has_theme_file ) ), }; - }, - [] - ); + }, [] ); const [ popoverAnchor, setPopoverAnchor ] = useState( null ); const label = shouldBeUsedAsDescription ? __( 'Description' ) @@ -145,22 +163,23 @@ function PrivateExcerpt() { } ), [ popoverAnchor, label ] ); - - if ( ! isEnabled ) { - return null; + if ( ! shouldRender ) { + return false; } - - // TODO: if not editable show just text.. - - // TODO: if empty should have placeholder... - // we need to make different checks for `wp_block` - // type and template/template parts. The reason for this is that we want to allow - // editing excerpt/description for templates/template parts that are - // user generated and this shouldn't abide by the isPanelEnabled flag. - // const canEditExcerpt = - // isRemovable || - // ( eligibleToEditExcerpt && template?.type === 'wp_block' ); - + const excerptText = !! excerpt && ( + + { excerpt } + + ); + if ( ! allowEditing ) { + return excerptText; + } + const excerptPlaceholder = shouldBeUsedAsDescription + ? __( 'Add a description..' ) + : __( 'Add an excerpt..' ); + const triggerEditLabel = shouldBeUsedAsDescription + ? __( 'Edit description' ) + : __( 'Edit excerpt' ); return ( - { excerpt } + { excerptText || excerptPlaceholder } ) } renderContent={ ( { onClose } ) => ( @@ -186,7 +207,7 @@ function PrivateExcerpt() { { ( fills ) => ( <> - + { fills } ) } From 2101509f59c6a8234624d562014c2a7ee75fd62e Mon Sep 17 00:00:00 2001 From: James Koster Date: Wed, 24 Apr 2024 15:21:09 +0100 Subject: [PATCH 05/10] Adjustments --- .../src/components/post-excerpt/index.js | 20 ++++++++++--------- .../src/components/post-excerpt/panel.js | 14 ++++++++++--- .../src/components/post-excerpt/style.scss | 9 +++++++++ 3 files changed, 31 insertions(+), 12 deletions(-) diff --git a/packages/editor/src/components/post-excerpt/index.js b/packages/editor/src/components/post-excerpt/index.js index f29e346fe905fc..e4a1141f8a7d24 100644 --- a/packages/editor/src/components/post-excerpt/index.js +++ b/packages/editor/src/components/post-excerpt/index.js @@ -54,16 +54,18 @@ function PostExcerpt( { hideLabelFromVision = false } ) { editPost( { [ usedAttribute ]: value } ) } value={ excerpt } + help={ + ! shouldUseDescriptionLabel && ( + + { __( 'Learn more about manual excerpts' ) } + + ) + } /> - { ! shouldUseDescriptionLabel && ( - - { __( 'Learn more about manual excerpts' ) } - - ) } ); } diff --git a/packages/editor/src/components/post-excerpt/panel.js b/packages/editor/src/components/post-excerpt/panel.js index bd537acf362707..77a479ac7fa458 100644 --- a/packages/editor/src/components/post-excerpt/panel.js +++ b/packages/editor/src/components/post-excerpt/panel.js @@ -1,3 +1,8 @@ +/** + * External dependencies + */ +import classnames from 'classnames'; + /** * WordPress dependencies */ @@ -175,8 +180,8 @@ function PrivateExcerpt() { return excerptText; } const excerptPlaceholder = shouldBeUsedAsDescription - ? __( 'Add a description..' ) - : __( 'Add an excerpt..' ); + ? __( 'Add a description…' ) + : __( 'Add an excerpt…' ); const triggerEditLabel = shouldBeUsedAsDescription ? __( 'Edit description' ) : __( 'Edit excerpt' ); @@ -188,7 +193,10 @@ function PrivateExcerpt() { ref={ setPopoverAnchor } renderToggle={ ( { onToggle } ) => ( diff --git a/test/e2e/specs/editor/plugins/meta-boxes.spec.js b/test/e2e/specs/editor/plugins/meta-boxes.spec.js index 5999dc07aeafe0..1b7adc18760ff8 100644 --- a/test/e2e/specs/editor/plugins/meta-boxes.spec.js +++ b/test/e2e/specs/editor/plugins/meta-boxes.spec.js @@ -95,21 +95,12 @@ test.describe( 'Meta boxes', () => { .getByRole( 'textbox', { name: 'Add title' } ) .fill( 'A published post' ); - const documentSettings = page.getByRole( 'region', { - name: 'Editor settings', + const excerptButton = page.getByRole( 'button', { + name: 'Add an excerpt…', } ); - const excerptButton = documentSettings.getByRole( 'button', { - name: 'Excerpt', - } ); - - // eslint-disable-next-line playwright/no-conditional-in-test - if ( - ( await excerptButton.getAttribute( 'aria-expanded' ) ) === 'false' - ) { - await excerptButton.click(); - } + await excerptButton.click(); - await documentSettings + await page .getByRole( 'textbox', { name: 'Write an Excerpt' } ) .fill( 'Explicitly set excerpt.' ); diff --git a/test/e2e/specs/editor/various/new-post-default-content.spec.js b/test/e2e/specs/editor/various/new-post-default-content.spec.js index db9e3c38dc2962..6495cb3da012ef 100644 --- a/test/e2e/specs/editor/various/new-post-default-content.spec.js +++ b/test/e2e/specs/editor/various/new-post-default-content.spec.js @@ -23,8 +23,6 @@ test.describe( 'new editor filtered state', () => { test( 'should respect default content', async ( { editor, page } ) => { await editor.openDocumentSettingsSidebar(); - await page.click( 'role=button[name="Excerpt"i]' ); - // Assert they match what the plugin set. await expect( editor.canvas.locator( 'role=textbox[name="Add title"i]' ) @@ -33,7 +31,7 @@ test.describe( 'new editor filtered state', () => { .poll( editor.getEditedPostContent ) .toBe( 'My default content' ); await expect( - page.locator( 'role=textbox[name="Write an excerpt (optional)"i]' ) + page.getByRole( 'button', { name: 'Edit excerpt' } ) ).toHaveText( 'My default excerpt' ); } ); } ); diff --git a/test/e2e/specs/editor/various/sidebar.spec.js b/test/e2e/specs/editor/various/sidebar.spec.js index 9c332b192f41ae..465f37ea9625b3 100644 --- a/test/e2e/specs/editor/various/sidebar.spec.js +++ b/test/e2e/specs/editor/various/sidebar.spec.js @@ -115,9 +115,17 @@ test.describe( 'Sidebar', () => { 'Summary', 'Categories', 'Tags', - 'Excerpt', 'Discussion', ] ); + // Also check 'panels' that are not rendered as TabPanels. + const postExcerptPanel = page.getByRole( 'button', { + name: 'Add an excerpt…', + } ); + const postFeaturedImagePanel = page.getByRole( 'button', { + name: 'Set featured image', + } ); + await expect( postExcerptPanel ).toHaveCount( 1 ); + await expect( postFeaturedImagePanel ).toHaveCount( 1 ); await page.evaluate( () => { const { removeEditorPanel } = @@ -132,5 +140,7 @@ test.describe( 'Sidebar', () => { } ); await expect( documentSettingsPanels ).toHaveCount( 1 ); + await expect( postExcerptPanel ).toHaveCount( 0 ); + await expect( postFeaturedImagePanel ).toHaveCount( 0 ); } ); } ); From 069c8a4a70d27c176063532c6eb5d2552f17f20d Mon Sep 17 00:00:00 2001 From: ntsekouras Date: Thu, 25 Apr 2024 10:58:21 +0300 Subject: [PATCH 10/10] dropdown: display block --- packages/editor/src/components/post-excerpt/panel.js | 1 + packages/editor/src/components/post-excerpt/style.scss | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/packages/editor/src/components/post-excerpt/panel.js b/packages/editor/src/components/post-excerpt/panel.js index 09e4e76cc9a0cd..36646e07b4ce8b 100644 --- a/packages/editor/src/components/post-excerpt/panel.js +++ b/packages/editor/src/components/post-excerpt/panel.js @@ -187,6 +187,7 @@ function PrivateExcerpt() { : __( 'Edit excerpt' ); return (