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
#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

1 comment on commit 5b06788

@github-actions
Copy link

Choose a reason for hiding this comment

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

Flaky tests detected in 5b06788.
Some tests passed with failed attempts. The failures may not be related to this commit but are still reported for visibility. See the documentation for more information.

🔍 Workflow run URL: https://github.com/WordPress/gutenberg/actions/runs/12581058622
📝 Reported issues:

Please sign in to comment.