Skip to content

Commit

Permalink
Shuffle template parts by creating new ones from patterns
Browse files Browse the repository at this point in the history
  • Loading branch information
kevin940726 committed Feb 3, 2023
1 parent d056cc6 commit 3d24633
Show file tree
Hide file tree
Showing 2 changed files with 110 additions and 39 deletions.
59 changes: 37 additions & 22 deletions packages/block-library/src/template-part/edit/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,9 @@ import {
store as blockEditorStore,
__experimentalRecursionProvider as RecursionProvider,
__experimentalUseHasRecursion as useHasRecursion,
BlockControls,
} from '@wordpress/block-editor';
import { Spinner, Modal, MenuItem } from '@wordpress/components';
import { Spinner, Modal, MenuItem, ToolbarButton } from '@wordpress/components';
import { __, sprintf } from '@wordpress/i18n';
import { store as coreStore } from '@wordpress/core-data';
import { useState, createInterpolateElement } from '@wordpress/element';
Expand All @@ -33,6 +34,7 @@ import {
useAlternativeBlockPatterns,
useAlternativeTemplateParts,
useTemplatePartArea,
useShuffleTemplatePart,
} from './utils/hooks';

export default function TemplatePartEdit( {
Expand Down Expand Up @@ -92,6 +94,12 @@ export default function TemplatePartEdit( {
const isPlaceholder = ! slug;
const isEntityAvailable = ! isPlaceholder && ! isMissing && isResolved;
const TagName = tagName || areaObject.tagName;
const shuffleTemplatePart = useShuffleTemplatePart(
area,
clientId,
templatePartId,
setAttributes
);

// The `isSelected` check ensures the `BlockSettingsMenuControls` fill
// doesn't render multiple times. The block controls has similar internal check.
Expand Down Expand Up @@ -157,27 +165,34 @@ export default function TemplatePartEdit( {
</TagName>
) }
{ canReplace && (
<BlockSettingsMenuControls>
{ () => (
<MenuItem
onClick={ () => {
setIsTemplatePartSelectionOpen( true );
} }
>
{ createInterpolateElement(
__( 'Replace <BlockTitle />' ),
{
BlockTitle: (
<BlockTitle
clientId={ clientId }
maximumLength={ 25 }
/>
),
}
) }
</MenuItem>
) }
</BlockSettingsMenuControls>
<>
<BlockSettingsMenuControls>
{ () => (
<MenuItem
onClick={ () => {
setIsTemplatePartSelectionOpen( true );
} }
>
{ createInterpolateElement(
__( 'Replace <BlockTitle />' ),
{
BlockTitle: (
<BlockTitle
clientId={ clientId }
maximumLength={ 25 }
/>
),
}
) }
</MenuItem>
) }
</BlockSettingsMenuControls>
<BlockControls group="other">
<ToolbarButton onClick={ shuffleTemplatePart }>
{ __( 'Shuffle' ) }
</ToolbarButton>
</BlockControls>
</>
) }
{ isEntityAvailable && (
<TemplatePartInnerBlocks
Expand Down
90 changes: 73 additions & 17 deletions packages/block-library/src/template-part/edit/utils/hooks.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,28 @@ import { __ } from '@wordpress/i18n';
*/
import { createTemplatePartId } from './create-template-part-id';

function createTemplatePartRecordFromBlocks( area, blocks, title ) {
// Currently template parts only allow latin chars.
// Fallback slug will receive suffix by default.
const cleanSlug =
kebabCase( title ).replace( /[^\w-]+/g, '' ) || 'wp-custom-part';

// If we have `area` set from block attributes, means an exposed
// block variation was inserted. So add this prop to the template
// part entity on creation. Afterwards remove `area` value from
// block attributes.
const record = {
title,
slug: cleanSlug,
content: serialize( blocks ),
// `area` is filterable on the server and defaults to `UNCATEGORIZED`
// if provided value is not allowed.
area,
};

return record;
}

/**
* Retrieves the available template parts for the given area.
*
Expand Down Expand Up @@ -61,7 +83,7 @@ export function useAlternativeTemplateParts( area, excludedId ) {
templatePart.area === area )
) || []
);
}, [ templateParts, area ] );
}, [ templateParts, area, excludedId ] );

return {
templateParts: filteredTemplateParts,
Expand Down Expand Up @@ -96,23 +118,12 @@ export function useCreateTemplatePartFromBlocks( area, setAttributes ) {
const { saveEntityRecord } = useDispatch( coreStore );

return async ( blocks = [], title = __( 'Untitled Template Part' ) ) => {
// Currently template parts only allow latin chars.
// Fallback slug will receive suffix by default.
const cleanSlug =
kebabCase( title ).replace( /[^\w-]+/g, '' ) || 'wp-custom-part';

// If we have `area` set from block attributes, means an exposed
// block variation was inserted. So add this prop to the template
// part entity on creation. Afterwards remove `area` value from
// block attributes.
const record = {
title,
slug: cleanSlug,
content: serialize( blocks ),
// `area` is filterable on the server and defaults to `UNCATEGORIZED`
// if provided value is not allowed.
const record = createTemplatePartRecordFromBlocks(
area,
};
blocks,
title
);

const templatePart = await saveEntityRecord(
'postType',
'wp_template_part',
Expand Down Expand Up @@ -161,3 +172,48 @@ export function useTemplatePartArea( area ) {
[ area ]
);
}

export function useShuffleTemplatePart(
area,
clientId,
templatePartId,
setAttributes
) {
const { templateParts } = useAlternativeTemplateParts(
area,
templatePartId
);
const blockPatterns = useAlternativeBlockPatterns( area, clientId );
const createTemplatePartFromBlocks = useCreateTemplatePartFromBlocks(
area,
setAttributes
);

return async function shuffleTemplatePart() {
const list = [
...templateParts,
...blockPatterns.filter( ( pattern ) =>
templateParts.every(
( templatePart ) =>
templatePart.content.raw !== serialize( pattern.blocks )
)
),
];
// We explicitly want the randomness here.
// eslint-disable-next-line no-restricted-syntax
const randomIndex = Math.floor( Math.random() * list.length );
const randomItem = list[ randomIndex ];

if ( randomIndex < templateParts.length ) {
const templatePart = randomItem;
setAttributes( {
slug: templatePart.slug,
theme: templatePart.theme,
area: undefined,
} );
} else {
const pattern = randomItem;
await createTemplatePartFromBlocks( pattern.blocks, pattern.title );
}
};
}

0 comments on commit 3d24633

Please sign in to comment.