From 406f4b7158fa26e7b79cd8aa1caf26213549d421 Mon Sep 17 00:00:00 2001 From: Aaron Robertshaw <60436221+aaronrobertshaw@users.noreply.github.com> Date: Mon, 13 May 2024 12:37:58 +0900 Subject: [PATCH] Block Styles: Add extended version of register block style functions (#61029) Co-authored-by: aaronrobertshaw Co-authored-by: scruffian Co-authored-by: youknowriad Co-authored-by: carolinan Co-authored-by: cbirdsong --- lib/experimental/blocks.php | 43 ++++++++++++++++++ packages/blocks/README.md | 4 +- packages/blocks/src/api/registration.js | 10 ++-- packages/blocks/src/store/actions.js | 8 ++-- packages/blocks/src/store/reducer.js | 13 +++--- packages/blocks/src/store/test/reducer.js | 48 +++++++++++++++----- phpunit/blocks/register-block-style-test.php | 32 +++++++++++++ 7 files changed, 130 insertions(+), 28 deletions(-) create mode 100644 phpunit/blocks/register-block-style-test.php diff --git a/lib/experimental/blocks.php b/lib/experimental/blocks.php index fc67f2c9d43770..bfe57c26b3ecab 100644 --- a/lib/experimental/blocks.php +++ b/lib/experimental/blocks.php @@ -77,3 +77,46 @@ function wp_enqueue_block_view_script( $block_name, $args ) { add_filter( 'render_block', $callback, 10, 2 ); } } + +/* + * WP_Block_Styles_Registry was marked as `final` in core so it cannot be + * updated via Gutenberg to allow registration of a style across multiple + * block types as well as with an optional style object. This function will + * support the desired functionality until the styles registry can be updated + * in core. + */ +if ( ! function_exists( 'gutenberg_register_block_style' ) ) { + /** + * Registers a new block style for one or more block types. + * + * @param string|array $block_name Block type name including namespace or array of namespaced block type names. + * @param array $style_properties Array containing the properties of the style name, label, + * style_handle (name of the stylesheet to be enqueued), + * inline_style (string containing the CSS to be added), + * style_data (theme.json-like object to generate CSS from). + * + * @return bool True if all block styles were registered with success and false otherwise. + */ + function gutenberg_register_block_style( $block_name, $style_properties ) { + if ( ! is_string( $block_name ) && ! is_array( $block_name ) ) { + _doing_it_wrong( + __METHOD__, + __( 'Block name must be a string or array.', 'gutenberg' ), + '6.6.0' + ); + + return false; + } + + $block_names = is_string( $block_name ) ? array( $block_name ) : $block_name; + $result = true; + + foreach ( $block_names as $name ) { + if ( ! WP_Block_Styles_Registry::get_instance()->register( $name, $style_properties ) ) { + $result = false; + } + } + + return $result; + } +} diff --git a/packages/blocks/README.md b/packages/blocks/README.md index 8e6fdc9d900dbb..40861862585739 100644 --- a/packages/blocks/README.md +++ b/packages/blocks/README.md @@ -507,7 +507,7 @@ _Parameters_ ### registerBlockStyle -Registers a new block style for the given block. +Registers a new block style for the given block types. For more information on connecting the styles with CSS [the official documentation](https://developer.wordpress.org/block-editor/reference-guides/block-api/block-styles/#styles). @@ -536,7 +536,7 @@ const ExampleComponent = () => { _Parameters_ -- _blockName_ `string`: Name of block (example: “core/latest-posts”). +- _blockNames_ `string|Array`: Name of blocks e.g. “core/latest-posts” or `["core/group", "core/columns"]`. - _styleVariation_ `Object`: Object containing `name` which is the class name applied to the block and `label` which identifies the variation to the user. ### registerBlockType diff --git a/packages/blocks/src/api/registration.js b/packages/blocks/src/api/registration.js index 52a2f309837326..fb21b7083b0c54 100644 --- a/packages/blocks/src/api/registration.js +++ b/packages/blocks/src/api/registration.js @@ -611,13 +611,13 @@ export const hasChildBlocksWithInserterSupport = ( blockName ) => { }; /** - * Registers a new block style for the given block. + * Registers a new block style for the given block types. * * For more information on connecting the styles with CSS * [the official documentation](https://developer.wordpress.org/block-editor/reference-guides/block-api/block-styles/#styles). * - * @param {string} blockName Name of block (example: “core/latest-posts”). - * @param {Object} styleVariation Object containing `name` which is the class name applied to the block and `label` which identifies the variation to the user. + * @param {string|Array} blockNames Name of blocks e.g. “core/latest-posts” or `["core/group", "core/columns"]`. + * @param {Object} styleVariation Object containing `name` which is the class name applied to the block and `label` which identifies the variation to the user. * * @example * ```js @@ -642,8 +642,8 @@ export const hasChildBlocksWithInserterSupport = ( blockName ) => { * }; * ``` */ -export const registerBlockStyle = ( blockName, styleVariation ) => { - dispatch( blocksStore ).addBlockStyles( blockName, styleVariation ); +export const registerBlockStyle = ( blockNames, styleVariation ) => { + dispatch( blocksStore ).addBlockStyles( blockNames, styleVariation ); }; /** diff --git a/packages/blocks/src/store/actions.js b/packages/blocks/src/store/actions.js index d3bd71c067ebe3..34216e05808ad7 100644 --- a/packages/blocks/src/store/actions.js +++ b/packages/blocks/src/store/actions.js @@ -98,18 +98,18 @@ export function removeBlockTypes( names ) { * Returns an action object used in signalling that new block styles have been added. * Ignored from documentation as the recommended usage for this action through registerBlockStyle from @wordpress/blocks. * - * @param {string} blockName Block name. - * @param {Array|Object} styles Block style object or array of block style objects. + * @param {string|Array} blockNames Block names to register new styles for. + * @param {Array|Object} styles Block style object or array of block style objects. * * @ignore * * @return {Object} Action object. */ -export function addBlockStyles( blockName, styles ) { +export function addBlockStyles( blockNames, styles ) { return { type: 'ADD_BLOCK_STYLES', styles: Array.isArray( styles ) ? styles : [ styles ], - blockName, + blockNames: Array.isArray( blockNames ) ? blockNames : [ blockNames ], }; } diff --git a/packages/blocks/src/store/reducer.js b/packages/blocks/src/store/reducer.js index 7a3a866485e4a9..17af10331e4ed7 100644 --- a/packages/blocks/src/store/reducer.js +++ b/packages/blocks/src/store/reducer.js @@ -201,13 +201,14 @@ export function blockStyles( state = {}, action ) { ), }; case 'ADD_BLOCK_STYLES': - return { - ...state, - [ action.blockName ]: getUniqueItemsByName( [ - ...( state[ action.blockName ] ?? [] ), + const updatedStyles = {}; + action.blockNames.forEach( ( blockName ) => { + updatedStyles[ blockName ] = getUniqueItemsByName( [ + ...( state[ blockName ] ?? [] ), ...action.styles, - ] ), - }; + ] ); + } ); + return { ...state, ...updatedStyles }; case 'REMOVE_BLOCK_STYLES': return { ...state, diff --git a/packages/blocks/src/store/test/reducer.js b/packages/blocks/src/store/test/reducer.js index 5664f9d876cb6e..babaaad4e0e0d7 100644 --- a/packages/blocks/src/store/test/reducer.js +++ b/packages/blocks/src/store/test/reducer.js @@ -10,6 +10,7 @@ import { addBlockVariations, addBlockTypes, removeBlockVariations, + addBlockStyles, } from '../actions'; import { unprocessedBlockTypes, @@ -108,30 +109,55 @@ describe( 'blockStyles', () => { expect( blockStyles( undefined, {} ) ).toEqual( {} ); } ); - it( 'should add a new block styles', () => { + it( 'should add new block styles for a single block type', () => { const original = deepFreeze( {} ); - let state = blockStyles( original, { - type: 'ADD_BLOCK_STYLES', - blockName, - styles: [ { name: 'fancy' } ], - } ); + let state = blockStyles( + original, + addBlockStyles( blockName, [ { name: 'fancy' } ] ) + ); expect( state ).toEqual( { [ blockName ]: [ { name: 'fancy' } ], } ); - state = blockStyles( state, { - type: 'ADD_BLOCK_STYLES', - blockName, - styles: [ { name: 'lightbox' } ], - } ); + state = blockStyles( + state, + addBlockStyles( blockName, [ { name: 'lightbox' } ] ) + ); expect( state ).toEqual( { [ blockName ]: [ { name: 'fancy' }, { name: 'lightbox' } ], } ); } ); + it( 'should add block styles for array of block types', () => { + const original = deepFreeze( {} ); + + let state = blockStyles( + original, + addBlockStyles( + [ 'core/group', 'core/columns' ], + [ { name: 'dark' } ] + ) + ); + + expect( state ).toEqual( { + 'core/group': [ { name: 'dark' } ], + 'core/columns': [ { name: 'dark' } ], + } ); + + state = blockStyles( + state, + addBlockStyles( [ 'core/group' ], [ { name: 'light' } ] ) + ); + + expect( state ).toEqual( { + 'core/group': [ { name: 'dark' }, { name: 'light' } ], + 'core/columns': [ { name: 'dark' } ], + } ); + } ); + it( 'should prepend block styles when adding a block', () => { const original = deepFreeze( { [ blockName ]: [ { name: 'fancy' } ], diff --git a/phpunit/blocks/register-block-style-test.php b/phpunit/blocks/register-block-style-test.php new file mode 100644 index 00000000000000..1becaff347e5fa --- /dev/null +++ b/phpunit/blocks/register-block-style-test.php @@ -0,0 +1,32 @@ + 'fancy', + 'label' => 'Fancy', + ); + + gutenberg_register_block_style( $block_types, $style_properties ); + $registry = WP_Block_Styles_Registry::get_instance(); + + $this->assertTrue( $registry->is_registered( 'core/group', 'fancy' ) ); + $this->assertTrue( $registry->is_registered( 'core/columns', 'fancy' ) ); + $this->assertTrue( $registry->is_registered( 'core/cover', 'fancy' ) ); + } +}