Skip to content

Commit

Permalink
Patterns: Add user categories to site editor sidebar navigation screen (
Browse files Browse the repository at this point in the history
#53837)

Co-authored-by: Aaron Robertshaw <60436221+aaronrobertshaw@users.noreply.github.com>
  • Loading branch information
glendaviesnz and aaronrobertshaw committed Sep 14, 2023
1 parent 1ad421b commit 359d1da
Show file tree
Hide file tree
Showing 10 changed files with 182 additions and 130 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -11,19 +11,14 @@ import { privateApis as routerPrivateApis } from '@wordpress/router';
/**
* Internal dependencies
*/
import {
TEMPLATE_PARTS,
PATTERNS,
SYNC_TYPES,
USER_PATTERNS,
USER_PATTERN_CATEGORY,
} from './utils';
import { TEMPLATE_PARTS, PATTERNS, SYNC_TYPES, USER_PATTERNS } from './utils';
import {
useExistingTemplateParts,
getUniqueTemplatePartTitle,
getCleanTemplatePartSlug,
} from '../../utils/template-part-create';
import { unlock } from '../../lock-unlock';
import usePatternCategories from '../sidebar-navigation-screen-patterns/use-pattern-categories';

const { useHistory } = unlock( routerPrivateApis );

Expand All @@ -32,11 +27,11 @@ function getPatternMeta( item ) {
return { wp_pattern_sync_status: SYNC_TYPES.unsynced };
}

const syncStatus = item.reusableBlock.wp_pattern_sync_status;
const syncStatus = item.patternBlock.wp_pattern_sync_status;
const isUnsynced = syncStatus === SYNC_TYPES.unsynced;

return {
...item.reusableBlock.meta,
...item.patternBlock.meta,
wp_pattern_sync_status: isUnsynced ? syncStatus : undefined,
};
}
Expand All @@ -47,12 +42,13 @@ export default function DuplicateMenuItem( {
label = __( 'Duplicate' ),
onClose,
} ) {
const { saveEntityRecord } = useDispatch( coreStore );
const { saveEntityRecord, invalidateResolution } = useDispatch( coreStore );
const { createErrorNotice, createSuccessNotice } =
useDispatch( noticesStore );

const history = useHistory();
const existingTemplateParts = useExistingTemplateParts();
const { patternCategories } = usePatternCategories();

async function createTemplatePart() {
try {
Expand Down Expand Up @@ -111,6 +107,45 @@ export default function DuplicateMenuItem( {
}
}

async function findOrCreateTerm( term ) {
try {
const newTerm = await saveEntityRecord(
'taxonomy',
'wp_pattern_category',
{
name: term.label,
slug: term.name,
description: term.description,
},
{
throwOnError: true,
}
);
invalidateResolution( 'getUserPatternCategories' );
return newTerm.id;
} catch ( error ) {
if ( error.code !== 'term_exists' ) {
throw error;
}

return error.data.term_id;
}
}

async function getCategories( categories ) {
const terms = categories.map( ( category ) => {
const fullCategory = patternCategories.find(
( cat ) => cat.name === category
);
if ( fullCategory.id ) {
return fullCategory.id;
}
return findOrCreateTerm( fullCategory );
} );

return Promise.all( terms );
}

async function createPattern() {
try {
const isThemePattern = item.type === PATTERNS;
Expand All @@ -119,17 +154,19 @@ export default function DuplicateMenuItem( {
__( '%s (Copy)' ),
item.title
);
const categories = await getCategories( item.categories );

const result = await saveEntityRecord(
'postType',
'wp_block',
{
content: isThemePattern
? item.content
: item.reusableBlock.content,
: item.patternBlock.content,
meta: getPatternMeta( item ),
status: 'publish',
title,
wp_pattern_category: categories,
},
{ throwOnError: true }
);
Expand All @@ -147,8 +184,8 @@ export default function DuplicateMenuItem( {
);

history.push( {
categoryType: USER_PATTERNS,
categoryId: USER_PATTERN_CATEGORY,
categoryType: PATTERNS,
categoryId,
postType: USER_PATTERNS,
postId: result?.id,
} );
Expand Down
15 changes: 7 additions & 8 deletions packages/edit-site/src/components/page-patterns/grid-item.js
Original file line number Diff line number Diff line change
Expand Up @@ -119,9 +119,12 @@ function GridItem( { categoryId, item, ...props } ) {
);
}

const itemIcon =
templatePartIcons[ categoryId ] ||
( item.syncStatus === SYNC_TYPES.full ? symbol : undefined );
let itemIcon;
if ( ! isUserPattern && templatePartIcons[ categoryId ] ) {
itemIcon = templatePartIcons[ categoryId ];
} else {
itemIcon = item.syncStatus === SYNC_TYPES.full ? symbol : undefined;
}

const confirmButtonText = hasThemeFile ? __( 'Clear' ) : __( 'Delete' );
const confirmPrompt = hasThemeFile
Expand Down Expand Up @@ -246,11 +249,7 @@ function GridItem( { categoryId, item, ...props } ) {
categoryId={ categoryId }
item={ item }
onClose={ onClose }
label={
isNonUserPattern
? __( 'Copy to My patterns' )
: __( 'Duplicate' )
}
label={ __( 'Duplicate' ) }
/>
{ isCustomPattern && (
<MenuItem
Expand Down
13 changes: 2 additions & 11 deletions packages/edit-site/src/components/page-patterns/header.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,14 @@ import {
__experimentalHeading as Heading,
__experimentalText as Text,
} from '@wordpress/components';
import { __ } from '@wordpress/i18n';
import { store as editorStore } from '@wordpress/editor';
import { useSelect } from '@wordpress/data';

/**
* Internal dependencies
*/
import usePatternCategories from '../sidebar-navigation-screen-patterns/use-pattern-categories';
import {
USER_PATTERN_CATEGORY,
USER_PATTERNS,
TEMPLATE_PARTS,
PATTERNS,
} from './utils';
import { TEMPLATE_PARTS, PATTERNS } from './utils';

export default function PatternsHeader( {
categoryId,
Expand All @@ -35,10 +29,7 @@ export default function PatternsHeader( {
);

let title, description;
if ( categoryId === USER_PATTERN_CATEGORY && type === USER_PATTERNS ) {
title = __( 'My Patterns' );
description = '';
} else if ( type === TEMPLATE_PARTS ) {
if ( type === TEMPLATE_PARTS ) {
const templatePartArea = templatePartAreas.find(
( area ) => area.area === categoryId
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ import usePatterns from './use-patterns';
import SidebarButton from '../sidebar-button';
import useDebouncedInput from '../../utils/use-debounced-input';
import { unlock } from '../../lock-unlock';
import { SYNC_TYPES, USER_PATTERN_CATEGORY, PATTERNS } from './utils';
import { SYNC_TYPES, PATTERNS } from './utils';
import Pagination from './pagination';

const { useLocation, useHistory } = unlock( routerPrivateApis );
Expand Down Expand Up @@ -155,7 +155,7 @@ export default function PatternsList( { categoryId, type } ) {
__nextHasNoMarginBottom
/>
</FlexBlock>
{ categoryId === USER_PATTERN_CATEGORY && (
{ type === PATTERNS && (
<ToggleGroupControl
className="edit-site-patterns__sync-status-filter"
hideLabelFromVision
Expand Down
14 changes: 12 additions & 2 deletions packages/edit-site/src/components/page-patterns/search-items.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,11 @@
import removeAccents from 'remove-accents';
import { noCase } from 'change-case';

/**
* Internal dependencies
*/
import { ALL_PATTERNS_CATEGORY } from './utils';

// Default search helpers.
const defaultGetName = ( item ) => item.name || '';
const defaultGetTitle = ( item ) => item.title;
Expand Down Expand Up @@ -84,7 +89,9 @@ const removeMatchingTerms = ( unmatchedTerms, unprocessedTerms ) => {
*/
export const searchItems = ( items = [], searchInput = '', config = {} ) => {
const normalizedSearchTerms = getNormalizedSearchTerms( searchInput );
const onlyFilterByCategory = ! normalizedSearchTerms.length;
const onlyFilterByCategory =
config.categoryId !== ALL_PATTERNS_CATEGORY &&
! normalizedSearchTerms.length;
const searchRankConfig = { ...config, onlyFilterByCategory };

// If we aren't filtering on search terms, matching on category is satisfactory.
Expand Down Expand Up @@ -131,7 +138,10 @@ function getItemSearchRank( item, searchTerm, config ) {
onlyFilterByCategory,
} = config;

let rank = hasCategory( item, categoryId ) ? 1 : 0;
let rank =
categoryId === ALL_PATTERNS_CATEGORY || hasCategory( item, categoryId )
? 1
: 0;

// If an item doesn't belong to the current category or we don't have
// search terms to filter by, return the initial rank value.
Expand Down
66 changes: 49 additions & 17 deletions packages/edit-site/src/components/page-patterns/use-patterns.js
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ const selectTemplatePartsAsPatterns = (
return { patterns, isResolving };
};

const selectThemePatterns = ( select, { categoryId, search = '' } = {} ) => {
const selectThemePatterns = ( select ) => {
const { getSettings } = unlock( select( editSiteStore ) );
const settings = getSettings();
const blockPatterns =
Expand All @@ -96,7 +96,7 @@ const selectThemePatterns = ( select, { categoryId, search = '' } = {} ) => {

const restBlockPatterns = select( coreStore ).getBlockPatterns();

let patterns = [
const patterns = [
...( blockPatterns || [] ),
...( restBlockPatterns || [] ),
]
Expand All @@ -114,6 +114,23 @@ const selectThemePatterns = ( select, { categoryId, search = '' } = {} ) => {
} ),
} ) );

return { patterns, isResolving: false };
};
const selectPatterns = (
select,
{ categoryId, search = '', syncStatus } = {}
) => {
const { patterns: themePatterns } = selectThemePatterns( select );
const { patterns: userPatterns } = selectUserPatterns( select );

let patterns = [ ...( themePatterns || [] ), ...( userPatterns || [] ) ];

if ( syncStatus ) {
patterns = patterns.filter(
( pattern ) => pattern.syncStatus === syncStatus
);
}

if ( categoryId ) {
patterns = searchItems( patterns, search, {
categoryId,
Expand All @@ -125,32 +142,43 @@ const selectThemePatterns = ( select, { categoryId, search = '' } = {} ) => {
hasCategory: ( item ) => ! item.hasOwnProperty( 'categories' ),
} );
}

return { patterns, isResolving: false };
};

const reusableBlockToPattern = ( reusableBlock ) => ( {
blocks: parse( reusableBlock.content.raw, {
const patternBlockToPattern = ( patternBlock, categories ) => ( {
blocks: parse( patternBlock.content.raw, {
__unstableSkipMigrationLogs: true,
} ),
categories: reusableBlock.wp_pattern,
id: reusableBlock.id,
name: reusableBlock.slug,
syncStatus: reusableBlock.wp_pattern_sync_status || SYNC_TYPES.full,
title: reusableBlock.title.raw,
type: reusableBlock.type,
reusableBlock,
...( patternBlock.wp_pattern_category.length > 0 && {
categories: patternBlock.wp_pattern_category.map(
( patternCategoryId ) =>
categories && categories.get( patternCategoryId )
? categories.get( patternCategoryId ).slug
: patternCategoryId
),
} ),
id: patternBlock.id,
name: patternBlock.slug,
syncStatus: patternBlock.wp_pattern_sync_status || SYNC_TYPES.full,
title: patternBlock.title.raw,
type: USER_PATTERNS,
patternBlock,
} );

const selectUserPatterns = ( select, { search = '', syncStatus } = {} ) => {
const { getEntityRecords, getIsResolving } = select( coreStore );
const { getEntityRecords, getIsResolving, getUserPatternCategories } =
select( coreStore );

const query = { per_page: -1 };
const records = getEntityRecords( 'postType', USER_PATTERNS, query );
const categories = getUserPatternCategories();

let patterns = records
? records.map( ( record ) => reusableBlockToPattern( record ) )
? records.map( ( record ) =>
patternBlockToPattern( record, categories.patternCategoriesMap )
)
: EMPTY_PATTERN_LIST;

const isResolving = getIsResolving( 'getEntityRecords', [
'postType',
USER_PATTERNS,
Expand All @@ -170,13 +198,13 @@ const selectUserPatterns = ( select, { search = '', syncStatus } = {} ) => {
hasCategory: () => true,
} );

return { patterns, isResolving };
return { patterns, isResolving, categories: categories.patternCategories };
};

export const usePatterns = (
categoryType,
categoryId,
{ search = '', syncStatus }
{ search = '', syncStatus } = {}
) => {
return useSelect(
( select ) => {
Expand All @@ -186,7 +214,11 @@ export const usePatterns = (
search,
} );
} else if ( categoryType === PATTERNS ) {
return selectThemePatterns( select, { categoryId, search } );
return selectPatterns( select, {
categoryId,
search,
syncStatus,
} );
} else if ( categoryType === USER_PATTERNS ) {
return selectUserPatterns( select, { search, syncStatus } );
}
Expand Down
5 changes: 3 additions & 2 deletions packages/edit-site/src/components/page-patterns/utils.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
export const DEFAULT_CATEGORY = 'my-patterns';
export const DEFAULT_TYPE = 'wp_block';
export const ALL_PATTERNS_CATEGORY = 'all-patterns';
export const DEFAULT_CATEGORY = ALL_PATTERNS_CATEGORY;
export const PATTERNS = 'pattern';
export const DEFAULT_TYPE = PATTERNS;
export const TEMPLATE_PARTS = 'wp_template_part';
export const USER_PATTERNS = 'wp_block';
export const USER_PATTERN_CATEGORY = 'my-patterns';
Expand Down
Loading

0 comments on commit 359d1da

Please sign in to comment.