Skip to content

Commit

Permalink
Template part 'replace' flow - don't show currently used template par…
Browse files Browse the repository at this point in the history
…t as option. (#31720)

* filter out current entity, apply message where necessary

* hide replace button when no options exist

* ensure boolean for enableSelection

* reverse params on createTemplatePartId function

* refactor group title translation to helper function, re-add fallback we should never see

* make new button primary when the only button

* contextual instructions based on options

* fix test

* fix other test
  • Loading branch information
Addison-Stavlo authored May 19, 2021
1 parent 7bd73e0 commit b3826d7
Show file tree
Hide file tree
Showing 6 changed files with 132 additions and 34 deletions.
30 changes: 25 additions & 5 deletions packages/block-library/src/template-part/edit/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,15 @@ import TemplatePartPlaceholder from './placeholder';
import TemplatePartSelection from './selection';
import { TemplatePartAdvancedControls } from './advanced-controls';
import TemplatePartInnerBlocks from './inner-blocks';
import { createTemplatePartId } from './utils/create-template-part-id';

export default function TemplatePartEdit( {
attributes,
setAttributes,
clientId,
} ) {
const { slug, theme, tagName, layout = {} } = attributes;
const templatePartId = theme && slug ? theme + '//' + slug : null;
const templatePartId = createTemplatePartId( theme, slug );

const [ hasAlreadyRendered, RecursionProvider ] = useNoRecursiveRenders(
templatePartId
Expand All @@ -48,11 +49,14 @@ export default function TemplatePartEdit( {
isMissing,
defaultWrapper,
area,
enableSelection,
} = useSelect(
( select ) => {
const { getEditedEntityRecord, hasFinishedResolution } = select(
coreStore
);
const {
getEditedEntityRecord,
getEntityRecords,
hasFinishedResolution,
} = select( coreStore );
const { getBlocks } = select( blockEditorStore );

const getEntityArgs = [
Expand All @@ -65,6 +69,19 @@ export default function TemplatePartEdit( {
: null;
const _area = entityRecord?.area || attributes.area;

// Check whether other entities exist for switching/selection.
const availableReplacementArgs = [
'postType',
'wp_template_part',
_area && 'uncategorized' !== _area && { area: _area },
];
const matchingReplacements = getEntityRecords(
...availableReplacementArgs
);
const _enableSelection = templatePartId
? matchingReplacements?.length > 1
: matchingReplacements?.length > 0;

const hasResolvedEntity = templatePartId
? hasFinishedResolution(
'getEditedEntityRecord',
Expand All @@ -82,6 +99,7 @@ export default function TemplatePartEdit( {
isMissing: hasResolvedEntity && ! entityRecord,
defaultWrapper: defaultWrapperElement || 'div',
area: _area,
enableSelection: _enableSelection,
};
},
[ templatePartId, clientId ]
Expand Down Expand Up @@ -138,10 +156,11 @@ export default function TemplatePartEdit( {
area={ attributes.area }
clientId={ clientId }
setAttributes={ setAttributes }
enableSelection={ enableSelection }
/>
</TagName>
) }
{ isEntityAvailable && (
{ isEntityAvailable && enableSelection && (
<BlockControls>
<ToolbarGroup className="wp-block-template-part__block-control-group">
<Dropdown
Expand All @@ -164,6 +183,7 @@ export default function TemplatePartEdit( {
setAttributes={ setAttributes }
onClose={ onClose }
area={ area }
templatePartId={ templatePartId }
/>
) }
/>
Expand Down
39 changes: 26 additions & 13 deletions packages/block-library/src/template-part/edit/placeholder/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ export default function TemplatePartPlaceholder( {
area,
clientId,
setAttributes,
enableSelection,
} ) {
const { saveEntityRecord } = useDispatch( coreStore );
const [ step, setStep ] = useState( PLACEHOLDER_STEPS.initial );
Expand Down Expand Up @@ -85,26 +86,38 @@ export default function TemplatePartPlaceholder( {
<Placeholder
icon={ areaIcon }
label={ areaLabel }
instructions={ sprintf(
// Translators: %s as template part area title ("Header", "Footer", etc.).
'Choose an existing %s or create a new one.',
areaLabel.toLowerCase()
) }
instructions={
enableSelection
? sprintf(
// Translators: %s as template part area title ("Header", "Footer", etc.).
'Choose an existing %s or create a new one.',
areaLabel.toLowerCase()
)
: sprintf(
// Translators: %s as template part area title ("Header", "Footer", etc.).
'Create a new %s.',
areaLabel.toLowerCase()
)
}
>
<Dropdown
contentClassName="wp-block-template-part__placeholder-preview-dropdown-content"
position="bottom right left"
renderToggle={ ( { isOpen, onToggle } ) => (
<>
{ enableSelection && (
<Button
isPrimary
onClick={ onToggle }
aria-expanded={ isOpen }
>
{ __( 'Choose existing' ) }
</Button>
) }
<Button
isPrimary
onClick={ onToggle }
aria-expanded={ isOpen }
>
{ __( 'Choose existing' ) }
</Button>
<Button
isTertiary
{ ...( enableSelection
? { isTertiary: true }
: { isPrimary: true } ) }
onClick={ () =>
setStep( PLACEHOLDER_STEPS.patterns )
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ export default function TemplatePartSelection( {
setAttributes,
onClose,
area,
templatePartId = null,
} ) {
const [ filterValue, setFilterValue ] = useState( '' );
return (
Expand All @@ -44,6 +45,7 @@ export default function TemplatePartSelection( {
filterValue={ filterValue }
onClose={ onClose }
area={ area }
templatePartId={ templatePartId }
/>
</div>
</div>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/**
* External dependencies
*/
import { groupBy, deburr } from 'lodash';
import { groupBy, deburr, flatten } from 'lodash';

/**
* WordPress dependencies
Expand All @@ -22,7 +22,18 @@ 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';
/**
* Internal dependencies
*/
import { createTemplatePartId } from '../utils/create-template-part-id';

function getAreaGroupTitle( areaLabel ) {
return sprintf(
// Translators: %s for the area the template part is assigned to (Header, Footer, General, etc.)
__( 'Area: %s' ),
areaLabel
);
}
function PreviewPlaceholder() {
return (
<div
Expand Down Expand Up @@ -111,23 +122,50 @@ function TemplatePartsByArea( {
area = 'uncategorized',
labelsByArea,
} ) {
const templatePartsByArea = useMemo( () => {
return Object.values( groupBy( templateParts, 'area' ) );
const { templatePartsByArea, templatePartsToShow } = useMemo( () => {
const _templatePartsToShow =
templateParts.filter(
( templatePart ) =>
'uncategorized' === area || templatePart.area === area
) || [];
const _templatePartsByArea = Object.values(
groupBy( _templatePartsToShow, 'area' )
);
const orderedTemplatePartsToShow = flatten( _templatePartsToShow );
return {
templatePartsByArea: _templatePartsByArea,
templatePartsToShow: orderedTemplatePartsToShow,
};
}, [ templateParts, area ] );
const currentShownTPs = useAsyncList( templateParts );

const currentShownTPs = useAsyncList( templatePartsToShow );

if ( ! templatePartsToShow.length ) {
return (
<PanelGroup
title={ getAreaGroupTitle(
labelsByArea[ area ] || labelsByArea.uncategorized
) }
>
{ sprintf(
// Translators: %s for the template part variation ("Header", "Footer", "Template Part").
'There is no other %s available. If you are looking for another type of template part, try searching for it using the input above.',
area && area !== 'uncategorized'
? labelsByArea[ area ] || area
: __( 'Template Part' )
) }
</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={
title={ getAreaGroupTitle(
labelsByArea[ templatePartList[ 0 ].area ] ||
__( 'General' )
}
labelsByArea.uncategorized
) }
>
{ templatePartList.map( ( templatePart ) => {
return currentShownTPs.includes( templatePart ) ? (
Expand Down Expand Up @@ -222,7 +260,9 @@ function TemplatePartSearchResults( {
return groupedResults.map( ( group ) => (
<PanelGroup
key={ group[ 0 ].id }
title={ labelsByArea[ group[ 0 ].area ] || __( 'General' ) }
title={ getAreaGroupTitle(
labelsByArea[ group[ 0 ].area ] || labelsByArea.uncategorized
) }
>
{ group.map( ( templatePart ) =>
currentShownTPs.includes( templatePart ) ? (
Expand All @@ -246,18 +286,26 @@ export default function TemplatePartPreviews( {
filterValue,
onClose,
area,
templatePartId,
} ) {
const composite = useCompositeState();

const { templateParts, labelsByArea } = useSelect( ( select ) => {
const _templateParts =
const _templateParts = (
select( coreStore ).getEntityRecords(
'postType',
'wp_template_part',
{
per_page: -1,
}
) || [];
) || []
).filter(
( templatePart ) =>
createTemplatePartId(
templatePart.theme,
templatePart.slug
) !== templatePartId
);

const definedAreas = select(
editorStore
Expand All @@ -274,7 +322,11 @@ export default function TemplatePartPreviews( {
}, [] );

if ( ! templateParts || ! templateParts.length ) {
return null;
return (
<PanelGroup>
{ __( 'There are no existing template parts to select.' ) }
</PanelGroup>
);
}

if ( filterValue ) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
/**
* Generates a template part Id based on slug and theme inputs.
*
* @param {string} theme the template part's theme.
* @param {string} slug the template part's slug
* @return {string|null} the template part's Id.
*/
export function createTemplatePartId( theme, slug ) {
return theme && slug ? theme + '//' + slug : null;
}
3 changes: 2 additions & 1 deletion packages/e2e-tests/specs/experiments/template-part.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -277,6 +277,7 @@ describe( 'Template Part', () => {
await disablePrePublishChecks();
// Create new template part.
await insertBlock( 'Template Part' );
await page.waitForXPath( chooseExistingButtonSelector );
const [ createNewButton ] = await page.$x(
createNewButtonSelector
);
Expand All @@ -297,7 +298,7 @@ describe( 'Template Part', () => {
await createNewPost();
// Try to insert the template part we created.
await insertBlock( 'Template Part' );
const [ chooseExistingButton ] = await page.$x(
const chooseExistingButton = await page.waitForXPath(
chooseExistingButtonSelector
);
await chooseExistingButton.click();
Expand Down

0 comments on commit b3826d7

Please sign in to comment.