-
Notifications
You must be signed in to change notification settings - Fork 4.5k
Description
What problem does this address?
It is possible to define multiple variations of the same block. Users can see in the UI a title, description, or icon if the currently applied block variation implements isActive
callback and it returns true
.
isActive
(optional, typeFunction
) - A function that accepts a block's attributes and the variation's attributes and determines if a variation is active. This function doesn't try to find a match dynamically based on all block's attributes, as in many cases some attributes are irrelevant. An example would be forembed
block where we only care aboutproviderNameSlug
attribute's value.It's worth mentioning that setting the
isActive
property can be useful for cases you want to use information from the block variation, after a block's creation. For example, this API is used inuseBlockDisplayInformation
hook to fetch and display proper information on places like theBlockCard
orBreadcrumbs
components.
See more in: https://github.com/WordPress/gutenberg/blob/trunk/docs/reference-guides/block-api/block-variations.md
However, it looks like the majority of current usage loops over the list of variations and dynamically injects the isActive
callback. Some examples:
gutenberg/packages/block-library/src/embed/variations.js
Lines 342 to 352 in bbd3333
/** | |
* Add `isActive` function to all `embed` variations, if not defined. | |
* `isActive` function is used to find a variation match from a created | |
* Block by providing its attributes. | |
*/ | |
variations.forEach( ( variation ) => { | |
if ( variation.isActive ) return; | |
variation.isActive = ( blockAttributes, variationAttributes ) => | |
blockAttributes.providerNameSlug === | |
variationAttributes.providerNameSlug; | |
} ); |
gutenberg/packages/block-library/src/social-link/variations.js
Lines 307 to 316 in bbd3333
/** | |
* Add `isActive` function to all `social link` variations, if not defined. | |
* `isActive` function is used to find a variation match from a created | |
* Block by providing its attributes. | |
*/ | |
variations.forEach( ( variation ) => { | |
if ( variation.isActive ) return; | |
variation.isActive = ( blockAttributes, variationAttributes ) => | |
blockAttributes.service === variationAttributes.service; | |
} ); |
With #29095, it is also possible to register block variations on the server. It is impossible to define isActive
in PHP as long as it needs to be represented as a JavaScript callback. It ends up being dynamically injected in JavaScript with the WordPress hook that creates another level of complexity.
gutenberg/packages/block-library/src/navigation-link/hooks.js
Lines 47 to 66 in b620c92
if ( settings.variations ) { | |
const isActive = ( blockAttributes, variationAttributes ) => { | |
return blockAttributes.type === variationAttributes.type; | |
}; | |
const variations = settings.variations.map( ( variation ) => { | |
return { | |
...variation, | |
...( ! variation.icon && { | |
icon: getIcon( variation.name ), | |
} ), | |
...( ! variation.isActive && { | |
isActive, | |
} ), | |
}; | |
} ); | |
return { | |
...settings, | |
variations, | |
}; | |
} |
What is your proposed solution?
Option 1: isActive
allows arrays
This is a simple idea where isActive
could be represented as an array in the case where block variations are registered on the server, e.g.:
array(
'name' => 'category',
'isActive' => array( 'type' ),
// ... other settings
)`
type
is the value of a block attribute in the editor and the type
set as an attribute for the variation. You can think of it as the following condition:
isActive = ( blockAttributes, variationAttributes ) => blockAttributes.type === variationAttributes.type;
Options 2: top-level function on the client
Another option is that we allow defining the top-level API method that returns the name of the currently applied variation. In fact, this is what @ntsekouras originally proposed in #27469 when working on the API, but I convinced him to start with a callback per block variation so we keep the list of top-level settings small.
registerBlockType( 'core/navigation-link', {
getCurrentlyAplliedVariation: ( blockAttributes, blockVariations ) => {
const { name } = find( blockVariations, ( { attributes } ) => blockAttributes.type === attributes.type );
return name;
},
// ... other settings
} );
We could ensure backward compatibility by giving the higher priority the isActive
matches defined on individual block variations.