diff --git a/packages/blocks/src/store/process-block-type.js b/packages/blocks/src/store/process-block-type.js index 8e5b7962adfe17..98fb044f8faadf 100644 --- a/packages/blocks/src/store/process-block-type.js +++ b/packages/blocks/src/store/process-block-type.js @@ -71,17 +71,32 @@ function stabilizeSupports( rawSupports ) { return rawSupports; } - const supports = { ...rawSupports }; - if ( supports?.typography && typeof supports.typography === 'object' ) { - supports.typography = Object.fromEntries( - Object.entries( supports.typography ).map( ( [ key, value ] ) => [ - TYPOGRAPHY_SUPPORTS_EXPERIMENTAL_TO_STABLE[ key ] || key, - value, - ] ) - ); + // Create a new object to avoid mutating the original. This ensures that + // custom block plugins that rely on immutable supports are not affected. + // See: https://github.com/WordPress/gutenberg/pull/66849#issuecomment-2463614281 + const newSupports = {}; + for ( const [ key, value ] of Object.entries( rawSupports ) ) { + if ( + key === 'typography' && + typeof value === 'object' && + value !== null + ) { + newSupports.typography = Object.fromEntries( + Object.entries( value ).map( + ( [ typographyKey, typographyValue ] ) => [ + TYPOGRAPHY_SUPPORTS_EXPERIMENTAL_TO_STABLE[ + typographyKey + ] || typographyKey, + typographyValue, + ] + ) + ); + } else { + newSupports[ key ] = value; + } } - return supports; + return newSupports; } /** @@ -150,10 +165,12 @@ export const processBlockType = if ( settings.deprecated ) { settings.deprecated = settings.deprecated.map( ( deprecation ) => { // Stabilize any experimental supports before applying filters. - deprecation.supports = stabilizeSupports( - deprecation.supports - ); - const filteredDeprecation = // Only keep valid deprecation keys. + let filteredDeprecation = { + ...deprecation, + supports: stabilizeSupports( deprecation.supports ), + }; + + filteredDeprecation = // Only keep valid deprecation keys. applyFilters( 'blocks.registerBlockType', // Merge deprecation keys with pre-filter settings @@ -163,10 +180,10 @@ export const processBlockType = // Omit deprecation keys here so that deprecations // can opt out of specific keys like "supports". ...omit( blockType, DEPRECATED_ENTRY_KEYS ), - ...deprecation, + ...filteredDeprecation, }, blockType.name, - deprecation + filteredDeprecation ); // Re-stabilize any experimental supports after applying filters. // This ensures that any supports updated by filters are also stabilized. diff --git a/packages/blocks/src/store/test/process-block-type.js b/packages/blocks/src/store/test/process-block-type.js index 3c6838e311f778..c82d08cc45d651 100644 --- a/packages/blocks/src/store/test/process-block-type.js +++ b/packages/blocks/src/store/test/process-block-type.js @@ -215,6 +215,12 @@ describe( 'processBlockType', () => { ], }; + // Freeze the deprecated block object and its supports so that the original is not mutated. + // This ensures the test covers a regression where the original object was mutated. + // See: https://github.com/WordPress/gutenberg/pull/63401#discussion_r1832394335. + Object.freeze( blockSettings.deprecated[ 0 ] ); + Object.freeze( blockSettings.deprecated[ 0 ].supports ); + const processedBlockType = processBlockType( 'test/block', blockSettings