Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Theme.json: Extend block style variations support #56540

Closed
wants to merge 25 commits into from

Conversation

aaronrobertshaw
Copy link
Contributor

@aaronrobertshaw aaronrobertshaw commented Nov 27, 2023

Related:

What?

Extends block style variations to include support for element and inner block type styles as well as registering across multiple block types.

Why?

Enhancing block style variations is an initial step to enabling section based styling.

What?

Extends block style variations to include support for element and inner block type styles as well as registering styles across multiple block types via register_block_style.

How?

  • Added updated gutenberg_register_block_style global function.
    • The WP_Block_Styles_Registry was made final so this was the only straightforward way to extend the block style registration there until it can be backported to core.
  • Theme.json schema was extended to allow inner block type and element styles.
    • The element and block type styles are only supported one level deep in variations there is no recursive support here until there is a real use case for it.
  • The WP_Theme_JSON_Resolver_Gutenberg class will now absorb block style variations registered via WP_Block_Styles_Registry into the theme's theme.json data.
    • This will only occur if the block style was registered with a style object.
  • WP_Theme_JSON_Gutenberg was updated to:
    • support style variations with nested element or inner block type styles
    • allow block styles registered via WP_Block_Styles_Registry instead of stripping them out during sanitization
  • useGlobalStylesOutput hook updated to generate the extended block style variation styles for the site editor
  • Util functions for scoping selectors were tweaked to guard against empty or missing selectors
  • Global Styles variations panel was tweaked to allow block style variations that are from core block styles and custom registered styles with matching variation nodes in the base (core + theme) theme.json.
  • Unit tests were for the extended block style variations

Testing Instructions

The following snippets may be used or provide guidance for testing this PR. They were added to a copy of TT3 for local testing and the demo videos below.

Theme.json snippet for variations
"styles": {
		"blocks": {
			"core/image": {
				"variations": {
					"framed": {
						"border": {
							"color": "darkseagreen",
							"width": "1em",
							"style": "solid"
						}
					}
				}
			},
			"core/group": {
				"variations": {
					"seventies": {
						"color": {
							"background": "#5a3d2b",
							"text": "#ffecb4"
						},
						"elements": {
							"button": {
								"color": {
									"background": "#75c8ae",
									"text": "#f4a127"
								},
								":hover": {
									"color": {
										"text": "#e5771e"
									}
								}
							}
						}
					},
					"eighties": {
						"color": {
							"background": "#1685f8",
							"text": "#faeb2c"
						},
						"elements": {
							"button": {
								"color": {
									"background": "#f52789"
								},
								":hover": {
									"color": {
										"background": "#e900ff"
									}
								}
							}
						}
					},
					"nineties": {
						"color": {
							"background": "#49297e",
							"text": "#90dcff"
						}
					},
					"futuristic": {
						"color": {
							"background": "#202060",
							"text": "#b030b0"
						},
						"typography": {
							"fontSize": "1.5em",
							"fontFamily": "var(--wp--preset--font-family--ibm-plex-mono)"
						},
						"blocks": {
							"core/heading": {
								"color": {
									"text": "#5bc8af"
								}
							},
							"core/paragraph": {
								"color": {
									"text": "#aee4ed"
								}
							},
							"core/image": {
								"border": {
									"color": "darkorange",
									"style": "solid",
									"width": "5px"
								}
							}
						},
						"elements": {
							"link": {
								"color": {
									"text": "#5bc8af"
								},
								":hover": {
									"color": {
										"text": "#b030b0"
									}
								}
							},
							"button": {
								"color": {
									"background": "#b030b0",
									"text": "#aee4ed"
								},
								":hover": {
									"color": {
										"background": "#602080"
									}
								}
							}
						}
					}
				}
			},
			"core/columns": {
				"variations": {
					"seventies": {
						"color": {
							"background": "#5a3d2b",
							"text": "#ffecb4"
						},
						"elements": {
							"button": {
								"color": {
									"background": "#75c8ae",
									"text": "#f4a127"
								},
								":hover": {
									"color": {
										"text": "#e5771e"
									}
								}
							}
						}
					},
					"eighties": {
						"color": {
							"background": "#1685f8",
							"text": "#faeb2c"
						},
						"elements": {
							"button": {
								"color": {
									"background": "#f52789"
								},
								":hover": {
									"color": {
										"background": "#e900ff"
									}
								}
							}
						}
					},
					"nineties": {
						"color": {
							"background": "#49297e",
							"text": "#90dcff"
						}
					},
					"futuristic": {
						"color": {
							"background": "#202060",
							"text": "#b030b0"
						},
						"typography": {
							"fontSize": "1.5em",
							"fontFamily": "var(--wp--preset--font-family--ibm-plex-mono)"
						},
						"blocks": {
							"core/heading": {
								"color": {
									"text": "#5bc8af"
								}
							},
							"core/paragraph": {
								"color": {
									"text": "#aee4ed"
								}
							},
							"core/image": {
								"border": {
									"color": "darkorange",
									"style": "solid",
									"width": "5px"
								}
							}
						},
						"elements": {
							"link": {
								"color": {
									"text": "#5bc8af"
								},
								":hover": {
									"color": {
										"text": "#b030b0"
									}
								}
							},
							"button": {
								"color": {
									"background": "#b030b0",
									"text": "#aee4ed"
								},
								":hover": {
									"color": {
										"background": "#602080"
									}
								}
							}
						}
					}
				}
			},
		},
	}
PHP snippet to register some custom block style variations
<?php

/**
 * Register block styles.
 */

if ( ! function_exists( 'twentytwentythree_block_styles' ) && function_exists( 'gutenberg_register_block_style' ) ) {
	function twentytwentythree_block_styles() {
		gutenberg_register_block_style(
			'core/image',
			array(
				'name'  => 'framed',
				'label' => __( 'Framed', 'twentytwentythree' ),
			)
		);

		gutenberg_register_block_style(
			array( 'core/group', 'core/columns' ),
			array(
				'name'  => 'seventies',
				'label' => __( '70s', 'twentytwentythree' ),
			)
		);
		gutenberg_register_block_style(
			array( 'core/group', 'core/columns' ),
			array(
				'name'  => 'eighties',
				'label' => __( '80s', 'twentytwentythree' ),
			)
		);

		gutenberg_register_block_style(
			array( 'core/columns', 'core/group' ),
			array(
				'name'  => 'nineties',
				'label' => __( '90s', 'twentytwentythree' ),
			)
		);

		gutenberg_register_block_style(
			array( 'core/group', 'core/columns' ),
			array(
				'name'       => 'futuristic',
				'label'      => __( 'Futuristic', 'twentytwentythree' ),
				'style_data' => array(
					'color'      => array(
						'background' => '#202060',
						'text'       => '#b030b0',
					),
					'typography' => array(
						'fontSize'   => '1.5em',
						'fontFamily' => 'var(--wp--preset--font-family--ibm-plex-mono)',
					),
					'blocks'     => array(
						'core/heading'   => array(
							'color' => array(
								'text' => '#5bc8af',
							),
						),
						'core/paragraph' => array(
							'color' => array(
								'text' => '#aee4ed',
							),
						),
						'core/image'     => array(
							'border' => array(
								'color' => 'darkorange',
								'style' => 'solid',
								'width' => '5px',
							),
						),
					),
					'elements'   => array(
						'link'   => array(
							'color'  => array(
								'text' => '#5bc8af',
							),
							':hover' => array(
								'color' => array(
									'text' => '#b030b0',
								),
							),
						),
						'button' => array(
							'color'  => array(
								'background' => '#b030b0',
								'text'       => '#aee4ed',
							),
							':hover' => array(
								'color' => array(
									'background' => '#602080',
								),
							),
						),
					),
				),
			),
		);
	}

	add_action( 'init', 'twentytwentythree_block_styles' );
}

WARNING: If editing theme.json variations that were registered via gutenberg_register_block_style across multiple block types, keep in mind until the theme.json API is extended you might have to update multiple variations in the theme.json

  1. Register some new block style variations in your theme.
    • Include some that contain no stylesheet, handle, or style object (these will validate entries in the theme.json).
    • Add some using the old stylesheet or handle approach
    • Add some with a style object under style_data in the style's properties
  2. Update your theme.json to define styles for desired block style variations registered in step 1.
  3. Edit a post, add blocks for the registered block style variations and apply some of them.
  4. Confirm that the blocks are styled as per the variations
  5. Save the post and confirm these display correctly on the frontend
  6. Switch to the site editor and edit a page or template
  7. Confirm block style variations are working as expected here
  8. Save and preview on the frontend and check everything shows correctly
  9. Now open the Global Styles and select Blocks
  10. Confirm that all the blocks you registered custom block style variations for, that have either a style object at registration or one matching within theme.json, are shown.
  11. Ensure that core block style variations e.g. Rounded for images still show
  12. Test configuring the custom block style variations through Global Styles
  13. Make sure these customized block style variations are reflected in the site editor, post editor, and frontend
  14. Make sure the unit tests for the Theme.json and Theme.json Resolver classes are passing
  • 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
  1. With a user without unfiltered_html capabilities (or emulating via adding add_action( 'init', 'kses_init_filters' ); to your theme functions.php, confirm you can customize element styles for block style variations.

Screenshots or screencast

Screen.Recording.2023-12-14.at.7.10.36.pm.mp4

@aaronrobertshaw aaronrobertshaw added [Type] Enhancement A suggestion for improvement. [Feature] Design Tools Tools that impact the appearance of blocks both to expand the number of tools and improve the experi labels Nov 27, 2023
@aaronrobertshaw aaronrobertshaw self-assigned this Nov 27, 2023
Copy link

github-actions bot commented Nov 27, 2023

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! ❤️

View changed files
❔ lib/compat/wordpress-6.5/blocks.php
❔ lib/block-supports/elements.php
❔ lib/class-wp-theme-json-gutenberg.php
❔ lib/class-wp-theme-json-resolver-gutenberg.php
❔ lib/load.php
❔ phpunit/block-supports/elements-test.php
❔ phpunit/class-wp-theme-json-resolver-test.php
❔ phpunit/class-wp-theme-json-test.php

Copy link

github-actions bot commented Dec 1, 2023

Size Change: +630 B (0%)

Total Size: 1.69 MB

Filename Size Change
build/block-editor/index.min.js 248 kB +160 B (0%)
build/block-library/index.min.js 215 kB +147 B (0%)
build/components/index.min.js 235 kB +79 B (0%)
build/dom/index.min.js 4.69 kB +10 B (0%)
build/edit-post/index.min.js 24.9 kB -5 B (0%)
build/edit-site/index.min.js 195 kB +34 B (0%)
build/editor/index.min.js 61.7 kB -22 B (0%)
build/interactivity/index.min.js 12.7 kB +227 B (+2%)
ℹ️ View Unchanged
Filename Size
build/a11y/index.min.js 964 B
build/annotations/index.min.js 2.71 kB
build/api-fetch/index.min.js 2.33 kB
build/autop/index.min.js 2.11 kB
build/blob/index.min.js 590 B
build/block-directory/index.min.js 7.25 kB
build/block-directory/style-rtl.css 1.04 kB
build/block-directory/style.css 1.04 kB
build/block-editor/content-rtl.css 4.31 kB
build/block-editor/content.css 4.31 kB
build/block-editor/default-editor-styles-rtl.css 403 B
build/block-editor/default-editor-styles.css 403 B
build/block-editor/style-rtl.css 15.3 kB
build/block-editor/style.css 15.3 kB
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 138 B
build/block-library/blocks/audio/theme.css 138 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/block/editor-rtl.css 305 B
build/block-library/blocks/block/editor.css 305 B
build/block-library/blocks/button/editor-rtl.css 419 B
build/block-library/blocks/button/editor.css 417 B
build/block-library/blocks/button/style-rtl.css 632 B
build/block-library/blocks/button/style.css 631 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/cover/editor-rtl.css 647 B
build/block-library/blocks/cover/editor.css 650 B
build/block-library/blocks/cover/style-rtl.css 1.7 kB
build/block-library/blocks/cover/style.css 1.69 kB
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 98 B
build/block-library/blocks/details/style.css 98 B
build/block-library/blocks/embed/editor-rtl.css 293 B
build/block-library/blocks/embed/editor.css 293 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 138 B
build/block-library/blocks/embed/theme.css 138 B
build/block-library/blocks/file/editor-rtl.css 316 B
build/block-library/blocks/file/editor.css 316 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 322 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 229 B
build/block-library/blocks/form-input/editor.css 228 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 343 B
build/block-library/blocks/form-submission-notification/editor.css 342 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 452 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 957 B
build/block-library/blocks/gallery/editor.css 962 B
build/block-library/blocks/gallery/style-rtl.css 1.75 kB
build/block-library/blocks/gallery/style.css 1.75 kB
build/block-library/blocks/gallery/theme-rtl.css 122 B
build/block-library/blocks/gallery/theme.css 122 B
build/block-library/blocks/group/editor-rtl.css 654 B
build/block-library/blocks/group/editor.css 654 B
build/block-library/blocks/group/style-rtl.css 57 B
build/block-library/blocks/group/style.css 57 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 340 B
build/block-library/blocks/html/editor.css 341 B
build/block-library/blocks/image/editor-rtl.css 834 B
build/block-library/blocks/image/editor.css 833 B
build/block-library/blocks/image/style-rtl.css 1.61 kB
build/block-library/blocks/image/style.css 1.6 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 2.02 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/editor-rtl.css 213 B
build/block-library/blocks/latest-posts/editor.css 212 B
build/block-library/blocks/latest-posts/style-rtl.css 478 B
build/block-library/blocks/latest-posts/style.css 478 B
build/block-library/blocks/list/style-rtl.css 88 B
build/block-library/blocks/list/style.css 88 B
build/block-library/blocks/media-text/editor-rtl.css 266 B
build/block-library/blocks/media-text/editor.css 263 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 671 B
build/block-library/blocks/navigation-link/editor.css 672 B
build/block-library/blocks/navigation-link/style-rtl.css 103 B
build/block-library/blocks/navigation-link/style.css 103 B
build/block-library/blocks/navigation-submenu/editor-rtl.css 299 B
build/block-library/blocks/navigation-submenu/editor.css 299 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.25 kB
build/block-library/blocks/navigation/style.css 2.23 kB
build/block-library/blocks/navigation/view.min.js 1.1 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 401 B
build/block-library/blocks/page-list/editor.css 401 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/paragraph/style-rtl.css 335 B
build/block-library/blocks/paragraph/style.css 335 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-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 666 B
build/block-library/blocks/post-featured-image/editor.css 662 B
build/block-library/blocks/post-featured-image/style-rtl.css 345 B
build/block-library/blocks/post-featured-image/style.css 345 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 409 B
build/block-library/blocks/post-template/style.css 408 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 335 B
build/block-library/blocks/pullquote/style.css 335 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/style-rtl.css 312 B
build/block-library/blocks/query/style.css 308 B
build/block-library/blocks/query/view.min.js 647 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 149 B
build/block-library/blocks/rss/editor.css 149 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 602 B
build/block-library/blocks/search/style.css 602 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 475 B
build/block-library/blocks/separator/editor-rtl.css 146 B
build/block-library/blocks/separator/editor.css 146 B
build/block-library/blocks/separator/style-rtl.css 234 B
build/block-library/blocks/separator/style.css 234 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 329 B
build/block-library/blocks/shortcode/editor.css 329 B
build/block-library/blocks/site-logo/editor-rtl.css 760 B
build/block-library/blocks/site-logo/editor.css 760 B
build/block-library/blocks/site-logo/style-rtl.css 204 B
build/block-library/blocks/site-logo/style.css 204 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 116 B
build/block-library/blocks/site-title/editor.css 116 B
build/block-library/blocks/site-title/style-rtl.css 57 B
build/block-library/blocks/site-title/style.css 57 B
build/block-library/blocks/social-link/editor-rtl.css 184 B
build/block-library/blocks/social-link/editor.css 184 B
build/block-library/blocks/social-links/editor-rtl.css 682 B
build/block-library/blocks/social-links/editor.css 681 B
build/block-library/blocks/social-links/style-rtl.css 1.49 kB
build/block-library/blocks/social-links/style.css 1.49 kB
build/block-library/blocks/spacer/editor-rtl.css 359 B
build/block-library/blocks/spacer/editor.css 359 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 646 B
build/block-library/blocks/table/style.css 645 B
build/block-library/blocks/table/theme-rtl.css 157 B
build/block-library/blocks/table/theme.css 157 B
build/block-library/blocks/tag-cloud/style-rtl.css 251 B
build/block-library/blocks/tag-cloud/style.css 253 B
build/block-library/blocks/template-part/editor-rtl.css 403 B
build/block-library/blocks/template-part/editor.css 403 B
build/block-library/blocks/template-part/theme-rtl.css 101 B
build/block-library/blocks/template-part/theme.css 101 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 191 B
build/block-library/blocks/video/style.css 191 B
build/block-library/blocks/video/theme-rtl.css 139 B
build/block-library/blocks/video/theme.css 139 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/editor-rtl.css 12.3 kB
build/block-library/editor.css 12.3 kB
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/style-rtl.css 14.7 kB
build/block-library/style.css 14.7 kB
build/block-library/theme-rtl.css 700 B
build/block-library/theme.css 705 B
build/block-serialization-default-parser/index.min.js 1.13 kB
build/block-serialization-spec-parser/index.min.js 2.87 kB
build/blocks/index.min.js 51.6 kB
build/commands/index.min.js 15.5 kB
build/commands/style-rtl.css 947 B
build/commands/style.css 942 B
build/components/style-rtl.css 12.1 kB
build/components/style.css 12.1 kB
build/compose/index.min.js 12.8 kB
build/core-commands/index.min.js 2.73 kB
build/core-data/index.min.js 72.7 kB
build/customize-widgets/index.min.js 12.1 kB
build/customize-widgets/style-rtl.css 1.36 kB
build/customize-widgets/style.css 1.36 kB
build/data-controls/index.min.js 651 B
build/data/index.min.js 8.94 kB
build/date/index.min.js 17.9 kB
build/deprecated/index.min.js 462 B
build/dom-ready/index.min.js 336 B
build/edit-post/classic-rtl.css 571 B
build/edit-post/classic.css 571 B
build/edit-post/style-rtl.css 5.68 kB
build/edit-post/style.css 5.68 kB
build/edit-site/style-rtl.css 15 kB
build/edit-site/style.css 15.1 kB
build/edit-widgets/index.min.js 17.3 kB
build/edit-widgets/style-rtl.css 4.44 kB
build/edit-widgets/style.css 4.43 kB
build/editor/style-rtl.css 5.48 kB
build/editor/style.css 5.48 kB
build/element/index.min.js 4.87 kB
build/escape-html/index.min.js 548 B
build/format-library/index.min.js 7.98 kB
build/format-library/style-rtl.css 500 B
build/format-library/style.css 500 B
build/hooks/index.min.js 1.57 kB
build/html-entities/index.min.js 454 B
build/i18n/index.min.js 3.61 kB
build/interactivity/file.min.js 442 B
build/interactivity/image.min.js 2.15 kB
build/interactivity/navigation.min.js 1.23 kB
build/interactivity/query.min.js 791 B
build/interactivity/search.min.js 610 B
build/is-shallow-equal/index.min.js 535 B
build/keyboard-shortcuts/index.min.js 1.76 kB
build/keycodes/index.min.js 1.49 kB
build/list-reusable-blocks/index.min.js 2.11 kB
build/list-reusable-blocks/style-rtl.css 865 B
build/list-reusable-blocks/style.css 865 B
build/media-utils/index.min.js 2.92 kB
build/modules/importmap-polyfill.min.js 12.2 kB
build/notices/index.min.js 964 B
build/nux/index.min.js 2.01 kB
build/nux/style-rtl.css 775 B
build/nux/style.css 771 B
build/patterns/index.min.js 5.37 kB
build/patterns/style-rtl.css 564 B
build/patterns/style.css 564 B
build/plugins/index.min.js 1.81 kB
build/preferences-persistence/index.min.js 2.08 kB
build/preferences/index.min.js 2.52 kB
build/preferences/style-rtl.css 725 B
build/preferences/style.css 728 B
build/primitives/index.min.js 994 B
build/priority-queue/index.min.js 1.52 kB
build/private-apis/index.min.js 1.02 kB
build/react-i18n/index.min.js 631 B
build/react-refresh-entry/index.min.js 9.46 kB
build/react-refresh-runtime/index.min.js 6.78 kB
build/redux-routine/index.min.js 2.71 kB
build/reusable-blocks/index.min.js 2.74 kB
build/reusable-blocks/style-rtl.css 265 B
build/reusable-blocks/style.css 265 B
build/rich-text/index.min.js 10.4 kB
build/router/index.min.js 1.79 kB
build/server-side-render/index.min.js 1.96 kB
build/shortcode/index.min.js 1.4 kB
build/style-engine/index.min.js 2.06 kB
build/token-list/index.min.js 587 B
build/url/index.min.js 3.83 kB
build/vendors/inert-polyfill.min.js 2.48 kB
build/vendors/react-dom.min.js 41.8 kB
build/vendors/react.min.js 4.02 kB
build/viewport/index.min.js 967 B
build/warning/index.min.js 259 B
build/widgets/index.min.js 7.22 kB
build/widgets/style-rtl.css 1.18 kB
build/widgets/style.css 1.18 kB
build/wordcount/index.min.js 1.03 kB

compressed-size-action

@aaronrobertshaw aaronrobertshaw force-pushed the try/extending-block-style-variations branch from 34ec6a1 to e10a879 Compare December 13, 2023 01:59
Copy link

github-actions bot commented Dec 13, 2023

Flaky tests detected in a88a18a488c06a98eb9540823348b660ee04239c.
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/7471653408
📝 Reported issues:

@aaronrobertshaw aaronrobertshaw force-pushed the try/extending-block-style-variations branch from e10a879 to c34ca0a Compare December 14, 2023 02:49
@SaxonF
Copy link
Contributor

SaxonF commented Dec 19, 2023

I think we can switch to using a custom select with render items for block style selection. Background and text colour for swatches.

pattern-styles.mp4

@aaronrobertshaw
Copy link
Contributor Author

I think we can switch to using a custom select with render items for block style selection. Background and text colour for swatches.

Any objections to this UI enhancement being done separately or as a follow-up? I take it we want that change regardless of these enhancements to block style variations. Splitting that out might help prevent this PR from blocking it.

@SaxonF
Copy link
Contributor

SaxonF commented Dec 19, 2023

Any objections to this UI enhancement being done separately or as a follow-up?

None at all

@aaronrobertshaw aaronrobertshaw force-pushed the try/extending-block-style-variations branch from efe74ee to 390daca Compare December 20, 2023 04:47
@aaronrobertshaw aaronrobertshaw marked this pull request as ready for review December 20, 2023 04:48
@aaronrobertshaw aaronrobertshaw force-pushed the try/extending-block-style-variations branch from 390daca to c90e238 Compare December 20, 2023 05:53
@aaronrobertshaw aaronrobertshaw changed the title [WIP] Theme.json: Extend block style variations support Theme.json: Extend block style variations support Dec 20, 2023
Copy link
Contributor Author

@aaronrobertshaw aaronrobertshaw left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It could just be me but some of this theme.json processing can be a little hard to grok, so I've tried to give a higher level view of the changes and their intent via inline comments.

Hopefully it helps make reviewing easier 🤞

Comment on lines 857 to 878
$schema_styles_variations = array();
$block_style_variation_styles = static::VALID_STYLES;
$block_style_variation_styles['blocks'] = null;
$block_style_variation_styles['elements'] = null;

$schema_styles_variations = array();
if ( ! empty( $style_variation_names ) ) {
$schema_styles_variations = array_fill_keys( $style_variation_names, $styles_non_top_level );
$schema_styles_variations = array_fill_keys( $style_variation_names, $block_style_variation_styles );
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Block style variations are being extended to allow styles for inner block types and elements. The changes to the schema here prevent blocks and elements properties from being stripped out.

Comment on lines 997 to 1024
$registered_styles = $style_registry->get_all_registered();
foreach ( static::$blocks_metadata as $block_name => $block_metadata ) {
if ( ! empty( $registered_styles[ $block_name ] ) ) {
$style_selectors = $block_metadata['styleVariations'] ?? array();

foreach ( $registered_styles[ $block_name ] as $block_style ) {
if ( ! isset( $style_selectors[ $block_style['name'] ] ) ) {
$style_selectors[ $block_style['name'] ] = static::append_to_selector(
'.is-style-' . $block_style['name'] . '.is-style-' . $block_style['name'],
$block_metadata['selector']
);
}
}

static::$blocks_metadata[ $block_name ]['styleVariations'] = $style_selectors;
}
}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While testing, I found this was required to ensure new block style variations in the styles registry were detected properly so matching config in the theme.json wasn't stripped out during sanitization. See the constructor and remove_insecure_properties functions.

Comment on lines 1055 to 1069
// Block style variations can be registered through the WP_Block_Styles_Registry as well as block.json.
$registered_styles = $style_registry->get_registered_styles_for_block( $block_name );
foreach ( $registered_styles as $style ) {
$style_selectors[ $style['name'] ] = static::append_to_selector( '.is-style-' . $style['name'] . '.is-style-' . $style['name'], static::$blocks_metadata[ $block_name ]['selector'] );
}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As static::$blocks_metadata[ $block_name ]['styleVariations'] is used to sanitize available block style variations, the changes here make sure to include anything from the block style registry.

Comment on lines +1787 to +1799
if ( ! $selector || ! $scope ) {
return $selector;
}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This tweak just allowed more flexible use of the scope_selector util function, simplifying code elsewhere.

Comment on lines 2440 to 2496
foreach ( $variation_blocks as $variation_block => $variation_block_node ) {
$variation_block_selector = static::scope_selector( $variation_selector, $selectors[ $variation_block ]['selector'] ?? null );
$variation_duotone_selector = static::scope_selector( $variation_selector, $selectors[ $variation_block ]['duotone'] ?? null );
$variation_feature_selectors = $selectors[ $variation_block ]['selectors'] ?? null;

if ( $variation_feature_selectors ) {
foreach ( $variation_feature_selectors as $feature => $feature_selector ) {
if ( is_string( $feature_selector ) ) {
$variation_feature_selectors[ $feature ] = static::scope_selector( $variation_selector, $feature_selector );
}

if ( is_array( $feature_selector ) ) {
foreach ( $feature_selector as $subfeature => $subfeature_selector ) {
$variation_feature_selectors[ $feature ][ $subfeature ] = static::scope_selector( $variation_selector, $subfeature_selector );
}
}
}
}

$variation_nodes[] = array(
'name' => $variation_block,
'path' => array( 'styles', 'blocks', $name, 'variations', $variation, 'blocks', $variation_block ),
'selector' => $variation_block_selector,
'selectors' => $variation_feature_selectors,
'duotone' => $variation_duotone_selector,
);
}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This code processes a block style variation's inner block type styles.

Blocks can define custom selectors for certain features, e.g., color, typography, etc., to be applied to inner markup. For this to work within a block style variation the block type's custom feature selectors need to be further scoped to the selector for the block style variation.

Once the feature selectors are correctly scoped, the inner block's node can be created as per a regular block node.

* style_data (theme.json-like object to generate CSS from).
* @return bool True if all block styles were registered with success and false otherwise.
*/
function gutenberg_register_block_style( $block_name, $style_properties ) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Initially, this extended block style registration also generated a stylesheet and enqueued it for block style variations that included a style object within its properties. This allowed only a single set of styles to be generated for a block style variation that was shared across multiple block types.

Future follow-ups to this PR will be to allow block style variations to be defined within theme.json outside of a block type. These definitions can then be referenced across multiple block types.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Future follow-ups to this PR will be to allow block style variations to be defined within theme.json outside of a block type. These definitions can then be referenced across multiple block types.

That will be very handy! I came across that in testing with your provided test style variations and it was a bit confusing at first when tweaking styles in one of the Group variations had no effect in Columns with the same variation 😅

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it was a bit confusing

Apologies for the confusion. I'll add a warning to the PR description for that gotcha.

I'm inclined to see if we can refine this to a point we're happy to land, while concurrently working on allowing the referenced variations within theme.json.

What do you think?

@@ -611,6 +611,33 @@ function pickStyleKeys( treeToPickFrom ) {
return Object.fromEntries( clonedEntries );
}

function scopeFeatureSelectors( scope, selectors ) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Blocks can define their own custom selectors for features such as color, typography, border etc. When such a block is styled as an inner block to a block style variation, its custom feature selectors need to be scoped by the block style variations selector to still be correctly applied. This function helps with that.

node.variations[ variation ]
);
} );

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The following changes mostly follow those in the PHP class for processing block style variations into nodes that can be later turned into actual styles.

@@ -22,8 +32,10 @@ export function useBlockVariations( name ) {
},
[ name ]
);
const coreBlockStyles = getCoreBlockStyles( blockStyles );
return coreBlockStyles;
const [ variations ] = useGlobalStyle( 'variations', name, 'base' );
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

At this point, the theme.json resolver has absorbed block style variations registered through the block styles registry into the merged global styles data so it can be used as a source of validated variations.

// Only core block styles (source === block) or block styles with
// a matching theme.json style variation will be configurable via
// Global Styles.
function getFilteredBlockStyles( blockStyles, variations ) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This function now opens up Global Styles to allow for non-core block style variations to be configured through the site editor.

At this stage, inner block type and element styles for the block style variation are not editable however this could be worked on in a follow-up.

@aaronrobertshaw
Copy link
Contributor Author

A future follow-up for this will be to explore refining the theme.json API around registering block style variations across multiple block types. For example, perhaps a shared block style variation could be defined under styles.blocks.variations and then referenced by each block type that wants to use it e.g.

{
  styles: {
    blocks: {
      variations: {
        light: { ... },
        dark: { ... }
      },
      core/group: {
        variations: {
          light: "ref:light" // or whatever the reference format needs to be
        }
      core/columns: {
        variations: {
          light: "ref:light",
          dark: "ref:dark"
        }
      }
    }
  }
}

Copy link
Contributor

@tellthemachines tellthemachines left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is looking pretty solid! Some comments and questions below. Testing shows all working as expected.

Is there any plan to make style variations declarable directly through theme.json without the additional step of registering them in PHP? Asking because part of the idea in #44417 was to provide the ability to create new variations through the global styles interface. It wasn't implemented straightaway and I subsequently created #49602 for it.

I'm also wondering why WP_Block_Styles_Registry is final; perhaps @jorgefilipecosta has some idea? The ticket that added the class to core doesn't explain much.

if ( isset( $selectors[ $name ]['selector'] ) ) {
$selector = $selectors[ $name ]['selector'];
}
$selector = $selectors[ $name ]['selector'] ?? null;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm afraid the null coalescing operator isn't officially supported in WP yet. There's a ticket for it here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for flagging that. I had a suspicion that was the case although I recalled some recent performance PRs swapping out _wp_array_get for it. It's used a fair bit now already within this class.

Do you think it is that much of a nuisance when it comes to backporting?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeahhh those perf improvements were changed before landing in core - see the discussion here. I'd avoid it if you don't want the backport PR to turn into an argument 😂


// Note that `get_feature_declarations_for_node` will also unset
// feature values so they aren't duplicated in declarations via
// the call below.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure I understand this comment. Which feature values are unset by get_feature_declarations_for_node and why might they be duplicated below? Might be worth adding a bit more context. (Also is it correct to assume "features" here means the feature selectors optionally declared by blocks?)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure I understand this comment.

Nor do I 😅. I suspect I messed up while rebasing an earlier incarnation of this PR.

Which feature values are unset by get_feature_declarations_for_node and why might they be duplicated below? Might be worth adding a bit more context. (Also is it correct to assume "features" here means the feature selectors optionally declared by blocks?)

Correct.

If a block defines custom selectors for features, the get_feature_declarations_for_node function will create the appropriate declarations from the normal style object given to it. If the values used in the feature declarations weren't unset, when the style object is processed for the normal block declarations we'd get styles applying the value to both the custom feature selector and the block's wrapper.

I've removed the comment as I don't think it adds much value now the sands have shifted underneath it.

lib/class-wp-theme-json-gutenberg.php Outdated Show resolved Hide resolved
* style_data (theme.json-like object to generate CSS from).
* @return bool True if all block styles were registered with success and false otherwise.
*/
function gutenberg_register_block_style( $block_name, $style_properties ) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Future follow-ups to this PR will be to allow block style variations to be defined within theme.json outside of a block type. These definitions can then be referenced across multiple block types.

That will be very handy! I came across that in testing with your provided test style variations and it was a bit confusing at first when tweaking styles in one of the Group variations had no effect in Columns with the same variation 😅

@aaronrobertshaw
Copy link
Contributor Author

Thanks for taking the time to review this one @tellthemachines 👍

Is there any plan to make style variations declarable directly through theme.json without the additional step of registering them in PHP?

Definitely!

#49602 is already on my radar, especially with the API refinements I mentioned above. I'll actually be digging into this over the next few days.

I'm also wondering why WP_Block_Styles_Registry is final; perhaps @jorgefilipecosta has some idea? The ticket that added the class to core doesn't explain much.

It puzzled me as well. Unfortunately, it is what it is and made extending the block style registration as suggested in the issue more awkward. I'm certainly open to better approaches.

In my view, it adds some extra justification to adding something like the style.blocks.variations property, so it's easier to register block style variations across multiple block types in a consistent manner regardless of if your on the WP 6.5 or an older version with Gutenberg active.

@tellthemachines
Copy link
Contributor

Just did another round of testing on this and everything is working as expected, taking into account the details @andrewserong outlined above. I can also confirm that nested block element styles (the fuchsia example) are now working correctly across editors and front end.

It could be expected behaviour in that the element styles being applied directly to blocks are supposed to be user generated styles and trump theme or block style variations. So in that regard, it should stick unless they decide to override it again on something within it.

I agree with this. User-generated styles should override theme styles, and it's up to the user to add them to the correct container.

One other thing I noticed is an issue with how elements styles works that I think is present on trunk, too, which is that the hierarchy of how styles are output is a bit inconsistent in the editor while you're editing, in that the order of the styles isn't always in the direction of parent to child.

Yeah this is a weird one. The latest added style always overrides earlier, more targeted styles. It may be related to how we load each new update in its own style tag, because I notice that switching the order of style tags in the DOM changes which styles apply. I'd expect that, if all the declarations were in the same stylesheet, it wouldn't matter what order they're in because the classname closer to the element in the DOM hierarchy would take precedence. In any case, this should be looked at separately.

This PR feels pretty ready to me. Is there anything still to do or is it final review time?

@andrewserong
Copy link
Contributor

I've pushed some changes to the useGlobalStylesOutput hook and its unit test to cover generating element styles within a variation's inner blocks. It appears to fix up the site editor for me.

All testing nicely for me, too. I haven't run into any other issues so far!

@aaronrobertshaw
Copy link
Contributor Author

Thanks for the patience and commitment to testing and reviewing this one @tellthemachines and @andrewserong 👍

This PR feels pretty ready to me. Is there anything still to do or is it final review time?

🎉 I think we're ready for a final review! I'll also give it a further once over with fresh eyes on Monday.

@andrewserong
Copy link
Contributor

I think we're ready for a final review! I'll also give it a further once over with fresh eyes on Monday.

Sounds good! I'll give it another proper look on Monday with fresh eyes, too 🙂

@tellthemachines
Copy link
Contributor

Sounds good! I'll give it another proper look on Monday with fresh eyes, too

Same 😄

@andrewserong
Copy link
Contributor

Just looking into the e2e test failures, and it seems they're legitimate for the Navigation block, where it expects Navigation link colors to inherit from a wrapping Group block, but not to be applied to submenus or overlays:

1) [chromium] › editor/blocks/navigation-colors.spec.js:78:2 › Navigation colors › Top level navigation links inherit the text color from the theme/group but do not apply to the submenu or overlay text

test( 'Top level navigation links inherit the text color from the theme/group but do not apply to the submenu or overlay text', async ( {

In manually testing locally, I can see that on trunk if I wrap the Navigation block in a Group block and give it a black background and white text, then the sub menu is still white background with black links. However, in this PR, the white link text wins out:

Trunk This PR
image image

So, unfortunately it seems we have a case of the Navigation block expecting the block-level link color to have a lower priority. In this case, would it be better to try to fix the Navigation block to account for the higher specificity, or does this point to potential breaking changes in other blocks (i.e. 3rd party blocks) that could potentially be an issue? 🤔

@tellthemachines
Copy link
Contributor

So, unfortunately it seems we have a case of the Navigation block expecting the block-level link color to have a lower priority.

Great catch @andrewserong ! From the comment above the line where submenu color is set it looks like specificity has been deliberately set to override element styles. I'm not sure what the best approach is tbh, there's no way of knowing how many custom blocks out there might be relying on the existing specificity.

@aaronrobertshaw
Copy link
Contributor Author

So, unfortunately, it seems we have a case of the Navigation block expecting the block-level link color to have a lower priority.

For all my attempts at creating a decent example of possible breakages, it was under my nose all along with the navigation block. It's rather obvious in hindsight!

Or does this point to potential breaking changes in other blocks (i.e. 3rd party blocks) that could potentially be an issue?

This has been the question all along.

Over recent discussions, the consensus was that this possible breakage would be very much an edge case. In the overwhelming majority of cases, a block should adopt the user's choice of element styles and it would be rare for a block to need differing element styles within itself. Then, should a user have applied element styles to a section or group and desire a different color for something within that, they'd need to manually apply it.

Does the example of the navigation block change this thinking? Do you both now believe this use case is more likely than our previous understanding?

Would it be better to try to fix the Navigation block to account for the higher specificity

I'm struggling to find any clean options here but that too, has been the problem all along 🤔

Bumping the specificity for that block further feels wrong and a course of action that might lead to further issues. I imagine this is one of the more heavily styled blocks out there.

Another option I've explored is tweaking the element styles selector such that it won't apply to navigation submenu links.

While we might be able to get this work and even allow for reducing the selector @tellthemachines noted was deliberately aimed at overcoming element styles. The solution isn't exactly scalable to every possible 3rd party block that might suffer a similar fate. It also adds some block-specific code where it doesn't really belong, not that this would be the first time the nav block has forced that.

Screenshot 2024-01-15 at 11 45 12 am

Example diff

diff --git a/lib/block-supports/elements.php b/lib/block-supports/elements.php
index c277e11012..33670c187e 100644
--- a/lib/block-supports/elements.php
+++ b/lib/block-supports/elements.php
@@ -148,8 +148,8 @@ function gutenberg_render_elements_support_styles( $pre_render, $block ) {
 			'skip'     => $skip_button_color_serialization,
 		),
 		'link'    => array(
-			'selector'       => "$class_name a",
-			'hover_selector' => "$class_name a:hover",
+			'selector'       => "$class_name a:not(.wp-block-navigation-submenu a)",
+			'hover_selector' => "$class_name a:not(.wp-block-navigation-submenu a):hover",
 			'skip'           => $skip_link_color_serialization,
 		),
 		'heading' => array(
diff --git a/packages/block-editor/src/hooks/style.js b/packages/block-editor/src/hooks/style.js
index fe1e25ae4b..f154e1aad4 100644
--- a/packages/block-editor/src/hooks/style.js
+++ b/packages/block-editor/src/hooks/style.js
@@ -397,9 +397,13 @@ function useBlockProps( { name, style } ) {
 
 			// Process primary element type styles.
 			if ( elementStyles ) {
+				const elementSelector =
+					elementType !== 'link'
+						? ELEMENTS[ elementType ]
+						: `${ ELEMENTS[ elementType ] }:not(.wp-block-navigation-submenu a)`;
 				const selector = scopeSelector(
 					baseElementSelector,
-					ELEMENTS[ elementType ]
+					elementSelector
 				);
 
 				elementCSSRules.push(
@@ -414,7 +418,7 @@ function useBlockProps( { name, style } ) {
 								compileCSS( elementStyles[ pseudoSelector ], {
 									selector: scopeSelector(
 										baseElementSelector,
-										`${ ELEMENTS[ elementType ] }${ pseudoSelector }`
+										`${ elementSelector }${ pseudoSelector }`
 									),
 								} )
 							);
diff --git a/packages/block-library/src/navigation/style.scss b/packages/block-library/src/navigation/style.scss
index 3f11c55643..46d1ee39aa 100644
--- a/packages/block-library/src/navigation/style.scss
+++ b/packages/block-library/src/navigation/style.scss
@@ -48,14 +48,6 @@ $navigation-icon-size: 24px;
 		display: block;
 	}
 
-	// This rule needs extra specificity so that it inherits the correct color from its parent.
-	// Otherwise, a link color set by a parent group can override the value.
-	// This also fixes an issue where a navigation with an explicitly set color is overridden
-	// by link colors defined in Global Styles.
-	.wp-block-navigation-item__content.wp-block-navigation-item__content {
-		color: inherit;
-	}
-
 	// The following rules provide class based application of user selected text
 	// decoration via block supports.
 	&.has-text-decoration-underline .wp-block-navigation-item__content {

This approach again comes back to the question, are there many other possible instances of this edge case out there?

@tellthemachines
Copy link
Contributor

I just tried something in #57841 that could potentially allow us to reduce specificity of the element selector.

I don't think there's any solution here that won't involve breaking changes of some sort: any specificity change is going to be a breaking change. My reasoning is it's usually better to reduce than increase specificity, so it's worth giving it a try 😄

@aaronrobertshaw
Copy link
Contributor Author

Revisiting the option to dial back block style variation functionality, such that a variation's block type styles cannot contain element styles, might be viable.

Example Diff

NOTE: This is incomplete as we'd still need to remove the inclusion of block style variation element styles within inner block types from the theme.json, its sanitization, processing etc.

diff --git a/lib/block-supports/elements.php b/lib/block-supports/elements.php
index c277e11012..eea2286c57 100644
--- a/lib/block-supports/elements.php
+++ b/lib/block-supports/elements.php
@@ -140,7 +140,7 @@ function gutenberg_render_elements_support_styles( $pre_render, $block ) {
 	// block style variation.
 	// See: https://github.com/WordPress/gutenberg/pull/56540
 	$class_name = wp_get_elements_class_name( $block );
-	$class_name = ".$class_name.$class_name.$class_name";
+	$class_name = ".$class_name.$class_name";
 
 	$element_types = array(
 		'button'  => array(
diff --git a/packages/block-editor/src/hooks/style.js b/packages/block-editor/src/hooks/style.js
index fe1e25ae4b..47a9600f48 100644
--- a/packages/block-editor/src/hooks/style.js
+++ b/packages/block-editor/src/hooks/style.js
@@ -372,7 +372,7 @@ function useBlockProps( { name, style } ) {
 	// specificity to correctly take precedence over block variation styles,
 	// including those for elements within a variation's block type styles.
 	// See: https://github.com/WordPress/gutenberg/pull/56540
-	const baseElementSelector = `.editor-styles-wrapper .${ blockElementsContainerIdentifier }.${ blockElementsContainerIdentifier }`;
+	const baseElementSelector = `.editor-styles-wrapper .${ blockElementsContainerIdentifier }`;
 	const blockElementStyles = style?.elements;
 
 	const styles = useMemo( () => {

It looks like the navigation blocks styles were accidentally a touch too specific on the frontend side to also counter the editor's increased specificity due to the .editor-styles-wrapper being added to the selector there.

Due to that, we can avoid touching the navigation block's styles, if we only bump the element styles selector once on the frontend (again, the editor is already more specific). This single bump in specificity means I think we can support element styles for block style variations, but only at the root level of the block style variation not within specific inner block types.

It would also mean should it become necessary to add that ability to style elements for a variation's inner block types, then we'd be forced to make a second change in specificity instead of one, as well as find a solution to the nav block issue.

@aaronrobertshaw
Copy link
Contributor Author

I've removed the ability to style elements for specific block types within a block style variation.

While testing the latest iteration, I've encountered a few further issues relating to nested variations and the application of element styles. It might be worth holding off on further testing and review of this PR until I can find a solution there or at least document the problems in further detail.

@aaronrobertshaw aaronrobertshaw force-pushed the try/extending-block-style-variations branch from 2abb7fc to 15270b6 Compare January 15, 2024 10:21
@jorgefilipecosta
Copy link
Member

I'm also wondering why WP_Block_Styles_Registry is final; perhaps @jorgefilipecosta has some idea? The ticket that added the class to core doesn't explain much.

I don't know why the class was final I think it was probably already final on the Gutenberg code and during the backport, I kept it as it was. I could think that the API may not have been ready at the time and making it final avoids unexpected extensibility using that class.

@aaronrobertshaw
Copy link
Contributor Author

There's a start on an alternate approach in #57908 that seems to work for nesting application of block style variations. It isn't fully functional yet.

It still needs the root styles of a block style variation to be generated properly in the editor, lots of clean up etc. The key to it though is reducing the specificity of global block styles so needs rebasing onto #57841 as that progresses.

With that said, if #57841 proves not to be possible, then this alternate approach will also be dead in the water 😅

@aaronrobertshaw
Copy link
Contributor Author

Thank you everyone for your help on this PR 🙇

I'm going to close it though in favour of pursuing the alternate approach in #57908.

The reasoning is that even if we took the quick option to bump the block instance element styles so they correctly overrode block style variation element styles, a user still can't reliably apply variation to a block that is within another block that also has a variation applied.

If you are still interested in following this feature, more updates will be made via the section styling tracking issue and PRs linked there.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
[Feature] Block Style Variations Issues or PRs that are related to the style variations for blocks [Feature] Design Tools Tools that impact the appearance of blocks both to expand the number of tools and improve the experi [Type] Enhancement A suggestion for improvement.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants