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

Block API: Convert block alias into canonical block (PoC) #61481

Draft
wants to merge 4 commits into
base: trunk
Choose a base branch
from
Draft
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
18 changes: 16 additions & 2 deletions packages/block-editor/src/store/selectors.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
* WordPress dependencies
*/
import {
getBlockDefaultClassName,
getBlockType,
getBlockTypes,
getBlockVariations,
Expand Down Expand Up @@ -1862,6 +1863,14 @@ const canIncludeBlockTypeInInserter = ( state, blockType, rootClientId ) => {
const getItemFromVariation = ( state, item ) => ( variation ) => {
const variationId = `${ item.id }/${ variation.name }`;
const { time, count = 0 } = getInsertUsage( state, variationId ) || {};
const supportsAlias = variation?.supports?.alias ?? false;
const initialAttributes = {
...item.initialAttributes,
...variation.attributes,
...( supportsAlias && {
className: getBlockDefaultClassName( variation.name ),
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe it would be better to move this to what generates the markup rather than a pre-set attribute?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Potential problem with this is block validation

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Additional custom class names are ignored during validations, so that should be good. That's also a design question whether we want to have two class names printed:

  • computed from the original block type
  • computer from the alias for the block variation

} ),
};
return {
...item,
id: variationId,
Expand All @@ -1874,8 +1883,13 @@ const getItemFromVariation = ( state, item ) => ( variation ) => {
? variation.example
: item.example,
initialAttributes: {
...item.initialAttributes,
...variation.attributes,
...initialAttributes,
metadata: {
...initialAttributes.metadata,
// If the variation supports alias, set the alias attribute to the variation name.
// This is needed for convertAliasBlockNameAndAttributes to convert it to/from the alias/canonical block name.
...( supportsAlias && { alias: variation.name } ),
},
},
innerBlocks: variation.innerBlocks,
keywords: variation.keywords || item.keywords,
Expand Down
21 changes: 21 additions & 0 deletions packages/blocks/src/api/parser/convert-alias-block.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/**
* Convert alias blocks to their canonical form. This function is used
* both in the parser level for previous content and to convert such blocks
* used in Custom Post Types templates.
*
* @param {string} name The block's name
* @param {Object} attributes The block's attributes
*
* @return {[string, Object]} The block's name and attributes, changed accordingly if a match was found
*/
export function convertAliasBlockNameAndAttributes( name, attributes ) {
const canonicalBlockName = attributes.metadata?.alias;
let blockName = name;
const newAttributes = { ...attributes };
if ( canonicalBlockName ) {
blockName = canonicalBlockName;
newAttributes.metadata.alias = name;
}

return [ blockName, newAttributes ];
}
29 changes: 29 additions & 0 deletions packages/blocks/src/api/parser/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import { getSaveContent } from '../serializer';
import { validateBlock } from '../validation';
import { createBlock } from '../factory';
import { convertLegacyBlockNameAndAttributes } from './convert-legacy-block';
import { convertAliasBlockNameAndAttributes } from './convert-alias-block';
import { serializeRawBlock } from './serialize-raw-block';
import { getBlockAttributes } from './get-block-attributes';
import { applyBlockDeprecatedVersions } from './apply-block-deprecated-versions';
Expand Down Expand Up @@ -78,6 +79,31 @@ function convertLegacyBlocks( rawBlock ) {
};
}

/**
* Convert alias blocks to their canonical form. This function is used
* both in the parser level for previous content and to convert such blocks
* used in Custom Post Types templates.
*
* We are swapping the alias value with the block name depending on whether we are serializing or parsing.
* This is because the alias is used to serialize the block name, but when parsing, we need to convert the alias to the block name.
*
* @param {WPRawBlock} rawBlock
*
* @return {WPRawBlock} The block's name and attributes, changed accordingly if a match was found
*/
function convertAliasBlocks( rawBlock ) {
const [ correctName, correctedAttributes ] =
convertAliasBlockNameAndAttributes(
rawBlock.blockName,
rawBlock.attrs
);
return {
...rawBlock,
blockName: correctName,
attrs: correctedAttributes,
};
}

/**
* Normalize the raw block by applying the fallback block name if none given,
* sanitize the parsed HTML...
Expand Down Expand Up @@ -201,6 +227,9 @@ export function parseRawBlock( rawBlock, options ) {
// we added this function to properly parse the old content.
normalizedBlock = convertLegacyBlocks( normalizedBlock );

// Convert alias blocks to their canonical form.
normalizedBlock = convertAliasBlocks( normalizedBlock );

// Try finding the type for known block name.
let blockType = getBlockType( normalizedBlock.blockName );

Expand Down
14 changes: 9 additions & 5 deletions packages/blocks/src/api/serializer.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import {
} from './registration';
import { serializeRawBlock } from './parser/serialize-raw-block';
import { isUnmodifiedDefaultBlock, normalizeBlockType } from './utils';
import { convertAliasBlockNameAndAttributes } from './parser/convert-alias-block';

/** @typedef {import('./parser').WPBlock} WPBlock */

Expand Down Expand Up @@ -322,15 +323,18 @@ export function getCommentDelimitedContent(
attributes,
content
) {
const [ correctBlockName, correctedAttributes ] =
convertAliasBlockNameAndAttributes( rawBlockName, attributes );

const serializedAttributes =
attributes && Object.entries( attributes ).length
? serializeAttributes( attributes ) + ' '
correctedAttributes && Object.entries( correctedAttributes ).length
? serializeAttributes( correctedAttributes ) + ' '
: '';

// Strip core blocks of their namespace prefix.
const blockName = rawBlockName?.startsWith( 'core/' )
? rawBlockName.slice( 5 )
: rawBlockName;
const blockName = correctBlockName?.startsWith( 'core/' )
? correctBlockName.slice( 5 )
: correctBlockName;

// @todo make the `wp:` prefix potentially configurable.

Expand Down
Loading