diff --git a/packages/edit-site/src/components/page-patterns/grid-item.js b/packages/edit-site/src/components/page-patterns/grid-item.js
index 7f40fbce9035cf..d8e3b2fe16d532 100644
--- a/packages/edit-site/src/components/page-patterns/grid-item.js
+++ b/packages/edit-site/src/components/page-patterns/grid-item.js
@@ -18,13 +18,14 @@ import {
Flex,
} from '@wordpress/components';
import { useDispatch } from '@wordpress/data';
-import { useState, useId } from '@wordpress/element';
+import { useState, useId, memo } from '@wordpress/element';
import { __, sprintf } from '@wordpress/i18n';
import {
Icon,
header,
footer,
symbolFilled as uncategorized,
+ symbol,
moreHorizontal,
lockSmall,
} from '@wordpress/icons';
@@ -37,13 +38,13 @@ import { DELETE, BACKSPACE } from '@wordpress/keycodes';
*/
import RenameMenuItem from './rename-menu-item';
import DuplicateMenuItem from './duplicate-menu-item';
-import { PATTERNS, TEMPLATE_PARTS, USER_PATTERNS } from './utils';
+import { PATTERNS, TEMPLATE_PARTS, USER_PATTERNS, SYNC_TYPES } from './utils';
import { store as editSiteStore } from '../../store';
import { useLink } from '../routes/link';
const templatePartIcons = { header, footer, uncategorized };
-export default function GridItem( { categoryId, composite, icon, item } ) {
+function GridItem( { categoryId, item, ...props } ) {
const descriptionId = useId();
const [ isDeleteDialogOpen, setIsDeleteDialogOpen ] = useState( false );
@@ -122,9 +123,9 @@ export default function GridItem( { categoryId, composite, icon, item } ) {
ariaDescriptions.push( __( 'Theme patterns cannot be edited.' ) );
}
- const itemIcon = templatePartIcons[ categoryId ]
- ? templatePartIcons[ categoryId ]
- : icon;
+ const itemIcon =
+ templatePartIcons[ categoryId ] ||
+ ( item.syncStatus === SYNC_TYPES.full ? symbol : undefined );
const confirmButtonText = hasThemeFile ? __( 'Clear' ) : __( 'Delete' );
const confirmPrompt = hasThemeFile
@@ -142,7 +143,10 @@ export default function GridItem( { categoryId, composite, icon, item } ) {
className={ previewClassNames }
role="option"
as="div"
- { ...composite }
+ // Even though still incomplete, passing ids helps performance.
+ // @see https://reakit.io/docs/composite/#performance.
+ id={ `edit-site-patterns-${ item.name }` }
+ { ...props }
onClick={ item.type !== PATTERNS ? onClick : undefined }
onKeyDown={ isCustomPattern ? onKeyDown : undefined }
aria-label={ item.title }
@@ -180,7 +184,7 @@ export default function GridItem( { categoryId, composite, icon, item } ) {
spacing={ 3 }
className="edit-site-patterns__pattern-title"
>
- { icon && (
+ { itemIcon && (
);
}
+
+export default memo( GridItem );
diff --git a/packages/edit-site/src/components/page-patterns/grid.js b/packages/edit-site/src/components/page-patterns/grid.js
index 3f6e5fd01f72fe..b9b7053c112ce6 100644
--- a/packages/edit-site/src/components/page-patterns/grid.js
+++ b/packages/edit-site/src/components/page-patterns/grid.js
@@ -4,36 +4,56 @@
import {
__unstableComposite as Composite,
__unstableUseCompositeState as useCompositeState,
+ __experimentalText as Text,
} from '@wordpress/components';
+import { useRef } from '@wordpress/element';
+import { __, sprintf } from '@wordpress/i18n';
/**
* Internal dependencies
*/
import GridItem from './grid-item';
-export default function Grid( { categoryId, label, icon, items } ) {
- const composite = useCompositeState( { orientation: 'vertical' } );
+const PAGE_SIZE = 100;
+
+export default function Grid( { categoryId, items, ...props } ) {
+ const composite = useCompositeState( { wrap: true } );
+ const gridRef = useRef();
if ( ! items?.length ) {
return null;
}
+ const list = items.slice( 0, PAGE_SIZE );
+ const restLength = items.length - PAGE_SIZE;
+
return (
-
- { items.map( ( item ) => (
-
- ) ) }
-
+ <>
+
+ { list.map( ( item ) => (
+
+ ) ) }
+
+ { restLength > 0 && (
+
+ { sprintf(
+ /* translators: %d: number of patterns */
+ __( '+ %d more patterns discoverable by searching' ),
+ restLength
+ ) }
+
+ ) }
+ >
);
}
diff --git a/packages/edit-site/src/components/page-patterns/header.js b/packages/edit-site/src/components/page-patterns/header.js
new file mode 100644
index 00000000000000..1237b85d6c9787
--- /dev/null
+++ b/packages/edit-site/src/components/page-patterns/header.js
@@ -0,0 +1,69 @@
+/**
+ * WordPress dependencies
+ */
+import {
+ __experimentalVStack as VStack,
+ __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';
+
+export default function PatternsHeader( {
+ categoryId,
+ type,
+ titleId,
+ descriptionId,
+} ) {
+ const { patternCategories } = usePatternCategories();
+ const templatePartAreas = useSelect(
+ ( select ) =>
+ select( editorStore ).__experimentalGetDefaultTemplatePartAreas(),
+ []
+ );
+
+ let title, description;
+ if ( categoryId === USER_PATTERN_CATEGORY && type === USER_PATTERNS ) {
+ title = __( 'My Patterns' );
+ description = '';
+ } else if ( type === TEMPLATE_PARTS ) {
+ const templatePartArea = templatePartAreas.find(
+ ( area ) => area.area === categoryId
+ );
+ title = templatePartArea?.label;
+ description = templatePartArea?.description;
+ } else if ( type === PATTERNS ) {
+ const patternCategory = patternCategories.find(
+ ( category ) => category.name === categoryId
+ );
+ title = patternCategory?.label;
+ description = patternCategory?.description;
+ }
+
+ if ( ! title ) return null;
+
+ return (
+
+
+ { title }
+
+ { description ? (
+
+ { description }
+
+ ) : null }
+
+ );
+}
diff --git a/packages/edit-site/src/components/page-patterns/index.js b/packages/edit-site/src/components/page-patterns/index.js
index 961ed51f39e5d6..d90fc748442444 100644
--- a/packages/edit-site/src/components/page-patterns/index.js
+++ b/packages/edit-site/src/components/page-patterns/index.js
@@ -32,7 +32,12 @@ export default function PagePatterns() {
title={ __( 'Patterns content' ) }
hideTitleFromUI
>
-
+
);
diff --git a/packages/edit-site/src/components/page-patterns/patterns-list.js b/packages/edit-site/src/components/page-patterns/patterns-list.js
index d59596f20e7952..bc2a18bf394567 100644
--- a/packages/edit-site/src/components/page-patterns/patterns-list.js
+++ b/packages/edit-site/src/components/page-patterns/patterns-list.js
@@ -1,51 +1,87 @@
/**
* WordPress dependencies
*/
-
+import { useState, useDeferredValue, useId } from '@wordpress/element';
import {
SearchControl,
- __experimentalHeading as Heading,
- __experimentalText as Text,
__experimentalVStack as VStack,
Flex,
FlexBlock,
+ __experimentalToggleGroupControl as ToggleGroupControl,
+ __experimentalToggleGroupControlOption as ToggleGroupControlOption,
+ __experimentalHeading as Heading,
+ __experimentalText as Text,
} from '@wordpress/components';
import { __, isRTL } from '@wordpress/i18n';
-import { symbol, chevronLeft, chevronRight } from '@wordpress/icons';
+import { chevronLeft, chevronRight } from '@wordpress/icons';
import { privateApis as routerPrivateApis } from '@wordpress/router';
-import { useViewportMatch } from '@wordpress/compose';
+import { useViewportMatch, useAsyncList } from '@wordpress/compose';
/**
* Internal dependencies
*/
+import PatternsHeader from './header';
import Grid from './grid';
import NoPatterns from './no-patterns';
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 } from './utils';
const { useLocation, useHistory } = unlock( routerPrivateApis );
+const SYNC_FILTERS = {
+ all: __( 'All' ),
+ [ SYNC_TYPES.full ]: __( 'Synced' ),
+ [ SYNC_TYPES.unsynced ]: __( 'Standard' ),
+};
+
+const SYNC_DESCRIPTIONS = {
+ all: '',
+ [ SYNC_TYPES.full ]: __(
+ 'Patterns that are kept in sync across your site.'
+ ),
+ [ SYNC_TYPES.unsynced ]: __(
+ 'Patterns that can be changed freely without affecting your site.'
+ ),
+};
+
export default function PatternsList( { categoryId, type } ) {
const location = useLocation();
const history = useHistory();
const isMobileViewport = useViewportMatch( 'medium', '<' );
const [ filterValue, setFilterValue, delayedFilterValue ] =
useDebouncedInput( '' );
+ const deferredFilterValue = useDeferredValue( delayedFilterValue );
- const [ patterns, isResolving ] = usePatterns(
- type,
- categoryId,
- delayedFilterValue
- );
+ const [ syncFilter, setSyncFilter ] = useState( 'all' );
+ const deferredSyncedFilter = useDeferredValue( syncFilter );
+ const { patterns, isResolving } = usePatterns( type, categoryId, {
+ search: deferredFilterValue,
+ syncStatus:
+ deferredSyncedFilter === 'all' ? undefined : deferredSyncedFilter,
+ } );
- const { syncedPatterns, unsyncedPatterns } = patterns;
- const hasPatterns = !! syncedPatterns.length || !! unsyncedPatterns.length;
+ const id = useId();
+ const titleId = `${ id }-title`;
+ const descriptionId = `${ id }-description`;
+
+ const hasPatterns = patterns.length;
+ const title = SYNC_FILTERS[ syncFilter ];
+ const description = SYNC_DESCRIPTIONS[ syncFilter ];
+ const shownPatterns = useAsyncList( patterns );
return (
-
+
+
+
{ isMobileViewport && (
) }
-
+
setFilterValue( value ) }
@@ -71,46 +107,48 @@ export default function PatternsList( { categoryId, type } ) {
__nextHasNoMarginBottom
/>
+ { categoryId === USER_PATTERN_CATEGORY && (
+ setSyncFilter( value ) }
+ __nextHasNoMarginBottom
+ >
+ { Object.entries( SYNC_FILTERS ).map(
+ ( [ key, label ] ) => (
+
+ )
+ ) }
+
+ ) }
- { isResolving && __( 'Loading' ) }
- { ! isResolving && !! syncedPatterns.length && (
- <>
-
-
- { __( 'Synced' ) }
-
-
- { __(
- 'Patterns that are kept in sync across the site'
- ) }
+ { syncFilter !== 'all' && (
+
+
+ { title }
+
+ { description ? (
+
+ { description }
-
-
- >
+ ) : null }
+
) }
- { ! isResolving && !! unsyncedPatterns.length && (
- <>
-
-
- { __( 'Standard' ) }
-
-
- { __(
- 'Patterns that can be changed freely without affecting the site'
- ) }
-
-
-
- >
+ { hasPatterns && (
+
) }
{ ! isResolving && ! hasPatterns && }
diff --git a/packages/edit-site/src/components/page-patterns/style.scss b/packages/edit-site/src/components/page-patterns/style.scss
index 7a7bf026b9c625..64dcb61ac1a74d 100644
--- a/packages/edit-site/src/components/page-patterns/style.scss
+++ b/packages/edit-site/src/components/page-patterns/style.scss
@@ -1,6 +1,13 @@
.edit-site-patterns {
- background: rgba(0, 0, 0, 0.05);
+ background: rgba(0, 0, 0, 0.15);
margin: $header-height 0 0;
+ .components-base-control {
+ width: 100%;
+ @include break-medium {
+ width: auto;
+ }
+ }
+
.components-text {
color: $gray-600;
}
@@ -12,25 +19,63 @@
@include break-medium {
margin: 0;
}
-}
-.edit-site-patterns__grid {
- column-gap: $grid-unit-30;
- @include break-large() {
- column-count: 2;
+ .edit-site-patterns__search-block {
+ min-width: fit-content;
+ flex-grow: 1;
}
+ // The increased specificity here is to overcome component styles
+ // without relying on internal component class names.
+ .edit-site-patterns__search {
+ input[type="search"] {
+ height: $button-size-next-default-40px;
+ background: $gray-800;
+ color: $gray-200;
+
+ &:focus {
+ background: $gray-800;
+ }
+ }
+
+ svg {
+ fill: $gray-600;
+ }
+ }
+
+ .edit-site-patterns__sync-status-filter {
+ background: $gray-800;
+ border: none;
+ height: $button-size-next-default-40px;
+ min-width: max-content;
+ width: 100%;
+ max-width: 100%;
+
+ @include break-medium {
+ width: 300px;
+ }
+ }
+ .edit-site-patterns__sync-status-filter-option:active {
+ background: $gray-700;
+ color: $gray-100;
+ }
+}
+
+.edit-site-patterns__grid {
+ display: grid;
+ grid-template-columns: 1fr;
+ gap: $grid-unit-40;
// Small top padding required to avoid cutting off the visible outline
// when hovering items.
padding-top: $border-width-focus-fallback;
margin-bottom: $grid-unit-40;
-
+ @include break-large {
+ grid-template-columns: 1fr 1fr;
+ }
.edit-site-patterns__pattern {
break-inside: avoid-column;
display: flex;
flex-direction: column;
- margin-bottom: $grid-unit-60;
-
.edit-site-patterns__preview {
border-radius: $radius-block-ui;
cursor: pointer;
@@ -68,26 +113,13 @@
}
.edit-site-patterns__preview {
- flex: 1;
+ flex: 0 1 auto;
margin-bottom: $grid-unit-20;
}
}
-// The increased specificity here is to overcome component styles
-// without relying on internal component class names.
-.edit-site-patterns__search {
- {&} input[type="search"] {
- background: $gray-800;
- color: $gray-200;
-
- &:focus {
- background: $gray-800;
- }
- }
-
- svg {
- fill: $gray-600;
- }
+.edit-site-patterns__load-more {
+ align-self: center;
}
.edit-site-patterns__pattern-title {
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 295d1eee8e410f..0bcc52c85cb621 100644
--- a/packages/edit-site/src/components/page-patterns/use-patterns.js
+++ b/packages/edit-site/src/components/page-patterns/use-patterns.js
@@ -4,7 +4,6 @@
import { parse } from '@wordpress/blocks';
import { useSelect } from '@wordpress/data';
import { store as coreStore } from '@wordpress/core-data';
-import { useMemo } from '@wordpress/element';
/**
* Internal dependencies
@@ -15,7 +14,6 @@ import {
SYNC_TYPES,
TEMPLATE_PARTS,
USER_PATTERNS,
- USER_PATTERN_CATEGORY,
filterOutDuplicatesByName,
} from './utils';
import { unlock } from '../../lock-unlock';
@@ -43,106 +41,64 @@ const templatePartToPattern = ( templatePart ) => ( {
const templatePartHasCategory = ( item, category ) =>
item.templatePart.area === category;
-const useTemplatePartsAsPatterns = (
- categoryId,
- postType = TEMPLATE_PARTS,
- filterValue = ''
+const selectTemplatePartsAsPatterns = (
+ select,
+ { categoryId, search = '' } = {}
) => {
- const { templateParts, isResolving } = useSelect(
- ( select ) => {
- if ( postType !== TEMPLATE_PARTS ) {
- return {
- templateParts: EMPTY_PATTERN_LIST,
- isResolving: false,
- };
- }
-
- const { getEntityRecords, isResolving: _isResolving } =
- select( coreStore );
- const query = { per_page: -1 };
- const rawTemplateParts = getEntityRecords(
- 'postType',
- postType,
- query
- );
- const partsAsPatterns = rawTemplateParts?.map( ( templatePart ) =>
- templatePartToPattern( templatePart )
- );
-
- return {
- templateParts: partsAsPatterns,
- isResolving: _isResolving( 'getEntityRecords', [
- 'postType',
- 'wp_template_part',
- query,
- ] ),
- };
- },
- [ postType ]
+ const { getEntityRecords, getIsResolving } = select( coreStore );
+ const query = { per_page: -1 };
+ const rawTemplateParts =
+ getEntityRecords( 'postType', TEMPLATE_PARTS, query ) ??
+ EMPTY_PATTERN_LIST;
+ const templateParts = rawTemplateParts.map( ( templatePart ) =>
+ templatePartToPattern( templatePart )
);
- const filteredTemplateParts = useMemo( () => {
- if ( ! templateParts ) {
- return EMPTY_PATTERN_LIST;
- }
+ const isResolving = getIsResolving( 'getEntityRecords', [
+ 'postType',
+ 'wp_template_part',
+ query,
+ ] );
- return searchItems( templateParts, filterValue, {
- categoryId,
- hasCategory: templatePartHasCategory,
- } );
- }, [ templateParts, filterValue, categoryId ] );
+ const patterns = searchItems( templateParts, search, {
+ categoryId,
+ hasCategory: templatePartHasCategory,
+ } );
- return { templateParts: filteredTemplateParts, isResolving };
+ return { patterns, isResolving };
};
-const useThemePatterns = (
- categoryId,
- postType = PATTERNS,
- filterValue = ''
-) => {
- const blockPatterns = useSelect( ( select ) => {
- const { getSettings } = unlock( select( editSiteStore ) );
- const settings = getSettings();
- return (
- settings.__experimentalAdditionalBlockPatterns ??
- settings.__experimentalBlockPatterns
- );
+const selectThemePatterns = ( select, { categoryId, search = '' } = {} ) => {
+ const { getSettings } = unlock( select( editSiteStore ) );
+ const settings = getSettings();
+ const blockPatterns =
+ settings.__experimentalAdditionalBlockPatterns ??
+ settings.__experimentalBlockPatterns;
+
+ const restBlockPatterns = select( coreStore ).getBlockPatterns();
+
+ let patterns = [
+ ...( blockPatterns || [] ),
+ ...( restBlockPatterns || [] ),
+ ]
+ .filter(
+ ( pattern ) => ! CORE_PATTERN_SOURCES.includes( pattern.source )
+ )
+ .filter( filterOutDuplicatesByName )
+ .map( ( pattern ) => ( {
+ ...pattern,
+ keywords: pattern.keywords || [],
+ type: 'pattern',
+ blocks: parse( pattern.content ),
+ } ) );
+
+ patterns = searchItems( patterns, search, {
+ categoryId,
+ hasCategory: ( item, currentCategory ) =>
+ item.categories?.includes( currentCategory ),
} );
- const restBlockPatterns = useSelect( ( select ) =>
- select( coreStore ).getBlockPatterns()
- );
-
- const patterns = useMemo(
- () =>
- [ ...( blockPatterns || [] ), ...( restBlockPatterns || [] ) ]
- .filter(
- ( pattern ) =>
- ! CORE_PATTERN_SOURCES.includes( pattern.source )
- )
- .filter( filterOutDuplicatesByName )
- .map( ( pattern ) => ( {
- ...pattern,
- keywords: pattern.keywords || [],
- type: 'pattern',
- blocks: parse( pattern.content ),
- } ) ),
- [ blockPatterns, restBlockPatterns ]
- );
-
- const filteredPatterns = useMemo( () => {
- if ( postType !== PATTERNS ) {
- return EMPTY_PATTERN_LIST;
- }
-
- return searchItems( patterns, filterValue, {
- categoryId,
- hasCategory: ( item, currentCategory ) =>
- item.categories?.includes( currentCategory ),
- } );
- }, [ patterns, filterValue, categoryId, postType ] );
-
- return filteredPatterns;
+ return { patterns, isResolving: false };
};
const reusableBlockToPattern = ( reusableBlock ) => ( {
@@ -156,88 +112,58 @@ const reusableBlockToPattern = ( reusableBlock ) => ( {
reusableBlock,
} );
-const useUserPatterns = (
- categoryId,
- categoryType = PATTERNS,
- filterValue = ''
-) => {
- const postType = categoryType === PATTERNS ? USER_PATTERNS : categoryType;
- const unfilteredPatterns = useSelect(
- ( select ) => {
- if (
- postType !== USER_PATTERNS ||
- categoryId !== USER_PATTERN_CATEGORY
- ) {
- return EMPTY_PATTERN_LIST;
- }
+const selectUserPatterns = ( select, { search = '', syncStatus } = {} ) => {
+ const { getEntityRecords, getIsResolving } = select( coreStore );
- const { getEntityRecords } = select( coreStore );
- const records = getEntityRecords( 'postType', postType, {
- per_page: -1,
- } );
+ const query = { per_page: -1 };
+ const records = getEntityRecords( 'postType', USER_PATTERNS, query );
- if ( ! records ) {
- return EMPTY_PATTERN_LIST;
- }
+ let patterns = records
+ ? records.map( ( record ) => reusableBlockToPattern( record ) )
+ : EMPTY_PATTERN_LIST;
+ const isResolving = getIsResolving( 'getEntityRecords', [
+ 'postType',
+ USER_PATTERNS,
+ query,
+ ] );
- return records.map( ( record ) =>
- reusableBlockToPattern( record )
- );
- },
- [ postType, categoryId ]
- );
+ if ( syncStatus ) {
+ patterns = patterns.filter(
+ ( pattern ) => pattern.syncStatus === syncStatus
+ );
+ }
- const filteredPatterns = useMemo( () => {
- if ( ! unfilteredPatterns.length ) {
- return EMPTY_PATTERN_LIST;
- }
-
- return searchItems( unfilteredPatterns, filterValue, {
- // We exit user pattern retrieval early if we aren't in the
- // catch-all category for user created patterns, so it has
- // to be in the category.
- hasCategory: () => true,
- } );
- }, [ unfilteredPatterns, filterValue ] );
-
- const patterns = { syncedPatterns: [], unsyncedPatterns: [] };
-
- filteredPatterns.forEach( ( pattern ) => {
- if ( pattern.syncStatus === SYNC_TYPES.full ) {
- patterns.syncedPatterns.push( pattern );
- } else {
- patterns.unsyncedPatterns.push( pattern );
- }
+ patterns = searchItems( patterns, search, {
+ // We exit user pattern retrieval early if we aren't in the
+ // catch-all category for user created patterns, so it has
+ // to be in the category.
+ hasCategory: () => true,
} );
- return patterns;
+ return { patterns, isResolving };
};
-export const usePatterns = ( categoryType, categoryId, filterValue ) => {
- const blockPatterns = useThemePatterns(
- categoryId,
- categoryType,
- filterValue
- );
-
- const { syncedPatterns = [], unsyncedPatterns = [] } = useUserPatterns(
- categoryId,
- categoryType,
- filterValue
- );
-
- const { templateParts, isResolving } = useTemplatePartsAsPatterns(
- categoryId,
- categoryType,
- filterValue
+export const usePatterns = (
+ categoryType,
+ categoryId,
+ { search = '', syncStatus }
+) => {
+ return useSelect(
+ ( select ) => {
+ if ( categoryType === TEMPLATE_PARTS ) {
+ return selectTemplatePartsAsPatterns( select, {
+ categoryId,
+ search,
+ } );
+ } else if ( categoryType === PATTERNS ) {
+ return selectThemePatterns( select, { categoryId, search } );
+ } else if ( categoryType === USER_PATTERNS ) {
+ return selectUserPatterns( select, { search, syncStatus } );
+ }
+ return { patterns: EMPTY_PATTERN_LIST, isResolving: false };
+ },
+ [ categoryId, categoryType, search, syncStatus ]
);
-
- const patterns = {
- syncedPatterns: [ ...templateParts, ...syncedPatterns ],
- unsyncedPatterns: [ ...blockPatterns, ...unsyncedPatterns ],
- };
-
- return [ patterns, isResolving ];
};
export default usePatterns;
diff --git a/packages/edit-site/src/components/sidebar-navigation-screen-patterns/use-my-patterns.js b/packages/edit-site/src/components/sidebar-navigation-screen-patterns/use-my-patterns.js
index e3d5cc297164a2..37f0b0f8a4e063 100644
--- a/packages/edit-site/src/components/sidebar-navigation-screen-patterns/use-my-patterns.js
+++ b/packages/edit-site/src/components/sidebar-navigation-screen-patterns/use-my-patterns.js
@@ -6,18 +6,19 @@ import { useSelect } from '@wordpress/data';
import { __ } from '@wordpress/i18n';
export default function useMyPatterns() {
- const myPatterns = useSelect( ( select ) =>
- select( coreStore ).getEntityRecords( 'postType', 'wp_block', {
- per_page: -1,
- } )
+ const myPatternsCount = useSelect(
+ ( select ) =>
+ select( coreStore ).getEntityRecords( 'postType', 'wp_block', {
+ per_page: -1,
+ } )?.length ?? 0
);
return {
myPatterns: {
- count: myPatterns?.length || 0,
+ count: myPatternsCount,
name: 'my-patterns',
label: __( 'My patterns' ),
},
- hasPatterns: !! myPatterns?.length,
+ hasPatterns: myPatternsCount > 0,
};
}