Skip to content

Blocks: Make it more flexible to match the currently applied block variation #30739

@gziolo

Description

@gziolo

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, type Function) - 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 for embed block where we only care about providerNameSlug 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 in useBlockDisplayInformation hook to fetch and display proper information on places like the BlockCard or Breadcrumbs 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:

/**
* 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;
} );

/**
* 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.

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.

Metadata

Metadata

Assignees

Labels

Good First IssueAn issue that's suitable for someone looking to contribute for the first timeNeeds DevReady for, and needs developer efforts[Feature] Block APIAPI that allows to express the block paradigm.[Feature] ExtensibilityThe ability to extend blocks or the editing experience[Status] In ProgressTracking issues with work in progress[Type] EnhancementA suggestion for improvement.

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions