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

ServerSideRender: add new skipBlockSupportAttributes prop #44491

Merged
merged 25 commits into from
Oct 7, 2022

Conversation

t-hamano
Copy link
Contributor

@t-hamano t-hamano commented Sep 27, 2022

Related to:

For more information, see the discussion that begins with this comment.

What?

This PR adds a new skipBlockSupportAttributes prop to the ServerSideRender component. If this prop is specified, the ServerSideRender component will not include attributes and styles applied by the block support in the API request data.

This will make it easier to properly add support to blocks with ServerSideRender components.

Why?

When styles are applied with block support, attributes such as attributes.textColor and attribites.style.border.radius are added. If these are passed to the callback function via the ServerSideRender component, get_block_wrapper_attributes will generate the styles and CSS classes. This is the correct behavior on the front end, but on the editor, both the block wrapper and the rendered element will have duplicate styles and CSS classes.

This problem can be solved by properly excluding properties and styles added by block support from the attributes passed to the ServerSideRender component. However, it would make sense for components to include the logic and provide them as props.

How?

Remove all properties and styles automatically added by the block supports from the attributes passed to the ServerSideRender component. This ensures that the block support styles are properly applied only to the block wrapper element on the editor.

Testing Instructions

  • Insert one of the following blocks using the server-side render component:
    • core/archives
    • core/latest-comments
    • core/rss
    • core/tag-cloud
  • In block.json, opt-in all block support as follows:
block.json support properties
{
	"supports": {
		"align": true,
		"html": false,
		"color": {
			"text": true,
			"background": true,
			"gradients": true,
			"link": true
		},
		"typography": {
			"fontSize": true,
			"lineHeight": true,
			"__experimentalFontFamily": true,
			"__experimentalFontWeight": true,
			"__experimentalFontStyle": true,
			"__experimentalTextTransform": true,
			"__experimentalTextDecoration": true,
			"__experimentalLetterSpacing": true
		},
		"spacing": {
			"margin": true,
			"padding": true
		},
		"__experimentalBorder": {
			"radius": true,
			"color": true,
			"width": true,
			"style": true
		}
	}
}
  • Specify the skipBlockSupportAttributes prop as follows:
<ServerSideRender
	skipBlockSupportAttributes
	block="core/latest-comments"
	attributes={ attributes }
	urlQueryArgs={ { _locale: 'site' } }
/>
  • Confirm that elements rendered by the server side are not given block support styles or classes.

Screenshots or screencast

Before

before

After

after

Next step

This PR does not fix the duplicate custom CSS class that #44439, #44438, and #43653 are trying to resolve. Because I think duplicate CSS classes should be fixed regardless of this new prop. Once this PR is properly merged, I would like to submit a new PR to resolve the CSS class duplication.

Once the CSS class duplication is resolved and the skipBlockSupportAttributes are available, the following PR should be solved with simpler code:

However, for calendar blocks, this option would not work because color support is need to be applied to the internal elements, as was done in #42029.

@github-actions
Copy link

github-actions bot commented Sep 27, 2022

Size Change: +162 B (0%)

Total Size: 1.27 MB

Filename Size Change
build/server-side-render/index.min.js 1.77 kB +162 B (+10%) ⚠️
ℹ️ 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 7.09 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 166 kB
build/block-editor/style-rtl.css 15.4 kB
build/block-editor/style.css 15.4 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 122 B
build/block-library/blocks/audio/style.css 122 B
build/block-library/blocks/audio/theme-rtl.css 126 B
build/block-library/blocks/audio/theme.css 126 B
build/block-library/blocks/avatar/editor-rtl.css 116 B
build/block-library/blocks/avatar/editor.css 116 B
build/block-library/blocks/avatar/style-rtl.css 84 B
build/block-library/blocks/avatar/style.css 84 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 482 B
build/block-library/blocks/button/editor.css 482 B
build/block-library/blocks/button/style-rtl.css 523 B
build/block-library/blocks/button/style.css 523 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 84 B
build/block-library/blocks/categories/editor.css 83 B
build/block-library/blocks/categories/style-rtl.css 100 B
build/block-library/blocks/categories/style.css 100 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 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 834 B
build/block-library/blocks/comments/editor.css 832 B
build/block-library/blocks/comments/style-rtl.css 632 B
build/block-library/blocks/comments/style.css 630 B
build/block-library/blocks/cover/editor-rtl.css 612 B
build/block-library/blocks/cover/editor.css 613 B
build/block-library/blocks/cover/style-rtl.css 1.57 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 126 B
build/block-library/blocks/embed/theme.css 126 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.53 kB
build/block-library/blocks/gallery/style.css 1.53 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 394 B
build/block-library/blocks/group/editor.css 394 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 884 B
build/block-library/blocks/image/editor.css 882 B
build/block-library/blocks/image/style-rtl.css 627 B
build/block-library/blocks/image/style.css 630 B
build/block-library/blocks/image/theme-rtl.css 126 B
build/block-library/blocks/image/theme.css 126 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 213 B
build/block-library/blocks/latest-posts/editor.css 212 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 507 B
build/block-library/blocks/media-text/style.css 505 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/editor-rtl.css 2.02 kB
build/block-library/blocks/navigation/editor.css 2.03 kB
build/block-library/blocks/navigation/style-rtl.css 2.17 kB
build/block-library/blocks/navigation/style.css 2.16 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 317 B
build/block-library/blocks/paragraph/editor.css 317 B
build/block-library/blocks/paragraph/style-rtl.css 279 B
build/block-library/blocks/paragraph/style.css 281 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 493 B
build/block-library/blocks/post-comments-form/style.css 493 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 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 586 B
build/block-library/blocks/post-featured-image/editor.css 584 B
build/block-library/blocks/post-featured-image/style-rtl.css 315 B
build/block-library/blocks/post-featured-image/style.css 315 B
build/block-library/blocks/post-navigation-link/style-rtl.css 153 B
build/block-library/blocks/post-navigation-link/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 96 B
build/block-library/blocks/post-terms/style.css 96 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 103 B
build/block-library/blocks/preformatted/style.css 103 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 326 B
build/block-library/blocks/pullquote/style.css 325 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 282 B
build/block-library/blocks/query-pagination/style.css 278 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 439 B
build/block-library/blocks/query/editor.css 439 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 409 B
build/block-library/blocks/search/style.css 406 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 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 464 B
build/block-library/blocks/shortcode/editor.css 464 B
build/block-library/blocks/site-logo/editor-rtl.css 488 B
build/block-library/blocks/site-logo/editor.css 488 B
build/block-library/blocks/site-logo/style-rtl.css 203 B
build/block-library/blocks/site-logo/style.css 203 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 674 B
build/block-library/blocks/social-links/editor.css 673 B
build/block-library/blocks/social-links/style-rtl.css 1.4 kB
build/block-library/blocks/social-links/style.css 1.39 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 190 B
build/block-library/blocks/table/theme.css 190 B
build/block-library/blocks/tag-cloud/style-rtl.css 239 B
build/block-library/blocks/tag-cloud/style.css 239 B
build/block-library/blocks/template-part/editor-rtl.css 235 B
build/block-library/blocks/template-part/editor.css 235 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 691 B
build/block-library/blocks/video/editor.css 694 B
build/block-library/blocks/video/style-rtl.css 174 B
build/block-library/blocks/video/style.css 174 B
build/block-library/blocks/video/theme-rtl.css 126 B
build/block-library/blocks/video/theme.css 126 B
build/block-library/classic-rtl.css 162 B
build/block-library/classic.css 162 B
build/block-library/common-rtl.css 1.02 kB
build/block-library/common.css 1.02 kB
build/block-library/editor-elements-rtl.css 75 B
build/block-library/editor-elements.css 75 B
build/block-library/editor-rtl.css 11.2 kB
build/block-library/editor.css 11.2 kB
build/block-library/elements-rtl.css 54 B
build/block-library/elements.css 54 B
build/block-library/index.min.js 192 kB
build/block-library/reset-rtl.css 478 B
build/block-library/reset.css 478 B
build/block-library/style-rtl.css 12.3 kB
build/block-library/style.css 12.3 kB
build/block-library/theme-rtl.css 719 B
build/block-library/theme.css 722 B
build/block-serialization-default-parser/index.min.js 1.12 kB
build/block-serialization-spec-parser/index.min.js 2.83 kB
build/blocks/index.min.js 49.8 kB
build/components/index.min.js 202 kB
build/components/style-rtl.css 11.2 kB
build/components/style.css 11.2 kB
build/compose/index.min.js 12.5 kB
build/core-data/index.min.js 15.5 kB
build/customize-widgets/index.min.js 11.3 kB
build/customize-widgets/style-rtl.css 1.38 kB
build/customize-widgets/style.css 1.38 kB
build/data-controls/index.min.js 653 B
build/data/index.min.js 8.08 kB
build/date/index.min.js 32.1 kB
build/deprecated/index.min.js 507 B
build/dom-ready/index.min.js 324 B
build/dom/index.min.js 4.7 kB
build/edit-navigation/index.min.js 16 kB
build/edit-navigation/style-rtl.css 3.99 kB
build/edit-navigation/style.css 4 kB
build/edit-post/classic-rtl.css 546 B
build/edit-post/classic.css 547 B
build/edit-post/index.min.js 31.1 kB
build/edit-post/style-rtl.css 6.97 kB
build/edit-post/style.css 6.97 kB
build/edit-site/index.min.js 57.9 kB
build/edit-site/style-rtl.css 8.36 kB
build/edit-site/style.css 8.35 kB
build/edit-widgets/index.min.js 16.5 kB
build/edit-widgets/style-rtl.css 4.34 kB
build/edit-widgets/style.css 4.34 kB
build/editor/index.min.js 41.6 kB
build/editor/style-rtl.css 3.62 kB
build/editor/style.css 3.61 kB
build/element/index.min.js 4.68 kB
build/escape-html/index.min.js 537 B
build/experiments/index.min.js 868 B
build/format-library/index.min.js 6.95 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.83 kB
build/list-reusable-blocks/index.min.js 2.13 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 963 B
build/nux/index.min.js 2.06 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 1.58 kB
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.74 kB
build/reusable-blocks/index.min.js 2.21 kB
build/reusable-blocks/style-rtl.css 256 B
build/reusable-blocks/style.css 256 B
build/rich-text/index.min.js 10.6 kB
build/shortcode/index.min.js 1.53 kB
build/style-engine/index.min.js 1.46 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.21 kB
build/widgets/style-rtl.css 1.18 kB
build/widgets/style.css 1.19 kB
build/wordcount/index.min.js 1.06 kB

compressed-size-action

@@ -2,6 +2,10 @@

## Unreleased

### Feature

- Add `skipBlockSupportAttributes` props to prevent duplication of styles in the block wrapper and the `ServerSideRender` components. [#44491](https://github.com/WordPress/gutenberg/pull/44491)
Copy link
Contributor Author

Choose a reason for hiding this comment

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

If the description is unnatural, please feel free to update it 🙏

@t-hamano t-hamano changed the title [WIP] ServerSideRender: add new skipBlockSupportAttributes prop ServerSideRender: add new skipBlockSupportAttributes prop Sep 27, 2022
@t-hamano t-hamano self-assigned this Sep 27, 2022
@t-hamano t-hamano added [Type] Enhancement A suggestion for improvement. [Package] Server Side Render /packages/server-side-render labels Sep 27, 2022
@t-hamano t-hamano marked this pull request as ready for review September 27, 2022 12:00
Copy link
Contributor

@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.

Thanks for your hard work on this @t-hamano 👍

It is testing pretty well for me so far. I was wondering, though, if we might need to add some additional logic to removeBlockSupportAttributes.

A block might wish for some block supports to be serialized on the outer wrapper while it skips other supports so they can be serialized on inner elements. In the latter case, we don't want to remove that support's attributes.

The Calendar block, as you mention, is a prime example of this. It applies typography support classes and styles to the wrapper while skipping serialization of the color support classes and styles so they can be applied internally.

Could we check each block support for __experimentalSkipSerialization within the block type's config? If it is set, don't remove those attributes. It is still possible for a block to skip serialization only to reapply it again on the wrapper. For such an edge case, the block itself would have to handle stripping the attributes itself. That should be pretty uncommon so I think that's fine.

Screenshot for Archives block showing no duplicate classes & styles Screen Shot 2022-09-30 at 4 05 11 pm

@t-hamano
Copy link
Contributor Author

t-hamano commented Oct 2, 2022

Thank you for the review, @aaronrobertshaw!
I think I managed to implement the logic to check for __experimentalSkipSerialization.

The process of removing the block supports was very complicated. For example, in the case of text color, the following two properties need to be deleted:

  • attributes.textColor
  • attributes.style.color.text

For borders, it is more complicated. For example, border-width requires consideration of all of the following properties:

  • attributes.style.border.width
    - attributes.style.border.top.width
  • attributes.style.border.left.width
  • attributes.style.border.bottom.width
  • attributes.style.border.left.width

At the same time, I made the following two changes:

  • I separated the processing into util.js and constants.js
  • Add more meaningful unit tests

I have tested in a calendar block where __experimentalSkipSerialization is used, and I believe that the intended rendering could be achieved by simply opting into skipBlockSupportAttributes.

A calendar block without skipBlockSupportAttributes

before

A calendar block with skipBlockSupportAttributes

after

I believe this new prop alone will solve the other PRs as well 🙂

borderColor: [ '__experimentalBorder', 'color' ],
};

export const STYLE_PROPERTY = {
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 definition is based on the following:

export const __EXPERIMENTAL_STYLE_PROPERTY = {

*
* @return {boolean} Whether serialization should occur.
*/
function shouldSkipSerialization( blockType, featureSet, feature ) {
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 is the same as:

export function shouldSkipSerialization( blockType, featureSet, feature ) {

Copy link
Contributor

@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.

Amazing effort persevering with the complexities here @t-hamano! 🙇

The process of removing the block supports was very complicated.

I didn't appreciate or maybe I'd repressed memories of how tangled the block supports config and skipping serialization can get 🙈

Knowing the effort you've already put in, I'm a bit reluctant to raise the question of whether this added complexity is worth it here. We might benefit from getting a second opinion on the direction. @andrewserong do you have any thoughts on this PR?

In case we do decide against adding the complexity to this component, you have my apologies for sending you down that path! I don't imagine it was much fun 🙂


I'll outline a few of my concerns below that give me a little cause to rethink our approach.

  1. There's quite a lot of code being duplicated from other packages here e.g. the constants config, shouldSkipSerialization, cleanEmptyObject etc.
  2. I'm not sure people working on block supports would know of or even find the new constants etc here to update.
  3. This PR introduces further usage of Lodash while there is a concerted effort in Gutenberg to remove our reliance on Lodash so that can be dropped altogether as a dependency.
  4. It appears that Calendar is the only block using ServerSideRender that skips block support serialization. So it would be the only one benefiting from all the extra complexity added in this PR now.

Would we be better off treating Calendar as a special case and having it not leverage the new skipBlockSupportAttributes prop and instead stripping its own attributes as needed?

What do you think is the best path forward?

@t-hamano
Copy link
Contributor Author

t-hamano commented Oct 4, 2022

I don't care about the additional implementation regarding serialization, as I have no problem if this is not incorporated 👍

I'm rethinking my thinking, it might be a rare case for blocks with the ServerSideRender component to skip serialization, like a calendar block? 🤔 If so, this additional implementation might not be beneficial enough to cover the concerns you listed (Use of lodash, duplication of functions and config, maintenance of config, etc).

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 echoing some of @aaronrobertshaw's thoughts here, but thank you so much @t-hamano for going down this particular rabbithole. I think it's very helpful for revealing some of the trade-offs of the decision making here surrounding both how we use the ServerSideRender component, and where should we put the complexity.

From my perspective, I think the scope of this PR now reveals that we might be better served to deal with the additional duplication in the original PRs that dealt with the block supports problem on a case-by-case basis for each block, in the block's edit components. The reason being that the complexity added here also winds up introducing duplication, that would then need to be maintained as the block supports evolve. Plus, there is also the concern that ideally in the long-term, blocks will reduce their dependency on using the ServerSideRender component altogether.

So, it might wind up being a bit easier for us if we deal with this specifically in the blocks' Edit components as in the original PRs (e.g #44438)?

I very much share @aaronrobertshaw's sentiment that this is great work here, I think it's hugely valuable to explore all our options in depth, and it's very much appreciated! It's always challenging with these sorts of problems where there isn't a single obvious, clean solution, but rather a set of trade-offs to manage complexity and maintainability.

What do you both think?

@bph
Copy link
Contributor

bph commented Oct 27, 2022

Although only four core/blocks benefit from the change in the ServerSideRender package, there are 620 plugins in the repo who also use it one way or other.

Would I be correct, when I write:

Before this is merged into Core with 6.2

  • Are there any backwards-compatibility concerns, that need to be considered?
  • stabilize of __experimentalSkipSerialization
  • write a devnote elaborating on this description:
    "Remove attributes and style properties applied by the block supports. This prevents duplication of styles in the block wrapper and the ServerSideRender components. Even if certain features skip serialization to HTML markup by __experimentalSkipSerialization, all attributes and style properties are removed."

@bph bph added the Needs Dev Note Requires a developer note for a major WordPress release cycle label Oct 27, 2022
@t-hamano
Copy link
Contributor Author

@bph

Are there any backwards-compatibility concerns, that need to be considered?

This new property will keep the existing behavior unless explicitly opted in by the developer. Therefore, I think that the backward compatibility doesn't need to be considered.

stabilize of __experimentalSkipSerialization

Perhaps this might need to be discussed in #45194; whether to stabilize __experimentalSkipSerialization is also discussed.

write a devnote elaborating on this description:

I am wondering if a dev note should be written on this.

This new prop is implemented to solve the problem of double application of block support styles in core blocks using ServerSideRender. Of course, this new prop can also be used by plugin developers, but the use of this component itself is currently discouraged.

Therefore, it might not be necessary to actively announce it.

@aaronrobertshaw
Please let us know if you have any feedback on this matter.

@bph
Copy link
Contributor

bph commented Oct 27, 2022

Thanks @t-hamano for entertaining my questions.

the use of this component itself is currently discouraged.

Ah interesting, was this formulized in any documentation? 620 plugins can't be that wrong :-)

@t-hamano
Copy link
Contributor Author

Please see: https://github.com/WordPress/gutenberg/tree/trunk/packages/server-side-render#serversiderender

My understanding is that this package used to be used to render dynamic blocks on the editor. And it had the advantage of being able to use the PHP rendering logic as it is done on the front end. However, nowadays, with the data API, it is possible to implement rendering on the editor side in JavaScript without using this Package.

Many developers may continue to use this package because it eliminates the need to write a lot of editor code 🤔

@aaronrobertshaw
Copy link
Contributor

Please let us know if you have any feedback on this matter.

Thanks for the ping 👍

I think @t-hamano sums everything up nicely.

The only point I would add relates to the stabilization of the __experimentalSkipSerialization API. It has actually come up on #45194. In addition to that, there are plans to stabilize all the block support-related APIs, which would include this one for skipping their serialization. You can see this as Phase 3 in the issue tracking design tool consistency.

For the moment, some other Gutenberg Phase 2 wrap-up tasks are taking priority, but the hope is to address those stabilizations soon.

@bph
Copy link
Contributor

bph commented Feb 7, 2023

My understanding is that this package used to be used to render dynamic blocks on the editor. And it had the advantage of being able to use the PHP rendering logic as it is done on the front end. However, nowadays, with the data API, it is possible to implement rendering on the editor side in JavaScript without using this Package.

Given that Gutenberg is six years old, the group of PHP developer using ServerSideRender, is not surprising. What would you relay to the extenders who are using the ServerSideRender as to what changed? They would really appreciate a heads-up.

This new property will keep the existing behavior unless explicitly opted in by the developer. Therefore, I think that the backward compatibility doesn't need to be considered.

That's good to know. So this shouldn't be more than a two paragraph information, as to the why, what, how?

@t-hamano
Copy link
Contributor Author

t-hamano commented Feb 8, 2023

I am wondering if we should put this PR in the dev note, I have two ideas:

  • Include in the dev note. However, as noted in the component documentation, I think it would be better to include an additional description that new blocks should be written in JavaScript instead. Of course, I would be happy to write the dev note 👍
  • Just add a code example about this attribute in the component's README.

@aaronrobertshaw If you don't mind, I'd like to know your opinion 🙏

@aaronrobertshaw
Copy link
Contributor

If you don't mind, I'd like to know your opinion 🙏

I don't think there is much harm in communicating the change.

For those already using ServerSideRender and wishing to adopt block supports without re-writing their blocks, knowing about the new prop would benefit them. We can still stress all new blocks should leverage the data API instead of ServerSideRender.

@t-hamano
Copy link
Contributor Author

t-hamano commented Feb 9, 2023

Thank you @aaronrobertshaw!

@bph

I have written a dev note here. Feel free to edit it.


Add new prop to ServerSideRender component

WordPress 6.2 introduces a new skipBlockSupportAttributes prop to exclude attributes and styles related to block supports in the ServerSideRender component. This will make it easier to properly add support to blocks with the ServerSideRender components.

Note: ServerSideRender component should be regarded as a fallback or legacy mechanism, it is not appropriate for developing new features against. New blocks should be built in conjunction with any necessary REST API endpoints, so that JavaScript can be used for rendering client-side in the edit function. This gives the best user experience, instead of relying on using the PHP render_callback. The logic necessary for rendering should be included in the endpoint, so that both the client-side JavaScript and server-side PHP logic should require a minimal amount of differences.

ServerSideRender is a component used for server-side rendering a preview of dynamic blocks to display in the editor. By passing the attributes prop to this component, it is processed on the server side and the block receives the rendered result.

import ServerSideRender from '@wordpress/server-side-render';
const MyServerSideRender = () => (
	<ServerSideRender
		block="core/archives"
		attributes={ attributes }
	/>
);

If you add block supports to the block that contains this component, the problem is that the styles from the block support will be applied to both the block wrapper element and the rendered HTML by ServerSiderender component. For example, if you opt for padding and margin as block support, and those styles are applied to the block, you will have double spaces.

<div
	...
	class="block-editor-block-list__block wp-block wp-block-archives"
	style="padding: 10px; margin: 10px;"
>
	<div inert="true" class="components-disabled">
  		<div>
  			<ul
				style="padding-top:10px;padding-right:10px;padding-bottom:10px;padding-left:10px;margin-top:10px;margin-right:10px;margin-bottom:10px;margin-left:10px;"
				class="wp-block-archives-list wp-block-archives"
			>
				<li><a href="http://example.com">Hello World</a></li>
			</ul>
		</div>
	</div>
</div>

By opting in to the new skipBlockSupportAttributes prop introduced in WordPress 6.2, all attributes related to block support will be removed before rendering on the server side, and you will be able to get proper rendering results.

import ServerSideRender from '@wordpress/server-side-render';
const MyServerSideRender = () => (
	<ServerSideRender
 		skipBlockSupportAttributes
		block="core/archives"
		attributes={ attributes }
	/>
);

However, if block styles are already defined in the global style or in theme.json, those styles will take precedence and individual block's overrides may not be applied. In such cases, explicitly handling the block support to be passed to the ServerSideRender component will produce the intended result.

import ServerSideRender from '@wordpress/server-side-render';

const serverSideAttributes = {
	...attributes,
	style: {
		...attributes?.style,
		// Ignore styles related to margin and padding.
		spacing: undefined,
	},
};

const MyServerSideRender = () => (
	<ServerSideRender
		// All block support attributes except margins and padding are passed.
 		attributes={ serverSideAttributes }
		block="core/archives"
		attributes={ attributes }
	/>
);

@t-hamano t-hamano added the has dev note when dev note is done (for upcoming WordPress release) label Feb 9, 2023
@t-hamano t-hamano mentioned this pull request Feb 9, 2023
47 tasks
@aaronrobertshaw
Copy link
Contributor

aaronrobertshaw commented Feb 9, 2023

@t-hamano One thing that might be worth highlighting for the dev note, is that the primary block supports that are negatively impacted by the duplication of classes and styles are the spacing supports (padding, margin).

Some blocks have Global Styles generated under their default class e.g. .wp-block-<name>. If the block support attributes corresponding to those global styles aren't passed through to the ServerSideRender component you may end up with a situation where the global styles or theme.json styles are shown in the editor not the individual block's overrides.

I encountered the above when rebasing the PR adopting typography supports for the Latest Comments block.

@t-hamano
Copy link
Contributor Author

Thank you for the advice, @aaronrobertshaw!

For example, if you opt for padding and margin as block support, and those styles are applied to the block, you will have double spaces.

I have added the above text and updated the code examples slightly.

Some blocks have Global Styles generated under their default class e.g. .wp-block-. If the block support attributes corresponding to those global styles aren't passed through to the ServerSideRender component you may end up with a situation where the global styles or theme.json styles are shown in the editor not the individual block's overrides.

My understanding is that such a case occurs when "__experimentalSelector" or __experimentalSkipSerialization is defined. I think it isn't necessary to communicate concerns about experimental APIs to third party developers, how do you think?

@aaronrobertshaw
Copy link
Contributor

My understanding is that such a case occurs when "__experimentalSelector" or __experimentalSkipSerialization is defined.

This isn't the case, unfortunately.

Using #43310 as an example. It doesn't define any custom selector and doesn't skip serialization.

If you set global styles for the Latest Comments block's typography, then switch to the editor and try to change these typography styles for a single Latest Comments block, they wouldn't be applied in the editor unless we still allow those individual block typography styles to be applied to the ServerSideRendered markup.

It's this fact that led me to need to remove the skipBlockSupportAttributes from the LatestComments block and instead filter the attributes passed to the ServerSideRender component.

Given that example doesn't relate to experimental APIs such as __experimentalSelector or __experimentalSkipSerialization, I think it is worth noting.

@t-hamano
Copy link
Contributor Author

Okay, I understand.
So you are saying that such a problem would occur if the styles related to the block support are already applied to elements within the block?

However, if block styles are already defined in the global style or in theme.json, those styles will take precedence and individual block's overrides may not be applied. In such cases, explicitly handling the block support to be passed to the ServerSideRender component will produce the intended result.

I have added the above instructions and a new code example. Feel free to update if there is anything that is not clear 🙏

@aaronrobertshaw
Copy link
Contributor

So you are saying that such a problem would occur if the styles related to the block support are already applied to elements within the block?

I'll try and clarify this further, still using the latest comments block example;

In the editor, the block's wrapper gets the wp-block-latest-comments class, but so does the markup returned by the ServerSideRender component. This means we end up with something like the following:

Screenshot 2023-02-10 at 2 18 40 pm

If you set, say font family, on the block in Global Styles, the global styles stylesheet gets the following:
.wp-block-latest-comments { font-family: 'my-custom-font'; }. That would be applied to both elements with that class in the above screenshot.

If you then apply a new font family on an individual block in the post editor, that gets applied to the block's outer wrapper. If you also pass skipBlockSupportAttributes to the ServerSideRender component, that individual block's style isn't applied on the inner wp-block-latest-comments element and the CSS from the global styles stylesheet would override the inheritance from the outer wrapper.

I hope that makes things a little clearer 🤞

@t-hamano
Copy link
Contributor Author

Thanks for the detailed explanation, @aaronrobertshaw! I think I have understood it well enough 🙏

@bph
Copy link
Contributor

bph commented Feb 27, 2023

@t-hamano Thanks for going through the process and finalizing the Dev Note. Would you please add this to the Make blog as draft so we can have it reviewed for publishing? Please let me know if you need author access to the site.

@bph bph removed the Needs Dev Note Requires a developer note for a major WordPress release cycle label Feb 27, 2023
@t-hamano
Copy link
Contributor Author

@bph

I have written a dev note draft: https://make.wordpress.org/core/?p=102933

@mcsf
Copy link
Contributor

mcsf commented Mar 7, 2023

Hi! 👋 I'm catching up on this PR after reading the dev note.

One thing that struck me is that this setup with removeBlockSupportAttributes may easily get out of sync: if a new feature is added to lib/block-supports, there is nothing to remind the developers to update removeBlockSupportAttributes.

Even as we speak, there are discrepancies between that function and the actual map of support attributes:

# List all attributes names corresponding to block-supports features:
$ grep -Eho "attributes\['\w+'\]" lib/block-supports/*.php | awk -F\' '{print $2}' | sort | uniq

anchor
backgroundColor
borderColor
class
fontFamily
fontSize
gradient
layout
shadow
style
textColor

If we treat className and style as special attributes, this still leaves two keys out of removeBlockSupportAttributes: anchor and layout. How can we properly keep track of what attributes should be removed? How do we prevent future problems?

@t-hamano
Copy link
Contributor Author

t-hamano commented Mar 7, 2023

@mcsf
Thanks for letting me know.

We discussed in this PR whether we should finally introduce the skipBlockSupportAttributes prop.

As you say, when new block support is added, its attributes and styles should be added in the ServerSideRender component as well. Conversely, if this prop were not in place, then each time we add new support to a block rendered by the SeverSideRender component, we would need to properly exclude attributes and styles in each block.

Maintenance would occur either way, but after consideration, I made a decision that introducing this prop would be less costly to maintain.

As far as I can see, the new properties that should be added as exclusions are the anchor and shadow attributes. If these properties need to be excluded (and if it is possible to backport to WordPress 6.2 now), I would be happy to accommodate.

In any case, we may want to explore whether there is a way to detect when new block support is added in the future and update this package automatically or manually.

cc: @aaronrobertshaw, @andrewserong

@t-hamano
Copy link
Contributor Author

t-hamano commented Mar 7, 2023

As far as I know, the shadow property is not supported at the block level and can only be controlled by the global style. Therefore, no block-specific attributes are generated from this property.

I added the shadow property to an archive block with a ServerSideRender component as a test. Yes, styles are applied in duplicate, but this is due to inline styles generated from global styles, which are not controllable by the ServerSideRender component.

To prevent this, it is generally necessary to control this with the __experimentalSkipSerialization or __experimentalSelector property. However, since the shadow property only allows boolean types, it appears that these cannot be addressed. Therefore, as far as the shadow property is concerned, this is not a problem that can be handled by the ServerSideRender component, and I believe that it needs to be addressed in some way by the block support itself.

shadow

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
has dev note when dev note is done (for upcoming WordPress release) [Package] Server Side Render /packages/server-side-render [Type] Enhancement A suggestion for improvement.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants