Block supports, global styles, and work to consolidate style generation in Gutenberg

Workshop of a painter on glass.

With full site editing and global styles landing in WordPress 5.9, there’s been a lot of feedback and interest in how WordPress (and in particular Gutenberg) generates styles for blocks, and the relationship between styles generated by WordPress, and styles provided by themes.

As some of us explore how all this is hooked together, this post seeks to highlight some of the places in the codebases where things happen, and points to a couple of posts and issues in the Gutenberg repository where work is happening to attempt to consolidate and streamline how styles are generated.

Block supports and where the code lives

So that each block doesn’t have to implement its own ad hoc controls for common features like spacing, color and typography support, block supports are used to consolidate the logic for these shared features. The public documentation on opting-in to supports can be found here and a great read is the architectural overview of styles in the block editor that was recently added. That document wonderfully captures the current state of things, particularly the section on the current limitations of the global styles API.

If you’re taking a look at how things are hooked together, some good places to check out in the Gutenberg and WordPress codebase(s) are:

Individual block level

JS implementation

At an individual block level for (relatively) simple block supports like padding, the style is often saved directly to post content as inline styles, e.g. in hooks/style.js take a look at the filter addSaveProps — this calls the corresponding function that then calls getInlineStyles which looks up the hard-coded style properties in packages/blocks/src/api/constants.js — in this set of style properties, the support array defines the path to the support feature (whether or not it’s opted-into) and the path to get the value from the style object in the block’s attributes.

PHP implementation

For server-rendered blocks, or block supports that require more complexity than rendering to inline styles, then the server-side implementation of block supports is applicable. If you take a look at each of them in lib/block-supports, you should see that the supports will check that the block has opted-in to the support, and that there is currently a style value that needs to be rendered.

Some of the supports, such as the Layout support can get particularly complex. Part the work folks are looking into, will be to try to reduce the complexity and / or improve the API here for how to handle very complex block supports in a more intuitive and less error-prone way. For example, instead of echoing out CSS one string at a time, can the rendering be consolidated?

Global styles level

As pointed out in the styles in the block editor documentation, some of the limitations of global styles, are that unlike the individual block-level block supports, they lack any control over how they output their styles and what they target. Global styles is a fairly simple mechanism of looking up a property and rendering a single property assigned to the container of a block via its classname. Some places to look to see how it’s put together:

  • In class-wp-theme-json.php in core (and overridden in Gutenberg) the PROPERTIES_METADATA constant holds an array of CSS properties matched to their path in theme.json and block attributes. E.g. padding-top comes from within the style object.
  • compute_style_properties is responsible for performing the lookup and outputting an array of declarations.
  • This function is called from get_block_classes for each style node (and also handles the root block selector).
  • And that function is originally called from get_stylesheet.

How could things be consolidated?

There is a tracking issue in the Gutenberg repository for exploring building a “style engine” — this is a general idea that there should be a centralised place for generating and outputting the generated block styles. Given that it’s still an exploratory idea, the scope of what that project might become hasn’t really yet been decided. But, for anyone interested, it’s worth having a read of the linked discussions from the style engine tracking issue — there’s a lot of linked discussion and issues so there’s a fair bit of context to gather!

The style engine conversation came out of this discussion on improving the saving and rendering of block styles, to address problems of inconsistencies and dealing with deprecations. Some of the things folks have stated that they’d like to achieve by consolidating style rendering include:

  • Currently some block supports (such as the Layout support) render an individual style tag with a randomly generated class name, to link the style to the rendered block. It’d be great to consolidate and de-dupe all these styles and class names, for a cleaner DOM but also, to factor in feedback like this issue raised from the perspective of theme authors.
  • Reduce the duplication and separation between individual block supports and global styles, the JS implementation and PHP implementations.
  • Make it easier to safely add additional block supports / additional layouts, etc, and improve support for more complex blocks.
  • Move more of the block supports to consolidate around a consistent server-rendering approach, to reduce the need for saving styles in post content. This should also help avoid the problem where updating how styling works then requires adding or updating deprecations, or accidentally invalidating blocks.

It’s still early days in thinking about how all this should work, so there’s ample room for discussion and exploration in all of the topics. Hopefully some of the above links will be useful for folks curious in seeing how things are hooked together, and where there are suggestions for improving how it all works. One potential direction is an early exploratory PR that seeks to explore how the styles generated for the Layout block support can be consolidated into a single style tag, with de-duped styles and meaningful, non-random class names.

If you’re at all interested in how all this develops, feel free to chime in on any of the issues and discussions!

Leave a Reply

Your email address will not be published. Required fields are marked *