Skip to content

Commit

Permalink
Editor: Update post excerpt panel with new designs (#60894)
Browse files Browse the repository at this point in the history
Co-authored-by: ntsekouras <[email protected]>
Co-authored-by: jameskoster <[email protected]>
Co-authored-by: youknowriad <[email protected]>
Co-authored-by: paulwilde <[email protected]>
  • Loading branch information
5 people authored Apr 25, 2024
1 parent 63d7f37 commit b17cc77
Show file tree
Hide file tree
Showing 14 changed files with 373 additions and 114 deletions.
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 /> }
<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 @@ -172,7 +171,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>
{ 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 ),
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

0 comments on commit b17cc77

Please sign in to comment.