diff --git a/packages/block-library/src/template-part/block.json b/packages/block-library/src/template-part/block.json index 5ad3a052cc3415..8ffb9be3fe1ce0 100644 --- a/packages/block-library/src/template-part/block.json +++ b/packages/block-library/src/template-part/block.json @@ -11,6 +11,9 @@ }, "tagName": { "type": "string" + }, + "area": { + "type": "string" } }, "supports": { diff --git a/packages/block-library/src/template-part/edit/index.js b/packages/block-library/src/template-part/edit/index.js index 999987e157be8c..fb5e5adc431a9c 100644 --- a/packages/block-library/src/template-part/edit/index.js +++ b/packages/block-library/src/template-part/edit/index.js @@ -28,10 +28,11 @@ import { TemplatePartAdvancedControls } from './advanced-controls'; import { getTagBasedOnArea } from './get-tag-based-on-area'; export default function TemplatePartEdit( { - attributes: { slug, theme, tagName, layout = {} }, + attributes, setAttributes, clientId, } ) { + const { slug, theme, tagName, layout = {} } = attributes; const templatePartId = theme && slug ? theme + '//' + slug : null; const [ hasAlreadyRendered, RecursionProvider ] = useNoRecursiveRenders( @@ -116,6 +117,7 @@ export default function TemplatePartEdit( { { isPlaceholder && ( diff --git a/packages/block-library/src/template-part/edit/placeholder/index.js b/packages/block-library/src/template-part/edit/placeholder/index.js index caaa42e35ea601..4a8462b278b9c7 100644 --- a/packages/block-library/src/template-part/edit/placeholder/index.js +++ b/packages/block-library/src/template-part/edit/placeholder/index.js @@ -15,26 +15,36 @@ import { store as coreStore } from '@wordpress/core-data'; import TemplatePartSelection from '../selection'; export default function TemplatePartPlaceholder( { + area, setAttributes, innerBlocks, } ) { const { saveEntityRecord } = useDispatch( coreStore ); const onCreate = useCallback( async () => { const title = __( 'Untitled Template 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: 'template-part', + content: serialize( innerBlocks ), + // `area` is filterable on the server and defaults to `UNCATEGORIZED` + // if provided value is not allowed. + area, + }; const templatePart = await saveEntityRecord( 'postType', 'wp_template_part', - { - title, - slug: 'template-part', - content: serialize( innerBlocks ), - } + record ); setAttributes( { slug: templatePart.slug, theme: templatePart.theme, + area: undefined, } ); - }, [ setAttributes ] ); + }, [ setAttributes, area ] ); return ( { - setAttributes( { slug, theme } ); + setAttributes( { slug, theme, area: undefined } ); createSuccessNotice( sprintf( /* translators: %s: template part title. */ diff --git a/packages/block-library/src/template-part/variations.js b/packages/block-library/src/template-part/variations.js index 2653c0dadf96aa..52fddbb53ae22c 100644 --- a/packages/block-library/src/template-part/variations.js +++ b/packages/block-library/src/template-part/variations.js @@ -6,20 +6,6 @@ import { store as coreDataStore } from '@wordpress/core-data'; import { select } from '@wordpress/data'; import { __ } from '@wordpress/i18n'; -const createIsActiveBasedOnArea = ( area ) => ( { theme, slug } ) => { - if ( ! slug ) { - return false; - } - - const entity = select( coreDataStore ).getEntityRecord( - 'postType', - 'wp_template_part', - `${ theme }//${ slug }` - ); - - return entity?.area === area; -}; - const variations = [ { name: 'header', @@ -28,7 +14,7 @@ const variations = [ "The header template defines a page area that typically contains a title, logo, and main navigation. Since it's a global element it can be present across all pages and posts." ), icon: header, - isActive: createIsActiveBasedOnArea( 'header' ), + attributes: { area: 'header' }, scope: [ 'inserter' ], }, { @@ -38,9 +24,33 @@ const variations = [ "The footer template defines a page area that typically contains site credits, social links, or any other combination of blocks. Since it's a global element it can be present across all pages and posts." ), icon: footer, - isActive: createIsActiveBasedOnArea( 'footer' ), + attributes: { area: 'footer' }, scope: [ 'inserter' ], }, ]; +/** + * Add `isActive` function to all `Template Part` variations, if not defined. + * `isActive` function is used to find a variation match from a created + * Block by providing its attributes. + */ +variations.forEach( ( variation ) => { + if ( variation.isActive ) return; + variation.isActive = ( blockAttributes, variationAttributes ) => { + const { area, theme, slug } = blockAttributes; + // We first check the `area` block attribute which is set during insertion. + // This property is removed on the creation of a template part. + if ( area ) return area === variationAttributes.area; + // Find a matching variation from the created template part + // by checking the entity's `area` property. + if ( ! slug ) return false; + const entity = select( coreDataStore ).getEntityRecord( + 'postType', + 'wp_template_part', + `${ theme }//${ slug }` + ); + return entity?.area === variationAttributes.area; + }; +} ); + export default variations;