Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix template part selection searches to use title/area instead of slug/theme. #31520

Merged
merged 6 commits into from
May 11, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 12 additions & 5 deletions packages/block-library/src/template-part/edit/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,13 @@ export default function TemplatePartEdit( {
// Set the postId block attribute if it did not exist,
// but wait until the inner blocks have loaded to allow
// new edits to trigger this.
const { isResolved, innerBlocks, isMissing, defaultWrapper } = useSelect(
const {
isResolved,
innerBlocks,
isMissing,
defaultWrapper,
area,
} = useSelect(
( select ) => {
const { getEditedEntityRecord, hasFinishedResolution } = select(
coreStore
Expand All @@ -57,6 +63,8 @@ export default function TemplatePartEdit( {
const entityRecord = templatePartId
? getEditedEntityRecord( ...getEntityArgs )
: null;
const _area = entityRecord?.area || attributes.area;

const hasResolvedEntity = templatePartId
? hasFinishedResolution(
'getEditedEntityRecord',
Expand All @@ -66,16 +74,14 @@ export default function TemplatePartEdit( {

const defaultWrapperElement = select( editorStore )
.__experimentalGetDefaultTemplatePartAreas()
.find(
( { area } ) =>
area === ( entityRecord?.area || attributes.area )
)?.area_tag;
.find( ( { area: value } ) => value === _area )?.area_tag;

return {
innerBlocks: getBlocks( clientId ),
isResolved: hasResolvedEntity,
isMissing: hasResolvedEntity && ! entityRecord,
defaultWrapper: defaultWrapperElement || 'div',
area: _area,
};
},
[ templatePartId, clientId ]
Expand Down Expand Up @@ -157,6 +163,7 @@ export default function TemplatePartEdit( {
<TemplatePartSelection
setAttributes={ setAttributes }
onClose={ onClose }
area={ area }
/>
) }
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ export default function TemplatePartPlaceholder( {
<TemplatePartSelection
setAttributes={ setAttributes }
onClose={ onClose }
area={ area }
/>
) }
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,11 @@ const stopKeyPropagation = ( event ) => event.stopPropagation();
// Disable reason (no-static-element-interactions): Navigational key-presses within
// the menu are prevented from triggering WritingFlow and ObserveTyping interactions.
/* eslint-disable jsx-a11y/no-static-element-interactions */
export default function TemplatePartSelection( { setAttributes, onClose } ) {
export default function TemplatePartSelection( {
setAttributes,
onClose,
area,
} ) {
const [ filterValue, setFilterValue ] = useState( '' );
return (
<div
Expand All @@ -39,6 +43,7 @@ export default function TemplatePartSelection( { setAttributes, onClose } ) {
setAttributes={ setAttributes }
filterValue={ filterValue }
onClose={ onClose }
area={ area }
/>
</div>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import {
import { useAsyncList } from '@wordpress/compose';
import { store as noticesStore } from '@wordpress/notices';
import { store as coreStore } from '@wordpress/core-data';
import { store as editorStore } from '@wordpress/editor';

function PreviewPlaceholder() {
return (
Expand Down Expand Up @@ -102,34 +103,48 @@ function PanelGroup( { title, icon, children } ) {
);
}

function TemplatePartsByTheme( {
function TemplatePartsByArea( {
templateParts,
setAttributes,
onClose,
composite,
area = 'uncategorized',
labelsByArea,
} ) {
const templatePartsByTheme = useMemo( () => {
return Object.values( groupBy( templateParts, 'theme' ) );
}, [ templateParts ] );
const templatePartsByArea = useMemo( () => {
return Object.values( groupBy( templateParts, 'area' ) );
}, [ templateParts, area ] );
const currentShownTPs = useAsyncList( templateParts );

return templatePartsByTheme.map( ( templatePartList ) => (
<PanelGroup key={ templatePartList[ 0 ].theme }>
{ templatePartList.map( ( templatePart ) => {
return currentShownTPs.includes( templatePart ) ? (
<TemplatePartItem
key={ templatePart.id }
templatePart={ templatePart }
setAttributes={ setAttributes }
onClose={ onClose }
composite={ composite }
/>
) : (
<PreviewPlaceholder key={ templatePart.id } />
);
} ) }
</PanelGroup>
) );
return templatePartsByArea.map( ( templatePartList ) => {
// Only return corresponding area if block/entity is not uncategorized/general version.
if ( 'uncategorized' !== area && templatePartList[ 0 ].area !== area ) {
return null;
}
return (
<PanelGroup
key={ templatePartList[ 0 ].area }
title={
labelsByArea[ templatePartList[ 0 ].area ] ||
__( 'General' )
}
>
{ templatePartList.map( ( templatePart ) => {
return currentShownTPs.includes( templatePart ) ? (
<TemplatePartItem
key={ templatePart.id }
templatePart={ templatePart }
setAttributes={ setAttributes }
onClose={ onClose }
composite={ composite }
/>
) : (
<PreviewPlaceholder key={ templatePart.id } />
);
} ) }
</PanelGroup>
);
} );
}

function TemplatePartSearchResults( {
Expand All @@ -138,62 +153,89 @@ function TemplatePartSearchResults( {
filterValue,
onClose,
composite,
labelsByArea,
} ) {
const filteredTPs = useMemo( () => {
const { filteredTPs, groupedResults } = useMemo( () => {
// Filter based on value.
// Remove diacritics and convert to lowercase to normalize.
const normalizedFilterValue = deburr( filterValue ).toLowerCase();
const searchResults = templateParts.filter(
( { slug, theme } ) =>
slug.toLowerCase().includes( normalizedFilterValue ) ||
( { title: { rendered: title }, area } ) =>
deburr( title )
.toLowerCase()
.includes( normalizedFilterValue ) ||
// Since diacritics can be used in theme names, remove them for the comparison.
deburr( theme ).toLowerCase().includes( normalizedFilterValue )
deburr( labelsByArea[ area ] )
.toLowerCase()
.includes( normalizedFilterValue )
);
// Order based on value location.
searchResults.sort( ( a, b ) => {
// First prioritize index found in slug.
const indexInSlugA = a.slug
// First prioritize index found in title.
// Deburr for diacritics.
const indexInTitleA = deburr( a.title.rendered )
.toLowerCase()
.indexOf( normalizedFilterValue );
const indexInSlugB = b.slug
const indexInTitleB = deburr( b.title.rendered )
.toLowerCase()
.indexOf( normalizedFilterValue );
if ( indexInSlugA !== -1 && indexInSlugB !== -1 ) {
return indexInSlugA - indexInSlugB;
} else if ( indexInSlugA !== -1 ) {
if ( indexInTitleA !== -1 && indexInTitleB !== -1 ) {
return indexInTitleA - indexInTitleB;
} else if ( indexInTitleA !== -1 ) {
return -1;
} else if ( indexInSlugB !== -1 ) {
} else if ( indexInTitleB !== -1 ) {
return 1;
}
// Second prioritize index found in theme.
// Since diacritics can be used in theme names, remove them for the comparison.
// Second prioritize index found in area.
return (
deburr( a.theme )
deburr( labelsByArea[ a.area ] )
.toLowerCase()
.indexOf( normalizedFilterValue ) -
deburr( b.theme ).toLowerCase().indexOf( normalizedFilterValue )
deburr( labelsByArea[ b.area ] )
.toLowerCase()
.indexOf( normalizedFilterValue )
);
} );
return searchResults;
// Group filtered results together if their neighbors share the same area.
// This helps not show redundant panel groups side by side in the results.
const _groupedResults = [];
for ( let i = 0; i < searchResults.length; i++ ) {
if (
i !== 0 &&
searchResults[ i ].area === searchResults[ i - 1 ].area
) {
_groupedResults[ _groupedResults.length - 1 ].push(
searchResults[ i ]
);
} else {
_groupedResults.push( [ searchResults[ i ] ] );
}
}
return {
filteredTPs: searchResults,
groupedResults: _groupedResults,
};
}, [ filterValue, templateParts ] );

const currentShownTPs = useAsyncList( filteredTPs );

return filteredTPs.map( ( templatePart ) => (
return groupedResults.map( ( group ) => (
<PanelGroup
key={ templatePart.id }
title={ templatePart.theme || __( 'Custom' ) }
key={ group[ 0 ].id }
title={ labelsByArea[ group[ 0 ].area ] || __( 'General' ) }
>
{ currentShownTPs.includes( templatePart ) ? (
<TemplatePartItem
key={ templatePart.id }
templatePart={ templatePart }
setAttributes={ setAttributes }
onClose={ onClose }
composite={ composite }
/>
) : (
<PreviewPlaceholder key={ templatePart.id } />
{ group.map( ( templatePart ) =>
currentShownTPs.includes( templatePart ) ? (
<TemplatePartItem
key={ templatePart.id }
templatePart={ templatePart }
setAttributes={ setAttributes }
onClose={ onClose }
composite={ composite }
/>
) : (
<PreviewPlaceholder key={ templatePart.id } />
)
) }
</PanelGroup>
) );
Expand All @@ -203,15 +245,32 @@ export default function TemplatePartPreviews( {
setAttributes,
filterValue,
onClose,
area,
} ) {
const composite = useCompositeState();
const templateParts = useSelect( ( select ) => {
return (

const { templateParts, labelsByArea } = useSelect( ( select ) => {
const _templateParts =
select( coreStore ).getEntityRecords(
'postType',
'wp_template_part'
) || []
);
'wp_template_part',
{
per_page: -1,
}
) || [];

const definedAreas = select(
editorStore
).__experimentalGetDefaultTemplatePartAreas();
const _labelsByArea = {};
definedAreas.forEach( ( item ) => {
_labelsByArea[ item.area ] = item.label;
} );

return {
templateParts: _templateParts,
labelsByArea: _labelsByArea,
};
}, [] );

if ( ! templateParts || ! templateParts.length ) {
Expand All @@ -231,6 +290,7 @@ export default function TemplatePartPreviews( {
filterValue={ filterValue }
onClose={ onClose }
composite={ composite }
labelsByArea={ labelsByArea }
/>
</Composite>
);
Expand All @@ -242,11 +302,13 @@ export default function TemplatePartPreviews( {
role="listbox"
aria-label={ __( 'List of template parts' ) }
>
<TemplatePartsByTheme
<TemplatePartsByArea
templateParts={ templateParts }
setAttributes={ setAttributes }
onClose={ onClose }
composite={ composite }
area={ area }
labelsByArea={ labelsByArea }
/>
</Composite>
);
Expand Down