Skip to content

Conversation

@ockham
Copy link
Contributor

@ockham ockham commented Sep 3, 2025

What?

Alternative to #70642 and #71462.
Companion to WordPress/wordpress-develop#9702.

When saving the Image Block, include the <figcaption> element:

  • if the caption attribute is set, or
  • if it is bound to a Block Bindings source, or
  • if the whole block has pattern overrides.

Note that this PR should only be merged once WordPress/wordpress-develop#9702 has been merged to Core, and backported to GB, since this PR will otherwise lead to empty <figcaption>s being rendered on the frontend.

Why?

To allow Block Bindings to bind the caption attribute to a Block Bindings source. If the <figcaption> element remains empty -- even after binding -- it will be removed at render time (although probably not by the code in this PR, but by WordPress/wordpress-develop#9702).

How?

See "What?". Additionally, the caption control is now enabled in the block toolbar if the block is part of a pattern.

Code is largely stolen from inspired by #70642.

Testing Instructions

The following instructions describe using "normal" Block Bindings for testing this PR. Alternatively, you can use Pattern Overrides to test it; @cbravobernal will know how to do that 😬

  • Insert an Image block (and have it display an image that you uploaded or selected from the Media Library).
  • In the Code Editor, insert markup to bind its caption attribute to a Block Bindings source.
  • Switch back to the Visual Editor, and enable its caption.
  • Save (and/or publish) the post.
  • Reload, and switch to the code editor to verify that the Image block contains an empty <figcaption> element.
  • View the post on the frontend, and verify that the image caption shows the correct value obtained from the Block Bindings source.

@ockham ockham self-assigned this Sep 3, 2025
@ockham ockham added [Type] Enhancement A suggestion for improvement. [Block] Image Affects the Image Block [Feature] Block bindings labels Sep 3, 2025
@github-actions
Copy link

github-actions bot commented Sep 3, 2025

Size Change: +75 B (0%)

Total Size: 1.94 MB

Filename Size Change
build/block-editor/index.min.js 267 kB +8 B (0%)
build/block-library/index.min.js 237 kB +67 B (+0.03%)
ℹ️ View Unchanged
Filename Size
build-module/a11y/index.min.js 482 B
build-module/block-library/accordion/view.min.js 427 B
build-module/block-library/file/view.min.js 466 B
build-module/block-library/form/view.min.js 533 B
build-module/block-library/image/view.min.js 1.78 kB
build-module/block-library/navigation/view.min.js 1.19 kB
build-module/block-library/query/view.min.js 767 B
build-module/block-library/search/view.min.js 639 B
build-module/interactivity-router/full-page.min.js 565 B
build-module/interactivity-router/index.min.js 11.4 kB
build-module/interactivity/debug.min.js 17.6 kB
build-module/interactivity/index.min.js 14 kB
build/a11y/index.min.js 925 B
build/annotations/index.min.js 2.13 kB
build/api-fetch/index.min.js 2.41 kB
build/autop/index.min.js 2.12 kB
build/blob/index.min.js 579 B
build/block-directory/index.min.js 7.18 kB
build/block-directory/style-rtl.css 1.03 kB
build/block-directory/style.css 1.03 kB
build/block-editor/content-rtl.css 4.43 kB
build/block-editor/content.css 4.42 kB
build/block-editor/default-editor-styles-rtl.css 392 B
build/block-editor/default-editor-styles.css 392 B
build/block-editor/style-rtl.css 15.9 kB
build/block-editor/style.css 15.9 kB
build/block-library/blocks/accordion/style-rtl.css 573 B
build/block-library/blocks/accordion/style.css 573 B
build/block-library/blocks/archives/editor-rtl.css 61 B
build/block-library/blocks/archives/editor.css 61 B
build/block-library/blocks/archives/style-rtl.css 90 B
build/block-library/blocks/archives/style.css 90 B
build/block-library/blocks/audio/editor-rtl.css 149 B
build/block-library/blocks/audio/editor.css 151 B
build/block-library/blocks/audio/style-rtl.css 132 B
build/block-library/blocks/audio/style.css 132 B
build/block-library/blocks/audio/theme-rtl.css 134 B
build/block-library/blocks/audio/theme.css 134 B
build/block-library/blocks/avatar/editor-rtl.css 115 B
build/block-library/blocks/avatar/editor.css 115 B
build/block-library/blocks/avatar/style-rtl.css 104 B
build/block-library/blocks/avatar/style.css 104 B
build/block-library/blocks/button/editor-rtl.css 265 B
build/block-library/blocks/button/editor.css 265 B
build/block-library/blocks/button/style-rtl.css 554 B
build/block-library/blocks/button/style.css 554 B
build/block-library/blocks/buttons/editor-rtl.css 291 B
build/block-library/blocks/buttons/editor.css 291 B
build/block-library/blocks/buttons/style-rtl.css 349 B
build/block-library/blocks/buttons/style.css 349 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 132 B
build/block-library/blocks/categories/editor.css 131 B
build/block-library/blocks/categories/style-rtl.css 152 B
build/block-library/blocks/categories/style.css 152 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 139 B
build/block-library/blocks/code/style.css 139 B
build/block-library/blocks/code/theme-rtl.css 122 B
build/block-library/blocks/code/theme.css 122 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 420 B
build/block-library/blocks/columns/style.css 420 B
build/block-library/blocks/comment-author-avatar/editor-rtl.css 124 B
build/block-library/blocks/comment-author-avatar/editor.css 124 B
build/block-library/blocks/comment-author-name/style-rtl.css 72 B
build/block-library/blocks/comment-author-name/style.css 72 B
build/block-library/blocks/comment-content/style-rtl.css 120 B
build/block-library/blocks/comment-content/style.css 120 B
build/block-library/blocks/comment-date/style-rtl.css 65 B
build/block-library/blocks/comment-date/style.css 65 B
build/block-library/blocks/comment-edit-link/style-rtl.css 70 B
build/block-library/blocks/comment-edit-link/style.css 70 B
build/block-library/blocks/comment-reply-link/style-rtl.css 71 B
build/block-library/blocks/comment-reply-link/style.css 71 B
build/block-library/blocks/comment-template/style-rtl.css 191 B
build/block-library/blocks/comment-template/style.css 191 B
build/block-library/blocks/comments-pagination-numbers/editor-rtl.css 122 B
build/block-library/blocks/comments-pagination-numbers/editor.css 121 B
build/block-library/blocks/comments-pagination/editor-rtl.css 168 B
build/block-library/blocks/comments-pagination/editor.css 168 B
build/block-library/blocks/comments-pagination/style-rtl.css 201 B
build/block-library/blocks/comments-pagination/style.css 201 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 842 B
build/block-library/blocks/comments/editor.css 842 B
build/block-library/blocks/comments/style-rtl.css 637 B
build/block-library/blocks/comments/style.css 637 B
build/block-library/blocks/cover/editor-rtl.css 631 B
build/block-library/blocks/cover/editor.css 631 B
build/block-library/blocks/cover/style-rtl.css 1.7 kB
build/block-library/blocks/cover/style.css 1.69 kB
build/block-library/blocks/details/editor-rtl.css 65 B
build/block-library/blocks/details/editor.css 65 B
build/block-library/blocks/details/style-rtl.css 86 B
build/block-library/blocks/details/style.css 86 B
build/block-library/blocks/embed/editor-rtl.css 331 B
build/block-library/blocks/embed/editor.css 331 B
build/block-library/blocks/embed/style-rtl.css 419 B
build/block-library/blocks/embed/style.css 419 B
build/block-library/blocks/embed/theme-rtl.css 133 B
build/block-library/blocks/embed/theme.css 133 B
build/block-library/blocks/file/editor-rtl.css 326 B
build/block-library/blocks/file/editor.css 326 B
build/block-library/blocks/file/style-rtl.css 278 B
build/block-library/blocks/file/style.css 278 B
build/block-library/blocks/footnotes/style-rtl.css 198 B
build/block-library/blocks/footnotes/style.css 197 B
build/block-library/blocks/form-input/editor-rtl.css 229 B
build/block-library/blocks/form-input/editor.css 229 B
build/block-library/blocks/form-input/style-rtl.css 366 B
build/block-library/blocks/form-input/style.css 366 B
build/block-library/blocks/form-submission-notification/editor-rtl.css 344 B
build/block-library/blocks/form-submission-notification/editor.css 341 B
build/block-library/blocks/form-submit-button/style-rtl.css 69 B
build/block-library/blocks/form-submit-button/style.css 69 B
build/block-library/blocks/freeform/editor-rtl.css 2.59 kB
build/block-library/blocks/freeform/editor.css 2.59 kB
build/block-library/blocks/gallery/editor-rtl.css 615 B
build/block-library/blocks/gallery/editor.css 616 B
build/block-library/blocks/gallery/style-rtl.css 1.83 kB
build/block-library/blocks/gallery/style.css 1.83 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 334 B
build/block-library/blocks/group/editor.css 334 B
build/block-library/blocks/group/style-rtl.css 103 B
build/block-library/blocks/group/style.css 103 B
build/block-library/blocks/group/theme-rtl.css 79 B
build/block-library/blocks/group/theme.css 79 B
build/block-library/blocks/heading/style-rtl.css 188 B
build/block-library/blocks/heading/style.css 188 B
build/block-library/blocks/html/editor-rtl.css 353 B
build/block-library/blocks/html/editor.css 354 B
build/block-library/blocks/image/editor-rtl.css 763 B
build/block-library/blocks/image/editor.css 763 B
build/block-library/blocks/image/style-rtl.css 1.6 kB
build/block-library/blocks/image/style.css 1.59 kB
build/block-library/blocks/image/theme-rtl.css 137 B
build/block-library/blocks/image/theme.css 137 B
build/block-library/blocks/latest-comments/style-rtl.css 355 B
build/block-library/blocks/latest-comments/style.css 354 B
build/block-library/blocks/latest-posts/editor-rtl.css 139 B
build/block-library/blocks/latest-posts/editor.css 138 B
build/block-library/blocks/latest-posts/style-rtl.css 520 B
build/block-library/blocks/latest-posts/style.css 520 B
build/block-library/blocks/list/style-rtl.css 107 B
build/block-library/blocks/list/style.css 107 B
build/block-library/blocks/loginout/style-rtl.css 61 B
build/block-library/blocks/loginout/style.css 61 B
build/block-library/blocks/media-text/editor-rtl.css 321 B
build/block-library/blocks/media-text/editor.css 320 B
build/block-library/blocks/media-text/style-rtl.css 543 B
build/block-library/blocks/media-text/style.css 542 B
build/block-library/blocks/more/editor-rtl.css 393 B
build/block-library/blocks/more/editor.css 393 B
build/block-library/blocks/navigation-link/editor-rtl.css 625 B
build/block-library/blocks/navigation-link/editor.css 628 B
build/block-library/blocks/navigation-link/style-rtl.css 190 B
build/block-library/blocks/navigation-link/style.css 188 B
build/block-library/blocks/navigation-submenu/editor-rtl.css 295 B
build/block-library/blocks/navigation-submenu/editor.css 294 B
build/block-library/blocks/navigation/editor-rtl.css 2.23 kB
build/block-library/blocks/navigation/editor.css 2.24 kB
build/block-library/blocks/navigation/style-rtl.css 2.27 kB
build/block-library/blocks/navigation/style.css 2.26 kB
build/block-library/blocks/nextpage/editor-rtl.css 392 B
build/block-library/blocks/nextpage/editor.css 392 B
build/block-library/blocks/page-list/editor-rtl.css 356 B
build/block-library/blocks/page-list/editor.css 356 B
build/block-library/blocks/page-list/style-rtl.css 192 B
build/block-library/blocks/page-list/style.css 192 B
build/block-library/blocks/paragraph/editor-rtl.css 251 B
build/block-library/blocks/paragraph/editor.css 251 B
build/block-library/blocks/paragraph/style-rtl.css 341 B
build/block-library/blocks/paragraph/style.css 340 B
build/block-library/blocks/post-author-biography/style-rtl.css 74 B
build/block-library/blocks/post-author-biography/style.css 74 B
build/block-library/blocks/post-author-name/style-rtl.css 69 B
build/block-library/blocks/post-author-name/style.css 69 B
build/block-library/blocks/post-author/style-rtl.css 188 B
build/block-library/blocks/post-author/style.css 189 B
build/block-library/blocks/post-comments-count/style-rtl.css 72 B
build/block-library/blocks/post-comments-count/style.css 72 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 525 B
build/block-library/blocks/post-comments-form/style.css 525 B
build/block-library/blocks/post-comments-link/style-rtl.css 71 B
build/block-library/blocks/post-comments-link/style.css 71 B
build/block-library/blocks/post-content/style-rtl.css 61 B
build/block-library/blocks/post-content/style.css 61 B
build/block-library/blocks/post-date/style-rtl.css 62 B
build/block-library/blocks/post-date/style.css 62 B
build/block-library/blocks/post-excerpt/editor-rtl.css 71 B
build/block-library/blocks/post-excerpt/editor.css 71 B
build/block-library/blocks/post-excerpt/style-rtl.css 155 B
build/block-library/blocks/post-excerpt/style.css 155 B
build/block-library/blocks/post-featured-image/editor-rtl.css 715 B
build/block-library/blocks/post-featured-image/editor.css 712 B
build/block-library/blocks/post-featured-image/style-rtl.css 347 B
build/block-library/blocks/post-featured-image/style.css 347 B
build/block-library/blocks/post-navigation-link/style-rtl.css 215 B
build/block-library/blocks/post-navigation-link/style.css 214 B
build/block-library/blocks/post-template/style-rtl.css 414 B
build/block-library/blocks/post-template/style.css 414 B
build/block-library/blocks/post-terms/style-rtl.css 96 B
build/block-library/blocks/post-terms/style.css 96 B
build/block-library/blocks/post-time-to-read/style-rtl.css 70 B
build/block-library/blocks/post-time-to-read/style.css 70 B
build/block-library/blocks/post-title/style-rtl.css 162 B
build/block-library/blocks/post-title/style.css 162 B
build/block-library/blocks/preformatted/style-rtl.css 125 B
build/block-library/blocks/preformatted/style.css 125 B
build/block-library/blocks/pullquote/editor-rtl.css 133 B
build/block-library/blocks/pullquote/editor.css 133 B
build/block-library/blocks/pullquote/style-rtl.css 365 B
build/block-library/blocks/pullquote/style.css 365 B
build/block-library/blocks/pullquote/theme-rtl.css 176 B
build/block-library/blocks/pullquote/theme.css 176 B
build/block-library/blocks/query-pagination-numbers/editor-rtl.css 121 B
build/block-library/blocks/query-pagination-numbers/editor.css 118 B
build/block-library/blocks/query-pagination/editor-rtl.css 154 B
build/block-library/blocks/query-pagination/editor.css 154 B
build/block-library/blocks/query-pagination/style-rtl.css 237 B
build/block-library/blocks/query-pagination/style.css 237 B
build/block-library/blocks/query-title/style-rtl.css 64 B
build/block-library/blocks/query-title/style.css 64 B
build/block-library/blocks/query-total/style-rtl.css 64 B
build/block-library/blocks/query-total/style.css 64 B
build/block-library/blocks/query/editor-rtl.css 432 B
build/block-library/blocks/query/editor.css 432 B
build/block-library/blocks/quote/style-rtl.css 238 B
build/block-library/blocks/quote/style.css 238 B
build/block-library/blocks/quote/theme-rtl.css 233 B
build/block-library/blocks/quote/theme.css 236 B
build/block-library/blocks/read-more/style-rtl.css 131 B
build/block-library/blocks/read-more/style.css 131 B
build/block-library/blocks/rss/editor-rtl.css 126 B
build/block-library/blocks/rss/editor.css 126 B
build/block-library/blocks/rss/style-rtl.css 284 B
build/block-library/blocks/rss/style.css 283 B
build/block-library/blocks/search/editor-rtl.css 199 B
build/block-library/blocks/search/editor.css 199 B
build/block-library/blocks/search/style-rtl.css 665 B
build/block-library/blocks/search/style.css 666 B
build/block-library/blocks/search/theme-rtl.css 113 B
build/block-library/blocks/search/theme.css 113 B
build/block-library/blocks/separator/editor-rtl.css 100 B
build/block-library/blocks/separator/editor.css 100 B
build/block-library/blocks/separator/style-rtl.css 248 B
build/block-library/blocks/separator/style.css 248 B
build/block-library/blocks/separator/theme-rtl.css 195 B
build/block-library/blocks/separator/theme.css 195 B
build/block-library/blocks/shortcode/editor-rtl.css 286 B
build/block-library/blocks/shortcode/editor.css 286 B
build/block-library/blocks/site-logo/editor-rtl.css 773 B
build/block-library/blocks/site-logo/editor.css 770 B
build/block-library/blocks/site-logo/style-rtl.css 218 B
build/block-library/blocks/site-logo/style.css 218 B
build/block-library/blocks/site-tagline/editor-rtl.css 87 B
build/block-library/blocks/site-tagline/editor.css 87 B
build/block-library/blocks/site-tagline/style-rtl.css 65 B
build/block-library/blocks/site-tagline/style.css 65 B
build/block-library/blocks/site-title/editor-rtl.css 85 B
build/block-library/blocks/site-title/editor.css 85 B
build/block-library/blocks/site-title/style-rtl.css 143 B
build/block-library/blocks/site-title/style.css 143 B
build/block-library/blocks/social-link/editor-rtl.css 314 B
build/block-library/blocks/social-link/editor.css 314 B
build/block-library/blocks/social-links/editor-rtl.css 339 B
build/block-library/blocks/social-links/editor.css 338 B
build/block-library/blocks/social-links/style-rtl.css 1.51 kB
build/block-library/blocks/social-links/style.css 1.51 kB
build/block-library/blocks/spacer/editor-rtl.css 346 B
build/block-library/blocks/spacer/editor.css 346 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-of-contents/style-rtl.css 83 B
build/block-library/blocks/table-of-contents/style.css 83 B
build/block-library/blocks/table/editor-rtl.css 394 B
build/block-library/blocks/table/editor.css 394 B
build/block-library/blocks/table/style-rtl.css 640 B
build/block-library/blocks/table/style.css 639 B
build/block-library/blocks/table/theme-rtl.css 152 B
build/block-library/blocks/table/theme.css 152 B
build/block-library/blocks/tag-cloud/editor-rtl.css 92 B
build/block-library/blocks/tag-cloud/editor.css 92 B
build/block-library/blocks/tag-cloud/style-rtl.css 248 B
build/block-library/blocks/tag-cloud/style.css 248 B
build/block-library/blocks/template-part/editor-rtl.css 368 B
build/block-library/blocks/template-part/editor.css 368 B
build/block-library/blocks/template-part/theme-rtl.css 113 B
build/block-library/blocks/template-part/theme.css 113 B
build/block-library/blocks/term-description/style-rtl.css 126 B
build/block-library/blocks/term-description/style.css 126 B
build/block-library/blocks/term-template/editor-rtl.css 225 B
build/block-library/blocks/term-template/editor.css 225 B
build/block-library/blocks/term-template/style-rtl.css 135 B
build/block-library/blocks/term-template/style.css 135 B
build/block-library/blocks/terms-query/style-rtl.css 70 B
build/block-library/blocks/terms-query/style.css 70 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 165 B
build/block-library/blocks/text-columns/style.css 165 B
build/block-library/blocks/verse/style-rtl.css 98 B
build/block-library/blocks/verse/style.css 98 B
build/block-library/blocks/video/editor-rtl.css 413 B
build/block-library/blocks/video/editor.css 414 B
build/block-library/blocks/video/style-rtl.css 202 B
build/block-library/blocks/video/style.css 202 B
build/block-library/blocks/video/theme-rtl.css 134 B
build/block-library/blocks/video/theme.css 134 B
build/block-library/classic-rtl.css 179 B
build/block-library/classic.css 179 B
build/block-library/common-rtl.css 1.08 kB
build/block-library/common.css 1.08 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.5 kB
build/block-library/editor.css 11.5 kB
build/block-library/elements-rtl.css 54 B
build/block-library/elements.css 54 B
build/block-library/reset-rtl.css 472 B
build/block-library/reset.css 472 B
build/block-library/style-rtl.css 15.4 kB
build/block-library/style.css 15.4 kB
build/block-library/theme-rtl.css 715 B
build/block-library/theme.css 719 B
build/block-serialization-default-parser/index.min.js 1.12 kB
build/block-serialization-spec-parser/index.min.js 2.87 kB
build/blocks/index.min.js 52.7 kB
build/commands/index.min.js 16.3 kB
build/commands/style-rtl.css 956 B
build/commands/style.css 953 B
build/components/index.min.js 252 kB
build/components/style-rtl.css 13.7 kB
build/components/style.css 13.7 kB
build/compose/index.min.js 12.8 kB
build/core-commands/index.min.js 3.56 kB
build/core-data/index.min.js 75.1 kB
build/customize-widgets/index.min.js 11 kB
build/customize-widgets/style-rtl.css 1.43 kB
build/customize-widgets/style.css 1.43 kB
build/data-controls/index.min.js 641 B
build/data/index.min.js 8.7 kB
build/date/index.min.js 18 kB
build/deprecated/index.min.js 458 B
build/dom-ready/index.min.js 325 B
build/dom/index.min.js 4.68 kB
build/edit-post/classic-rtl.css 577 B
build/edit-post/classic.css 578 B
build/edit-post/index.min.js 13.4 kB
build/edit-post/style-rtl.css 2.69 kB
build/edit-post/style.css 2.69 kB
build/edit-site/index.min.js 240 kB
build/edit-site/posts-rtl.css 9.35 kB
build/edit-site/posts.css 9.35 kB
build/edit-site/style-rtl.css 15.4 kB
build/edit-site/style.css 15.4 kB
build/edit-widgets/index.min.js 17.8 kB
build/edit-widgets/style-rtl.css 4.05 kB
build/edit-widgets/style.css 4.06 kB
build/editor/index.min.js 134 kB
build/editor/style-rtl.css 9.41 kB
build/editor/style.css 9.42 kB
build/element/index.min.js 4.86 kB
build/escape-html/index.min.js 537 B
build/format-library/index.min.js 8.23 kB
build/format-library/style-rtl.css 472 B
build/format-library/style.css 472 B
build/hooks/index.min.js 1.65 kB
build/html-entities/index.min.js 467 B
build/i18n/index.min.js 2.23 kB
build/is-shallow-equal/index.min.js 526 B
build/keyboard-shortcuts/index.min.js 1.32 kB
build/keycodes/index.min.js 1.46 kB
build/list-reusable-blocks/index.min.js 2.13 kB
build/list-reusable-blocks/style-rtl.css 847 B
build/list-reusable-blocks/style.css 848 B
build/media-utils/index.min.js 3.69 kB
build/notices/index.min.js 946 B
build/nux/index.min.js 1.62 kB
build/nux/style-rtl.css 767 B
build/nux/style.css 763 B
build/patterns/index.min.js 7.55 kB
build/patterns/style-rtl.css 687 B
build/patterns/style.css 685 B
build/plugins/index.min.js 1.87 kB
build/preferences-persistence/index.min.js 2.06 kB
build/preferences/index.min.js 2.9 kB
build/preferences/style-rtl.css 562 B
build/preferences/style.css 562 B
build/primitives/index.min.js 829 B
build/priority-queue/index.min.js 1.54 kB
build/private-apis/index.min.js 978 B
build/react-i18n/index.min.js 640 B
build/react-refresh-entry/index.min.js 9.47 kB
build/react-refresh-runtime/index.min.js 6.76 kB
build/redux-routine/index.min.js 2.7 kB
build/reusable-blocks/index.min.js 2.53 kB
build/reusable-blocks/style-rtl.css 255 B
build/reusable-blocks/style.css 255 B
build/rich-text/index.min.js 12.2 kB
build/router/index.min.js 5.47 kB
build/server-side-render/index.min.js 1.6 kB
build/shortcode/index.min.js 1.4 kB
build/style-engine/index.min.js 2.04 kB
build/token-list/index.min.js 581 B
build/url/index.min.js 3.97 kB
build/vendors/react-dom.min.js 41.7 kB
build/vendors/react-jsx-runtime.min.js 556 B
build/vendors/react.min.js 4.02 kB
build/viewport/index.min.js 965 B
build/vips/index.min.js 36.2 kB
build/warning/index.min.js 250 B
build/widgets/index.min.js 7.16 kB
build/widgets/style-rtl.css 1.16 kB
build/widgets/style.css 1.16 kB
build/wordcount/index.min.js 1.04 kB

compressed-size-action

@gziolo
Copy link
Member

gziolo commented Sep 3, 2025

Do you have any reasons why complex alternatives should be even considered in contrast to this proposal?

@ockham
Copy link
Contributor Author

ockham commented Sep 3, 2025

Do you have any reasons why complex alternatives should be even considered in contrast to this proposal?

Right now I find the "simple" solution (this PR) quite compelling, as it doesn't require new directives, block deprecations, etc.

It does however depend on this assumption:

What I meant is a version with no directives at all -- where WP just determines based on the block attribute description that if this is a rich-text sourced attribute that can be connected to Block Bindings, and it's empty, then we also remove the HTML element denoted by the selector.

The latter is implemented by WordPress/wordpress-develop#9702. (I have yet to backport this to GB; I've started work on backporting the underlying Core changeset here).


As for potential advantages of the more complex solutions: It could be argued that solutions like the data-wp-maybe-remove directive decouple some of the required Block Bindings processing from the block, as they are agnostic of Block Bindings and simply instruct WP to remove an HTML element depending on the directive's value. However, it's kind of verbose (especially since it needs to be added to all Image blocks, and thus requires updates to existing markup), and I'm not 100% convinced how well it would scale (e.g. to constructs like loops). Finally, I ended up with the current approach since all the information that data-wp-maybe-remove expresses is readily available from the caption attribute (i.e. its value, block binding, or pattern override), so the directive seemed redundant.


We have full control over which block attributes are supported by Block Bindings, so we could try to go ahead with this PR and see which of the attributes that conditionally add HTML elements we can cover with it (e.g. Pullquote's citation should work), and if we run into any cases where this approach doesn't cut it. Since we're not introducing any deprecations, it should be easy enough to change course.

@gziolo
Copy link
Member

gziolo commented Sep 3, 2025

Thank you for sharing the additional context. It feels like focusing on this PR and addressing all the points from #71483 (comment) is the most straightforward way to go without going into complex backward compatibility challenges.

@ockham ockham added the [Status] Blocked Used to indicate that a current effort isn't able to move forward label Sep 5, 2025
@ockham ockham marked this pull request as ready for review September 5, 2025 10:09
@github-actions
Copy link

github-actions bot commented Sep 5, 2025

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

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

Co-authored-by: ockham <[email protected]>
Co-authored-by: gziolo <[email protected]>

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

@gziolo
Copy link
Member

gziolo commented Sep 10, 2025

Once #71389 lands, we can use the block_bindings_supported_attributes_{$block_type} filter to set the caption attribute as supported by Block Bindings as part of this PR.

Yes, let's include it. One remark, I would put the filter inside the Gutenberg compat layer, rather than next to the code that gets synced to WordPress core.

@gziolo
Copy link
Member

gziolo commented Sep 12, 2025

After rebasing with trunk and including the filter with a callback presented in the description, everything works as advertised:

Screenshot 2025-09-12 at 14 28 06 Screenshot 2025-09-12 at 14 28 20

I was able to use the default UI in the Attributes panel to connect caption with the source.

@gziolo
Copy link
Member

gziolo commented Sep 12, 2025

I found one edge case, when working with Pattern Overrides:

Screenshot 2025-09-12 at 14 34 35 Screenshot 2025-09-12 at 14 36 10 Screenshot 2025-09-12 at 14 34 46

On the frontend, the Image block gets completely removed.

The code of the pattern that I created:

<!-- wp:heading {"metadata":{"name":"Headline","bindings":{"__default":{"source":"core/pattern-overrides"}}}} -->
<h2 class="wp-block-heading">Just do it!</h2>
<!-- /wp:heading -->

<!-- wp:image {"metadata":{"name":"Featured image","bindings":{"__default":{"source":"core/pattern-overrides"}}}} -->
<figure class="wp-block-image"><img alt=""/><figcaption class="wp-element-caption"></figcaption></figure>
<!-- /wp:image -->

It might be something related to the fact, that I didn't set the fallback image. If I do it, it works as expected.

Well, if I set a fallback image, and pick a different one in the pattern, then it doesn't get replaced. In effect, it means that url replacement doesn't work properly.

@ockham ockham force-pushed the try/image-block-always-save-figcaption-if-bound branch 2 times, most recently from 3d24e43 to 077c0f4 Compare September 15, 2025 11:14
@github-actions
Copy link

github-actions bot commented Sep 15, 2025

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

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

@ockham
Copy link
Contributor Author

ockham commented Sep 15, 2025

Once #71389 lands, we can use the block_bindings_supported_attributes_{$block_type} filter to set the caption attribute as supported by Block Bindings as part of this PR.

Yes, let's include it. One remark, I would put the filter inside the Gutenberg compat layer, rather than next to the code that gets synced to WordPress core.

Good point. Done in 4d94de2.

I'll file a PR to do the same to move this filter out of the Date block's code.

@gziolo
Copy link
Member

gziolo commented Sep 15, 2025

Is it ready for the final round of testing? Any leads on what wasn't working for me that I noted in #71483 (comment)?

@ockham ockham force-pushed the try/image-block-always-save-figcaption-if-bound branch from b4a27f5 to 53d072e Compare September 16, 2025 10:03
@ockham
Copy link
Contributor Author

ockham commented Sep 16, 2025

Thank you!

I'd like to merge #71691 before this, since otherwise, this PR has the potential to actually break Pattern Overrides in the edge case that you found. I'll keep it set to "Blocked" for now.

@ockham ockham force-pushed the try/image-block-always-save-figcaption-if-bound branch from 3dbc15d to 3b103b2 Compare September 16, 2025 19:22
@ockham ockham removed the [Status] Blocked Used to indicate that a current effort isn't able to move forward label Sep 16, 2025
@ockham ockham merged commit 485c4a3 into trunk Sep 17, 2025
71 checks passed
@ockham ockham deleted the try/image-block-always-save-figcaption-if-bound branch September 17, 2025 07:48
@github-actions github-actions bot added this to the Gutenberg 21.7 milestone Sep 17, 2025
@dmsnell
Copy link
Member

dmsnell commented Sep 18, 2025

@ockham is there a reason we need to limit this to the image block, or would this work generally for all blocks as part of passing data into save()? For instance, what if we provided a value for the block bindings to the attributes on save() such that each block rendered assuming that content were there?

We could save some zero-width space, or an internal Unicode code point, or a zero, or whatever is appropriate for the type of the attribute, and clear it out after save(). Perhaps that would at least cover existing issues with conditionally-generated HTML structure?

@ockham
Copy link
Contributor Author

ockham commented Sep 18, 2025

@ockham is there a reason we need to limit this to the image block, or would this work generally for all blocks as part of passing data into save()?

I think it's going to be our strategy for all blocks that have attributes that we want to support Block Bindings, and whose presence determines whether or not certain elements are included in the markup. (Another example would be the Pullquote block's citation attribute which, if present, leads to a <cite> tag being included.)

AFAICS, this will always require some logic in the individual block's save() method, as only the block can know which elements depend on which attributes.

For instance, what if we provided a value for the block bindings to the attributes on save() such that each block rendered assuming that content were there?

We could save some zero-width space, or an internal Unicode code point, or a zero, or whatever is appropriate for the type of the attribute, and clear it out after save(). Perhaps that would at least cover existing issues with conditionally-generated HTML structure?

Based on the points you raised on this ticket, and on some further discussion with @gziolo and @cbravobernal, our current thinking is to conditionally remove empty elements in the block's render method, rather than trying a more "magic" approach that would attempt to work for all such blocks.

IIUC, the placeholder characters you're suggesting would unlock a more generic way of removing "unneeded"/empty HTML elements. They do seem to come with some drawbacks; for example, as you hinted at, we might need to make them compatible with different attribute types. Do you think they're overall preferential over "making it the individual block's problem"?

@dmsnell
Copy link
Member

dmsnell commented Sep 18, 2025

IIUC, the placeholder characters you're suggesting would unlock a more generic way of removing "unneeded"/empty HTML elements. They do seem to come with some drawbacks; for example, as you hinted at, we might need to make them compatible with different attribute types. Do you think they're overall preferential over "making it the individual block's problem"?

I still believe that it will be simpler and more reliable and easier for developers to simply duplicate their block rendering code in PHP than constructing all of these systems.

However, I hadn’t considered previously that we might have ways to automate this a bit in a more reliable way. Actually this is more akin to the approach Bits would provide were they were. The Bit itself is content inside an attribute so the situation kind of takes care of itself.

Basically, I think it’s reasonable to assume that the presence of a binding suggests non-empty data. This is definitely not always the case, but usually will be. A post’s author or item’s price will likely be there, otherwise we wouldn’t add them as a binding. Conditional logic has to be handled in any system using it.

On the other hand, the placeholder is a blurry way of saying, “just store a Bit”. By passing bindings into attribute on the way into the save() function maybe we can ignore the problems just enough that in most cases the system handles itself properly. We won’t have to solve the common problem of finding an element which isn’t there (the FIGCAPTION or CITE elements, for example), meanwhile the simpler problem of removing an empty element is still there.

@cbravobernal
Copy link
Contributor

I still believe that it will be simpler and more reliable and easier for developers to simply duplicate their block rendering code in PHP than constructing all of these systems.

Correct me if I'm wrong. Do you propose we start working on bits, and use them too as placeholders for bindings?

That way, the bit is added on the save.js function, and later processed in PHP?

How do you imagine adding a figcaption? Can you provide an example?

@dmsnell
Copy link
Member

dmsnell commented Sep 22, 2025

Correct me if I'm wrong. Do you propose we start working on bits, and use them too as placeholders for bindings?

Well I do think that Bits is still good to work on, but a different problem than this one, as Bits still don’t answer the question of what to do when markup is conditional, or computed based on the value of the Bit.

That way, the bit is added on the save.js function, and later processed in PHP?

If we do store the Bit as the placeholder then we don’t have to do anything on the Gutenberg side — the Image block will save a <ficaption> because there’s content inside of the caption attribute. It’s a Bit placeholder, meaning it’s not an empty string.

How do you imagine adding a figcaption? Can you provide an example?

The main thrust of what I was getting at with the quote you provided is that I think building a generalized system to handle conditional rendering is going to be a deadend and we’ll hit it fast. My proposal is that if someone wants to add or remove FIGURE and FIGCAPTION markup, it will be easier for them and easier for us and easier for everyone if we avoid creating a new third system for trying to harmonize between JS and PHP. The cognitive overhead of learning a new custom system, the lack of documentation, the lack of debugging tools, and the introduction of new complications and bugs will far outweigh the costs of duplicating the JS logic from save() into a PHP function that replaces the markup dynamically on render.

Whether by block Bindings or by Bits, these realized values can be passed into the render callback and the block rendering code need not be aware of the fact that an attribute’s value is pulled from a binding vs. having been written statically. All it knows is that there is HTML already there and there are concrete attribute values.

@@ -0,0 +1,3 @@
https://github.com/WordPress/wordpress-develop/pull/9702
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I've closed WordPress/wordpress-develop#9702 in favor of WordPress/wordpress-develop#9949.

I've filed a GB PR to update this backport changelog: #71849.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

[Block] Image Affects the Image Block [Feature] Block bindings [Type] Enhancement A suggestion for improvement.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants