diff --git a/packages/edit-site/src/components/page-patterns/index.js b/packages/edit-site/src/components/page-patterns/index.js index e9114e53184ccf..2fe8a543a8663b 100644 --- a/packages/edit-site/src/components/page-patterns/index.js +++ b/packages/edit-site/src/components/page-patterns/index.js @@ -117,6 +117,7 @@ function PreviewWrapper( { item, onClick, ariaDescribedBy, children } ) { function Preview( { item, viewType } ) { const descriptionId = useId(); + const description = item.description || item?.excerpt?.raw; const isUserPattern = item.type === PATTERN_TYPES.user; const isTemplatePart = item.type === TEMPLATE_PART_POST_TYPE; const [ backgroundColor ] = useGlobalStyle( 'color.background' ); @@ -143,7 +144,7 @@ function Preview( { item, viewType } ) { { isEmpty && isTemplatePart && __( 'Empty template part' ) } { isEmpty && ! isTemplatePart && __( 'Empty pattern' ) } @@ -156,9 +157,9 @@ function Preview( { item, viewType } ) { ) } - { item.description && ( + { !! description && ( ) } @@ -222,7 +223,7 @@ function Title( { item } ) { // See https://github.com/WordPress/gutenberg/pull/51898#discussion_r1243399243. tabIndex="-1" > - { title || item.name } + { title } ) } @@ -300,23 +301,20 @@ export default function DataviewsPatterns() { header: __( 'Sync status' ), id: 'sync-status', render: ( { item } ) => { + const syncStatus = + 'wp_pattern_sync_status' in item + ? item.wp_pattern_sync_status || + PATTERN_SYNC_TYPES.full + : PATTERN_SYNC_TYPES.unsynced; // User patterns can have their sync statuses checked directly. // Non-user patterns are all unsynced for the time being. return ( { - ( - SYNC_FILTERS.find( - ( { value } ) => - value === item.syncStatus - ) || - SYNC_FILTERS.find( - ( { value } ) => - value === - PATTERN_SYNC_TYPES.unsynced - ) + SYNC_FILTERS.find( + ( { value } ) => value === syncStatus ).label } diff --git a/packages/edit-site/src/components/page-patterns/search-items.js b/packages/edit-site/src/components/page-patterns/search-items.js index 64565d951e833f..1d03400c86c8cc 100644 --- a/packages/edit-site/src/components/page-patterns/search-items.js +++ b/packages/edit-site/src/components/page-patterns/search-items.js @@ -24,11 +24,42 @@ import { } from '../../utils/constants'; // Default search helpers. -const defaultGetName = ( item ) => - item.type !== TEMPLATE_PART_POST_TYPE ? item.name || '' : ''; -export const defaultGetTitle = ( item ) => - typeof item.title === 'string' ? item.title : item.title.rendered; -const defaultGetDescription = ( item ) => item.description || ''; +const defaultGetName = ( item ) => { + if ( item.type === PATTERN_TYPES.user ) { + return item.slug; + } + + if ( item.type === TEMPLATE_PART_POST_TYPE ) { + return ''; + } + + return item.name || ''; +}; + +export const defaultGetTitle = ( item ) => { + if ( typeof item.title === 'string' ) { + return item.title; + } + + if ( item.title && item.title.rendered ) { + return item.title.rendered; + } + + if ( item.title && item.title.raw ) { + return item.title.raw; + } + + return ''; +}; + +const defaultGetDescription = ( item ) => { + if ( item.type === PATTERN_TYPES.user ) { + return item.excerpt.raw; + } + + return item.description || ''; +}; + const defaultGetKeywords = ( item ) => item.keywords || []; const defaultHasCategory = () => false; diff --git a/packages/edit-site/src/components/page-patterns/use-patterns.js b/packages/edit-site/src/components/page-patterns/use-patterns.js index dc5a92b560537d..ecbc6adee75587 100644 --- a/packages/edit-site/src/components/page-patterns/use-patterns.js +++ b/packages/edit-site/src/components/page-patterns/use-patterns.js @@ -128,8 +128,11 @@ const selectPatterns = createSelector( patterns: themePatterns, isResolving: isResolvingThemePatterns, } = selectThemePatterns( select ); - const { patterns: userPatterns, isResolving: isResolvingUserPatterns } = - selectUserPatterns( select ); + const { + patterns: userPatterns, + isResolving: isResolvingUserPatterns, + categories: userPatternCategories, + } = selectUserPatterns( select ); let patterns = [ ...( themePatterns || [] ), @@ -141,7 +144,8 @@ const selectPatterns = createSelector( // Non-user patterns are all unsynced for the time being. patterns = patterns.filter( ( pattern ) => { return pattern.type === PATTERN_TYPES.user - ? pattern.syncStatus === syncStatus + ? ( pattern.wp_pattern_sync_status || + PATTERN_SYNC_TYPES.full ) === syncStatus : syncStatus === PATTERN_SYNC_TYPES.unsynced; } ); } @@ -149,12 +153,35 @@ const selectPatterns = createSelector( if ( categoryId ) { patterns = searchItems( patterns, search, { categoryId, - hasCategory: ( item, currentCategory ) => - item.categories?.includes( currentCategory ), + hasCategory: ( item, currentCategory ) => { + if ( item.type === PATTERN_TYPES.user ) { + return item.wp_pattern_category.some( + ( catId ) => + userPatternCategories.find( + ( cat ) => cat.id === catId + )?.slug === currentCategory + ); + } + return item.categories?.includes( currentCategory ); + }, } ); } else { patterns = searchItems( patterns, search, { - hasCategory: ( item ) => ! item.hasOwnProperty( 'categories' ), + hasCategory: ( item ) => { + if ( item.type === PATTERN_TYPES.user ) { + return ( + userPatternCategories?.length && + ( ! item.wp_pattern_category?.length || + ! item.wp_pattern_category.some( ( catId ) => + userPatternCategories.find( + ( cat ) => cat.id === catId + ) + ) ) + ); + } + + return ! item.hasOwnProperty( 'categories' ); + }, } ); } return { @@ -168,41 +195,6 @@ const selectPatterns = createSelector( ] ); -/** - * Converts a post of type `wp_block` to a 'pattern item' that more closely - * matches the structure of theme provided patterns. - * - * @param {Object} patternPost The `wp_block` record being normalized. - * @param {Map} categories A Map of user created categories. - * - * @return {Object} The normalized item. - */ -const convertPatternPostToItem = ( patternPost, categories ) => ( { - blocks: parse( patternPost.content.raw, { - __unstableSkipMigrationLogs: true, - } ), - ...( patternPost.wp_pattern_category.length > 0 && { - categories: patternPost.wp_pattern_category.map( - ( patternCategoryId ) => - categories && categories.get( patternCategoryId ) - ? categories.get( patternCategoryId ).slug - : patternCategoryId - ), - } ), - termLabels: patternPost.wp_pattern_category.map( ( patternCategoryId ) => - categories?.get( patternCategoryId ) - ? categories.get( patternCategoryId ).label - : patternCategoryId - ), - id: patternPost.id, - name: patternPost.slug, - syncStatus: patternPost.wp_pattern_sync_status || PATTERN_SYNC_TYPES.full, - title: patternPost.title.raw, - type: patternPost.type, - description: patternPost.excerpt.raw, - patternPost, -} ); - const selectUserPatterns = createSelector( ( select, syncStatus, search = '' ) => { const { @@ -222,12 +214,7 @@ const selectUserPatterns = createSelector( userPatternCategories.forEach( ( userCategory ) => categories.set( userCategory.id, userCategory ) ); - let patterns = patternPosts - ? patternPosts.map( ( record ) => - convertPatternPostToItem( record, categories ) - ) - : EMPTY_PATTERN_LIST; - + let patterns = patternPosts ?? EMPTY_PATTERN_LIST; const isResolving = isResolvingSelector( 'getEntityRecords', [ 'postType', PATTERN_TYPES.user, @@ -236,7 +223,9 @@ const selectUserPatterns = createSelector( if ( syncStatus ) { patterns = patterns.filter( - ( pattern ) => pattern.syncStatus === syncStatus + ( pattern ) => + pattern.wp_pattern_sync_status || + PATTERN_SYNC_TYPES.full === syncStatus ); } diff --git a/packages/edit-site/src/components/sidebar-navigation-screen-patterns/use-pattern-categories.js b/packages/edit-site/src/components/sidebar-navigation-screen-patterns/use-pattern-categories.js index 4d80d838ae90d5..a41e0ea7660616 100644 --- a/packages/edit-site/src/components/sidebar-navigation-screen-patterns/use-pattern-categories.js +++ b/packages/edit-site/src/components/sidebar-navigation-screen-patterns/use-pattern-categories.js @@ -58,13 +58,21 @@ export default function usePatternCategories() { // Update the category counts to reflect user registered patterns. userPatterns.forEach( ( pattern ) => { - pattern.categories?.forEach( ( category ) => { + pattern.wp_pattern_category?.forEach( ( catId ) => { + const category = userPatternCategories.find( + ( cat ) => cat.id === catId + )?.name; if ( categoryMap[ category ] ) { categoryMap[ category ].count += 1; } } ); // If the pattern has no categories, add it to uncategorized. - if ( ! pattern.categories?.length ) { + if ( + ! pattern.wp_pattern_category?.length || + ! pattern.wp_pattern_category.some( ( catId ) => + userPatternCategories.find( ( cat ) => cat.id === catId ) + ) + ) { categoryMap.uncategorized.count += 1; } } ); diff --git a/packages/editor/src/components/post-actions/actions.js b/packages/editor/src/components/post-actions/actions.js index 8050999e8a71bc..c750c202e76fe4 100644 --- a/packages/editor/src/components/post-actions/actions.js +++ b/packages/editor/src/components/post-actions/actions.js @@ -33,6 +33,7 @@ import { store as editorStore } from '../../store'; import { unlock } from '../../lock-unlock'; import { exportPatternAsJSONAction } from './export-pattern-action'; import { CreateTemplatePartModalContents } from '../create-template-part-modal'; +import { getItemTitle } from '../../dataviews/actions/utils'; // Patterns. const { PATTERN_TYPES, CreatePatternModalContents, useDuplicatePatternProps } = @@ -72,13 +73,6 @@ function isTemplateRemovable( template ) { ); } -function getItemTitle( item ) { - if ( typeof item.title === 'string' ) { - return decodeEntities( item.title ); - } - return decodeEntities( item.title?.rendered || '' ); -} - const trashPostAction = { id: 'move-to-trash', label: __( 'Move to Trash' ), @@ -805,10 +799,8 @@ export const duplicatePatternAction = { modalHeader: _x( 'Duplicate pattern', 'action label' ), RenderModal: ( { items, closeModal } ) => { const [ item ] = items; - const isThemePattern = item.type === PATTERN_TYPES.theme; const duplicatedProps = useDuplicatePatternProps( { - pattern: - isThemePattern || ! item.patternPost ? item : item.patternPost, + pattern: item, onSuccess: () => closeModal(), } ); return ( diff --git a/packages/editor/src/components/post-actions/export-pattern-action.js b/packages/editor/src/components/post-actions/export-pattern-action.js index deeac4314f653f..959cfe1a4abc7b 100644 --- a/packages/editor/src/components/post-actions/export-pattern-action.js +++ b/packages/editor/src/components/post-actions/export-pattern-action.js @@ -15,6 +15,7 @@ import { privateApis as patternsPrivateApis } from '@wordpress/patterns'; * Internal dependencies */ import { unlock } from '../../lock-unlock'; +import { getItemTitle } from '../../dataviews/actions/utils'; // Patterns. const { PATTERN_TYPES } = unlock( patternsPrivateApis ); @@ -23,9 +24,9 @@ function getJsonFromItem( item ) { return JSON.stringify( { __file: item.type, - title: item.title || item.name, - content: item.patternPost.content.raw, - syncStatus: item.patternPost.wp_pattern_sync_status, + title: getItemTitle( item ), + content: item.content.raw, + syncStatus: item.wp_pattern_sync_status, }, null, 2 @@ -45,14 +46,16 @@ export const exportPatternAsJSONAction = { callback: async ( items ) => { if ( items.length === 1 ) { return downloadBlob( - `${ kebabCase( items[ 0 ].title || items[ 0 ].name ) }.json`, + `${ kebabCase( + getItemTitle( items[ 0 ] ) || items[ 0 ].slug + ) }.json`, getJsonFromItem( items[ 0 ] ), 'application/json' ); } const nameCount = {}; const filesToZip = items.map( ( item ) => { - const name = kebabCase( item.title || item.name ); + const name = kebabCase( getItemTitle( item ) || item.slug ); nameCount[ name ] = ( nameCount[ name ] || 0 ) + 1; return { name: `${ diff --git a/packages/editor/src/dataviews/actions/utils.ts b/packages/editor/src/dataviews/actions/utils.ts index efbb7c590e6510..56c8c9f54c8507 100644 --- a/packages/editor/src/dataviews/actions/utils.ts +++ b/packages/editor/src/dataviews/actions/utils.ts @@ -24,7 +24,13 @@ export function getItemTitle( item: Post ) { if ( typeof item.title === 'string' ) { return decodeEntities( item.title ); } - return decodeEntities( item.title?.rendered || '' ); + if ( 'rendered' in item.title ) { + return decodeEntities( item.title.rendered ); + } + if ( 'raw' in item.title ) { + return decodeEntities( item.title.raw ); + } + return ''; } /** diff --git a/packages/editor/src/dataviews/types.ts b/packages/editor/src/dataviews/types.ts index 29f4358456324d..3d8906284a5971 100644 --- a/packages/editor/src/dataviews/types.ts +++ b/packages/editor/src/dataviews/types.ts @@ -9,7 +9,7 @@ type PostStatus = export interface BasePost { status?: PostStatus; - title: string | { rendered: string }; + title: string | { rendered: string } | { raw: string }; type: string; id: string | number; }