Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Editor: Update post excerpt panel with new designs #60894

Merged
merged 10 commits into from
Apr 25, 2024
38 changes: 27 additions & 11 deletions packages/edit-post/src/components/sidebar/post-status/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,24 +28,39 @@ 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
*/
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 ) {
Expand All @@ -64,6 +79,7 @@ export default function PostStatus() {
<>
<PostStatusPanel />
<PostFeaturedImagePanel withPanelBody={ false } />
{ showPostExcerptPanel && <PrivatePostExcerptPanel /> }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe this check should probably move within the component itself like the other PostSomething components.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

// 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.

Do you think there is a better way by adding some kind of flag or something?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is the post excerpt rendered in different places depending on the post type?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Based on the designs: #59689 (comment). I think the main reason is that in the entities that we treat excerpt as a description feels better above in the card where we essentially describe the entity. In regular post types excerpt is more of part of the entity with a different functionality - describe the content.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are we really helping ourselves by creating these inconsistencies?

<PostSchedulePanel />
<PostTemplatePanel />
<PostURLPanel />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ import {
PluginDocumentSettingPanel,
PluginSidebar,
PostDiscussionPanel,
PostExcerptPanel,
PostLastRevisionPanel,
PostTaxonomiesPanel,
privateApis as editorPrivateApis,
Expand Down Expand Up @@ -130,7 +129,6 @@ const SidebarContent = ( { tabName, keyboardShortcut, isEditingTemplate } ) => {
<PluginDocumentSettingPanel.Slot />
<PostLastRevisionPanel />
<PostTaxonomiesPanel />
<PostExcerptPanel />
<PostDiscussionPanel />
<PageAttributesPanel />
<PatternOverridesPanel />
Expand Down
2 changes: 0 additions & 2 deletions packages/edit-site/src/components/sidebar-edit-mode/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ import { store as coreStore } from '@wordpress/core-data';
import {
PageAttributesPanel,
PostDiscussionPanel,
PostExcerptPanel,
PostLastRevisionPanel,
PostTaxonomiesPanel,
privateApis as editorPrivateApis,
Expand Down Expand Up @@ -100,7 +99,6 @@ const FillContents = ( { tabName, isEditingPage, supportsGlobalStyles } ) => {
{ isEditingPage ? <PagePanels /> : <TemplatePanel /> }
<PostLastRevisionPanel />
<PostTaxonomiesPanel />
<PostExcerptPanel />
<PostDiscussionPanel />
<PageAttributesPanel />
<PatternOverridesPanel />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -29,6 +33,7 @@ export default function PageSummary( {
{ ( fills ) => (
<>
<PostFeaturedImagePanel withPanelBody={ false } />
<PrivatePostExcerptPanel />
<PageStatus
status={ status }
date={ date }
Expand Down
8 changes: 7 additions & 1 deletion packages/editor/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -821,7 +821,13 @@ Undocumented declaration.

### PostExcerpt

Undocumented declaration.
Renders an editable textarea for the post excerpt. Templates, template parts and patterns use the `excerpt` field as a description semantically. Additionally templates and template parts override the `excerpt` field as `description` in REST API. So this component handles proper labeling and updating the edited entity.

_Parameters_

- _props_ `Object`: - Component props.
- _props.hideLabelFromVision_ `[boolean]`: - Whether to visually hide the textarea's label.
- _props.updateOnBlur_ `[boolean]`: - Whether to update the post on change or use local state and update on blur.

### PostExcerptCheck

Expand Down
93 changes: 50 additions & 43 deletions packages/editor/src/components/post-card-panel/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down Expand Up @@ -98,20 +111,14 @@ export default function PostCardPanel( { className, actions } ) {
{ actions }
</HStack>
<VStack className="editor-post-card-panel__content">
{ ( description ||
lastEditedText ||
showPostContentInfo ) && (
<VStack
className="editor-post-card-panel__description"
spacing={ 2 }
>
{ description && <Text>{ description }</Text> }
{ showPostContentInfo && <PostContentInfo /> }
{ lastEditedText && (
<Text>{ lastEditedText }</Text>
) }
</VStack>
) }
<VStack
className="editor-post-card-panel__description"
spacing={ 2 }
>
{ showPostExcerptPanel && <PrivatePostExcerptPanel /> }
{ showPostContentInfo && <PostContentInfo /> }
{ lastEditedText && <Text>{ lastEditedText }</Text> }
</VStack>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where is this rendered so I can test it? If I'm not wrong it's the top of the inspector no? I didn't see the excerpt there in my testing, so I'm missing something.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's in the top of the inspector yes, but for patterns, templates and template parts.

Then it will be shown if there is a description/excerpt and if it's a user create entity it will be editable too..

{ postType === TEMPLATE_POST_TYPE && <TemplateAreas /> }
</VStack>
</div>
Expand Down
18 changes: 0 additions & 18 deletions packages/editor/src/components/post-excerpt/check.js
Original file line number Diff line number Diff line change
@@ -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.
Expand All @@ -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 (
<PostTypeSupportCheck supportKeys="excerpt">
{ children }
Expand Down
81 changes: 66 additions & 15 deletions packages/editor/src/components/post-excerpt/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,37 +4,88 @@
import { __ } from '@wordpress/i18n';
import { ExternalLink, TextareaControl } from '@wordpress/components';
import { useDispatch, useSelect } from '@wordpress/data';
import { useState } from '@wordpress/element';

/**
* Internal dependencies
*/
import { store as editorStore } from '../../store';

function PostExcerpt() {
const excerpt = useSelect(
( select ) => select( editorStore ).getEditedPostAttribute( 'excerpt' ),
/**
* Renders an editable textarea for the post excerpt.
* Templates, template parts and patterns use the `excerpt` field as a description semantically.
* Additionally templates and template parts override the `excerpt` field as `description` in
* REST API. So this component handles proper labeling and updating the edited entity.
*
* @param {Object} props - Component props.
* @param {boolean} [props.hideLabelFromVision=false] - Whether to visually hide the textarea's label.
* @param {boolean} [props.updateOnBlur=false] - Whether to update the post on change or use local state and update on blur.
*/
export default function PostExcerpt( {
hideLabelFromVision = false,
updateOnBlur = 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 ),
youknowriad marked this conversation as resolved.
Show resolved Hide resolved
usedAttribute: _usedAttribute,
};
},
[]
);
const { editPost } = useDispatch( editorStore );
const [ localExcerpt, setLocalExcerpt ] = useState( excerpt );
const updatePost = ( value ) => {
editPost( { [ usedAttribute ]: value } );
};
const label = shouldUseDescriptionLabel
? __( 'Write a description (optional)' )
: __( 'Write an excerpt (optional)' );

return (
<div className="editor-post-excerpt">
<TextareaControl
__nextHasNoMarginBottom
label={ __( 'Write an excerpt (optional)' ) }
label={ label }
hideLabelFromVision={ hideLabelFromVision }
className="editor-post-excerpt__textarea"
onChange={ ( value ) => editPost( { excerpt: value } ) }
value={ excerpt }
onChange={ updateOnBlur ? setLocalExcerpt : updatePost }
onBlur={
updateOnBlur ? () => updatePost( localExcerpt ) : undefined
}
value={ updateOnBlur ? localExcerpt : excerpt }
help={
! shouldUseDescriptionLabel ? (
<ExternalLink
href={ __(
'https://wordpress.org/documentation/article/page-post-settings-sidebar/#excerpt'
) }
>
{ __( 'Learn more about manual excerpts' ) }
</ExternalLink>
) : (
__( 'Write a description' )
)
}
/>
<ExternalLink
href={ __(
'https://wordpress.org/documentation/article/page-post-settings-sidebar/#excerpt'
) }
>
{ __( 'Learn more about manual excerpts' ) }
</ExternalLink>
</div>
);
}

export default PostExcerpt;
Loading
Loading