gutenberg icon indicating copy to clipboard operation
gutenberg copied to clipboard

[WIP] Block Styles: Explore per-instance stylesheets for application of block style variations

Open aaronrobertshaw opened this issue 2 years ago • 11 comments

Depends on: Try reducing specificity of global styles block selector. #57841 Addresses: Section Styling, Colorways, and Typesets for WP 6.6 #57537

⚠️ Important: This PR depends on the feasibility of https://github.com/WordPress/gutenberg/pull/57841 and broadly reducing the specificity of global styles. Any help testing and reviewing https://github.com/WordPress/gutenberg/pull/57841 would help land this feature. ⚠️

Note: There are several less than ideal hacks and workarounds in the current approach here but it works. The plan is to use this PR to inform what foundational changes we might make e.g. new APIs, hooks etc., such that the implementation of extended block style variations here can be much cleaner.

What?

This PR explores an alternate approach to https://github.com/WordPress/gutenberg/pull/56540.

https://github.com/WordPress/gutenberg/pull/56540 aimed to render block style variation styles within the overall global styles stylesheet. This was problematic in that it required increasing specificity of element styles applied to block instances as well as being unable to be reliably nested.

The idea in this PR is to reduce the specificity as far as possible for block style variations and their inner element and block type styles. Then generate stylesheets for the application of these variations in the order of their application (parent > child > grandchild etc) such that the correct cascade is maintained. This is so block style variations can be applied on nested blocks.

The reduction of specificity for normal global block styles is being done in https://github.com/WordPress/gutenberg/pull/57841. This PR will need to be rebased on that work as it progresses.

Why?

The ability to style entire sections of a page without having to tediously reapply the same sets of styles is greatly desired. Block style variations seemed to be the best mechanism for defining these styles.

How?

  • Extends registration of block style variations so they can be:
    • registered across multiple block types
    • registered with an optional style object in place of a stylesheet or handle
  • Supports automatic registration of block style variations that are defined via:
    • Standalone theme.json partial files within a theme's /block-styles directory
    • The styles.blocks.variations property of a theme's primary theme.json file
    • The styles.blocks.variations property of a theme style variation partial theme.json
  • Existing theme.json data filters have been leveraged to absorb the above shared block style variation definitions into their respective block type styles: e.g. styles.blocks.core/group.variations
  • A "variations" block support has been added that injects a unique CSS class per block instance application of a block style variation.
  • The "variations" block support also generates a partial theme.json stylesheet for each application of a variation (this is the key to nesting variations)
  • Updates the global styles output hook to allow better control over what styles are generated, e.g. skipping layout styles.
  • Adds JS hook for variations and defines useBlockProps to generate the styles on the editor side so they update correctly upon application to blocks.
  • Exposes theme.json data within the block editor so variation styles can be generated on the fly
  • Block style variation definitions are applied in the following order:
    • Block style registry
    • Shared theme.json partials in /block-styles
    • Primary theme.json file
    • User origin data e.g. applied theme style variation definitions
  • Theme.json class has been updated to not strip out extended block style variation data e.g. inner element/block type styles or shared variation definitions.
  • The theme.json class generation of block metadata was tweaked so that:
    • Block style variations within the block styles registry are included in the valid variations
    • The block style registry is still checked when retrieving cached block metadata in the case the registered block types hasn't changed.
  • Theme.json stylesheet generation now allows skipping layout styles so that partial stylesheets can be generated with reduced styles
  • useGlobalStylesOutput updated in the same way to allow opting out of certain styles
  • useStyleOverride was updated to preserve the insertion order of style overrides so the correct cascade is maintained in face of the zero specificity styles used.
  • Group block example has had its hardcoded styles removed so its block style previews aren't impacted
  • Global Styles Provider required updating to merge user origin definitions (those from theme style variations) into their respective block types
  • Global Styles variation panel has been updated to include core block style variations and those with definitions with merged theme.json data
  • New test theme added with standalone partial theme.json files for block style variations

Next Steps

  • [x] Actually make this functional if the approach is feasible (concerns over performance, excess CSS etc)
  • [x] Test to see if it solves the difficulties #56540 is facing
  • [x] Update theme.json resolver unit tests for new sources of block style variations
  • [ ] UI updates (e.g. allowing updates to inner element / block type styles for variations)

Testing Instructions

Setting up test block style variations

There are several methods by which block style variations can be added.

  1. Programmatically via gutenberg_register_block_style
  2. By standalone theme.json partials within a theme's /block-styles subdirectory
  3. Via theme style variations defining block style variations under styles.blocks.variations

Programmatically

Within a theme's functions.php or a plugin, a call can me made to the new extended version of gutenberg_register_block_style, passing it an array of block types the variation can be used with as well as a style object definition the variation's styles. The theme.json resolver will absorb any styles registered via this approach into the theme's theme.json data.

Example usage
gutenberg_register_block_style(
	array( 'core/group', 'core/columns' ),
	array(
		'name'       => 'green',
		'label'      => __( 'Green', 'twentytwentythree' ),
		'style_data' => array(
			'color'    => array(
				'background' => '#4f6f52',
				'text'       => '#d2e3c8',
			),
			'blocks'   => array(
				'core/group' => array(
					'color' => array(
						'background' => '#739072',
						'text'       => '#e3eedd',
					),
				),
			),
			'elements' => array(
				'link'   => array(
					'color'  => array(
						'text' => '#ead196',
					),
					':hover' => array(
						'color' => array(
							'text' => '#ebd9b4',
						),
					),
				),
			),
		),
	)
)

Standalone partial files

These partials will live (for now) under the /block-styles directory in the theme directory. They'll also need a new top-level property supportedBlockTypes to define an array of block types the variation is available for. These block style variations will be automatically registered and absorbed into the theme's theme.json data by the resolver.

Example
{
	"$schema": "https://schemas.wp.org/trunk/theme.json",
	"version": 2,
	"title": "Variation A",
	"supportedBlockTypes": [
		"core/group",
		"core/columns",
		"core/media-text"
	],
	"styles": {
		"color": {
			"background": "var(--wp--preset--color--tertiary)",
			"text": "var(--wp--preset--color--light)"
		},
		"elements": {
			"heading": {
				"color": {
					"text": "var(--wp--preset--color--light)"
				}
			}
		},
		"blocks": {
			"core/group": {
				"color": {
					"background": "var(--wp--preset--color--light)",
					"text": "var(--wp--preset--color--tertiary)"
				},
				"elements": {
					"heading": {
						"color": {
							"text": "var(--wp--preset--color--tertiary)"
						}
					}
				}
			}
		}
	}
}

Defined by theme style variations

As theme style variations are essentially theme.json partials themselves that are copied into the user origin's theme.json data, they can't easily pull into other partials for block style variations. This lead to reintroducing the styles.blocks.variations property for theme.json.

Similar to the standalone block style variations, each definition under styles.blocks.variations will require a new property supportedBlockTypes to define the block types that get the variation.

Example
{
	"$schema": "https://schemas.wp.org/trunk/theme.json",
	"version": 2,
	"title": "Red",
	"styles": {
		"blocks": {
			"variations": {
				"variation-a": {
					"supportedBlockTypes": [
						"core/group",
						"core/columns"
					],
					"color": {
						"background": "var(--wp--preset--color--dark)",
						"text": "var(--wp--preset--color--secondary)"
					},
					"elements": {
						"heading": {
							"color": {
								"text": "var(--wp--preset--color--secondary)"
							}
						}
					},
					"blocks": {
						"core/group": {
							"color": {
								"background": "var(--wp--preset--color--subdued)",
								"text": "var(--wp--preset--color--tertiary)"
							},
							"elements": {
								"heading": {
									"color": {
										"text": "var(--wp--preset--color--tertiary)"
									}
								}
							}
						}
					}
				}
			}
		}
	}
}

Things to test

  1. Confirm each method of block style variation registration works and they are available in both editors
  2. Check that existing block style variations on core blocks continue to work
  3. Test applying a block style variation correctly applies its styles to the block, inner elements, and inner blocks as per the variation's definition
  4. Test that applying a variation within a block that already has a variation has the correct styles applied i.e. the inner variation's styles should be applied even if the variation applied to an outer block defines inner block styles
  5. With variations applied to several blocks including nesting variations, ensure that switching block style variations works as expected in the editors
  6. Make sure that setting element styles on an individual block instance continues to take precedence
  7. Check that the frontend matches the display in the editor
  8. Try out editing a theme.json file, setting its schema to the updated version in this PR, and check the auto-completion, linting etc works as desired.
  9. Updated unit tests should be passing as well:
npm run test:unit:php:base -- --filter WP_Theme_JSON_Gutenberg_Test
npm run test:unit:php:base -- --filter WP_Theme_JSON_Resolver_Gutenberg_Test
npm run test:unit packages/block-editor/src/components/global-styles/test/use-global-styles-output.js

Testing Instructions for Keyboard

Screenshots or screencast

https://github.com/WordPress/gutenberg/assets/60436221/34f708c5-a0d9-4535-9087-fd93a1a380db

aaronrobertshaw avatar Jan 17 '24 07:01 aaronrobertshaw

This pull request has changed or added PHP files. Please confirm whether these changes need to be synced to WordPress Core, and therefore featured in the next release of WordPress.

If so, it is recommended to create a new Trac ticket and submit a pull request to the WordPress Core Github repository soon after this pull request is merged.

If you're unsure, you can always ask for help in the #core-editor channel in WordPress Slack.

Thank you! :heart:

View changed files
:grey_question: lib/block-supports/block-style-variations.php
:grey_question: phpunit/block-supports/block-style-variations-test.php
:grey_question: phpunit/data/themedir1/block-theme-child-with-block-style-variations/style.css
:grey_question: phpunit/data/themedir1/block-theme-child-with-block-style-variations/styles/block-style-variation-a.json
:grey_question: phpunit/data/themedir1/block-theme-child-with-block-style-variations/theme.json
:grey_question: phpunit/data/themedir1/block-theme/styles/block-style-variation-a.json
:grey_question: phpunit/data/themedir1/block-theme/styles/block-style-variation-b.json
:grey_question: lib/class-wp-theme-json-gutenberg.php
:grey_question: lib/class-wp-theme-json-resolver-gutenberg.php
:grey_question: lib/load.php
:grey_question: phpunit/class-wp-theme-json-resolver-test.php

github-actions[bot] avatar Jan 24 '24 06:01 github-actions[bot]

Size Change: -422 B (-0.02%)

Total Size: 1.74 MB

Filename Size Change
build/block-editor/index.min.js 260 kB +394 B (+0.15%)
build/block-editor/style-rtl.css 15.6 kB +65 B (+0.42%)
build/block-editor/style.css 15.6 kB +66 B (+0.43%)
build/block-library/blocks/block/editor-rtl.css 0 B -277 B (removed) 🏆
build/block-library/blocks/block/editor.css 0 B -277 B (removed) 🏆
build/block-library/blocks/cover/editor-rtl.css 667 B -4 B (-0.6%)
build/block-library/blocks/cover/editor.css 670 B -4 B (-0.59%)
build/block-library/blocks/cover/style-rtl.css 1.62 kB -48 B (-2.87%)
build/block-library/blocks/cover/style.css 1.61 kB -48 B (-2.89%)
build/block-library/blocks/latest-posts/editor-rtl.css 205 B -32 B (-13.5%) 👏
build/block-library/blocks/latest-posts/editor.css 205 B -31 B (-13.14%) 👏
build/block-library/blocks/list/style-rtl.css 102 B +14 B (+15.91%) ⚠️
build/block-library/blocks/list/style.css 102 B +14 B (+15.91%) ⚠️
build/block-library/blocks/paragraph/style-rtl.css 341 B +6 B (+1.79%)
build/block-library/blocks/paragraph/style.css 341 B +6 B (+1.79%)
build/block-library/editor-rtl.css 12 kB -165 B (-1.36%)
build/block-library/editor.css 12 kB -172 B (-1.42%)
build/block-library/index.min.js 218 kB +22 B (+0.01%)
build/block-library/style-rtl.css 14.6 kB -40 B (-0.27%)
build/block-library/style.css 14.6 kB -40 B (-0.27%)
build/compose/index.min.js 12.8 kB -3 B (-0.02%)
build/edit-post/index.min.js 14.5 kB -30 B (-0.21%)
build/edit-post/style-rtl.css 2.36 kB -88 B (-3.59%)
build/edit-post/style.css 2.36 kB -87 B (-3.56%)
build/edit-site/index.min.js 210 kB +57 B (+0.03%)
build/edit-site/style-rtl.css 12 kB -192 B (-1.58%)
build/edit-site/style.css 12 kB -191 B (-1.57%)
build/edit-widgets/style-rtl.css 4.19 kB +9 B (+0.22%)
build/edit-widgets/style.css 4.18 kB +4 B (+0.1%)
build/editor/index.min.js 92.6 kB +495 B (+0.54%)
build/editor/style-rtl.css 8.78 kB +7 B (+0.08%)
build/editor/style.css 8.78 kB +1 B (+0.01%)
build/interactivity/debug.min.js 16.5 kB +75 B (+0.46%)
build/interactivity/index.min.js 13.3 kB +72 B (+0.54%)
ℹ️ View Unchanged
Filename Size
build/a11y/index.min.js 955 B
build/annotations/index.min.js 2.27 kB
build/api-fetch/index.min.js 2.32 kB
build/autop/index.min.js 2.1 kB
build/blob/index.min.js 578 B
build/block-directory/index.min.js 7.29 kB
build/block-directory/style-rtl.css 1.03 kB
build/block-directory/style.css 1.03 kB
build/block-editor/content-rtl.css 4.58 kB
build/block-editor/content.css 4.57 kB
build/block-editor/default-editor-styles-rtl.css 395 B
build/block-editor/default-editor-styles.css 395 B
build/block-library/blocks/archives/editor-rtl.css 61 B
build/block-library/blocks/archives/editor.css 60 B
build/block-library/blocks/archives/style-rtl.css 90 B
build/block-library/blocks/archives/style.css 90 B
build/block-library/blocks/audio/editor-rtl.css 150 B
build/block-library/blocks/audio/editor.css 150 B
build/block-library/blocks/audio/style-rtl.css 122 B
build/block-library/blocks/audio/style.css 122 B
build/block-library/blocks/audio/theme-rtl.css 126 B
build/block-library/blocks/audio/theme.css 126 B
build/block-library/blocks/avatar/editor-rtl.css 116 B
build/block-library/blocks/avatar/editor.css 116 B
build/block-library/blocks/avatar/style-rtl.css 104 B
build/block-library/blocks/avatar/style.css 104 B
build/block-library/blocks/button/editor-rtl.css 307 B
build/block-library/blocks/button/editor.css 307 B
build/block-library/blocks/button/style-rtl.css 539 B
build/block-library/blocks/button/style.css 539 B
build/block-library/blocks/buttons/editor-rtl.css 337 B
build/block-library/blocks/buttons/editor.css 337 B
build/block-library/blocks/buttons/style-rtl.css 332 B
build/block-library/blocks/buttons/style.css 332 B
build/block-library/blocks/calendar/style-rtl.css 239 B
build/block-library/blocks/calendar/style.css 239 B
build/block-library/blocks/categories/editor-rtl.css 113 B
build/block-library/blocks/categories/editor.css 112 B
build/block-library/blocks/categories/style-rtl.css 124 B
build/block-library/blocks/categories/style.css 124 B
build/block-library/blocks/code/editor-rtl.css 53 B
build/block-library/blocks/code/editor.css 53 B
build/block-library/blocks/code/style-rtl.css 121 B
build/block-library/blocks/code/style.css 121 B
build/block-library/blocks/code/theme-rtl.css 124 B
build/block-library/blocks/code/theme.css 124 B
build/block-library/blocks/columns/editor-rtl.css 108 B
build/block-library/blocks/columns/editor.css 108 B
build/block-library/blocks/columns/style-rtl.css 421 B
build/block-library/blocks/columns/style.css 421 B
build/block-library/blocks/comment-author-avatar/editor-rtl.css 125 B
build/block-library/blocks/comment-author-avatar/editor.css 125 B
build/block-library/blocks/comment-content/style-rtl.css 92 B
build/block-library/blocks/comment-content/style.css 92 B
build/block-library/blocks/comment-template/style-rtl.css 199 B
build/block-library/blocks/comment-template/style.css 198 B
build/block-library/blocks/comments-pagination-numbers/editor-rtl.css 123 B
build/block-library/blocks/comments-pagination-numbers/editor.css 121 B
build/block-library/blocks/comments-pagination/editor-rtl.css 222 B
build/block-library/blocks/comments-pagination/editor.css 209 B
build/block-library/blocks/comments-pagination/style-rtl.css 235 B
build/block-library/blocks/comments-pagination/style.css 231 B
build/block-library/blocks/comments-title/editor-rtl.css 75 B
build/block-library/blocks/comments-title/editor.css 75 B
build/block-library/blocks/comments/editor-rtl.css 840 B
build/block-library/blocks/comments/editor.css 839 B
build/block-library/blocks/comments/style-rtl.css 637 B
build/block-library/blocks/comments/style.css 636 B
build/block-library/blocks/details/editor-rtl.css 65 B
build/block-library/blocks/details/editor.css 65 B
build/block-library/blocks/details/style-rtl.css 86 B
build/block-library/blocks/details/style.css 86 B
build/block-library/blocks/embed/editor-rtl.css 312 B
build/block-library/blocks/embed/editor.css 312 B
build/block-library/blocks/embed/style-rtl.css 410 B
build/block-library/blocks/embed/style.css 410 B
build/block-library/blocks/embed/theme-rtl.css 126 B
build/block-library/blocks/embed/theme.css 126 B
build/block-library/blocks/file/editor-rtl.css 326 B
build/block-library/blocks/file/editor.css 327 B
build/block-library/blocks/file/style-rtl.css 280 B
build/block-library/blocks/file/style.css 281 B
build/block-library/blocks/file/view.min.js 324 B
build/block-library/blocks/footnotes/style-rtl.css 201 B
build/block-library/blocks/footnotes/style.css 199 B
build/block-library/blocks/form-input/editor-rtl.css 227 B
build/block-library/blocks/form-input/editor.css 227 B
build/block-library/blocks/form-input/style-rtl.css 343 B
build/block-library/blocks/form-input/style.css 343 B
build/block-library/blocks/form-submission-notification/editor-rtl.css 340 B
build/block-library/blocks/form-submission-notification/editor.css 340 B
build/block-library/blocks/form-submit-button/style-rtl.css 69 B
build/block-library/blocks/form-submit-button/style.css 69 B
build/block-library/blocks/form/view.min.js 471 B
build/block-library/blocks/freeform/editor-rtl.css 2.61 kB
build/block-library/blocks/freeform/editor.css 2.61 kB
build/block-library/blocks/gallery/editor-rtl.css 962 B
build/block-library/blocks/gallery/editor.css 965 B
build/block-library/blocks/gallery/style-rtl.css 1.72 kB
build/block-library/blocks/gallery/style.css 1.72 kB
build/block-library/blocks/gallery/theme-rtl.css 108 B
build/block-library/blocks/gallery/theme.css 108 B
build/block-library/blocks/group/editor-rtl.css 403 B
build/block-library/blocks/group/editor.css 403 B
build/block-library/blocks/group/style-rtl.css 103 B
build/block-library/blocks/group/style.css 103 B
build/block-library/blocks/group/theme-rtl.css 78 B
build/block-library/blocks/group/theme.css 78 B
build/block-library/blocks/heading/style-rtl.css 189 B
build/block-library/blocks/heading/style.css 189 B
build/block-library/blocks/html/editor-rtl.css 336 B
build/block-library/blocks/html/editor.css 337 B
build/block-library/blocks/image/editor-rtl.css 891 B
build/block-library/blocks/image/editor.css 891 B
build/block-library/blocks/image/style-rtl.css 1.52 kB
build/block-library/blocks/image/style.css 1.52 kB
build/block-library/blocks/image/theme-rtl.css 137 B
build/block-library/blocks/image/theme.css 137 B
build/block-library/blocks/image/view.min.js 1.54 kB
build/block-library/blocks/latest-comments/style-rtl.css 357 B
build/block-library/blocks/latest-comments/style.css 357 B
build/block-library/blocks/latest-posts/style-rtl.css 512 B
build/block-library/blocks/latest-posts/style.css 512 B
build/block-library/blocks/media-text/editor-rtl.css 306 B
build/block-library/blocks/media-text/editor.css 305 B
build/block-library/blocks/media-text/style-rtl.css 505 B
build/block-library/blocks/media-text/style.css 503 B
build/block-library/blocks/more/editor-rtl.css 431 B
build/block-library/blocks/more/editor.css 431 B
build/block-library/blocks/navigation-link/editor-rtl.css 668 B
build/block-library/blocks/navigation-link/editor.css 669 B
build/block-library/blocks/navigation-link/style-rtl.css 193 B
build/block-library/blocks/navigation-link/style.css 192 B
build/block-library/blocks/navigation-submenu/editor-rtl.css 296 B
build/block-library/blocks/navigation-submenu/editor.css 295 B
build/block-library/blocks/navigation/editor-rtl.css 2.26 kB
build/block-library/blocks/navigation/editor.css 2.26 kB
build/block-library/blocks/navigation/style-rtl.css 2.26 kB
build/block-library/blocks/navigation/style.css 2.25 kB
build/block-library/blocks/navigation/view.min.js 1.03 kB
build/block-library/blocks/nextpage/editor-rtl.css 395 B
build/block-library/blocks/nextpage/editor.css 395 B
build/block-library/blocks/page-list/editor-rtl.css 377 B
build/block-library/blocks/page-list/editor.css 377 B
build/block-library/blocks/page-list/style-rtl.css 175 B
build/block-library/blocks/page-list/style.css 175 B
build/block-library/blocks/paragraph/editor-rtl.css 235 B
build/block-library/blocks/paragraph/editor.css 235 B
build/block-library/blocks/post-author/style-rtl.css 175 B
build/block-library/blocks/post-author/style.css 176 B
build/block-library/blocks/post-comments-form/editor-rtl.css 96 B
build/block-library/blocks/post-comments-form/editor.css 96 B
build/block-library/blocks/post-comments-form/style-rtl.css 508 B
build/block-library/blocks/post-comments-form/style.css 508 B
build/block-library/blocks/post-content/editor-rtl.css 74 B
build/block-library/blocks/post-content/editor.css 74 B
build/block-library/blocks/post-date/style-rtl.css 61 B
build/block-library/blocks/post-date/style.css 61 B
build/block-library/blocks/post-excerpt/editor-rtl.css 71 B
build/block-library/blocks/post-excerpt/editor.css 71 B
build/block-library/blocks/post-excerpt/style-rtl.css 141 B
build/block-library/blocks/post-excerpt/style.css 141 B
build/block-library/blocks/post-featured-image/editor-rtl.css 734 B
build/block-library/blocks/post-featured-image/editor.css 732 B
build/block-library/blocks/post-featured-image/style-rtl.css 342 B
build/block-library/blocks/post-featured-image/style.css 342 B
build/block-library/blocks/post-navigation-link/style-rtl.css 215 B
build/block-library/blocks/post-navigation-link/style.css 214 B
build/block-library/blocks/post-template/editor-rtl.css 99 B
build/block-library/blocks/post-template/editor.css 98 B
build/block-library/blocks/post-template/style-rtl.css 397 B
build/block-library/blocks/post-template/style.css 396 B
build/block-library/blocks/post-terms/style-rtl.css 96 B
build/block-library/blocks/post-terms/style.css 96 B
build/block-library/blocks/post-time-to-read/style-rtl.css 69 B
build/block-library/blocks/post-time-to-read/style.css 69 B
build/block-library/blocks/post-title/style-rtl.css 100 B
build/block-library/blocks/post-title/style.css 100 B
build/block-library/blocks/preformatted/style-rtl.css 125 B
build/block-library/blocks/preformatted/style.css 125 B
build/block-library/blocks/pullquote/editor-rtl.css 135 B
build/block-library/blocks/pullquote/editor.css 135 B
build/block-library/blocks/pullquote/style-rtl.css 344 B
build/block-library/blocks/pullquote/style.css 343 B
build/block-library/blocks/pullquote/theme-rtl.css 168 B
build/block-library/blocks/pullquote/theme.css 168 B
build/block-library/blocks/query-pagination-numbers/editor-rtl.css 122 B
build/block-library/blocks/query-pagination-numbers/editor.css 121 B
build/block-library/blocks/query-pagination/editor-rtl.css 221 B
build/block-library/blocks/query-pagination/editor.css 211 B
build/block-library/blocks/query-pagination/style-rtl.css 288 B
build/block-library/blocks/query-pagination/style.css 284 B
build/block-library/blocks/query-title/style-rtl.css 63 B
build/block-library/blocks/query-title/style.css 63 B
build/block-library/blocks/query/editor-rtl.css 486 B
build/block-library/blocks/query/editor.css 486 B
build/block-library/blocks/query/view.min.js 958 B
build/block-library/blocks/quote/style-rtl.css 237 B
build/block-library/blocks/quote/style.css 237 B
build/block-library/blocks/quote/theme-rtl.css 223 B
build/block-library/blocks/quote/theme.css 226 B
build/block-library/blocks/read-more/style-rtl.css 140 B
build/block-library/blocks/read-more/style.css 140 B
build/block-library/blocks/rss/editor-rtl.css 101 B
build/block-library/blocks/rss/editor.css 101 B
build/block-library/blocks/rss/style-rtl.css 289 B
build/block-library/blocks/rss/style.css 288 B
build/block-library/blocks/search/editor-rtl.css 184 B
build/block-library/blocks/search/editor.css 184 B
build/block-library/blocks/search/style-rtl.css 690 B
build/block-library/blocks/search/style.css 689 B
build/block-library/blocks/search/theme-rtl.css 114 B
build/block-library/blocks/search/theme.css 114 B
build/block-library/blocks/search/view.min.js 478 B
build/block-library/blocks/separator/editor-rtl.css 99 B
build/block-library/blocks/separator/editor.css 99 B
build/block-library/blocks/separator/style-rtl.css 248 B
build/block-library/blocks/separator/style.css 248 B
build/block-library/blocks/separator/theme-rtl.css 194 B
build/block-library/blocks/separator/theme.css 194 B
build/block-library/blocks/shortcode/editor-rtl.css 286 B
build/block-library/blocks/shortcode/editor.css 286 B
build/block-library/blocks/site-logo/editor-rtl.css 805 B
build/block-library/blocks/site-logo/editor.css 805 B
build/block-library/blocks/site-logo/style-rtl.css 218 B
build/block-library/blocks/site-logo/style.css 218 B
build/block-library/blocks/site-tagline/editor-rtl.css 86 B
build/block-library/blocks/site-tagline/editor.css 86 B
build/block-library/blocks/site-title/editor-rtl.css 124 B
build/block-library/blocks/site-title/editor.css 124 B
build/block-library/blocks/site-title/style-rtl.css 70 B
build/block-library/blocks/site-title/style.css 70 B
build/block-library/blocks/social-link/editor-rtl.css 335 B
build/block-library/blocks/social-link/editor.css 335 B
build/block-library/blocks/social-links/editor-rtl.css 683 B
build/block-library/blocks/social-links/editor.css 681 B
build/block-library/blocks/social-links/style-rtl.css 1.51 kB
build/block-library/blocks/social-links/style.css 1.51 kB
build/block-library/blocks/spacer/editor-rtl.css 350 B
build/block-library/blocks/spacer/editor.css 350 B
build/block-library/blocks/spacer/style-rtl.css 48 B
build/block-library/blocks/spacer/style.css 48 B
build/block-library/blocks/table/editor-rtl.css 395 B
build/block-library/blocks/table/editor.css 395 B
build/block-library/blocks/table/style-rtl.css 639 B
build/block-library/blocks/table/style.css 639 B
build/block-library/blocks/table/theme-rtl.css 146 B
build/block-library/blocks/table/theme.css 146 B
build/block-library/blocks/tag-cloud/style-rtl.css 265 B
build/block-library/blocks/tag-cloud/style.css 266 B
build/block-library/blocks/template-part/editor-rtl.css 393 B
build/block-library/blocks/template-part/editor.css 393 B
build/block-library/blocks/template-part/theme-rtl.css 112 B
build/block-library/blocks/template-part/theme.css 112 B
build/block-library/blocks/term-description/style-rtl.css 111 B
build/block-library/blocks/term-description/style.css 111 B
build/block-library/blocks/text-columns/editor-rtl.css 95 B
build/block-library/blocks/text-columns/editor.css 95 B
build/block-library/blocks/text-columns/style-rtl.css 166 B
build/block-library/blocks/text-columns/style.css 166 B
build/block-library/blocks/verse/style-rtl.css 99 B
build/block-library/blocks/verse/style.css 99 B
build/block-library/blocks/video/editor-rtl.css 552 B
build/block-library/blocks/video/editor.css 555 B
build/block-library/blocks/video/style-rtl.css 185 B
build/block-library/blocks/video/style.css 185 B
build/block-library/blocks/video/theme-rtl.css 126 B
build/block-library/blocks/video/theme.css 126 B
build/block-library/classic-rtl.css 179 B
build/block-library/classic.css 179 B
build/block-library/common-rtl.css 1.11 kB
build/block-library/common.css 1.11 kB
build/block-library/editor-elements-rtl.css 75 B
build/block-library/editor-elements.css 75 B
build/block-library/elements-rtl.css 54 B
build/block-library/elements.css 54 B
build/block-library/reset-rtl.css 472 B
build/block-library/reset.css 472 B
build/block-library/theme-rtl.css 703 B
build/block-library/theme.css 706 B
build/block-serialization-default-parser/index.min.js 1.12 kB
build/block-serialization-spec-parser/index.min.js 2.87 kB
build/blocks/index.min.js 51.8 kB
build/commands/index.min.js 15.2 kB
build/commands/style-rtl.css 953 B
build/commands/style.css 951 B
build/components/index.min.js 222 kB
build/components/style-rtl.css 12 kB
build/components/style.css 12 kB
build/core-commands/index.min.js 2.71 kB
build/core-data/index.min.js 72.5 kB
build/customize-widgets/index.min.js 10.9 kB
build/customize-widgets/style-rtl.css 1.36 kB
build/customize-widgets/style.css 1.36 kB
build/data-controls/index.min.js 640 B
build/data/index.min.js 9.01 kB
build/date/index.min.js 17.9 kB
build/deprecated/index.min.js 451 B
build/dom-ready/index.min.js 324 B
build/dom/index.min.js 4.65 kB
build/edit-post/classic-rtl.css 578 B
build/edit-post/classic.css 578 B
build/edit-widgets/index.min.js 17.5 kB
build/element/index.min.js 4.83 kB
build/escape-html/index.min.js 537 B
build/format-library/index.min.js 8.09 kB
build/format-library/style-rtl.css 493 B
build/format-library/style.css 492 B
build/hooks/index.min.js 1.55 kB
build/html-entities/index.min.js 448 B
build/i18n/index.min.js 3.58 kB
build/interactivity/file.min.js 447 B
build/interactivity/image.min.js 1.67 kB
build/interactivity/navigation.min.js 1.17 kB
build/interactivity/query.min.js 740 B
build/interactivity/router.min.js 2.81 kB
build/interactivity/search.min.js 618 B
build/is-shallow-equal/index.min.js 527 B
build/keyboard-shortcuts/index.min.js 1.31 kB
build/keycodes/index.min.js 1.46 kB
build/list-reusable-blocks/index.min.js 2.14 kB
build/list-reusable-blocks/style-rtl.css 851 B
build/list-reusable-blocks/style.css 851 B
build/media-utils/index.min.js 2.92 kB
build/modules/importmap-polyfill.min.js 12.2 kB
build/notices/index.min.js 948 B
build/nux/index.min.js 1.58 kB
build/nux/style-rtl.css 748 B
build/nux/style.css 744 B
build/patterns/index.min.js 6.51 kB
build/patterns/style-rtl.css 595 B
build/patterns/style.css 595 B
build/plugins/index.min.js 1.81 kB
build/preferences-persistence/index.min.js 2.06 kB
build/preferences/index.min.js 2.9 kB
build/preferences/style-rtl.css 719 B
build/preferences/style.css 721 B
build/primitives/index.min.js 831 B
build/priority-queue/index.min.js 1.52 kB
build/private-apis/index.min.js 1 kB
build/react-i18n/index.min.js 629 B
build/react-refresh-entry/index.min.js 9.47 kB
build/react-refresh-runtime/index.min.js 6.78 kB
build/redux-routine/index.min.js 2.7 kB
build/reusable-blocks/index.min.js 2.72 kB
build/reusable-blocks/style-rtl.css 256 B
build/reusable-blocks/style.css 256 B
build/rich-text/index.min.js 10.1 kB
build/router/index.min.js 1.96 kB
build/server-side-render/index.min.js 1.97 kB
build/shortcode/index.min.js 1.39 kB
build/style-engine/index.min.js 2.02 kB
build/token-list/index.min.js 582 B
build/url/index.min.js 3.74 kB
build/vendors/react-dom.min.js 42.8 kB
build/vendors/react-jsx-runtime.min.js 554 B
build/vendors/react.min.js 2.65 kB
build/viewport/index.min.js 964 B
build/warning/index.min.js 249 B
build/widgets/index.min.js 7.13 kB
build/widgets/style-rtl.css 1.17 kB
build/widgets/style.css 1.17 kB
build/wordcount/index.min.js 1.02 kB

compressed-size-action

github-actions[bot] avatar Jan 24 '24 06:01 github-actions[bot]

Testing this now: registering styles via PHP is working as expected but I can't get it to work by adding a "variations" section to TT4's styles/ember.json. I just added

"variations": {
				"variation-b": {
					"supportedBlockTypes": [
						"core/group",
						"core/navigation",
						"core/buttons"
					],
					"color": {
						"background": "#334455",
						"text": "#236789"
					},
					"elements": {
						"heading": {
							"color": {
								"text": "#9988dd"
							}
						},
						"button": {
							"background": "#aa22aa"
						}
					},
					"blocks": {
						"core/group": {
							"color": {
								"background": "#229977",
								"text": "#0000ff"
							},
							"elements": {
								"heading": {
									"color": {
										"text": "#00ff00"
									}
								}
							}
						}
					}
				}
			},

under styles > blocks, not sure if that's right?

tellthemachines avatar Feb 12 '24 04:02 tellthemachines

Thanks for giving this a run @tellthemachines 👍

Testing this now: registering styles via PHP is working as expected but I can't get it to work by adding a "variations" section to TT4's styles/ember.json

This is a known issue flagged by @richtabor a few days ago.

The issue is there is no automatic registration of block style variations defined in a theme style variation. It currently relies on the block style variation being registered either by the primary theme (e.g. standalone partial theme.json file under /block-styles) or through the PHP gutenberg_register_block_style function.

I've been AFK recently but am just now picking this back up. So automatic registration of theme style variations should be implemented here soon. What might delay that though is we need to decide if theme style variation definitions of block style variations, should completely replace those defined by the theme or be merged as per about all other Global Styles.

aaronrobertshaw avatar Feb 12 '24 06:02 aaronrobertshaw

we need to decide if theme style variation definitions of block style variations, should completely replace those defined by the theme or be merged as per about all other Global Styles.

I'd lean towards merging to start. Reasoning is you might have variations that just change certain characteristics but not others e.g. you want dark background of parent variation but border radius of child. It's a little more flexible.

SaxonF avatar Feb 12 '24 06:02 SaxonF

I'd lean towards merging to start. Reasoning is you might have variations that just change certain characteristics but not others e.g. you want dark background of parent variation but border radius of child. It's a little more flexible.

Thanks for the quick feedback on that @SaxonF 🚀

The current approach in this PR is to merge any block style variation definitions.

When a theme style variation is applied, its data is basically copied into the user's Global Styles. This includes the new styles.blocks.variations property containing the theme style variation's block style variation definitions.

There is a new filter that resolves these definitions under their respective block types within the user origin. That process honours any current tweaks a user has made to a block style variation for the current theme (including theme style variation).

That side of it is working ok from recent testing. The one catch is how a theme style variation might opt out of a block style variation defined by the primary theme. We might be able to allow the theme style variations to set the block style variation it wants to opt out of to false or something to flag it to be deregistered. This is on my list of things to do.

FWIW, the merging of variation styles is also in line with some other ongoing conversations around how settings should be merged across origins.

Moving forward, I don't think beginning with a merge-based approach hurts us long term.

Any early adopters who would have preferred the "replacement" approach can just define complete overrides for the block style variations within a theme style variation. By that I mean, any styles set on the original variation would have a matching one in the theme style variation version. If we then later moved to a complete replacement of block style variations with those in the theme style variation, those early definitions would only have a few extra styles defined that could potentially be removed.

aaronrobertshaw avatar Feb 12 '24 06:02 aaronrobertshaw

Flaky tests detected in a24faafab6634ce97e55a6d6b0712bc3719a143d. Some tests passed with failed attempts. The failures may not be related to this commit but are still reported for visibility. See the documentation for more information.

🔍 Workflow run URL: https://github.com/WordPress/gutenberg/actions/runs/9263075329 📝 Reported issues:

  • #60678 in /test/e2e/specs/site-editor/site-editor-url-navigation.spec.js

github-actions[bot] avatar Feb 13 '24 08:02 github-actions[bot]

I think this PR is getting closer to being ready to move out of draft status but there are a few aspects to it I'd like to flag and see if there are some better approaches.

~Storing selected block style variation name in block attribtues (style.variation)~

~To support nesting block style variations, the variations styles need to be generated specifically for each application of a variation. For the correct cascade, a parent block's variation styles need to be created before any variation styles for its inner blocks. This led to the use of the pre_render_block filter.~

~The catch is that to retrieve the variation's style data, the name of the variation is required and within the pre_render_block filter, the variation class isn't added to the className attribute. To get this working, the selected variation is stored within the style block attribute.~

~Is there a better approach here?~

Update: As flagged in https://github.com/WordPress/gutenberg/pull/57908#issuecomment-1960708750, the style.variation attribute wasn't required. I haven't tracked down what lead to the incorrect approach above, might have been a bug in a previous iteration of this work I failed to revisit.

Maintaining style load order for editor overrides

With zero specificity styles, the load order is key to the cascade functioning correctly. Before this PR, useStyleOverride would delete and re-add style overrides which alters the insertion order of the underlying Map, breaking the load order of variation styles.

This is complicated further by the need to be able to apply variations to blocks at different levels in the hierarchy, in different orders.

Achieving the desired behaviour, required passing along data that indicated which applications of variations occurred within the inner blocks. This meant that if an existing variation was being changed in the editor, its style overrides could be updated but any overrides for inner variations would be kept/moved after the parent in the load order. While this would already be the case for an existing application of a variation, a new entry in the Map would be required when applying new variations at different levels of the block markup.

To be able to keep the variation IDs predictable and aligned with the generated stylesheet for the variation, it turned out the clientId was a better option than using useInstanceId. Are there any issues with this that I might be missing?

Merging user origin block style variation data in the editor

The requirement to support block style variation definitions from within a theme style variation meant that the variation definitions would live at the user origin level in Global Styles. This meant needing to resolve these definitions into their respective block types on the JS side in the site editor. I wasn't sure where the best place was for this to occur but the GlobalStylesProvider seemed like the best bet, but I'm happy to change this up if anyone has a better idea.

@youknowriad and @ellatrix, if you can spare some time, it would be great to get your thoughts, suggestions, and wisdom on this PR 🙏

aaronrobertshaw avatar Feb 19 '24 02:02 aaronrobertshaw

within the pre_render_block filter, the variation class isn't added to the className attribute

I'm seeing the variation class in there if I print out $block in the pre_render_block filter. It's a direct descendant of $block, so a sibling of style in the array.

Regarding using pre_render_block, I'm not sure if there's any reason not to 😅 . In any case, render_block_data also seems to run in the correct order, so that could be another option here.

tellthemachines avatar Feb 23 '24 04:02 tellthemachines

Thanks for flagging that @tellthemachines, I'll need to revisit that aspect and dig through old notes to see what I was thinking or witnessing when implementing that part. Might be a next week job though.

aaronrobertshaw avatar Feb 23 '24 05:02 aaronrobertshaw

I've pushed a quick fix to remove the superfluous addition of the style.variation attribtue value. After a smoke test, it all still seems to be working ok. Thanks again for challenging that one @tellthemachines, I still don't know what I was thinking or lead me to that.

aaronrobertshaw avatar Feb 23 '24 07:02 aaronrobertshaw

@aaronrobertshaw do you mind rebasing and resolving? I'm looking to test alongside the latest specificity and style presets work.

richtabor avatar Apr 05 '24 15:04 richtabor

do you mind rebasing and resolving?

Rebasing this work onto trunk is already underway although I was balancing efforts there against other work and reviews etc. Should have this up-to-date early this week.

aaronrobertshaw avatar Apr 08 '24 00:04 aaronrobertshaw

Quick Update:

I started the process of rebasing this PR onto trunk but have run into lots of conflicts from varying sources. To be able to discuss some of the requirements of these extended block style variations, I've (hopefully 😅) restored this PR to what it was.

Pending the results of such discussions, it might be easiest to create a fresh PR off trunk. If that eventuates, I'll update this accordingly.

aaronrobertshaw avatar Apr 08 '24 05:04 aaronrobertshaw

The following accounts have interacted with this PR and/or linked issues. I will continue to update these lists as activity occurs. You can also manually ask me to refresh this list by adding the props-bot label.

If you're merging code through a pull request on GitHub, copy and paste the following into the bottom of the merge commit message.

Co-authored-by: aaronrobertshaw <[email protected]>
Co-authored-by: tellthemachines <[email protected]>
Co-authored-by: ramonjd <[email protected]>
Co-authored-by: talldan <[email protected]>
Co-authored-by: youknowriad <[email protected]>
Co-authored-by: ellatrix <[email protected]>
Co-authored-by: SaxonF <[email protected]>
Co-authored-by: richtabor <[email protected]>
Co-authored-by: fabiankaegy <[email protected]>
Co-authored-by: cbirdsong <[email protected]>
Co-authored-by: bacoords <[email protected]>
Co-authored-by: getdave <[email protected]>
Co-authored-by: colorful-tones <[email protected]>
Co-authored-by: hanneslsm <[email protected]>

To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook.

github-actions[bot] avatar Apr 10 '24 07:04 github-actions[bot]

I've reworked a few aspects of this PR and rebased it onto trunk. After some smoke testing locally, I think it's ready for a closer look 🤞

Let me know if you run into any issues with this @richtabor

aaronrobertshaw avatar Apr 10 '24 07:04 aaronrobertshaw

Tagging @WordPress/outreach here to get some more feedback :)

fabiankaegy avatar Apr 10 '24 07:04 fabiankaegy

I just started testing this and the first thing I noticed is that there seems to be something of with the default border radius. This is a clean installation of the tt4 theme comparing trunk (left) with this branch (right)

Trunk This branch
CleanShot 2024-04-10 at 09 43 41@2x CleanShot 2024-04-10 at 09 45 21@2x

fabiankaegy avatar Apr 10 '24 07:04 fabiankaegy

Question:

Would it also be possible to set theme.json "settings" for these block style variations?

I'm asking because a lot of the code that we have to write with this becomes very verbose and repetitive. If instead of having to manually change the background, text, hover etc color for each individual block we could change the actual variable assignment I think that could make this a lot easier to maintain 🤔

Like for example if my theme has a primary-accent color defined. Instead of having to find all the blocks where I used this color and mapping it to a different one in the styles, I would like to remap the primary-accent color from one color to another color.

fabiankaegy avatar Apr 10 '24 09:04 fabiankaegy

First of all, thank you for all the hard work to actually get this working :) This has been a massive effort.

On a high level I have one concern with this currently though. With tying this feature to the block styles API we are again running into the limitation that you can only have one style active at a time. This becomes problematic when you want to offer various color modes like for example light, dark, & colorful and at the same time want to allow different sections to have different section styles for spacing / typography.

As soon as you want to mix these styles you have to duplicate a lot of work and the list of available styles you have to maintain grows exponentially.

The only way around this would be if this feature could be divided to offer different standalone color section styles, spacing section styles, typography section styles etc.

fabiankaegy avatar Apr 10 '24 09:04 fabiankaegy

On a high level I have one concern with this currently though. With tying this feature to the block styles API we are again running into the limitation that you can only have one style active at a time.

Yeah, my first thought was that using a class name prefixed with is-style- would conflict with the traditional registerBlockStyle-based block style system. Could this use a class like has-variation-<whatever> or is-section-style-<whatever> instead? When writing CSS I often use add :not([class*='is-style-']) to selectors so I can avoid targeting elements that already have styles via a block style.

Also, unless I'm misunderstanding, this feature also is not a full replacement for the traditional block style system and will need to work alongside it? For instance, I might want to set a quote block to have different colors/typography in addition to selecting a style that appends a big decorative quote mark using a pseudo element.

Given that, shouldn't this new feature have a distinct name anyway? It's already confusing trying to talk about block styles (the editor feature you use with register_block_style/registerBlockStyle) and block styles (the CSS that is applied to a block), and it will get far worse if this new feature is also called "block styles".

This becomes problematic when you want to offer various color modes like for example light, dark, & colorful and at the same time want to allow different sections to have different section styles for spacing / typography.

The only way around this would be if this feature could be divided to offer different standalone color section styles, spacing section styles, typography section styles etc.

I like this idea. In general colors and typography are separate concerns and forcing them together creates an exponential scaling issue. I expounded on that in a comment over here: https://github.com/WordPress/gutenberg/pull/56234#issuecomment-1819263115

Splitting variations up like this would also address the CSS class issue mentioned above.

cbirdsong avatar Apr 10 '24 16:04 cbirdsong

Given that, shouldn't this new feature have a distinct name anyway? It's already confusing trying to talk about block styles (the editor feature you use with register_block_style/registerBlockStyle) and block styles (the CSS that is applied to a block), and it will get far worse if this new feature is also called "block styles".

As-is, this isn't a "new" feature, but rather than extending block styles to support assigning variations via theme.json, and to multiple blocks at the same time. It's leveraging the existing foundations.

richtabor avatar Apr 10 '24 23:04 richtabor

With tying this feature to the block styles API we are again running into the limitation that you can only have one style active at a time. This becomes problematic when you want to offer various color modes like for example light, dark, & colorful and at the same time want to allow different sections to have different section styles for spacing / typography.

A potential course of action in the near future is to use the same filtering mechanisms that are in place for theme style variations and their color and typography presets here—to have color-only and typography-only block style variations.

There would be the same level of hierarchy, but applied at the block style variation rather than theme.

richtabor avatar Apr 10 '24 23:04 richtabor

On a high level I have one concern with this currently though. With tying this feature to the block styles API we are again running into the limitation that you can only have one style active at a time. This becomes problematic when you want to offer various color modes like for example light, dark, & colorful and at the same time want to allow different sections to have different section styles for spacing / typography.

I think that the ability for block styles to layer/cascade (much like CSS itself) is so critical for them to be much more useful than they are now. If you look at #49278 - one concept is that we would be able to trace a hierarchy of style choices on a particular block attribute, from theme.json through block styles and variations down to the final user preferences.

I understand that multiple styles applied to the same block might cause style conflicts, but that's more like a normal use case of CSS styling that we should account for, rather than letting it limit the view on what block styles could be.

Imagine style variations for the core/button block: one variation could focus on size (increases the padding and font size) and another variation focuses on colors (sets a border, colors, etc). Some style variations would be more narrowly focused like this, and yes some would be more comprehensive and cover a wide range of attributes to fully style an entire block. But the ability to layer multiple block styles and order them would be much more useful and much closer to the way CSS itself (and components in general) expect styling elements to work.

In that respect, the block would be responsible for parsing the variations to give the final value (again, see #49278) and by doing so only needs to render the final set of attribute/utility classes - meaning there's less need for the custom .is-style* classes.

bacoords avatar Apr 10 '24 23:04 bacoords

Thank you, everyone, for all the great feedback, discussion, and testing so far! It's greatly appreciated 🙇

My apologies in advance for the incoming wall of text, but several recent comments all sort of relate and intertwine 🙈

Would it also be possible to set theme.json settings for these block style variations

Yes @fabiankaegy, potentially. It was part of the thinking around offering the standalone theme.json partial files for block style variations. In future iterations of the feature, they could store custom settings for the variation neatly.

Block's currently already support a theme.json settings attribute, so color palettes etc can be switched out. The proposed use case might be close to achievable as is, through those attribute settings. It's a little out of scope for this PR now but could be explored as things stabilize.

On a high level I have one concern with this currently though. With tying this feature to the block styles API we are again running into the limitation that you can only have one style active at a time

Correct, there would be a current limitation of only a single variation being applied at one time.

This has been touched on in several places, most notably in https://github.com/WordPress/gutenberg/pull/57780 and some of the earlier proof of concept PRs linked via the tracking issue in the PR description.

The TL;DR here is:

  • Yes, this feature will initially be limited to a single application of a block style variation, due to single CSS class
  • This PR is only the initial iteration of the feature
  • There should be a path toward being able to apply multiple block style variations to a single block. This may include:
    • Updating logic for determining active block style variation/s
    • Updating the per-variation-application style generation to handle multiple variations or possible merge the data sets
    • Crafting a UX that makes sense, provides necessary guardrails etc. e.g. when selecting traditional block style
  • The general consensus to date has been that we can get to where we need to go from the foundation this PR provides
  • An alternative to support multiple concurrently applied block style variations, is to allow those that represent a subset e.g. color-only, typeset-only etc. to be composed into full block style variations through Global Styles

Yeah, my first thought was that using a class name prefixed with is-style- would conflict with the traditional registerBlockStyle-based block style system

My apologies @cbirdsong if my long-winded PR description made this seem like a new separate feature or concept.

As Rich noted, this isn't really a "new" feature and deliberately builds upon the existing block styles feature. The naming here is tricky but the term "block style variation" is mostly stemming from how these are referred to already within the theme.json code to distinguish them from general styles that are applied to blocks.

Conceptually, this aligns with theme style variations as well as they are all just subsets of theme.json. Different style objects applied at different levels or contexts.

Additionally, core block style variations (block styles registered via block.json for core blocks) already work with theme.json and are configurable through Global Styles.

This enhanced version of block style variations opens that up to custom block style variations, not just those found in core. It also then extends these variations such that they can support inner block type and inner element styles. Lastly, it also allows them to be nested which is one key to making these truly useful in terms of site building. For example, creating a dark full width section within an otherwise overall light theme, then within the dark section displaying cards or something that needs an alternate set of lighter colors/styles.

Could this use a class like has-variation- or is-section-style- instead?

A separate section within theme.json and similar classes to those proposed were explored in earlier proof of concepts. As those explorations progressed however the styles there, more and more, just reflected a block style variation. I think there is too much overlap here to introduce a separate feature that users need to grasp. That said, I do understand extending an existing feature with greater capabilities has similar consequences.

When writing CSS I often use add :not([class*='is-style-']) to selectors so I can avoid targeting elements that already have styles via a block style.

You should still be able to do this. The extended block style variations are really a mechanism to apply preset styles the same as before. It is just the source of those styles that changes given it could be an enqueued stylesheet or something generated via a theme.json-shaped style object.

I do appreciate that if complex block style variations which style inner elements and inner block types are being used, it may be a little trickier to craft the :not selector if you are looking to apply default styles to those inner items. I don't think this poses to be too much of a problem though.

Also, unless I'm misunderstanding, this feature also is not a full replacement for the traditional block style system and will need to work alongside it?

For clarity, I see these extended block style variations as an enhancement and extension of traditional block styles.

You can still register block styles as before, so it's not a replacement, true. Given core blocks can have their block style variations configured already through theme.json it's more of an extension than the separate feature as described.

Given that, shouldn't this new feature have a distinct name anyway?

This is a good question but as this isn't really a new feature it should keep something close to the original terminology. That doesn't mean we can't improve that though!

On the naming and terminology side of things, I have previously questioned the wording around "variations" as we have:

  • Theme style variations (aka Style Variations)
  • Block Styles (aka block style variations)
  • Block Variations (unrelated to styles just preset attributes)

It would be great to rebrand some of those however I think this is a bigger shift that should be outside the scope of this PR.

one concept is that we would be able to trace a hierarchy of style choices on a particular block attribute, from theme.json through block styles and variations down to the final user preferences.

Thanks @bacoords for raising the possible connection here to the style inheritance efforts.

In a way, the extension of block style variations to be generated from theme.json-shaped style objects will help facilitate the tracing of style inheritance better than block styles that enqueue separate stylesheets.

I understand that multiple styles applied to the same block might cause style conflicts...But the ability to layer multiple block styles and order them would be much more useful

Agreed. Working through these edge cases or conflicts, and crafting a UX that makes working with style variations painless and fun, is something we can explore in a follow-up after making what block style variations can do more powerful.

In that respect, the block would be responsible for parsing the variations to give the final value (again, see #49278) and by doing so only needs to render the final set of attribute/utility classes - meaning there's less need for the custom .is-style* classes.

I'm not sure blocks can really be responsible to this degree given backwards compatibility with old block styles enqueuing stylesheets etc. Also, the desire to be able to style inner elements and block types within a section effectively blocks the proposed application of attribute/utility classes by the block on itself, I think.

🤞 I hope all this helps clear up a few things. Thanks for taking the time to read it all.


TL;DR

  • This PR represents and extension of the existing block styles feature rather than a new separate feature
  • This PR is only the initial iteration for enhanced block style variations
  • There should be a path forward, with further explorations, to allow multiple block style variations to be applied at once
  • The UI can be evolved as it becomes clearer how best to compose different variations
  • Block style variations could in future also contain settings (despite the name literally saying "styles")

If there is agreement and confidence around a potential path to supporting or composing multiple variations on a single block, I propose we move forward with this PR as the initial foundation for that.

The hope is we can land this in Gutenberg soon so there are a number of release cycles for feedback and testing before WordPress 6.6.

aaronrobertshaw avatar Apr 11 '24 06:04 aaronrobertshaw

I noticed is that there seems to be something of with the default border radius

Thanks for flagging that @fabiankaegy, I can replicate the issue 👍

Turns out I missed the opinionated core block styles setting the 9999px border radius in the core image block when reworking this after the recent global styles specificity reduction efforts.

I've added it to my todo list along with an issue raised by @richtabor where block style variations registered in a theme style variation aren't registered in the site editor until the global styles are saved after theme style variation selection.

aaronrobertshaw avatar Apr 11 '24 06:04 aaronrobertshaw

Thanks for all of your work here @aaronrobertshaw 👏

Testing this PR

I took this for a spin by creating a custom version of TT4 and registering some new block style variations aganst the core/group block. I see this as being one of the primary use cases given that it's the most common "sectioning" block.

I found that registering the block style variation as a [theme.json-like] style object in the block-styles/ directory was the most powerful method. The principle reason is that I was able to make use of existing color definitions supplied in the theme's theme.json.

Not only that, but by utilising variables that mirrored the Theme's preset color slugs in my block style variation, I was able to register a new section style called Contrast which was able to adapt nearly seamlessly to all the the Theme Style Variations provided by TT4. I found this to be a powerful feature.

I was also able to successfully test:

  • typography styles
  • element styles
  • sub block styles
Video overview

https://github.com/WordPress/gutenberg/assets/444434/86e709c9-8c2c-473b-834e-6ed4da877bbe

Conclusion

As I understand it, the goal of this effort is to allow users to style entire sections of a template without having to tediously (manually) apply the same sets of styles at a block level.

Augmenting the existing Block Style Variations API (whilst retaining the existing API) seems like a good choice here and utilising the familiar Theme JSON style object format makes this very powerful and seems to achieve at least the majority of the original goal.

I appreciate the concerns others have raised that this API doesn't provide full composability of styles due to the fact that only a single block style variation can be applied at any one time. However, I believe this is acceptable for the first iteration as it moves us a considerable way forward towards achieving the goal of section specific styling.

Moreover, the API is not set in stone. If, following testing in the Gutenberg Plugin, it is determined that this approach is not good enough to land in WordPress 6.6 then we can exclude it from the release and continue to iterate towards a fully composable approach in the Plugin.

Personally, I'm yet to be convinced that users will desire the full composability offered by the possibility of combining multiple variations. I can see this quickly becoming extremely complex to reason about given concerns about specificity and order of application of the block style variations. What a UX for this would look like seems like a difficult problem and I'm not sure users will thank us for providing them with the possibility to mix and match to this level of granularity. Generally I would lean towards allowing Theme authors to provide handpicked variations and keeping choice to a minimal in order to avoid choice paralysis. I'm open to being proven wrong however!

I would also like to encourage us to lean into allowing sufficient time for new features to be tested early in the 6.6 release cycle. If - following a technical review - this feature is deemed "good enough" we should look to land it and experiment in the Plugin as soon as possible. This will then allow plenty of time for the feature to be assessed prior to Beta 1 feature cut off for WordPress 6.6. As I suggested above, if it's not deemed to have sufficient utility we can exclude it from the release, but I believe the best way to test our assumptions is landing the Plugin and allowing folks to make use of it.

getdave avatar Apr 11 '24 14:04 getdave

@getdave I agree with that sentiment. However, I have one question that is a slight tangent from the actual conversation here. But I'm not sure where else to raise it :)

Regarding your final note here:

I would also like to encourage us to lean into allowing sufficient time for new features to be tested early in the 6.6 release cycle. If - following a technical review - this feature is deemed "good enough" we should look to land it and experiment in the Plugin as soon as possible. This will then allow plenty of time for the feature to be assessed prior to Beta 1 feature cut-off for WordPress 6.6. As I suggested above, if it's not deemed to have sufficient utility we can exclude it from the release, but I believe the best way to test our assumptions is landing the Plugin and allowing folks to make use of it.

The piece that I'm struggling with when we do these "fast" merges and want to do quick iterations is that the process of merging something into core is not really a process where we can choose and opt into individual new features that we deem ready. Instead, it is a catch-all unless we do explicit work that excludes a feature from getting moved into core.

This is not at all about this feature here, but I would love to find some way to change that so that we use the "experiment" feature flags much more so that we can actually make a call whether something is ready or not...

fabiankaegy avatar Apr 11 '24 14:04 fabiankaegy

The piece that I'm struggling with when we do these "fast" merges and want to do quick iterations is that the process of merging something into core is not really a process where we can choose and opt into individual new features that we deem ready

It's my understanding that this is a feature that has been top of several contributors' minds for a while now and which has reached an acceptable level of maturity to allow it to land. Therefore, I don't personally consider it an experiment within the context of the Gutenberg Plugin when we consider that by nature is for development and testing "bleeding edge" features.

As I see it (and I am only one contributor so I'd welcome other viewpoints) is that once a "roadmapped" feature reaches a certain level of maturity we should land it in the Plugin to maximise the time available for testing and feedback prior to the next major release of WP Core. It is precisely this cycle that gives us (some of) the information required to determine whether a feature should land in the next major WP release.

What I'm not advocating for is merging unstable or highly experimental features into Gutenberg releases. Those things should probably be behind an experiment flag like Data Views was for a long while before it was considered stable.

Perhaps we should start a Discussion on Github and continue there if required? It would be good to have alignment on these sorts of things.

getdave avatar Apr 11 '24 16:04 getdave

For clarity, I see these extended block style variations as an enhancement and extension of traditional block styles.

You can still register block styles as before, so it's not a replacement, true. Given core blocks can have their block style variations configured already through theme.json it's more of an extension than the separate feature as described.

I find this really confusing - I'm 100% on board with the idea of this feature, but it absolutely does not feel like a enhancement or extension of the existing block style system considering how little it can do. The existing feature is extremely broad in what it can be used to accomplish - it literally just adds a class to the block, which a theme author can use to do anything. In comparison, this new feature is very narrow and is only able to apply a set of color, typography and spacing values to a block.

I can also easily imagine how the two could work well together. For example, here are some ways I've used block styles in recent projects:

  • A quote block style that adds a big decorative quote mark before the text
  • A media & text block style that puts a gradient over the image and pushes it under the edge of the text
  • A list block style to display list items across multiple columns
  • A heading style that adds a decorative dotted line using a pseudo element and an SVG mask

All of these could easily work alongside the ability to select alternate section styles. Making the two mutually exclusive and forcing theme developers and users to choose between them feels like a huge misstep.

cbirdsong avatar Apr 11 '24 17:04 cbirdsong