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: Add block support feature level selectors for blocks #42087

Merged
merged 11 commits into from
Jul 15, 2022

Conversation

aaronrobertshaw
Copy link
Contributor

@aaronrobertshaw aaronrobertshaw commented Jul 1, 2022

Related: #31366

What?

Allows custom CSS selectors for individual block support features e.g. for border support. This means styles generated for individual block support features can be applied to different elements within a block e.g the block wrapper or another element that can't be targeted via the elements API.

Why?

While attempting to add border support to the image block we hit the issue where we need to skip border support serialization so we can apply the borders only to the inner img element.

If we add the img element to the Elements API, we end up creating a disjoint between the block editor and theme.json/global styles. The problem lies in the fact that we can't style the img elements via Global Styles. This leads us to a situation where a theme author could style all image block's img elements but if a user wished to tweak that styling they would have to edit every individual image.

Adding a "feature level selector" to theme.json and global styles means that we can keep the usual theme.json shape (no elements API use) and also keep using the Global Styles UI as per normal. The difference is that the generated styles target new custom CSS selectors.

How?

  • Adds support for defining __experimentalSelector prop within each individual block support
  • Leverages the new feature level __experimentalSelector values to generate scoped CSS selectors specific to that block support
  • Generates the styles for each block support opting into this, under the appropriate selector instead of under the block's root selector
  • Some minor spelling and typo fixes

Note: PHP unit tests were a little tricky to implement given that WordPress is loaded prior to the tests running meaning that WordPress' theme.json generates block metadata before our single, feature-level selector test could register a block. As a means of still having a programmatic test for the new selectors, I've added a tests_add_filter() call to the bootstrap to get a suitable block registered in time for testing. Once the Image block adopts these new selectors via #31366 we could remove this filter and test via the image block.

We can also remove the tests_add_filter prior to merging this PR if we wish to keep things cleaner in the interim.

Testing Instructions

  1. Run npm run test-unit-php
  2. Run npm run test-unit packages/edit-site/src/components/global-styles/test/use-global-styles-output.js

Manual Testing

The generated styles can be manually tested via #31366 which has been based on this PR.

  1. Checkout Image: Add border block support for color, width, and style #31366
  2. Edit your theme.json to style image blocks with a border (See snipped below for example image border config)
  3. Create a new post, add an image, confirm the image border has been applied.
  4. Save the post and view on the front end.
  5. Inspect the image and ensure styles have been generated for .wp-block-image img, .wp-block-image .wp-block-image__crop-area
{
	...
	"styles": {
		"blocks": {
			"core/image": {
				"border": {
					"radius": "9999px",
					"color": "fuchsia",
					"style": "dashed",
					"width": "3px"
				},
			}
		}
	}
}

Alternatively;

  1. Update a block's support config to include an __experimentalSelector at the feature level (not root supports config)
  2. Style that block and block support feature via theme.json
  3. Load the editor and confirm styles have been generated for the block matching the selector you set.

@aaronrobertshaw aaronrobertshaw added [Type] Enhancement A suggestion for improvement. Global Styles Anything related to the broader Global Styles efforts, including Styles Engine and theme.json [Feature] Design Tools Tools that impact the appearance of blocks both to expand the number of tools and improve the experi labels Jul 1, 2022
@aaronrobertshaw aaronrobertshaw self-assigned this Jul 1, 2022
@github-actions
Copy link

github-actions bot commented Jul 1, 2022

Size Change: +196 B (0%)

Total Size: 1.25 MB

Filename Size Change
build/edit-site/index.min.js 53.3 kB +196 B (0%)
ℹ️ View Unchanged
Filename Size
build/a11y/index.min.js 982 B
build/annotations/index.min.js 2.76 kB
build/api-fetch/index.min.js 2.26 kB
build/autop/index.min.js 2.14 kB
build/blob/index.min.js 475 B
build/block-directory/index.min.js 6.58 kB
build/block-directory/style-rtl.css 990 B
build/block-directory/style.css 991 B
build/block-editor/default-editor-styles-rtl.css 378 B
build/block-editor/default-editor-styles.css 378 B
build/block-editor/index.min.js 153 kB
build/block-editor/style-rtl.css 14.6 kB
build/block-editor/style.css 14.6 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 65 B
build/block-library/blocks/archives/style.css 65 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 103 B
build/block-library/blocks/audio/style.css 103 B
build/block-library/blocks/audio/theme-rtl.css 110 B
build/block-library/blocks/audio/theme.css 110 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 59 B
build/block-library/blocks/avatar/style.css 59 B
build/block-library/blocks/block/editor-rtl.css 161 B
build/block-library/blocks/block/editor.css 161 B
build/block-library/blocks/button/editor-rtl.css 441 B
build/block-library/blocks/button/editor.css 441 B
build/block-library/blocks/button/style-rtl.css 543 B
build/block-library/blocks/button/style.css 543 B
build/block-library/blocks/buttons/editor-rtl.css 292 B
build/block-library/blocks/buttons/editor.css 292 B
build/block-library/blocks/buttons/style-rtl.css 275 B
build/block-library/blocks/buttons/style.css 275 B
build/block-library/blocks/calendar/style-rtl.css 207 B
build/block-library/blocks/calendar/style.css 207 B
build/block-library/blocks/categories/editor-rtl.css 84 B
build/block-library/blocks/categories/editor.css 83 B
build/block-library/blocks/categories/style-rtl.css 79 B
build/block-library/blocks/categories/style.css 79 B
build/block-library/blocks/code/style-rtl.css 103 B
build/block-library/blocks/code/style.css 103 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 406 B
build/block-library/blocks/columns/style.css 406 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 187 B
build/block-library/blocks/comment-template/style.css 185 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 95 B
build/block-library/blocks/comments/editor.css 95 B
build/block-library/blocks/cover/editor-rtl.css 615 B
build/block-library/blocks/cover/editor.css 616 B
build/block-library/blocks/cover/style-rtl.css 1.55 kB
build/block-library/blocks/cover/style.css 1.55 kB
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 110 B
build/block-library/blocks/embed/theme.css 110 B
build/block-library/blocks/file/editor-rtl.css 300 B
build/block-library/blocks/file/editor.css 300 B
build/block-library/blocks/file/style-rtl.css 253 B
build/block-library/blocks/file/style.css 254 B
build/block-library/blocks/file/view.min.js 346 B
build/block-library/blocks/freeform/editor-rtl.css 2.44 kB
build/block-library/blocks/freeform/editor.css 2.44 kB
build/block-library/blocks/gallery/editor-rtl.css 948 B
build/block-library/blocks/gallery/editor.css 950 B
build/block-library/blocks/gallery/style-rtl.css 1.5 kB
build/block-library/blocks/gallery/style.css 1.49 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 333 B
build/block-library/blocks/group/editor.css 333 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 76 B
build/block-library/blocks/heading/style.css 76 B
build/block-library/blocks/html/editor-rtl.css 327 B
build/block-library/blocks/html/editor.css 329 B
build/block-library/blocks/image/editor-rtl.css 738 B
build/block-library/blocks/image/editor.css 737 B
build/block-library/blocks/image/style-rtl.css 524 B
build/block-library/blocks/image/style.css 530 B
build/block-library/blocks/image/theme-rtl.css 110 B
build/block-library/blocks/image/theme.css 110 B
build/block-library/blocks/latest-comments/style-rtl.css 284 B
build/block-library/blocks/latest-comments/style.css 284 B
build/block-library/blocks/latest-posts/editor-rtl.css 199 B
build/block-library/blocks/latest-posts/editor.css 198 B
build/block-library/blocks/latest-posts/style-rtl.css 463 B
build/block-library/blocks/latest-posts/style.css 462 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 493 B
build/block-library/blocks/media-text/style.css 490 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 705 B
build/block-library/blocks/navigation-link/editor.css 703 B
build/block-library/blocks/navigation-link/style-rtl.css 115 B
build/block-library/blocks/navigation-link/style.css 115 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-submenu/view.min.js 423 B
build/block-library/blocks/navigation/editor-rtl.css 2.03 kB
build/block-library/blocks/navigation/editor.css 2.04 kB
build/block-library/blocks/navigation/style-rtl.css 1.96 kB
build/block-library/blocks/navigation/style.css 1.95 kB
build/block-library/blocks/navigation/view-modal.min.js 2.78 kB
build/block-library/blocks/navigation/view.min.js 443 B
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 363 B
build/block-library/blocks/page-list/editor.css 363 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 157 B
build/block-library/blocks/paragraph/editor.css 157 B
build/block-library/blocks/paragraph/style-rtl.css 260 B
build/block-library/blocks/paragraph/style.css 260 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 495 B
build/block-library/blocks/post-comments-form/style.css 495 B
build/block-library/blocks/post-comments/editor-rtl.css 77 B
build/block-library/blocks/post-comments/editor.css 77 B
build/block-library/blocks/post-comments/style-rtl.css 632 B
build/block-library/blocks/post-comments/style.css 630 B
build/block-library/blocks/post-excerpt/editor-rtl.css 73 B
build/block-library/blocks/post-excerpt/editor.css 73 B
build/block-library/blocks/post-excerpt/style-rtl.css 69 B
build/block-library/blocks/post-excerpt/style.css 69 B
build/block-library/blocks/post-featured-image/editor-rtl.css 605 B
build/block-library/blocks/post-featured-image/editor.css 605 B
build/block-library/blocks/post-featured-image/style-rtl.css 153 B
build/block-library/blocks/post-featured-image/style.css 153 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 282 B
build/block-library/blocks/post-template/style.css 282 B
build/block-library/blocks/post-terms/style-rtl.css 73 B
build/block-library/blocks/post-terms/style.css 73 B
build/block-library/blocks/post-title/style-rtl.css 80 B
build/block-library/blocks/post-title/style.css 80 B
build/block-library/blocks/preformatted/style-rtl.css 103 B
build/block-library/blocks/preformatted/style.css 103 B
build/block-library/blocks/pullquote/editor-rtl.css 198 B
build/block-library/blocks/pullquote/editor.css 198 B
build/block-library/blocks/pullquote/style-rtl.css 370 B
build/block-library/blocks/pullquote/style.css 370 B
build/block-library/blocks/pullquote/theme-rtl.css 167 B
build/block-library/blocks/pullquote/theme.css 167 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 234 B
build/block-library/blocks/query-pagination/style.css 231 B
build/block-library/blocks/query/editor-rtl.css 365 B
build/block-library/blocks/query/editor.css 364 B
build/block-library/blocks/quote/style-rtl.css 213 B
build/block-library/blocks/quote/style.css 213 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 132 B
build/block-library/blocks/read-more/style.css 132 B
build/block-library/blocks/rss/editor-rtl.css 202 B
build/block-library/blocks/rss/editor.css 204 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 165 B
build/block-library/blocks/search/editor.css 165 B
build/block-library/blocks/search/style-rtl.css 385 B
build/block-library/blocks/search/style.css 386 B
build/block-library/blocks/search/theme-rtl.css 114 B
build/block-library/blocks/search/theme.css 114 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 233 B
build/block-library/blocks/separator/style.css 233 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 464 B
build/block-library/blocks/shortcode/editor.css 464 B
build/block-library/blocks/site-logo/editor-rtl.css 708 B
build/block-library/blocks/site-logo/editor.css 708 B
build/block-library/blocks/site-logo/style-rtl.css 192 B
build/block-library/blocks/site-logo/style.css 192 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 84 B
build/block-library/blocks/site-title/editor.css 84 B
build/block-library/blocks/social-link/editor-rtl.css 177 B
build/block-library/blocks/social-link/editor.css 177 B
build/block-library/blocks/social-links/editor-rtl.css 674 B
build/block-library/blocks/social-links/editor.css 673 B
build/block-library/blocks/social-links/style-rtl.css 1.37 kB
build/block-library/blocks/social-links/style.css 1.36 kB
build/block-library/blocks/spacer/editor-rtl.css 322 B
build/block-library/blocks/spacer/editor.css 322 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 494 B
build/block-library/blocks/table/editor.css 494 B
build/block-library/blocks/table/style-rtl.css 611 B
build/block-library/blocks/table/style.css 609 B
build/block-library/blocks/table/theme-rtl.css 175 B
build/block-library/blocks/table/theme.css 175 B
build/block-library/blocks/tag-cloud/style-rtl.css 226 B
build/block-library/blocks/tag-cloud/style.css 227 B
build/block-library/blocks/template-part/editor-rtl.css 149 B
build/block-library/blocks/template-part/editor.css 149 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/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 87 B
build/block-library/blocks/verse/style.css 87 B
build/block-library/blocks/video/editor-rtl.css 561 B
build/block-library/blocks/video/editor.css 563 B
build/block-library/blocks/video/style-rtl.css 159 B
build/block-library/blocks/video/style.css 159 B
build/block-library/blocks/video/theme-rtl.css 110 B
build/block-library/blocks/video/theme.css 110 B
build/block-library/common-rtl.css 987 B
build/block-library/common.css 984 B
build/block-library/editor-rtl.css 10.2 kB
build/block-library/editor.css 10.2 kB
build/block-library/elements-rtl.css 54 B
build/block-library/elements.css 54 B
build/block-library/index.min.js 183 kB
build/block-library/reset-rtl.css 478 B
build/block-library/reset.css 478 B
build/block-library/style-rtl.css 11.5 kB
build/block-library/style.css 11.5 kB
build/block-library/theme-rtl.css 695 B
build/block-library/theme.css 700 B
build/block-serialization-default-parser/index.min.js 1.11 kB
build/block-serialization-spec-parser/index.min.js 2.83 kB
build/blocks/index.min.js 47 kB
build/components/index.min.js 230 kB
build/components/style-rtl.css 14 kB
build/components/style.css 14 kB
build/compose/index.min.js 11.7 kB
build/core-data/index.min.js 14.7 kB
build/customize-widgets/index.min.js 11.2 kB
build/customize-widgets/style-rtl.css 1.4 kB
build/customize-widgets/style.css 1.4 kB
build/data-controls/index.min.js 653 B
build/data/index.min.js 7.95 kB
build/date/index.min.js 32 kB
build/deprecated/index.min.js 507 B
build/dom-ready/index.min.js 324 B
build/dom/index.min.js 4.66 kB
build/edit-navigation/index.min.js 16 kB
build/edit-navigation/style-rtl.css 4.02 kB
build/edit-navigation/style.css 4.03 kB
build/edit-post/classic-rtl.css 546 B
build/edit-post/classic.css 547 B
build/edit-post/index.min.js 30.5 kB
build/edit-post/style-rtl.css 6.97 kB
build/edit-post/style.css 6.97 kB
build/edit-site/style-rtl.css 8.23 kB
build/edit-site/style.css 8.22 kB
build/edit-widgets/index.min.js 16.5 kB
build/edit-widgets/style-rtl.css 4.35 kB
build/edit-widgets/style.css 4.35 kB
build/editor/index.min.js 39.4 kB
build/editor/style-rtl.css 3.65 kB
build/editor/style.css 3.65 kB
build/element/index.min.js 4.27 kB
build/escape-html/index.min.js 537 B
build/format-library/index.min.js 6.75 kB
build/format-library/style-rtl.css 571 B
build/format-library/style.css 571 B
build/hooks/index.min.js 1.64 kB
build/html-entities/index.min.js 448 B
build/i18n/index.min.js 3.77 kB
build/is-shallow-equal/index.min.js 527 B
build/keyboard-shortcuts/index.min.js 1.78 kB
build/keycodes/index.min.js 1.38 kB
build/list-reusable-blocks/index.min.js 1.74 kB
build/list-reusable-blocks/style-rtl.css 835 B
build/list-reusable-blocks/style.css 835 B
build/media-utils/index.min.js 2.93 kB
build/notices/index.min.js 953 B
build/nux/index.min.js 2.05 kB
build/nux/style-rtl.css 732 B
build/nux/style.css 728 B
build/plugins/index.min.js 1.94 kB
build/preferences-persistence/index.min.js 2.22 kB
build/preferences/index.min.js 1.3 kB
build/primitives/index.min.js 933 B
build/priority-queue/index.min.js 612 B
build/react-i18n/index.min.js 696 B
build/react-refresh-entry/index.min.js 8.44 kB
build/react-refresh-runtime/index.min.js 7.31 kB
build/redux-routine/index.min.js 2.68 kB
build/reusable-blocks/index.min.js 2.22 kB
build/reusable-blocks/style-rtl.css 256 B
build/reusable-blocks/style.css 256 B
build/rich-text/index.min.js 11.1 kB
build/server-side-render/index.min.js 1.61 kB
build/shortcode/index.min.js 1.53 kB
build/token-list/index.min.js 644 B
build/url/index.min.js 3.61 kB
build/vendors/react-dom.min.js 38.5 kB
build/vendors/react.min.js 4.34 kB
build/viewport/index.min.js 1.08 kB
build/warning/index.min.js 268 B
build/widgets/index.min.js 7.19 kB
build/widgets/style-rtl.css 1.16 kB
build/widgets/style.css 1.16 kB
build/wordcount/index.min.js 1.06 kB

compressed-size-action

@aaronrobertshaw aaronrobertshaw force-pushed the add/feature-level-selectors-to-theme-json branch from 637f2f5 to 6d0592a Compare July 4, 2022 02:50
@aaronrobertshaw aaronrobertshaw marked this pull request as ready for review July 4, 2022 02:57
@aaronrobertshaw aaronrobertshaw changed the title [WIP] Theme.json Add block support feature level selectors for blocks Theme.json: Add block support feature level selectors for blocks Jul 4, 2022
@ramonjd
Copy link
Member

ramonjd commented Jul 5, 2022

WordPress is loaded prior to the tests running meaning that WordPress' theme.json generates block metadata before our single, feature-level selector test could register a block

Just checking, are we blocked from testing manually due to this loading sequence?

@aaronrobertshaw
Copy link
Contributor Author

Just checking, are we blocked from testing manually due to this loading sequence?

Sorry for the confusion @ramonjd

You can test manually either via:

  1. Image: Add border block support for color, width, and style #31366 which leverages the new feature level selectors from this PR.
  2. Or, manually updating a block's block.json supports to include an __experimentalSelector flag within an individual block support configuration and then inspecting the theme.json or global styles generated styles for the expected resulting selectors.

I'll update the PR description and testing instructions.

Copy link
Contributor

@andrewserong andrewserong 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 testing pretty nicely for me @aaronrobertshaw. It's working well for me in global styles, and the individual block-level border overrides the global styles version correctly on the site front-end:

Global styles Individual block overriding global styles (this is a different gallery block to the previous screenshot)
image image

Overall, I quite like the idea of the feature, too — it slots in nicely with the existing __experimentalSelector and I like how it concatenates the root level selector with the feature-level one, too. While it is adding extra complexity to the global styles class, the changeset is a bit smaller than I'd imagined, so from my perspective, I think it's a worthwhile addition. Also the filter-based approach for ensuring a test block is available in the test environment sounds like a reasonable approach to me — it could be useful for other tests, too, having a test block around.

The one issue I ran into is that the border didn't appear to be displaying for me at the block level within the post editor, however, it renders correctly on the front end of the site: :

Post editor Site front end
image image

I'm testing with TwentyTwentyTwo theme and via checking out #31366, so I wasn't sure if it's more to do with that PR?


$this->assertEquals( $expected, $theme_json->get_stylesheet() );

unregister_block_type( 'test/test' );
Copy link
Contributor

Choose a reason for hiding this comment

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

Tiny nit: Does this test still need to unregister the block? If so, should the unregister be moved to before the assertEquals so that if the test fails it doesn't potentially affect other tests?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Honestly, I'd missed this when moving the block registration to the tests_add_filter. I did wonder though if unregistering the block limits unexpected results for other tests or creates more variability. I think I'd lean towards removing this.

@aaronrobertshaw
Copy link
Contributor Author

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

The one issue I ran into is that the border didn't appear to be displaying for me at the block level within the post editor, however, it renders correctly on the front end of the site: :

This one is due to WP core adding generic img { border: none; } and iframe, img { border: 0; } styles to the common.css for wp-admin. This means the CSS provided by border block support to apply default border styles via a :where selector is being overridden for img elements. It's therefore also a theme independent issue.

If I select a border style in the Post Editor the border displays correctly.

Screen.Recording.2022-07-05.at.5.39.21.pm.mp4

As you noted the issue is more to do with #31366 rather than this one so I don't think it's a blocker here. I'll address this in #31366, even if it is by adding img:where() selectors to apply the fallback/default border style that way.

@@ -47,6 +47,15 @@ class WP_Theme_JSON_6_1 extends WP_Theme_JSON_6_0 {
'caption' => 'wp-element-caption',
);

// List of block support features that can have their related styles
// generated under their own feature level selector rather than the block's.
const SUPPORT_FEATURES = array(
Copy link
Member

Choose a reason for hiding this comment

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

Probably a nitpick:

The comment is pretty clear, but I'm thinking about whether SUPPORT_FEATURE describes the role of the whitelist to folks digging about in the code.

Would BLOCK_SUPPORT_FEATURES or even BLOCK_SUPPORT_FEATURE_LEVEL_SELECTORS add anything?

// to leverage existing `compute_style_properties` function.
$feature = array( $feature_name => $node[ $feature_name ] );
// Generate the feature's declarations only.
$feature_declarations[ $feature_selector ] = static::compute_style_properties( $feature, $settings, null, $this->theme_json );
Copy link
Member

@ramonjd ramonjd Jul 6, 2022

Choose a reason for hiding this comment

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

I'm not sure what I'm seeing is correct, but I can't get multiple features to work at the same time, and I suspect it's because the features are either being unset or overwritten here.

So the border styles won't show when I have color/spacing/typography defined.

block.json supports example
	"supports": {
		"anchor": true,
		"align": true,
		"color": {
			"__experimentalSkipSerialization": true,
			"gradients": true,
			"__experimentalDefaultControls": {
				"background": true,
				"text": true
			},
			"__experimentalSelector": "> table"
		},
		"typography": {
			"fontSize": true,
			"lineHeight": true,
			"__experimentalFontStyle": true,
			"__experimentalFontWeight": true,
			"__experimentalLetterSpacing": true,
			"__experimentalTextTransform": true,
			"__experimentalDefaultControls": {
				"fontSize": true
			},
			"__experimentalSelector": "> table"
		},
		"__experimentalBorder": {
			"__experimentalSkipSerialization": true,
			"color": true,
			"style": true,
			"width": true,
			"__experimentalSelector": "> table",
			"__experimentalDefaultControls": {
				"color": true,
				"style": true,
				"width": true
			}
		},
		"__experimentalSelector": ".wp-block-table",
		"__experimentalStyle": {
			"spacing": {
				"margin": "0 0 1em 0"
			}
		}
	},
theme.json styles
"styles": {
		"blocks": {
			"core/cover": {
				"border": {
					"color": "fuchsia",
					"style": "dashed",
					"width": "3px"
				},
				"color": {
					"text": "fuchsia",
					"background": "black"
				},
				"typography": {
					"fontSize": "1px"
				},
				"spacing": {
					"padding": "100px"
				}
			},
			"core/table": {
				"border": {
					"color": "fuchsia",
					"style": "dashed",
					"width": "3px"
				},
				"color": {
					"text": "fuchsia",
					"background": "black"
				},
				"typography": {
					"fontSize": "100px"
				},
				"spacing": {
					"padding": "100px"
				}
			}
		}
	},

The only way I can get it to work is:

// Generate the feature's declarations only.
if ( isset( $feature_declarations[ $feature_selector ] ) ) {
    $feature_declarations[ $feature_selector ] = array_merge( $feature_declarations[ $feature_selector ], static::compute_style_properties( $feature, $settings, null, $this->theme_json ) );
} else {
    $feature_declarations[ $feature_selector ] = static::compute_style_properties( $feature, $settings, null, $this->theme_json );
}

But it might an indicator of a deeper issue.

It could be related to the fact that I'm seeing duplicate rules in the HTML source? Here's what I'm seeing when testing the cover block:

<style id='global-styles-inline-css'> \* lots of styles here*\ .wp-block-cover > .wp-block-cover__inner-container > p{padding: 100px;} \* lots of styles here*\ .
</style>


<style id='wp-block-cover-inline-css'>
    .wp-block-cover{font-size: 1px;}.wp-block-cover > .wp-block-cover__inner-container > p{padding: 100px;}
</style>

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 catching this issue @ramonjd. I'd clearly been caught up testing different supports targeting different inner elements.

I've fixed this by leveraging your snippet, adding an explanatory inline comment, and expanding the unit tests to cover:

  • two supports using a shared custom feature level selector e.g. .inner
  • one other support using its own unique selector e.g. .sub-heading
  • and, a further support that doesn't have a feature level selector specified.

But it might an indicator of a deeper issue.

It could be related to the fact that I'm seeing duplicate rules in the HTML source? Here's what I'm seeing when testing the cover block:

This looks to be unrelated to me. There was definitely a flaw in the previous logic generating the feature styles.

Copy link
Member

@ramonjd ramonjd Jul 7, 2022

Choose a reason for hiding this comment

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

It could be related to the fact that I'm seeing duplicate rules in the HTML source? Here's what I'm seeing when testing the cover block:

Thanks for looking into it.

I'm also seeing it on trunk and suspect it's because we're enqueuing block styles in both places after #42005

Edit: fix attempt here

Copy link
Member

@ramonjd ramonjd 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 a nice change. And compact too!

With one rule, say, border, the selectors are output as expected in the frontend and site/block editors.

So I see .wp-block-table > table .some_selector, where .wp-block-table > table is the root __experimentalSelector and .some_selector is the feature selector.

I was wondering if there'd ever be a case for & like selectors, where we could conditionally apply only one feature's style to the container? Sounds a bit weird when I type it out, but was just curious.

With various feature rules added, I noticed that CSS rules are missing when I activate multiple features (color/border etc). See comment

@aaronrobertshaw
Copy link
Contributor Author

Thanks for reviewing @ramonjd 👍

I was wondering if there'd ever be a case for & like selectors, where we could conditionally apply only one feature's style to the container? Sounds a bit weird when I type it out, but was just curious.

I did wonder about something similar as well. I'm not sure how valid the following hypothetical would be but might illustrate the potential for a future desire to modify the root __experimentalSelector instead of only using it to scope an inner one.

It could be possible that we'd have a block that has a few Block Styles. Maybe we'd like to apply the block support styles only if a certain block style hasn't been selected. Such as;

  • The block has a root __experimentalSelector of .wp-block-example.
  • It might have a block style that would add .is-example-block-style.
  • We wish to only apply a given block support's styles if that block style wasn't selected. The styles should also still be applied it to the same element as the root selector. e.g. via something like &:not(.is-example-block-style).
  • We'd end up with a feature level selector like: .wp-block-example:not(.is-example-block-style)

In future iterations of these feature level selectors, I'd like to think we could extend it to perhaps check if the feature level selector starts with & and resolve that when scoping the selector. For the time being though, the current scoping should solve immediate needs and buy us more time to consider changes.

With various feature rules added, I noticed that CSS rules are missing when I activate multiple features (color/border etc). See comment

Thanks for flagging this, I'll look into it.

@andrewserong
Copy link
Contributor

andrewserong commented Jul 6, 2022

I had another thought (and it isn't at all a blocker for this PR), that when it comes to rendering block supports at the individual block level for server-rendered blocks, we might need to add a conditional that switches between inline styles (if no experimental selector is used) and a style block — so we'd potentially call the style engine differently based on whether or not the current feature uses the experimental selector? I imagine that'd be a bit neater than attempting to inject a style attribute further down the DOM tree of the server-rendered block.

Just thought I'd mention it as a potential to-do list item for the future, or in case it affects plans for server-rendered blocks like Search 🤔 (Apologies if this has been discussed already!)

@aaronrobertshaw
Copy link
Contributor Author

when it comes to rendering block supports at the individual block level for server-rendered blocks, we might need to add a conditional that switches between inline styles (if no experimental selector is used) and a style block

I see these selectors primarily being used when skipping the serialization of individual block styles. A means to offer control via both theme.json and Global Styles when the styles generated would otherwise be incorrectly targetted.

If skipping serialization the block would have the styles manually generated and applied directly where it sees fit during its render callback. Could the choice between inline styles or a style block be made here avoiding an additional config flag?

Do you think it makes sense that we only enable the feature level selectors if the block support also skips serialization?

I imagine that'd be a bit neater than attempting to inject a style attribute further down the DOM tree of the server-rendered block.

It might do although I'm not sure if we'd then run into specificity issues. For all their downsides, the inline styles make it clear that the individual block's support styles will be taking precedence.

@andrewserong
Copy link
Contributor

For all their downsides, the inline styles make it clear that the individual block's support styles will be taking precedence.

Agreed! It's one of the things I like about the Image block PR — that it seems quite natural injecting the inline style at the correct level in the hierarchy in the JS implementation.

Do you think it makes sense that we only enable the feature level selectors if the block support also skips serialization?

Yes, I think that's a good way to handle it at the individual block support level. It means that in the shorter-term, this is a feature for blocks that skip serialization, but it doesn't stop us from exploring options in the style engine further down the track, if we want to leverage the feature-level selector for outputting style block rules. Sounds good to me! (We probably don't need to make any changes in this PR, we could leave that to when we tackle a server-side block like Search, if it makes things simpler 🙂)

@aaronrobertshaw
Copy link
Contributor Author

We probably don't need to make any changes in this PR, we could leave that to when we tackle a server-side block like Search, if it makes things simpler

Sounds like a plan to me. Happy to tweak the approach as more blocks leverage feature-level selectors but for now it would be great to be able to land this to unblock the application of borders on images in #31366.

I'll add a few extra reviewers and 🤞 that we can get this merged in the near future.

@andrewserong
Copy link
Contributor

andrewserong commented Jul 7, 2022

I'll add a few extra reviewers and 🤞 that we can get this merged in the near future.

Sounds great — I think this feature is looking really good, and the scope of this PR is nice and incremental, so opening up for wider review sounds like a plan to me, too!

@ajlende
Copy link
Contributor

ajlende commented Jul 8, 2022

@aaronrobertshaw Nice to see someone else working on this! I did an exploration in a gist a while back for multiple selectors in the context of using them to to apply SVG filters (duotone) to the inner parts of a block since filter is also a non-inherited property like border.

I'd like to stabilize a method of allowing blocks to choose multiple selectors and wrap __experimentalDuotone and __experimentalSelector into one; although, to be clear, that doesn't need to happen right now in this PR. In stabilizing it, I wanted to make room for plugins to utilize the selectors that a block specifies by adding generic selectors like media (for thing like duotone) or container (for things like border) rather than tying things to specific block support features.

I'm in transit to a meetup at the moment, so I'll do a proper code review when I arrive, but I figured it would be worth sharing my initial thoughts first. If the details of stabilizing that API are too far out of scope for here, feel free to comment on the gist or I can open up a proper discussion when I have a bit more time.

@aaronrobertshaw aaronrobertshaw force-pushed the add/feature-level-selectors-to-theme-json branch from a9a9cf1 to 3740ddb Compare July 12, 2022 03:06
@aaronrobertshaw
Copy link
Contributor Author

I've rebased this and resolved the conflicts after #40875 landed. The PR is still working for me and the unit tests pass. Any extra testing is still welcome of course.

@jorgefilipecosta do you have any thoughts or objections to the approach taken in this PR? If not, I'll look to merge this soon.

Copy link
Member

@ramonjd ramonjd left a comment

Choose a reason for hiding this comment

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

I've taken this for another spin and, despite trying, I can't break it 😄

I've added __experimentalSelector values to different styles in block.json and then styled blocks via theme.json.

The correct CSS is generated even when I mix selectors and use multiple styles.

Great stuff.

Copy link
Contributor

@andrewserong andrewserong left a comment

Choose a reason for hiding this comment

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

Just thought I'd take this for a spin, too — the code change looks good to me, and it's working nicely in both the editor and global styles. Nice work honing in on this feature! 🚀

image

@jorgefilipecosta
Copy link
Member

I've rebased this and resolved the conflicts after #40875 landed. The PR is still working for me and the unit tests pass. Any extra testing is still welcome of course.

@jorgefilipecosta do you have any thoughts or objections to the approach taken in this PR? If not, I'll look to merge this soon.

This PR seems to have been very well discussed and passed by many reviewers so I trust your judgment here.

@aaronrobertshaw aaronrobertshaw merged commit 87cdeb3 into trunk Jul 15, 2022
@aaronrobertshaw aaronrobertshaw deleted the add/feature-level-selectors-to-theme-json branch July 15, 2022 00:41
@github-actions github-actions bot added this to the Gutenberg 13.8 milestone Jul 15, 2022
@aaronrobertshaw
Copy link
Contributor Author

Thanks everyone for the reviews, testing and feedback. Appreciate it 👍

@carolinan
Copy link
Contributor

Do I understand correctly that I do not make any changes or add any new keys to theme.json?
If the selector changes without me making changes to theme.json, wont that break existing styles?

@aaronrobertshaw
Copy link
Contributor Author

Hi @carolinan 👋

I'm not sure I follow your questions exactly, so my apologies if I miss the mark answering them here.

Do I understand correctly that I do not make any changes or add any new keys to theme.json?

No new keys or changes to your theme.json are required. A block support feature's values are configured the same way whether they are applied to the block's root wrapper or a specific selector for that feature.

When a theme.json configuration is being processed, CSS declarations are created for each block. These are then converted to a ruleset for a given selector. Before this PR, the block could define its root level selector via supports.__experimentalSelector or fall back to the default block class, e.g. wp-block-image.

Now a block can define the selector for a specific block support feature, e.g. supports.__experimentalBorder.__experimentalSelector. If a custom selector is set for a specific block support feature, any CSS declarations for that support feature are converted to a ruleset using the custom selector instead of the block's root selector.

If the selector changes without me making changes to theme.json, wont that break existing styles?

If I understand correctly, you are concerned a block might suddenly change the selector configured in its block.json? The same could happen with the root level __experimentalSelector as it does not actually have to target the root element for a block.

If a block is changing its markup such that it needs a new selector to apply feature-level styles, it would likely already be needing a deprecation or to maintain the old selector to maintain stylings on deprecated blocks. The __experimentalSelector flags allow for comma-separated selectors, which could be an option in such a situation.

Hope that helps clarify things 🤞

@carolinan
Copy link
Contributor

Yes thank you. It doesn't literally "Add a "feature level selector" to theme.json ".

@aaronrobertshaw
Copy link
Contributor Author

It doesn't literally "Add a "feature level selector" to theme.json ".

Correct. Apologies if the PR title is misleading.

Theme.json: Add block support feature level selectors for blocks

It adds processing and support for feature level selectors to the theme.json class ( e.g. WP_Theme_JSON_6_1 ) and global styles.

@femkreations femkreations added the Needs User Documentation Needs new user documentation label Sep 4, 2022
pento pushed a commit to WordPress/wordpress-develop that referenced this pull request Sep 14, 2022
This change backports the following changes from Gutenberg repository:

- [WordPress/gutenberg#40875 gutenberg#40875] Layout: Use semantic classnames, centralize layout definitions, reduce duplication, and fix blockGap in theme.json
- [WordPress/gutenberg#42544 gutenberg#42544] Layout: Add a disable-layout-styles theme supports flag to opt out of all layout styles gutenberg#42544
- [WordPress/gutenberg#42087 gutenberg#42087] Theme.json: Add block support feature level selectors for blocks gutenberg#42087
- [WordPress/gutenberg#43792 gutenberg#43792] Global Styles: Split root layout rules into a different function gutenberg#43792
- [WordPress/gutenberg#42544 gutenberg#42544] Layout: Add a disable-layout-styles theme supports flag to opt out of all layout styles gutenberg#42544
- [WordPress/gutenberg#42665 gutenberg#42665] Layout: Reduce specificity of fallback blockGap styles gutenberg#42665
- [WordPress/gutenberg#42085 gutenberg#42085] Core CSS support for root padding and alignfull blocks gutenberg#42085

Note that it doesn't entirely port over PR40875 — the remaining PHP changes for that PR will be explored in a separate PR targeting `layout.php`.

Props andrewserong, aaronrobertshaw, isabel_brison.
See #56467.


git-svn-id: https://develop.svn.wordpress.org/trunk@54159 602fd350-edb4-49c9-b593-d223f7449a82
markjaquith pushed a commit to markjaquith/WordPress that referenced this pull request Sep 14, 2022
This change backports the following changes from Gutenberg repository:

- [WordPress/gutenberg#40875 gutenberg#40875] Layout: Use semantic classnames, centralize layout definitions, reduce duplication, and fix blockGap in theme.json
- [WordPress/gutenberg#42544 gutenberg#42544] Layout: Add a disable-layout-styles theme supports flag to opt out of all layout styles gutenberg#42544
- [WordPress/gutenberg#42087 gutenberg#42087] Theme.json: Add block support feature level selectors for blocks gutenberg#42087
- [WordPress/gutenberg#43792 gutenberg#43792] Global Styles: Split root layout rules into a different function gutenberg#43792
- [WordPress/gutenberg#42544 gutenberg#42544] Layout: Add a disable-layout-styles theme supports flag to opt out of all layout styles gutenberg#42544
- [WordPress/gutenberg#42665 gutenberg#42665] Layout: Reduce specificity of fallback blockGap styles gutenberg#42665
- [WordPress/gutenberg#42085 gutenberg#42085] Core CSS support for root padding and alignfull blocks gutenberg#42085

Note that it doesn't entirely port over PR40875 — the remaining PHP changes for that PR will be explored in a separate PR targeting `layout.php`.

Props andrewserong, aaronrobertshaw, isabel_brison.
See #56467.

Built from https://develop.svn.wordpress.org/trunk@54159


git-svn-id: http://core.svn.wordpress.org/trunk@53718 1a063a9b-81f0-0310-95a4-ce76da25c4cd
github-actions bot pushed a commit to gilzow/wordpress-performance that referenced this pull request Sep 14, 2022
This change backports the following changes from Gutenberg repository:

- [WordPress/gutenberg#40875 gutenberg#40875] Layout: Use semantic classnames, centralize layout definitions, reduce duplication, and fix blockGap in theme.json
- [WordPress/gutenberg#42544 gutenberg#42544] Layout: Add a disable-layout-styles theme supports flag to opt out of all layout styles gutenberg#42544
- [WordPress/gutenberg#42087 gutenberg#42087] Theme.json: Add block support feature level selectors for blocks gutenberg#42087
- [WordPress/gutenberg#43792 gutenberg#43792] Global Styles: Split root layout rules into a different function gutenberg#43792
- [WordPress/gutenberg#42544 gutenberg#42544] Layout: Add a disable-layout-styles theme supports flag to opt out of all layout styles gutenberg#42544
- [WordPress/gutenberg#42665 gutenberg#42665] Layout: Reduce specificity of fallback blockGap styles gutenberg#42665
- [WordPress/gutenberg#42085 gutenberg#42085] Core CSS support for root padding and alignfull blocks gutenberg#42085

Note that it doesn't entirely port over PR40875 — the remaining PHP changes for that PR will be explored in a separate PR targeting `layout.php`.

Props andrewserong, aaronrobertshaw, isabel_brison.
See #56467.

Built from https://develop.svn.wordpress.org/trunk@54159


git-svn-id: https://core.svn.wordpress.org/trunk@53718 1a063a9b-81f0-0310-95a4-ce76da25c4cd
whereiscodedude pushed a commit to whereiscodedude/wpss that referenced this pull request Sep 18, 2022
This change backports the following changes from Gutenberg repository:

- [WordPress/gutenberg#40875 gutenberg#40875] Layout: Use semantic classnames, centralize layout definitions, reduce duplication, and fix blockGap in theme.json
- [WordPress/gutenberg#42544 gutenberg#42544] Layout: Add a disable-layout-styles theme supports flag to opt out of all layout styles gutenberg#42544
- [WordPress/gutenberg#42087 gutenberg#42087] Theme.json: Add block support feature level selectors for blocks gutenberg#42087
- [WordPress/gutenberg#43792 gutenberg#43792] Global Styles: Split root layout rules into a different function gutenberg#43792
- [WordPress/gutenberg#42544 gutenberg#42544] Layout: Add a disable-layout-styles theme supports flag to opt out of all layout styles gutenberg#42544
- [WordPress/gutenberg#42665 gutenberg#42665] Layout: Reduce specificity of fallback blockGap styles gutenberg#42665
- [WordPress/gutenberg#42085 gutenberg#42085] Core CSS support for root padding and alignfull blocks gutenberg#42085

Note that it doesn't entirely port over PR40875 — the remaining PHP changes for that PR will be explored in a separate PR targeting `layout.php`.

Props andrewserong, aaronrobertshaw, isabel_brison.
See #56467.

Built from https://develop.svn.wordpress.org/trunk@54159
@femkreations femkreations removed the Needs User Documentation Needs new user documentation label Sep 25, 2022
ootwch pushed a commit to ootwch/wordpress-develop that referenced this pull request Nov 4, 2022
This change backports the following changes from Gutenberg repository:

- [WordPress/gutenberg#40875 gutenberg#40875] Layout: Use semantic classnames, centralize layout definitions, reduce duplication, and fix blockGap in theme.json
- [WordPress/gutenberg#42544 gutenberg#42544] Layout: Add a disable-layout-styles theme supports flag to opt out of all layout styles gutenberg#42544
- [WordPress/gutenberg#42087 gutenberg#42087] Theme.json: Add block support feature level selectors for blocks gutenberg#42087
- [WordPress/gutenberg#43792 gutenberg#43792] Global Styles: Split root layout rules into a different function gutenberg#43792
- [WordPress/gutenberg#42544 gutenberg#42544] Layout: Add a disable-layout-styles theme supports flag to opt out of all layout styles gutenberg#42544
- [WordPress/gutenberg#42665 gutenberg#42665] Layout: Reduce specificity of fallback blockGap styles gutenberg#42665
- [WordPress/gutenberg#42085 gutenberg#42085] Core CSS support for root padding and alignfull blocks gutenberg#42085

Note that it doesn't entirely port over PR40875 — the remaining PHP changes for that PR will be explored in a separate PR targeting `layout.php`.

Props andrewserong, aaronrobertshaw, isabel_brison.
See #56467.


git-svn-id: https://develop.svn.wordpress.org/trunk@54159 602fd350-edb4-49c9-b593-d223f7449a82
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
[Feature] Design Tools Tools that impact the appearance of blocks both to expand the number of tools and improve the experi Global Styles Anything related to the broader Global Styles efforts, including Styles Engine and theme.json [Type] Enhancement A suggestion for improvement.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants