Skip to content

Commit

Permalink
Fail gracefully when block in createBlock function is not registered (
Browse files Browse the repository at this point in the history
WordPress#68043)

* Make __experimentalSanitizeBlockAttributes fail gracefully when block is not registered

* Check if block is registered before sanitizing attributes

* Update tests and add new ones

* Bring back the error throwing

* Simplify the test

* Refactor block creation functions for improved readability/ In both cases they rely on internal handling of `createBlock` function.

Co-authored-by: kmanijak <[email protected]>
Co-authored-by: gziolo <[email protected]>
  • Loading branch information
3 people authored Jan 2, 2025
1 parent 7534ae9 commit 5b06788
Show file tree
Hide file tree
Showing 4 changed files with 58 additions and 36 deletions.
55 changes: 31 additions & 24 deletions packages/blocks/src/api/factory.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import {
getGroupingBlockName,
} from './registration';
import {
isBlockRegistered,
normalizeBlockType,
__experimentalSanitizeBlockAttributes,
} from './utils';
Expand All @@ -31,6 +32,14 @@ import {
* @return {Object} Block object.
*/
export function createBlock( name, attributes = {}, innerBlocks = [] ) {
if ( ! isBlockRegistered( name ) ) {
return createBlock( 'core/missing', {
originalName: name,
originalContent: '',
originalUndelimitedContent: '',
} );
}

const sanitizedAttributes = __experimentalSanitizeBlockAttributes(
name,
attributes
Expand Down Expand Up @@ -94,15 +103,22 @@ export function __experimentalCloneSanitizedBlock(
mergeAttributes = {},
newInnerBlocks
) {
const { name } = block;

if ( ! isBlockRegistered( name ) ) {
return createBlock( 'core/missing', {
originalName: name,
originalContent: '',
originalUndelimitedContent: '',
} );
}

const clientId = uuid();

const sanitizedAttributes = __experimentalSanitizeBlockAttributes(
block.name,
{
...block.attributes,
...mergeAttributes,
}
);
const sanitizedAttributes = __experimentalSanitizeBlockAttributes( name, {
...block.attributes,
...mergeAttributes,
} );

return {
...block,
Expand Down Expand Up @@ -583,20 +599,11 @@ export function switchToBlockType( blocks, name ) {
*
* @return {Object} block.
*/
export const getBlockFromExample = ( name, example ) => {
try {
return createBlock(
name,
example.attributes,
( example.innerBlocks ?? [] ).map( ( innerBlock ) =>
getBlockFromExample( innerBlock.name, innerBlock )
)
);
} catch {
return createBlock( 'core/missing', {
originalName: name,
originalContent: '',
originalUndelimitedContent: '',
} );
}
};
export const getBlockFromExample = ( name, example ) =>
createBlock(
name,
example.attributes,
( example.innerBlocks ?? [] ).map( ( innerBlock ) =>
getBlockFromExample( innerBlock.name, innerBlock )
)
);
13 changes: 1 addition & 12 deletions packages/blocks/src/api/templates.js
Original file line number Diff line number Diff line change
Expand Up @@ -109,23 +109,12 @@ export function synchronizeBlocksWithTemplate( blocks = [], template ) {
attributes
);

let [ blockName, blockAttributes ] =
const [ blockName, blockAttributes ] =
convertLegacyBlockNameAndAttributes(
name,
normalizedAttributes
);

// If a Block is undefined at this point, use the core/missing block as
// a placeholder for a better user experience.
if ( undefined === getBlockType( blockName ) ) {
blockAttributes = {
originalName: name,
originalContent: '',
originalUndelimitedContent: '',
};
blockName = 'core/missing';
}

return createBlock(
blockName,
blockAttributes,
Expand Down
15 changes: 15 additions & 0 deletions packages/blocks/src/api/test/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {
isUnmodifiedDefaultBlock,
getAccessibleBlockLabel,
getBlockLabel,
isBlockRegistered,
__experimentalSanitizeBlockAttributes,
getBlockAttributesNamesByRole,
isContentBlock,
Expand Down Expand Up @@ -213,6 +214,20 @@ describe( 'getAccessibleBlockLabel', () => {
} );
} );

describe( 'isBlockRegistered', () => {
it( 'returns true if the block is registered', () => {
registerBlockType( 'core/test-block', { title: 'Test block' } );
expect( isBlockRegistered( 'core/test-block' ) ).toBe( true );
unregisterBlockType( 'core/test-block' );
} );

it( 'returns false if the block is not registered', () => {
expect( isBlockRegistered( 'core/not-registered-test-block' ) ).toBe(
false
);
} );
} );

describe( 'sanitizeBlockAttributes', () => {
afterEach( () => {
getBlockTypes().forEach( ( block ) => {
Expand Down
11 changes: 11 additions & 0 deletions packages/blocks/src/api/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,17 @@ export function getDefault( attributeSchema ) {
}
}

/**
* Check if a block is registered.
*
* @param {string} name The block's name.
*
* @return {boolean} Whether the block is registered.
*/
export function isBlockRegistered( name ) {
return getBlockType( name ) !== undefined;
}

/**
* Ensure attributes contains only values defined by block type, and merge
* default values for missing attributes.
Expand Down

0 comments on commit 5b06788

Please sign in to comment.