Skip to content

Commit

Permalink
Template part - register block variations and area selection inputs f…
Browse files Browse the repository at this point in the history
…rom original area definitions. (#30821)

* register variations from editor store

* add definitons to post editor settings

* remove unnecessary export var

* minor refactor

* update block inspector area selection

* move icons to original definitions

* fix unit tests

* move default wrapper element to original definition

* update default tag on front end

* update jsdoc param description

* update jsdoc description

* add properties to general, handle defaultWrapper in placeholder

* remove unnecessary null check

* Update packages/editor/src/store/utils/get-template-part-icon.js

Co-authored-by: Nik Tsekouras <ntsekouras@outlook.com>

Co-authored-by: Nik Tsekouras <ntsekouras@outlook.com>
  • Loading branch information
Addison-Stavlo and ntsekouras authored Apr 23, 2021
1 parent a3acd0d commit e5b0a86
Show file tree
Hide file tree
Showing 11 changed files with 122 additions and 103 deletions.
4 changes: 4 additions & 0 deletions lib/editor-settings.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@ function gutenberg_extend_post_editor_settings( $settings ) {
$settings['imageDefaultSize'] = in_array( $image_default_size, $image_sizes, true ) ? $image_default_size : 'large';
$settings['__unstableEnableFullSiteEditingBlocks'] = gutenberg_supports_block_templates();

if ( gutenberg_is_fse_theme() ) {
$settings['defaultTemplatePartAreas'] = gutenberg_get_allowed_template_part_areas();
}

return $settings;
}
add_filter( 'block_editor_settings', 'gutenberg_extend_post_editor_settings' );
Expand Down
6 changes: 6 additions & 0 deletions lib/full-site-editing/template-parts.php
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,8 @@ function gutenberg_get_allowed_template_part_areas() {
'General templates often perform a specific role like displaying post content, and are not tied to any particular area.',
'gutenberg'
),
'icon' => 'layout',
'area_tag' => 'div',
),
array(
'area' => WP_TEMPLATE_PART_AREA_HEADER,
Expand All @@ -184,6 +186,8 @@ function gutenberg_get_allowed_template_part_areas() {
'The Header template defines a page area that typically contains a title, logo, and main navigation.',
'gutenberg'
),
'icon' => 'header',
'area_tag' => 'header',
),
array(
'area' => WP_TEMPLATE_PART_AREA_FOOTER,
Expand All @@ -192,6 +196,8 @@ function gutenberg_get_allowed_template_part_areas() {
'The Footer template defines a page area that typically contains site credits, social links, or any other combination of blocks.',
'gutenberg'
),
'icon' => 'footer',
'area_tag' => 'footer',
),
);

Expand Down
33 changes: 17 additions & 16 deletions packages/block-library/src/template-part/edit/advanced-controls.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,26 +5,15 @@ import { useEntityProp } from '@wordpress/core-data';
import { SelectControl, TextControl } from '@wordpress/components';
import { sprintf, __ } from '@wordpress/i18n';
import { InspectorAdvancedControls } from '@wordpress/block-editor';

/**
* Internal dependencies
*/
import { getTagBasedOnArea } from './get-tag-based-on-area';

const AREA_OPTIONS = [
{ label: __( 'Header' ), value: 'header' },
{ label: __( 'Footer' ), value: 'footer' },
{
label: __( 'General' ),
value: 'uncategorized',
},
];
import { useSelect } from '@wordpress/data';
import { store as editorStore } from '@wordpress/editor';

export function TemplatePartAdvancedControls( {
tagName,
setAttributes,
isEntityAvailable,
templatePartId,
defaultWrapper,
} ) {
const [ area, setArea ] = useEntityProp(
'postType',
Expand All @@ -40,6 +29,18 @@ export function TemplatePartAdvancedControls( {
templatePartId
);

const { areaOptions } = useSelect( ( select ) => {
const definedAreas = select(
editorStore
).__experimentalGetDefaultTemplatePartAreas();
return {
areaOptions: definedAreas.map( ( { label, area: _area } ) => ( {
label,
value: _area,
} ) ),
};
}, [] );

return (
<InspectorAdvancedControls>
{ isEntityAvailable && (
Expand All @@ -56,7 +57,7 @@ export function TemplatePartAdvancedControls( {
<SelectControl
label={ __( 'Area' ) }
labelPosition="top"
options={ AREA_OPTIONS }
options={ areaOptions }
value={ area }
onChange={ setArea }
/>
Expand All @@ -69,7 +70,7 @@ export function TemplatePartAdvancedControls( {
label: sprintf(
/* translators: %s: HTML tag based on area. */
__( 'Default based on area (%s)' ),
`<${ getTagBasedOnArea( area ) }>`
`<${ defaultWrapper }>`
),
value: '',
},
Expand Down

This file was deleted.

16 changes: 12 additions & 4 deletions packages/block-library/src/template-part/edit/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import {
} from '@wordpress/components';
import { __, sprintf } from '@wordpress/i18n';
import { store as coreStore } from '@wordpress/core-data';
import { store as editorStore } from '@wordpress/editor';

/**
* Internal dependencies
Expand All @@ -25,7 +26,6 @@ import TemplatePartInnerBlocks from './inner-blocks';
import TemplatePartPlaceholder from './placeholder';
import TemplatePartSelection from './selection';
import { TemplatePartAdvancedControls } from './advanced-controls';
import { getTagBasedOnArea } from './get-tag-based-on-area';

export default function TemplatePartEdit( {
attributes,
Expand All @@ -42,7 +42,7 @@ 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, area } = useSelect(
const { isResolved, innerBlocks, isMissing, defaultWrapper } = useSelect(
( select ) => {
const { getEditedEntityRecord, hasFinishedResolution } = select(
coreStore
Expand All @@ -64,11 +64,18 @@ export default function TemplatePartEdit( {
)
: false;

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

return {
innerBlocks: getBlocks( clientId ),
isResolved: hasResolvedEntity,
isMissing: hasResolvedEntity && ! entityRecord,
area: entityRecord?.area,
defaultWrapper: defaultWrapperElement || 'div',
};
},
[ templatePartId, clientId ]
Expand All @@ -77,7 +84,7 @@ export default function TemplatePartEdit( {
const blockProps = useBlockProps();
const isPlaceholder = ! slug;
const isEntityAvailable = ! isPlaceholder && ! isMissing && isResolved;
const TagName = tagName || getTagBasedOnArea( area );
const TagName = tagName || defaultWrapper;

// We don't want to render a missing state if we have any inner blocks.
// A new template part is automatically created if we have any inner blocks but no entity.
Expand Down Expand Up @@ -117,6 +124,7 @@ export default function TemplatePartEdit( {
setAttributes={ setAttributes }
isEntityAvailable={ isEntityAvailable }
templatePartId={ templatePartId }
defaultWrapper={ defaultWrapper }
/>
{ isPlaceholder && (
<TagName { ...blockProps }>
Expand Down
3 changes: 1 addition & 2 deletions packages/block-library/src/template-part/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import { layout } from '@wordpress/icons';
*/
import metadata from './block.json';
import edit from './edit';
import variations from './variations';
import './variations';

const { name } = metadata;
export { metadata, name };
Expand Down Expand Up @@ -47,5 +47,4 @@ export const settings = {
return startCase( entity.title?.rendered || entity.slug );
},
edit,
variations,
};
14 changes: 8 additions & 6 deletions packages/block-library/src/template-part/index.php
Original file line number Diff line number Diff line change
Expand Up @@ -109,12 +109,14 @@ function render_block_core_template_part( $attributes ) {
$content = do_shortcode( $content );

if ( empty( $attributes['tagName'] ) ) {
$area_tags = array(
WP_TEMPLATE_PART_AREA_HEADER => 'header',
WP_TEMPLATE_PART_AREA_FOOTER => 'footer',
WP_TEMPLATE_PART_AREA_UNCATEGORIZED => 'div',
);
$html_tag = null !== $area && isset( $area_tags[ $area ] ) ? $area_tags[ $area ] : $area_tags[ WP_TEMPLATE_PART_AREA_UNCATEGORIZED ];
$defined_areas = gutenberg_get_allowed_template_part_areas();
$area_tag = 'div';
foreach ( $defined_areas as $defined_area ) {
if ( $defined_area['area'] === $area && isset( $defined_area['area_tag'] ) ) {
$area_tag = $defined_area['area_tag'];
}
}
$html_tag = $area_tag;
} else {
$html_tag = esc_attr( $attributes['tagName'] );
}
Expand Down
102 changes: 53 additions & 49 deletions packages/block-library/src/template-part/variations.js
Original file line number Diff line number Diff line change
@@ -1,56 +1,60 @@
/**
* WordPress dependencies
*/
import { footer, header } from '@wordpress/icons';
import { store as coreDataStore } from '@wordpress/core-data';
import { select } from '@wordpress/data';
import { __ } from '@wordpress/i18n';
import { store as editorStore } from '@wordpress/editor';
import { store as blocksStore } from '@wordpress/blocks';
import { dispatch, select, subscribe } from '@wordpress/data';

const variations = [
{
name: 'header',
title: __( 'Header' ),
description: __(
"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,
attributes: { area: 'header' },
scope: [ 'inserter' ],
},
{
name: 'footer',
title: __( 'Footer' ),
description: __(
"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,
attributes: { area: 'footer' },
scope: [ 'inserter' ],
},
];
const unsubscribe = subscribe( () => {
const definedVariations = select(
editorStore
).__experimentalGetDefaultTemplatePartAreas();

/**
* 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;
};
} );
if ( ! definedVariations?.length ) {
return;
}
unsubscribe();

export default variations;
const variations = definedVariations
.filter( ( { area } ) => 'uncategorized' !== area )
.map( ( { area, label, description, icon } ) => {
return {
name: area,
title: label,
description,
icon,
attributes: { area },
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;
};
} );

dispatch( blocksStore ).addBlockVariations(
'core/template-part',
variations
);
} );
13 changes: 9 additions & 4 deletions packages/editor/src/store/selectors.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import { addQueryArgs } from '@wordpress/url';
import { createRegistrySelector } from '@wordpress/data';
import deprecated from '@wordpress/deprecated';
import { Platform } from '@wordpress/element';
import { layout } from '@wordpress/icons';

/**
* Internal dependencies
Expand All @@ -40,7 +41,7 @@ import {
} from './constants';
import { getPostRawValue } from './reducer';
import { cleanForSlug } from '../utils/url';
import { getTemplatePartIconByArea } from './utils/get-template-part-icon';
import { getTemplatePartIcon } from './utils/get-template-part-icon';

/**
* Shared reference to an empty object for cases where it is important to avoid
Expand Down Expand Up @@ -1680,9 +1681,10 @@ export function __experimentalGetDefaultTemplateTypes( state ) {
*/
export const __experimentalGetDefaultTemplatePartAreas = createSelector(
( state ) => {
const areas = getEditorSettings( state )?.defaultTemplatePartAreas;
const areas =
getEditorSettings( state )?.defaultTemplatePartAreas || [];
return areas?.map( ( item ) => {
return { ...item, icon: getTemplatePartIconByArea( item.area ) };
return { ...item, icon: getTemplatePartIcon( item.icon ) };
} );
},
( state ) => [ getEditorSettings( state )?.defaultTemplatePartAreas ]
Expand Down Expand Up @@ -1723,7 +1725,10 @@ export function __experimentalGetTemplateInfo( state, template ) {

const templateTitle = isString( title ) ? title : title?.rendered;
const templateDescription = isString( excerpt ) ? excerpt : excerpt?.raw;
const templateIcon = getTemplatePartIconByArea( area );
const templateIcon =
__experimentalGetDefaultTemplatePartAreas( state ).find(
( item ) => area === item.area
)?.icon || layout;

return {
title:
Expand Down
Loading

0 comments on commit e5b0a86

Please sign in to comment.