Proposal: Block Variation Aliases

To provide an easy way for blockBlock Block is the abstract term used to describe units of markup that, composed together, form the content or layout of a webpage using the WordPress editor. The idea combines concepts of what in the past may have achieved with shortcodes, custom HTML, and embed discovery into a single consistent API and user experience. authors to specify variations of a given block that only differ in some attributes and/or inner blocks, WordPress has been providing the Block Variations mechanism, first introduced in version 5.4. This mechanism is widely used in CoreCore Core is the set of software required to run WordPress. The Core Development Team builds WordPress. itself; for example, the Group block has “Row”, “Stack”, and “Grid” variations (that can be selected from the block inspector); the Social Icon block has variations for individual social networks, e.g. wordpress, tumblr, etc.

For WordPress 6.7, we’d like to propose some changes to Block Variations, most notably the following:

  1. Add a variation-specific class name to the block wrapper (i.e. wp-block-${blockName}-${variationName} in addition to the existing wp-block-${blockName}).
    1. Implement server-side detection of the active block variation.
  2. Include the variation name in block markup persisted in the database (e.g. <!-- wp:core/social-link/wordpress {"url":"wordpress.org","service":"wordpress"} /-->).

Below, we discuss each of these suggested changes in more detail.

Add a variation-specific class name to the block wrapper

TracTrac An open source project by Edgewall Software that serves as a bug tracker and project management tool for WordPress. Ticketticket Created for both bug reports and feature development on the bug tracker.: #61265. GutenbergGutenberg The Gutenberg project is the new Editor Interface for WordPress. The editor improves the process and experience of creating new content, making writing rich content much simpler. It uses ‘blocks’ to add richness rather than shortcodes, custom HTML etc. https://wordpress.org/gutenberg/ PR: #61864.

Adding a variation-specific class name will allow block authors to style individual variations of their blocks differently. Some blocks do this already on an individual basis, e.g. the Social Icon block adds a wp-block-social-link-${service} class name.

There is a number of questions that need to be answered here:

First, should a block need to opt in to having the variation class name added, or should it be added automatically? Since there’s already the className block-supports flag – which also controls the addition of the “default” wp-block-${blockName} class name – it might make sense to couple the variation class name to the same flag.

Second, how should existing block markup be handled? There’s the precedent of block deprecations (and migrations) which applies changes to existing blocks when they’re edited – and leaves them otherwise unchanged. If we follow this pattern (albeit probably not on an individual block level but more globally), blocks won’t get the variation class name added as long as the existing markup is not edited.

A different strategy was chosen for the List block whose wrapper element was only recently given the wp-block-list default class name. Here, a server-side render callback was added to inject the new class name into the (otherwise static) existing block markup; i.e., existing List blocks now have the wp-block-list class name added to their wrapper element on the frontend, even if they’re never edited.

In Gutenberg PR #61864, we’ve opted against introducing a new block-supports flag for the variation-specific class name; furthermore, the new class name is currently only added to existing markup when editing it.

If we want a mechanism to add the wp-block-${blockName}-${variationName} class name on the frontend, we need to be able to infer the active block variation for a given block on the server side. This problem is covered in the next section.

Implement server-side detection of the active block variation

Core PR: #6602

Block variations support an isActive property to determine if a given block instance matches the variation, i.e. if the variation is active. That property can either be a JavaScriptJavaScript JavaScript or JS is an object-oriented computer programming language commonly used to create interactive effects within web browsers. WordPress makes extensive use of JS for a better user experience. While PHP is executed on the server, JS executes within a user’s browser. https://www.javascript.com/. function (only if registration of the variation happens on the client side) or an array of block attribute names to compare.

In order for the block variation class name to be added on the server side – which is required to include it on the frontend for dynamic blocks, or for existing static blocks (see previous section) – the server needs to be able to determine which variation is active. To that end, there needs to be a server-side counterpart to the client’s getActiveBlockVariation function that, given the same set of variations, yields the same result. (Note some recent improvements made to the client-side function that the server would need to reproduce.)

Include the variation name in block markup persisted in the database

Gutenberg Issue: #43743. PR: #61678 (experimental).

Finally, we propose to append the variation name (separated by a slash) to the block type name that’s used in block delimiters when persisting markup to the database, so that e.g.  <!-- wp:social-link {"url":"wordpress.org","service":"wordpress"} /--> becomes <!-- wp:core/social-link/wordpress {"url":"wordpress.org","service":"wordpress"} /-->.

This was first proposed by #43743 for the following reasons:

To allow theme developers and users to customize block variations’ styles granularly, e.g. in theme.json, or in the Global Styles panel (#40621). As a corollary, this would allow for an optimization, by attaching variation-specific CSSCSS Cascading Style Sheets. only when the corresponding block variation is present.

Developers could furthermore benefit from all other Block APIAPI An API or Application Programming Interface is a software intermediary that allows programs to interact with each other and share data in limited, clearly defined ways. tools that work on a block type basis. For example, it could be possible to limit usage of a given block variation as another block’s child block via the allowedBlocks field, or to limit the number of instances of a variation in a given post via multiple block support.

One particularly noteworthy example of how block variations can unlock some desirable enhancements for other features is the Block Hooks API: It is currently not possible to use it to insert multiple blocks in the same position if they share the same block type (and are only distinguished by their attributes). Including variation names in the persisted block names can solve this problem, allowing multiple different variations of the same block to be inserted as hooked blocks in the same position.

Finally, using named block variations in persisted markup would give easier access for site owners to the content analysis to determine which blocks and variations are used in posts and templates.

Architecture

Note that while this change would affect the persisted markup, we would seek to contain it there, so that it becomes at once available to some tooling but doesn’t affect everything else adversely. Specifically, we’re not planning to introduce a separate WP_Block_Type object for every single variation; even for WP_Block class instances, we’re currently thinking to strip the /${variationName} part from the block type name upon construction. This way, the appended variation name would be confined to the lowest level of block markup processing, i.e. the “parsed block format” that parses block markup into nested arrays that look as follows:

array(
	'blockName'    => 'core/social-link/wordpress',
	'attrs'        => array(
		'service' => 'wordpress',
		'url'     => 'wordpress.org',
	),
	'innerBlocks'  => array(),
	'innerContent' => array(),
);

Note that this parsing step – unlike the later creation of WP_Block objects – is “dumb” in that it doesn’t have any knowledge of what blocks and block variations are registered.

Furthermore, we would shield the client from this new format by simply removing the appended /${variationName} upon loading the markup in the editor, and by re-appending it upon saving, i.e. when loading markup like <!-- wp:core/social-link/wordpress {"url":"wordpress.org","service":"wordpress"} /--> , it will be transformed into  <!-- wp:social-link {"url":"wordpress.org","service":"wordpress"} /-->  (and back when saving it).

Generated vs arbitrary aliases

Note that #43743 originally proposed allowing arbitrary aliases (e.g. wp:core/wordpress-link). Arbitrary aliases would allow some further improvements that go beyond what is possible with generated aliases. For example, a number of Core blocks could be redefined as variations of other (simpler) Core blocks, by using Block Bindings: For instance, the Post Title block could be redefined as an alias of a variation of the Heading block, where the latter’s content is bound to the current post’s title (which is done via the block’s metadata.bindings attribute and can thus be used to define the variation).

Another benefit of arbitrary aliases is that they do not require the server to determine the active block variation based on the block’s attribute values, as that information is already contained in the alias.

While we’re considering arbitrary aliases for a later stage, we’d like to start by using the information that’s readily available (the block and variation names) rather than introducing a new alias field; it also simplifies the required transformation in the editor (which can simply remove the /${variationName} suffix; inferring the correct variation name on the client side to re-attach it upon saving is no different than determining the active variation via getActiveBlockVariation).

Conclusion

We’re curious to hear your thoughts and feedback on these suggestions, and on the architecture we’re having in mind. Please use the comments below this post to share your feedback on this proposal. Alternatively, you can comment on the individual Trac tickets, issues, and pull requests linked from it.

The feedback period for this proposal will end in three weeks’ time, on 2024-07-14, in order to give us enough time for implementation.

Props @gziolo and @tjcafferkey for review.