Skip to content

Commit 9a331f1

Browse files
youknowriadellatrixntsekourasoandregal
authored
Patterns: Avoid mapping template parts objects to patterns (#62927)
Co-authored-by: youknowriad <[email protected]> Co-authored-by: ellatrix <[email protected]> Co-authored-by: ntsekouras <[email protected]> Co-authored-by: oandregal <[email protected]>
1 parent 15da2aa commit 9a331f1

File tree

6 files changed

+57
-72
lines changed

6 files changed

+57
-72
lines changed

packages/edit-site/src/components/page-patterns/index.js

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ import { usePrevious } from '@wordpress/compose';
3030
import { useEntityRecords } from '@wordpress/core-data';
3131
import { privateApis as editorPrivateApis } from '@wordpress/editor';
3232
import { privateApis as routerPrivateApis } from '@wordpress/router';
33+
import { parse } from '@wordpress/blocks';
34+
import { decodeEntities } from '@wordpress/html-entities';
3335

3436
/**
3537
* Internal dependencies
@@ -53,6 +55,7 @@ import PatternsHeader from './header';
5355
import { useLink } from '../routes/link';
5456
import { useAddedBy } from '../page-templates/hooks';
5557
import { useEditPostAction } from '../dataviews-actions';
58+
import { defaultGetTitle } from './search-items';
5659

5760
const { ExperimentalBlockEditorProvider, useGlobalStyle } = unlock(
5861
blockEditorPrivateApis
@@ -116,14 +119,21 @@ function Preview( { item, viewType } ) {
116119
const descriptionId = useId();
117120
const isUserPattern = item.type === PATTERN_TYPES.user;
118121
const isTemplatePart = item.type === TEMPLATE_PART_POST_TYPE;
119-
const isEmpty = ! item.blocks?.length;
120-
121122
const [ backgroundColor ] = useGlobalStyle( 'color.background' );
122123
const { onClick } = useLink( {
123124
postType: item.type,
124-
postId: isUserPattern ? item.id : item.name,
125+
postId: isUserPattern || isTemplatePart ? item.id : item.name,
125126
canvas: 'edit',
126127
} );
128+
const blocks = useMemo( () => {
129+
return (
130+
item.blocks ??
131+
parse( item.content.raw, {
132+
__unstableSkipMigrationLogs: true,
133+
} )
134+
);
135+
}, [ item?.content?.raw, item.blocks ] );
136+
const isEmpty = ! blocks?.length;
127137

128138
return (
129139
<div
@@ -140,7 +150,7 @@ function Preview( { item, viewType } ) {
140150
{ ! isEmpty && (
141151
<Async>
142152
<BlockPreview
143-
blocks={ item.blocks }
153+
blocks={ blocks }
144154
viewportWidth={ item.viewportWidth }
145155
/>
146156
</Async>
@@ -187,11 +197,13 @@ function Author( { item, viewType } ) {
187197

188198
function Title( { item } ) {
189199
const isUserPattern = item.type === PATTERN_TYPES.user;
200+
const isTemplatePart = item.type === TEMPLATE_PART_POST_TYPE;
190201
const { onClick } = useLink( {
191202
postType: item.type,
192-
postId: isUserPattern ? item.id : item.name,
203+
postId: isUserPattern || isTemplatePart ? item.id : item.name,
193204
canvas: 'edit',
194205
} );
206+
const title = decodeEntities( defaultGetTitle( item ) );
195207
return (
196208
<HStack alignment="center" justify="flex-start" spacing={ 2 }>
197209
<Flex
@@ -201,7 +213,7 @@ function Title( { item } ) {
201213
className="edit-site-patterns__pattern-title"
202214
>
203215
{ item.type === PATTERN_TYPES.theme ? (
204-
item.title
216+
title
205217
) : (
206218
<Button
207219
variant="link"
@@ -210,7 +222,7 @@ function Title( { item } ) {
210222
// See https://github.com/WordPress/gutenberg/pull/51898#discussion_r1243399243.
211223
tabIndex="-1"
212224
>
213-
{ item.title || item.name }
225+
{ title || item.name }
214226
</Button>
215227
) }
216228
</Flex>
@@ -321,7 +333,7 @@ export default function DataviewsPatterns() {
321333
_fields.push( {
322334
header: __( 'Author' ),
323335
id: 'author',
324-
getValue: ( { item } ) => item.templatePart.author_text,
336+
getValue: ( { item } ) => item.author_text,
325337
render: ( { item } ) => {
326338
return <Author viewType={ view.type } item={ item } />;
327339
},
@@ -406,7 +418,7 @@ export default function DataviewsPatterns() {
406418
fields={ fields }
407419
actions={ actions }
408420
data={ data || EMPTY_ARRAY }
409-
getItemId={ ( item ) => item.name }
421+
getItemId={ ( item ) => item.name ?? item.id }
410422
isLoading={ isResolving }
411423
view={ view }
412424
onChangeView={ onChangeView }

packages/edit-site/src/components/page-patterns/search-items.js

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,14 @@ import {
2020
PATTERN_DEFAULT_CATEGORY,
2121
PATTERN_USER_CATEGORY,
2222
PATTERN_TYPES,
23+
TEMPLATE_PART_POST_TYPE,
2324
} from '../../utils/constants';
2425

2526
// Default search helpers.
26-
const defaultGetName = ( item ) => item.name || '';
27-
const defaultGetTitle = ( item ) => item.title;
27+
const defaultGetName = ( item ) =>
28+
item.type !== TEMPLATE_PART_POST_TYPE ? item.name || '' : '';
29+
export const defaultGetTitle = ( item ) =>
30+
typeof item.title === 'string' ? item.title : item.title.rendered;
2831
const defaultGetDescription = ( item ) => item.description || '';
2932
const defaultGetKeywords = ( item ) => item.keywords || [];
3033
const defaultHasCategory = () => false;

packages/edit-site/src/components/page-patterns/use-patterns.js

Lines changed: 6 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import { parse } from '@wordpress/blocks';
55
import { useSelect, createSelector } from '@wordpress/data';
66
import { store as coreStore } from '@wordpress/core-data';
77
import { store as editorStore } from '@wordpress/editor';
8-
import { decodeEntities } from '@wordpress/html-entities';
98

109
/**
1110
* Internal dependencies
@@ -16,7 +15,6 @@ import {
1615
PATTERN_TYPES,
1716
PATTERN_SYNC_TYPES,
1817
TEMPLATE_PART_POST_TYPE,
19-
TEMPLATE_ORIGINS,
2018
TEMPLATE_PART_AREA_DEFAULT_CATEGORY,
2119
} from '../../utils/constants';
2220
import { unlock } from '../../lock-unlock';
@@ -25,38 +23,16 @@ import { store as editSiteStore } from '../../store';
2523

2624
const EMPTY_PATTERN_LIST = [];
2725

28-
const createTemplatePartId = ( theme, slug ) =>
29-
theme && slug ? theme + '//' + slug : null;
30-
31-
const templatePartToPattern = ( templatePart ) => ( {
32-
blocks: parse( templatePart.content.raw, {
33-
__unstableSkipMigrationLogs: true,
34-
} ),
35-
categories: [ templatePart.area ],
36-
description: templatePart.description || '',
37-
isCustom: templatePart.source === TEMPLATE_ORIGINS.custom,
38-
keywords: templatePart.keywords || [],
39-
id: createTemplatePartId( templatePart.theme, templatePart.slug ),
40-
name: createTemplatePartId( templatePart.theme, templatePart.slug ),
41-
title: decodeEntities( templatePart.title.rendered ),
42-
type: templatePart.type,
43-
_links: templatePart._links,
44-
templatePart,
45-
} );
46-
47-
const selectTemplatePartsAsPatterns = createSelector(
26+
const selectTemplateParts = createSelector(
4827
( select, categoryId, search = '' ) => {
4928
const { getEntityRecords, isResolving: isResolvingSelector } =
5029
select( coreStore );
5130
const { __experimentalGetDefaultTemplatePartAreas } =
5231
select( editorStore );
5332
const query = { per_page: -1 };
54-
const rawTemplateParts =
33+
const templateParts =
5534
getEntityRecords( 'postType', TEMPLATE_PART_POST_TYPE, query ) ??
5635
EMPTY_PATTERN_LIST;
57-
const templateParts = rawTemplateParts.map( ( templatePart ) =>
58-
templatePartToPattern( templatePart )
59-
);
6036

6137
// In the case where a custom template part area has been removed we need
6238
// the current list of areas to cross check against so orphaned template
@@ -66,12 +42,12 @@ const selectTemplatePartsAsPatterns = createSelector(
6642

6743
const templatePartHasCategory = ( item, category ) => {
6844
if ( category !== TEMPLATE_PART_AREA_DEFAULT_CATEGORY ) {
69-
return item.templatePart.area === category;
45+
return item.area === category;
7046
}
7147

7248
return (
73-
item.templatePart.area === category ||
74-
! templatePartAreas.includes( item.templatePart.area )
49+
item.area === category ||
50+
! templatePartAreas.includes( item.area )
7551
);
7652
};
7753

@@ -298,11 +274,7 @@ export const usePatterns = (
298274
return useSelect(
299275
( select ) => {
300276
if ( postType === TEMPLATE_PART_POST_TYPE ) {
301-
return selectTemplatePartsAsPatterns(
302-
select,
303-
categoryId,
304-
search
305-
);
277+
return selectTemplateParts( select, categoryId, search );
306278
} else if ( postType === PATTERN_TYPES.user && !! categoryId ) {
307279
const appliedCategory =
308280
categoryId === 'uncategorized' ? '' : categoryId;

packages/editor/src/components/post-actions/actions.js

Lines changed: 23 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import { __, _n, sprintf, _x } from '@wordpress/i18n';
1010
import { store as noticesStore } from '@wordpress/notices';
1111
import { useMemo, useState } from '@wordpress/element';
1212
import { privateApis as patternsPrivateApis } from '@wordpress/patterns';
13+
import { parse } from '@wordpress/blocks';
1314

1415
import {
1516
Button,
@@ -52,17 +53,17 @@ function isTemplateRemovable( template ) {
5253
// than the one returned from the endpoint. This is why we need to check for
5354
// two props whether is custom or has a theme file.
5455
return (
55-
[ template.source, template.templatePart?.source ].includes(
56-
TEMPLATE_ORIGINS.custom
57-
) &&
58-
! template.has_theme_file &&
59-
! template.templatePart?.has_theme_file
56+
template?.source === TEMPLATE_ORIGINS.custom &&
57+
! template?.has_theme_file
6058
);
6159
}
6260
const canDeleteOrReset = ( item ) => {
6361
const isTemplatePart = item.type === TEMPLATE_PART_POST_TYPE;
6462
const isUserPattern = item.type === PATTERN_TYPES.user;
65-
return isUserPattern || ( isTemplatePart && item.isCustom );
63+
return (
64+
isUserPattern ||
65+
( isTemplatePart && item.source === TEMPLATE_ORIGINS.custom )
66+
);
6667
};
6768

6869
function getItemTitle( item ) {
@@ -630,19 +631,13 @@ const renamePostAction = {
630631
// two props whether is custom or has a theme file.
631632
const isCustomPattern =
632633
isUserPattern ||
633-
( isTemplatePart &&
634-
( post.isCustom || post.source === TEMPLATE_ORIGINS.custom ) );
635-
const hasThemeFile =
636-
isTemplatePart &&
637-
( post.templatePart?.has_theme_file || post.has_theme_file );
634+
( isTemplatePart && post.source === TEMPLATE_ORIGINS.custom );
635+
const hasThemeFile = post?.has_theme_file;
638636
return isCustomPattern && ! hasThemeFile;
639637
},
640638
RenderModal: ( { items, closeModal, onActionPerformed } ) => {
641639
const [ item ] = items;
642-
const originalTitle = decodeEntities(
643-
typeof item.title === 'string' ? item.title : item.title.rendered
644-
);
645-
const [ title, setTitle ] = useState( () => originalTitle );
640+
const [ title, setTitle ] = useState( () => getItemTitle( item ) );
646641
const { editEntityRecord, saveEditedEntityRecord } =
647642
useDispatch( coreStore );
648643
const { createSuccessNotice, createErrorNotice } =
@@ -879,7 +874,7 @@ const isTemplatePartRevertable = ( item ) => {
879874
if ( ! item ) {
880875
return false;
881876
}
882-
const hasThemeFile = item.templatePart?.has_theme_file;
877+
const hasThemeFile = item?.has_theme_file;
883878
return canDeleteOrReset( item ) && hasThemeFile;
884879
};
885880

@@ -1031,26 +1026,34 @@ export const duplicateTemplatePartAction = {
10311026
modalHeader: _x( 'Duplicate template part', 'action label' ),
10321027
RenderModal: ( { items, closeModal } ) => {
10331028
const [ item ] = items;
1029+
const blocks = useMemo( () => {
1030+
return (
1031+
item.blocks ??
1032+
parse( item.content.raw, {
1033+
__unstableSkipMigrationLogs: true,
1034+
} )
1035+
);
1036+
}, [ item?.content?.raw, item.blocks ] );
10341037
const { createSuccessNotice } = useDispatch( noticesStore );
10351038
function onTemplatePartSuccess() {
10361039
createSuccessNotice(
10371040
sprintf(
10381041
// translators: %s: The new template part's title e.g. 'Call to action (copy)'.
10391042
__( '"%s" duplicated.' ),
1040-
item.title
1043+
getItemTitle( item )
10411044
),
10421045
{ type: 'snackbar', id: 'edit-site-patterns-success' }
10431046
);
10441047
closeModal();
10451048
}
10461049
return (
10471050
<CreateTemplatePartModalContents
1048-
blocks={ item.blocks }
1049-
defaultArea={ item.templatePart?.area || item.area }
1051+
blocks={ blocks }
1052+
defaultArea={ item.area }
10501053
defaultTitle={ sprintf(
10511054
/* translators: %s: Existing template part title */
10521055
__( '%s (Copy)' ),
1053-
item.title
1056+
getItemTitle( item )
10541057
) }
10551058
onCreate={ onTemplatePartSuccess }
10561059
onError={ closeModal }

packages/editor/src/store/private-actions.js

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -370,12 +370,7 @@ export const revertTemplate =
370370
export const removeTemplates =
371371
( items ) =>
372372
async ( { registry } ) => {
373-
const isResetting = items.every(
374-
( item ) =>
375-
!! item &&
376-
( item.has_theme_file ||
377-
( item.templatePart && item.templatePart.has_theme_file ) )
378-
);
373+
const isResetting = items.every( ( item ) => item?.has_theme_file );
379374

380375
const promiseResult = await Promise.allSettled(
381376
items.map( ( item ) => {

test/e2e/specs/site-editor/site-editor-url-navigation.spec.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ test.describe( 'Site editor url navigation', () => {
8181
.getByRole( 'region', {
8282
name: 'Patterns content',
8383
} )
84-
.getByLabel( 'header', { exact: true } )
84+
.getByText( 'header', { exact: true } )
8585
.click();
8686
await expect(
8787
page.getByRole( 'region', { name: 'Editor content' } )

0 commit comments

Comments
 (0)