Skip to content

Conversation

@andrewserong
Copy link
Contributor

@andrewserong andrewserong commented Nov 18, 2025

What?

Part of #73261

Follows: #71730

Refactor the ContentOnlyControls to use DataForm for rendering editable fields. Note that this PR is an iterative step in this direction, it doesn't get the whole way there, but it (hopefully) sets things up to continue to make improvements in follow-ups. The goal is to not break things while we gradually improve how we're structuring things.

Why?

The editable fields in the right-hand sidebar for ContentOnlyControls should ideally use familiar components and interactions used elsewhere in Gutenberg (namely DataForm), so this PR is a step in that direction. Note that we don't (yet) have generalised media, link, or richtext fields, so those continue to be ad-hoc. However for simple text fields, like alt text on the Image block, we can re-use the text control from DataForm.

The idea with this PR is that we could eventually look at moving the ad hoc media, link, and richtext fields over to DataForm once we can build common components for them.

How?

  • Replace ToolsPanel and ToolsPanelItem with DataForm for ContentOnlyControls
  • Add a custom dropdown menu / header that resembles ToolsPanel for controlling field visibility
  • Update the settings.fields structure slightly to use id fields and types that more closely match DataForm — it's not an exact match, but it gets things a little closer
  • Add some mapping to ensure that the controls map correctly to the block attributes they're updating

A caveat: the mapping isn't very neat right now, and things are pretty messy in regards to how we're passing values into the control components. If it looks acceptable, my plan would be to try to merge this PR and then iteratively work on each of those controls.

Testing Instructions

  1. Enable the ContentOnly experiment in the Gutenberg experiments page
  2. Go to edit a pattern containing many different kinds of blocks, including Cover, Image, Media & Text, Buttons, etc, and try out each of the different kinds of controls and settings (i.e. adding and replacing media, resetting media, setting to featured image, adding links, etc) and check that nothing's broken

Screenshots or screencast

This should show a UI that's very close to what landed in #71730 with panel headers that look like the ToolsPanel. Here's a quick demo:

2025-11-19.15.05.50-optimised.mp4

@andrewserong andrewserong self-assigned this Nov 18, 2025
@andrewserong andrewserong added [Type] Code Quality Issues or PRs that relate to code quality [Feature] Patterns A collection of blocks that can be synced (previously reusable blocks) or unsynced labels Nov 18, 2025
@andrewserong andrewserong force-pushed the try/switch-content-only-controls-to-dataform branch from 12ff5ec to c13fd67 Compare November 19, 2025 01:17
@github-actions
Copy link

github-actions bot commented Nov 19, 2025

Size Change: +21.7 kB (+0.86%)

Total Size: 2.54 MB

Filename Size Change
build/scripts/block-editor/index.min.js 321 kB +21.6 kB (+7.22%) 🔍
build/scripts/block-library/index.min.js 275 kB +3 B (0%)
build/styles/block-editor/style-rtl.css 16.4 kB +19 B (+0.12%)
build/styles/block-editor/style.css 16.3 kB +24 B (+0.15%)
ℹ️ View Unchanged
Filename Size
build/modules/a11y/index.min.js 355 B
build/modules/abilities/index.min.js 43 kB
build/modules/block-editor/utils/fit-text-frontend.min.js 549 B
build/modules/block-library/accordion/view.min.js 528 B
build/modules/block-library/file/view.min.js 346 B
build/modules/block-library/form/view.min.js 528 B
build/modules/block-library/image/view.min.js 1.95 kB
build/modules/block-library/navigation/view.min.js 1.03 kB
build/modules/block-library/query/view.min.js 518 B
build/modules/block-library/search/view.min.js 498 B
build/modules/block-library/tabs/view.min.js 859 B
build/modules/boot/index.min.js 69.1 kB
build/modules/edit-site-init/index.min.js 1.3 kB
build/modules/interactivity-router/full-page.min.js 451 B
build/modules/interactivity-router/index.min.js 11.5 kB
build/modules/interactivity/index.min.js 14.9 kB
build/modules/latex-to-mathml/index.min.js 56.5 kB
build/modules/latex-to-mathml/loader.min.js 131 B
build/modules/lazy-editor/index.min.js 18.8 kB
build/modules/route/index.min.js 24.5 kB
build/modules/workflow/index.min.js 36.8 kB
build/scripts/a11y/index.min.js 1.06 kB
build/scripts/annotations/index.min.js 2.38 kB
build/scripts/api-fetch/index.min.js 2.83 kB
build/scripts/autop/index.min.js 2.18 kB
build/scripts/blob/index.min.js 631 B
build/scripts/block-directory/index.min.js 8.03 kB
build/scripts/block-serialization-default-parser/index.min.js 1.16 kB
build/scripts/block-serialization-spec-parser/index.min.js 3.08 kB
build/scripts/blocks/index.min.js 56.2 kB
build/scripts/commands/index.min.js 19.9 kB
build/scripts/components/index.min.js 271 kB
build/scripts/compose/index.min.js 13.8 kB
build/scripts/core-commands/index.min.js 4.13 kB
build/scripts/core-data/index.min.js 86.1 kB
build/scripts/customize-widgets/index.min.js 12.3 kB
build/scripts/data-controls/index.min.js 793 B
build/scripts/data/index.min.js 9.61 kB
build/scripts/date/index.min.js 23.6 kB
build/scripts/deprecated/index.min.js 752 B
build/scripts/dom-ready/index.min.js 476 B
build/scripts/dom/index.min.js 4.91 kB
build/scripts/edit-post/index.min.js 16.3 kB
build/scripts/edit-site/index.min.js 232 kB
build/scripts/edit-widgets/index.min.js 20 kB
build/scripts/editor/index.min.js 283 kB
build/scripts/element/index.min.js 5.19 kB
build/scripts/escape-html/index.min.js 586 B
build/scripts/format-library/index.min.js 10.8 kB
build/scripts/hooks/index.min.js 1.83 kB
build/scripts/html-entities/index.min.js 494 B
build/scripts/i18n/index.min.js 2.46 kB
build/scripts/is-shallow-equal/index.min.js 568 B
build/scripts/keyboard-shortcuts/index.min.js 1.57 kB
build/scripts/keycodes/index.min.js 1.53 kB
build/scripts/list-reusable-blocks/index.min.js 2.44 kB
build/scripts/media-utils/index.min.js 65.9 kB
build/scripts/notices/index.min.js 1.11 kB
build/scripts/nux/index.min.js 1.88 kB
build/scripts/patterns/index.min.js 7.88 kB
build/scripts/plugins/index.min.js 2.14 kB
build/scripts/preferences-persistence/index.min.js 2.15 kB
build/scripts/preferences/index.min.js 3.31 kB
build/scripts/primitives/index.min.js 1.01 kB
build/scripts/priority-queue/index.min.js 1.61 kB
build/scripts/private-apis/index.min.js 1.11 kB
build/scripts/react-i18n/index.min.js 832 B
build/scripts/react-refresh-entry/index.min.js 9.44 kB
build/scripts/react-refresh-runtime/index.min.js 3.59 kB
build/scripts/redux-routine/index.min.js 3.36 kB
build/scripts/reusable-blocks/index.min.js 2.93 kB
build/scripts/rich-text/index.min.js 12.9 kB
build/scripts/router/index.min.js 5.96 kB
build/scripts/server-side-render/index.min.js 1.91 kB
build/scripts/shortcode/index.min.js 1.58 kB
build/scripts/style-engine/index.min.js 2.32 kB
build/scripts/theme/index.min.js 20.8 kB
build/scripts/token-list/index.min.js 739 B
build/scripts/undo-manager/index.min.js 917 B
build/scripts/url/index.min.js 3.98 kB
build/scripts/vendors/react-dom.min.js 43 kB
build/scripts/vendors/react-jsx-runtime.min.js 691 B
build/scripts/vendors/react.min.js 4.27 kB
build/scripts/viewport/index.min.js 1.22 kB
build/scripts/warning/index.min.js 454 B
build/scripts/widgets/index.min.js 7.81 kB
build/scripts/wordcount/index.min.js 1.04 kB
build/styles/block-directory/style-rtl.css 1.05 kB
build/styles/block-directory/style.css 1.05 kB
build/styles/block-editor/content-rtl.css 4.79 kB
build/styles/block-editor/content.css 4.79 kB
build/styles/block-editor/default-editor-styles-rtl.css 224 B
build/styles/block-editor/default-editor-styles.css 224 B
build/styles/block-library/accordion-heading/style-rtl.css 395 B
build/styles/block-library/accordion-heading/style.css 395 B
build/styles/block-library/accordion-item/style-rtl.css 213 B
build/styles/block-library/accordion-item/style.css 213 B
build/styles/block-library/accordion-panel/style-rtl.css 121 B
build/styles/block-library/accordion-panel/style.css 121 B
build/styles/block-library/archives/editor-rtl.css 61 B
build/styles/block-library/archives/editor.css 61 B
build/styles/block-library/archives/style-rtl.css 90 B
build/styles/block-library/archives/style.css 90 B
build/styles/block-library/audio/editor-rtl.css 149 B
build/styles/block-library/audio/editor.css 151 B
build/styles/block-library/audio/style-rtl.css 132 B
build/styles/block-library/audio/style.css 132 B
build/styles/block-library/audio/theme-rtl.css 134 B
build/styles/block-library/audio/theme.css 134 B
build/styles/block-library/avatar/editor-rtl.css 115 B
build/styles/block-library/avatar/editor.css 115 B
build/styles/block-library/avatar/style-rtl.css 104 B
build/styles/block-library/avatar/style.css 104 B
build/styles/block-library/breadcrumbs/style-rtl.css 203 B
build/styles/block-library/breadcrumbs/style.css 203 B
build/styles/block-library/button/editor-rtl.css 265 B
build/styles/block-library/button/editor.css 265 B
build/styles/block-library/button/style-rtl.css 554 B
build/styles/block-library/button/style.css 554 B
build/styles/block-library/buttons/editor-rtl.css 291 B
build/styles/block-library/buttons/editor.css 291 B
build/styles/block-library/buttons/style-rtl.css 349 B
build/styles/block-library/buttons/style.css 349 B
build/styles/block-library/calendar/style-rtl.css 239 B
build/styles/block-library/calendar/style.css 239 B
build/styles/block-library/categories/editor-rtl.css 132 B
build/styles/block-library/categories/editor.css 131 B
build/styles/block-library/categories/style-rtl.css 152 B
build/styles/block-library/categories/style.css 152 B
build/styles/block-library/classic-rtl.css 179 B
build/styles/block-library/classic.css 179 B
build/styles/block-library/code/editor-rtl.css 53 B
build/styles/block-library/code/editor.css 53 B
build/styles/block-library/code/style-rtl.css 139 B
build/styles/block-library/code/style.css 139 B
build/styles/block-library/code/theme-rtl.css 122 B
build/styles/block-library/code/theme.css 122 B
build/styles/block-library/columns/editor-rtl.css 108 B
build/styles/block-library/columns/editor.css 108 B
build/styles/block-library/columns/style-rtl.css 421 B
build/styles/block-library/columns/style.css 421 B
build/styles/block-library/comment-author-avatar/editor-rtl.css 124 B
build/styles/block-library/comment-author-avatar/editor.css 124 B
build/styles/block-library/comment-author-name/style-rtl.css 72 B
build/styles/block-library/comment-author-name/style.css 72 B
build/styles/block-library/comment-content/style-rtl.css 120 B
build/styles/block-library/comment-content/style.css 120 B
build/styles/block-library/comment-date/style-rtl.css 65 B
build/styles/block-library/comment-date/style.css 65 B
build/styles/block-library/comment-edit-link/style-rtl.css 70 B
build/styles/block-library/comment-edit-link/style.css 70 B
build/styles/block-library/comment-reply-link/style-rtl.css 71 B
build/styles/block-library/comment-reply-link/style.css 71 B
build/styles/block-library/comment-template/style-rtl.css 191 B
build/styles/block-library/comment-template/style.css 191 B
build/styles/block-library/comments-pagination-numbers/editor-rtl.css 122 B
build/styles/block-library/comments-pagination-numbers/editor.css 121 B
build/styles/block-library/comments-pagination/editor-rtl.css 168 B
build/styles/block-library/comments-pagination/editor.css 168 B
build/styles/block-library/comments-pagination/style-rtl.css 201 B
build/styles/block-library/comments-pagination/style.css 201 B
build/styles/block-library/comments-title/editor-rtl.css 75 B
build/styles/block-library/comments-title/editor.css 75 B
build/styles/block-library/comments/editor-rtl.css 842 B
build/styles/block-library/comments/editor.css 842 B
build/styles/block-library/comments/style-rtl.css 637 B
build/styles/block-library/comments/style.css 637 B
build/styles/block-library/common-rtl.css 1.11 kB
build/styles/block-library/common.css 1.11 kB
build/styles/block-library/cover/editor-rtl.css 631 B
build/styles/block-library/cover/editor.css 631 B
build/styles/block-library/cover/style-rtl.css 1.7 kB
build/styles/block-library/cover/style.css 1.69 kB
build/styles/block-library/details/editor-rtl.css 65 B
build/styles/block-library/details/editor.css 65 B
build/styles/block-library/details/style-rtl.css 86 B
build/styles/block-library/details/style.css 86 B
build/styles/block-library/editor-elements-rtl.css 75 B
build/styles/block-library/editor-elements.css 75 B
build/styles/block-library/editor-rtl.css 11.8 kB
build/styles/block-library/editor.css 11.8 kB
build/styles/block-library/elements-rtl.css 54 B
build/styles/block-library/elements.css 54 B
build/styles/block-library/embed/editor-rtl.css 331 B
build/styles/block-library/embed/editor.css 331 B
build/styles/block-library/embed/style-rtl.css 448 B
build/styles/block-library/embed/style.css 448 B
build/styles/block-library/embed/theme-rtl.css 133 B
build/styles/block-library/embed/theme.css 133 B
build/styles/block-library/file/editor-rtl.css 324 B
build/styles/block-library/file/editor.css 324 B
build/styles/block-library/file/style-rtl.css 278 B
build/styles/block-library/file/style.css 278 B
build/styles/block-library/footnotes/style-rtl.css 198 B
build/styles/block-library/footnotes/style.css 197 B
build/styles/block-library/form-input/editor-rtl.css 229 B
build/styles/block-library/form-input/editor.css 229 B
build/styles/block-library/form-input/style-rtl.css 366 B
build/styles/block-library/form-input/style.css 366 B
build/styles/block-library/form-submission-notification/editor-rtl.css 344 B
build/styles/block-library/form-submission-notification/editor.css 341 B
build/styles/block-library/form-submit-button/style-rtl.css 69 B
build/styles/block-library/form-submit-button/style.css 69 B
build/styles/block-library/freeform/editor-rtl.css 2.59 kB
build/styles/block-library/freeform/editor.css 2.59 kB
build/styles/block-library/gallery/editor-rtl.css 615 B
build/styles/block-library/gallery/editor.css 616 B
build/styles/block-library/gallery/style-rtl.css 1.84 kB
build/styles/block-library/gallery/style.css 1.84 kB
build/styles/block-library/gallery/theme-rtl.css 108 B
build/styles/block-library/gallery/theme.css 108 B
build/styles/block-library/group/editor-rtl.css 335 B
build/styles/block-library/group/editor.css 335 B
build/styles/block-library/group/style-rtl.css 103 B
build/styles/block-library/group/style.css 103 B
build/styles/block-library/group/theme-rtl.css 79 B
build/styles/block-library/group/theme.css 79 B
build/styles/block-library/heading/style-rtl.css 205 B
build/styles/block-library/heading/style.css 205 B
build/styles/block-library/html/editor-rtl.css 440 B
build/styles/block-library/html/editor.css 441 B
build/styles/block-library/image/editor-rtl.css 763 B
build/styles/block-library/image/editor.css 763 B
build/styles/block-library/image/style-rtl.css 1.6 kB
build/styles/block-library/image/style.css 1.59 kB
build/styles/block-library/image/theme-rtl.css 137 B
build/styles/block-library/image/theme.css 137 B
build/styles/block-library/latest-comments/style-rtl.css 355 B
build/styles/block-library/latest-comments/style.css 354 B
build/styles/block-library/latest-posts/editor-rtl.css 139 B
build/styles/block-library/latest-posts/editor.css 138 B
build/styles/block-library/latest-posts/style-rtl.css 520 B
build/styles/block-library/latest-posts/style.css 520 B
build/styles/block-library/list/style-rtl.css 107 B
build/styles/block-library/list/style.css 107 B
build/styles/block-library/loginout/style-rtl.css 61 B
build/styles/block-library/loginout/style.css 61 B
build/styles/block-library/math/editor-rtl.css 105 B
build/styles/block-library/math/editor.css 105 B
build/styles/block-library/math/style-rtl.css 61 B
build/styles/block-library/math/style.css 61 B
build/styles/block-library/media-text/editor-rtl.css 321 B
build/styles/block-library/media-text/editor.css 320 B
build/styles/block-library/media-text/style-rtl.css 543 B
build/styles/block-library/media-text/style.css 542 B
build/styles/block-library/more/editor-rtl.css 393 B
build/styles/block-library/more/editor.css 393 B
build/styles/block-library/navigation-link/editor-rtl.css 645 B
build/styles/block-library/navigation-link/editor.css 647 B
build/styles/block-library/navigation-link/style-rtl.css 190 B
build/styles/block-library/navigation-link/style.css 188 B
build/styles/block-library/navigation-submenu/editor-rtl.css 295 B
build/styles/block-library/navigation-submenu/editor.css 294 B
build/styles/block-library/navigation/editor-rtl.css 2.24 kB
build/styles/block-library/navigation/editor.css 2.24 kB
build/styles/block-library/navigation/style-rtl.css 2.27 kB
build/styles/block-library/navigation/style.css 2.25 kB
build/styles/block-library/nextpage/editor-rtl.css 392 B
build/styles/block-library/nextpage/editor.css 392 B
build/styles/block-library/page-list/editor-rtl.css 356 B
build/styles/block-library/page-list/editor.css 356 B
build/styles/block-library/page-list/style-rtl.css 192 B
build/styles/block-library/page-list/style.css 192 B
build/styles/block-library/paragraph/editor-rtl.css 251 B
build/styles/block-library/paragraph/editor.css 251 B
build/styles/block-library/paragraph/style-rtl.css 341 B
build/styles/block-library/paragraph/style.css 340 B
build/styles/block-library/post-author-biography/style-rtl.css 74 B
build/styles/block-library/post-author-biography/style.css 74 B
build/styles/block-library/post-author-name/style-rtl.css 69 B
build/styles/block-library/post-author-name/style.css 69 B
build/styles/block-library/post-author/style-rtl.css 188 B
build/styles/block-library/post-author/style.css 189 B
build/styles/block-library/post-comments-count/style-rtl.css 72 B
build/styles/block-library/post-comments-count/style.css 72 B
build/styles/block-library/post-comments-form/editor-rtl.css 96 B
build/styles/block-library/post-comments-form/editor.css 96 B
build/styles/block-library/post-comments-form/style-rtl.css 525 B
build/styles/block-library/post-comments-form/style.css 525 B
build/styles/block-library/post-comments-link/style-rtl.css 71 B
build/styles/block-library/post-comments-link/style.css 71 B
build/styles/block-library/post-content/style-rtl.css 61 B
build/styles/block-library/post-content/style.css 61 B
build/styles/block-library/post-date/style-rtl.css 62 B
build/styles/block-library/post-date/style.css 62 B
build/styles/block-library/post-excerpt/editor-rtl.css 71 B
build/styles/block-library/post-excerpt/editor.css 71 B
build/styles/block-library/post-excerpt/style-rtl.css 155 B
build/styles/block-library/post-excerpt/style.css 155 B
build/styles/block-library/post-featured-image/editor-rtl.css 719 B
build/styles/block-library/post-featured-image/editor.css 717 B
build/styles/block-library/post-featured-image/style-rtl.css 347 B
build/styles/block-library/post-featured-image/style.css 347 B
build/styles/block-library/post-navigation-link/style-rtl.css 215 B
build/styles/block-library/post-navigation-link/style.css 214 B
build/styles/block-library/post-template/style-rtl.css 414 B
build/styles/block-library/post-template/style.css 414 B
build/styles/block-library/post-terms/style-rtl.css 96 B
build/styles/block-library/post-terms/style.css 96 B
build/styles/block-library/post-time-to-read/style-rtl.css 70 B
build/styles/block-library/post-time-to-read/style.css 70 B
build/styles/block-library/post-title/style-rtl.css 162 B
build/styles/block-library/post-title/style.css 162 B
build/styles/block-library/preformatted/style-rtl.css 125 B
build/styles/block-library/preformatted/style.css 125 B
build/styles/block-library/pullquote/editor-rtl.css 133 B
build/styles/block-library/pullquote/editor.css 133 B
build/styles/block-library/pullquote/style-rtl.css 365 B
build/styles/block-library/pullquote/style.css 365 B
build/styles/block-library/pullquote/theme-rtl.css 176 B
build/styles/block-library/pullquote/theme.css 176 B
build/styles/block-library/query-pagination-numbers/editor-rtl.css 121 B
build/styles/block-library/query-pagination-numbers/editor.css 118 B
build/styles/block-library/query-pagination/editor-rtl.css 154 B
build/styles/block-library/query-pagination/editor.css 154 B
build/styles/block-library/query-pagination/style-rtl.css 237 B
build/styles/block-library/query-pagination/style.css 237 B
build/styles/block-library/query-title/style-rtl.css 64 B
build/styles/block-library/query-title/style.css 64 B
build/styles/block-library/query-total/style-rtl.css 64 B
build/styles/block-library/query-total/style.css 64 B
build/styles/block-library/query/editor-rtl.css 438 B
build/styles/block-library/query/editor.css 438 B
build/styles/block-library/quote/style-rtl.css 238 B
build/styles/block-library/quote/style.css 238 B
build/styles/block-library/quote/theme-rtl.css 233 B
build/styles/block-library/quote/theme.css 236 B
build/styles/block-library/read-more/style-rtl.css 131 B
build/styles/block-library/read-more/style.css 131 B
build/styles/block-library/reset-rtl.css 472 B
build/styles/block-library/reset.css 472 B
build/styles/block-library/rss/editor-rtl.css 126 B
build/styles/block-library/rss/editor.css 126 B
build/styles/block-library/rss/style-rtl.css 284 B
build/styles/block-library/rss/style.css 283 B
build/styles/block-library/search/editor-rtl.css 199 B
build/styles/block-library/search/editor.css 199 B
build/styles/block-library/search/style-rtl.css 665 B
build/styles/block-library/search/style.css 666 B
build/styles/block-library/search/theme-rtl.css 113 B
build/styles/block-library/search/theme.css 113 B
build/styles/block-library/separator/editor-rtl.css 100 B
build/styles/block-library/separator/editor.css 100 B
build/styles/block-library/separator/style-rtl.css 248 B
build/styles/block-library/separator/style.css 248 B
build/styles/block-library/separator/theme-rtl.css 195 B
build/styles/block-library/separator/theme.css 195 B
build/styles/block-library/shortcode/editor-rtl.css 286 B
build/styles/block-library/shortcode/editor.css 286 B
build/styles/block-library/site-logo/editor-rtl.css 773 B
build/styles/block-library/site-logo/editor.css 770 B
build/styles/block-library/site-logo/style-rtl.css 218 B
build/styles/block-library/site-logo/style.css 218 B
build/styles/block-library/site-tagline/editor-rtl.css 87 B
build/styles/block-library/site-tagline/editor.css 87 B
build/styles/block-library/site-tagline/style-rtl.css 65 B
build/styles/block-library/site-tagline/style.css 65 B
build/styles/block-library/site-title/editor-rtl.css 85 B
build/styles/block-library/site-title/editor.css 85 B
build/styles/block-library/site-title/style-rtl.css 143 B
build/styles/block-library/site-title/style.css 143 B
build/styles/block-library/social-link/editor-rtl.css 314 B
build/styles/block-library/social-link/editor.css 314 B
build/styles/block-library/social-links/editor-rtl.css 339 B
build/styles/block-library/social-links/editor.css 338 B
build/styles/block-library/social-links/style-rtl.css 1.51 kB
build/styles/block-library/social-links/style.css 1.51 kB
build/styles/block-library/spacer/editor-rtl.css 346 B
build/styles/block-library/spacer/editor.css 346 B
build/styles/block-library/spacer/style-rtl.css 48 B
build/styles/block-library/spacer/style.css 48 B
build/styles/block-library/style-rtl.css 16.5 kB
build/styles/block-library/style.css 16.5 kB
build/styles/block-library/tab/style-rtl.css 202 B
build/styles/block-library/tab/style.css 202 B
build/styles/block-library/table-of-contents/style-rtl.css 83 B
build/styles/block-library/table-of-contents/style.css 83 B
build/styles/block-library/table/editor-rtl.css 394 B
build/styles/block-library/table/editor.css 394 B
build/styles/block-library/table/style-rtl.css 641 B
build/styles/block-library/table/style.css 640 B
build/styles/block-library/table/theme-rtl.css 152 B
build/styles/block-library/table/theme.css 152 B
build/styles/block-library/tabs/editor-rtl.css 236 B
build/styles/block-library/tabs/editor.css 236 B
build/styles/block-library/tabs/style-rtl.css 983 B
build/styles/block-library/tabs/style.css 983 B
build/styles/block-library/tag-cloud/editor-rtl.css 92 B
build/styles/block-library/tag-cloud/editor.css 92 B
build/styles/block-library/tag-cloud/style-rtl.css 248 B
build/styles/block-library/tag-cloud/style.css 248 B
build/styles/block-library/template-part/editor-rtl.css 368 B
build/styles/block-library/template-part/editor.css 368 B
build/styles/block-library/template-part/theme-rtl.css 113 B
build/styles/block-library/template-part/theme.css 113 B
build/styles/block-library/term-count/style-rtl.css 63 B
build/styles/block-library/term-count/style.css 63 B
build/styles/block-library/term-description/style-rtl.css 126 B
build/styles/block-library/term-description/style.css 126 B
build/styles/block-library/term-name/style-rtl.css 62 B
build/styles/block-library/term-name/style.css 62 B
build/styles/block-library/term-template/editor-rtl.css 225 B
build/styles/block-library/term-template/editor.css 225 B
build/styles/block-library/term-template/style-rtl.css 114 B
build/styles/block-library/term-template/style.css 114 B
build/styles/block-library/text-columns/editor-rtl.css 95 B
build/styles/block-library/text-columns/editor.css 95 B
build/styles/block-library/text-columns/style-rtl.css 165 B
build/styles/block-library/text-columns/style.css 165 B
build/styles/block-library/theme-rtl.css 715 B
build/styles/block-library/theme.css 719 B
build/styles/block-library/verse/style-rtl.css 98 B
build/styles/block-library/verse/style.css 98 B
build/styles/block-library/video/editor-rtl.css 415 B
build/styles/block-library/video/editor.css 416 B
build/styles/block-library/video/style-rtl.css 202 B
build/styles/block-library/video/style.css 202 B
build/styles/block-library/video/theme-rtl.css 134 B
build/styles/block-library/video/theme.css 134 B
build/styles/commands/style-rtl.css 1.72 kB
build/styles/commands/style.css 1.72 kB
build/styles/components/style-rtl.css 14 kB
build/styles/components/style.css 14 kB
build/styles/customize-widgets/style-rtl.css 1.44 kB
build/styles/customize-widgets/style.css 1.44 kB
build/styles/edit-post/classic-rtl.css 426 B
build/styles/edit-post/classic.css 427 B
build/styles/edit-post/style-rtl.css 3.42 kB
build/styles/edit-post/style.css 3.42 kB
build/styles/edit-site/style-rtl.css 16 kB
build/styles/edit-site/style.css 16 kB
build/styles/edit-widgets/style-rtl.css 4.67 kB
build/styles/edit-widgets/style.css 4.67 kB
build/styles/editor/style-rtl.css 18.6 kB
build/styles/editor/style.css 18.6 kB
build/styles/format-library/style-rtl.css 326 B
build/styles/format-library/style.css 326 B
build/styles/list-reusable-blocks/style-rtl.css 1.02 kB
build/styles/list-reusable-blocks/style.css 1.02 kB
build/styles/nux/style-rtl.css 622 B
build/styles/nux/style.css 618 B
build/styles/patterns/style-rtl.css 611 B
build/styles/patterns/style.css 611 B
build/styles/preferences/style-rtl.css 415 B
build/styles/preferences/style.css 415 B
build/styles/reusable-blocks/style-rtl.css 275 B
build/styles/reusable-blocks/style.css 275 B
build/styles/widgets/style-rtl.css 1.17 kB
build/styles/widgets/style.css 1.18 kB

compressed-size-action

@github-actions
Copy link

github-actions bot commented Nov 19, 2025

Flaky tests detected in 61164f9.
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/19489722408
📝 Reported issues:

Comment on lines +41 to +51
/**
* Creates a configured control component that wraps a custom control
* and passes configuration as props.
*
* @param {Object} config - The control configuration
* @param {string} config.control - The control type (key in CONTROLS map)
* @return {Function} A wrapped control component
*/
function createConfiguredControl( config ) {
const { control, ...controlConfig } = config;
const ControlComponent = CONTROLS[ control ];
Copy link
Contributor Author

@andrewserong andrewserong Nov 19, 2025

Choose a reason for hiding this comment

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

This function is effectively a copy of the same one that exists internally within DataForm. The goal here is to try to get these link, media, and richtext components a bit closer to how they might look if they were bundled controls within DataForm. We're not there yet with this PR — the intention here is to just take a step in that direction and to continue to refine in follow-ups.

This function is so that we can bundle configuration alongside using controls like media, link, or richtext.

id: fieldDef.id,
label: fieldDef.label,
type: fieldDef.type, // Use the field's type; DataForm will use built-in or custom Edit
config: { ...fieldDef.args, defaultValues },
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Not for now, but potentially in a follow-up we might move these from fieldDef.args to be properties of fieldDef.Edit. Similarly the config in this object might move to Edit config, too. I haven't gone further in this PR because I wanted to kind of mark a point of iteration and see if this is good enough for now.

@andrewserong andrewserong marked this pull request as ready for review November 19, 2025 04:42
@github-actions
Copy link

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: andrewserong <[email protected]>
Co-authored-by: talldan <[email protected]>
Co-authored-by: jeryj <[email protected]>

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

Copy link
Contributor

@talldan talldan 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 well, so TBH, I'm kinda happy to approve it. The only thing I notice from a UX point of view is that this dropdown isn't to the side of the inspector like other dropdowns:
Image

Most of the comments are questions or observations rather than requests to change anything.

Comment on lines -58 to -60
mapping: {
value: 'caption',
},
Copy link
Contributor

Choose a reason for hiding this comment

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

It's cool to see these removed in favour of using the id 👏

Comment on lines 114 to 118
href: value?.href ?? value?.url ?? '',
url: value?.url ?? value?.href ?? '', // url falls back to href
rel: value?.rel ?? '',
target: value?.target ?? value?.linkTarget ?? '',
linkTarget: value?.linkTarget ?? value?.target ?? '',
Copy link
Contributor

Choose a reason for hiding this comment

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

I'm curious why both href/url are needed, also target/linkTarget, as they seem to normalize to the same values. The attributes are also passed through the mapping process which should remove the inconsistencies.

Maybe some of the reasoning can be documented in inline comments.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Oh, this was a double-up while I was debugging and I forgot to remove it! Thanks for flagging, I've pushed an update to standardize, hopefully I haven't broken anything in the process 😄

}

const result = {};
Object.entries( fieldDef.mapping ).forEach( ( [ key ] ) => {
Copy link
Contributor

Choose a reason for hiding this comment

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

Not a blocker, as I realize this is still going to pass through several revisions, but it looks like normalize/denormalize aren't complete opposites as this one uses the mapping while normalize doesn't.

It feels like a gotcha because when functions are named like this I'd usually expect them to losslessly reverse the operation of the other.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, I've pushed an update that makes these a bit closer to each other, so normalize uses the mapping

Comment on lines +216 to +218
if ( fieldDef.type === 'media' ) {
return normalizeMediaValue( mappedValue, fieldDef );
}
Copy link
Contributor

Choose a reason for hiding this comment

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

I guess in future we might want this to become part of the field definition (in the media folder), and make it so that an if statement (which isn't really scalable to other field types) isn't required.

}

// Merge with existing value to preserve other field properties
updateAttributes( { ...value, ...resetValue } );
Copy link
Contributor

Choose a reason for hiding this comment

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

Would the plan be to make these use field.setValue in the future?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes! While troubleshooting, I found it easier for this PR to just pop updateAttributes in here for now, but I'd like to refactor this in a follow-up, too

const { allowedTypes = [], multiple = false } = config;

if ( multiple ) {
return 'todo multiple';
Copy link
Contributor

Choose a reason for hiding this comment

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

I guess we should get rid of this at some point 😆

@andrewserong
Copy link
Contributor Author

Thanks for the feedback, @talldan! I've pushed a few updates to hopefully streamline things a little bit and settle on a common name for some of the keys. I've switched to url from src, but happy to revert / iterate as needed. I've also tweaked the styling and positioning slightly so the dropdown menus should be in the right place now:

image

Copy link
Contributor

@talldan talldan 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 the changes, this is working well, very similar to before, so looks good to move forward with this refactor to DataForm. Nice work!

@andrewserong
Copy link
Contributor Author

Thanks for the review @talldan! While this PR is still a bit hacky in some places, it's all still behind an experiment, so I'll merge this in now and will add a quick update on #73261 with some ideas for follow-up tasks to dig into next.

@andrewserong andrewserong merged commit 5149e52 into trunk Nov 20, 2025
39 of 42 checks passed
@andrewserong andrewserong deleted the try/switch-content-only-controls-to-dataform branch November 20, 2025 02:37
@github-actions github-actions bot added this to the Gutenberg 22.2 milestone Nov 20, 2025
label: __( 'Audio' ),
type: 'Media',
type: 'media',
shownByDefault: true,
Copy link
Member

Choose a reason for hiding this comment

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

I've prepared #73479 so the block type declares both the fields and the form for DataForm. We were already doing that, but indirectly via shownByDefault prop, so 73479 makes it obvious.

@oandregal
Copy link
Member

It's great to see usage of Field API and DataForm in more places 👏

I'd like to offer a suggestion: the blocks should only use what's available in the Field API.

Being strict about this simple constraint will help us collaborate better and go faster. In this phase of the project, we need to uncover any missing pieces of the Field API as fast as possible. The current code that is shipped is a totally different API and doesn't help with that goal. If we keep the current direction, I'm concerned that it'd be difficult to reconcile the two APIs later — and it'd be harder to ship this great work in the 7.0 cycle.

In practical terms, this means:

  • Removing shownByDefault: controlling which fields are visible is a concern of the Form's API, not the Field's API. I've implemented this at #73479
  • The field's Edit function does not update the blocks. It just emits the new value, and the DataForm's onChange callback here is responsible to make the block calls. This is important for having reusable DataForm controls.
  • mapping: we need to implement support for the type: object in the Field API, so this:
{
	id: 'link',
	type: 'link',
	shownByDefault: true,
	mapping: {
		url: 'url',
		rel: 'rel',
		linkTarget: 'linkTarget',
	},
}

becomes:

{
	id: 'link',
	type: 'object',
	properties: {
		url: 'url',
		rel: 'rel',
		linkTarget: 'linkTarget',
	},
	Edit: 'link', // consider why the existing 'url' is enough? should we expand it?
}
  • args: remove and use Edit config instead. There's an issue to create a generic media control, and it'd be best for all of us if we implement it once and reuse everywhere. So far we've implemented two already (the existing in Site Editor > Pages and the one used here for content only). This:
{
	id: 'audio',
	label: __( 'Audio' ),
	type: 'media',
	shownByDefault: true,
	mapping: {
		id: 'id',
		url: 'src',
	},
	args: {
		allowedTypes: [ 'audio' ],
		multiple: false,
	},
},

becomes:

{
	id: 'audio',
	label: __( 'Audio' ),
	type: 'object',
	props: {
		id: 'id',
		url: 'src',
	},
	Edit: {
	    control: 'media',
		allowedTypes: [ 'audio' ],
		multiple: false,
	},
},

Take the examples I shared as illustration of the deviations we've taken from the Field API, and not as something normative. It's been only a few hours since I've looked at this code, and I'm sure I'm missing context. The essential part is about being strict with this constraint: the blocks should only use what's available in the Field API at any given point in time. Any other thing is a detail we need to figure it out together, as we make progress.

I'm happy to pair with any of you next week to migrate the existing config to using the Field API. I feel it's important that we align as soon as possible, otherwise the drift will increase, and it'll harder to reconcile later.

@andrewserong
Copy link
Contributor Author

the blocks should only use what's available in the Field API at any given point in time. Any other thing is a detail we need to figure it out together, as we make progress.
I'm happy to pair with any of you next week to migrate the existing config to using the Field API. I feel it's important that we align as soon as possible, otherwise the drift will increase, and it'll harder to reconcile later.

Thanks for flagging @oandregal — to be clear, it was always our intention to move in that direction! This PR was intended as a single step in that direction, with the code that's currently messy safely tucked away behind an experiment. @talldan was especially keen to make sure we don't expose any of the currently messy state, and so the settings.fields prop is further hidden in #73376

I'm occupied with other tasks this week, but also happy to help with iterative PRs that progress us toward using the DataForm and Fields APIs correctly. If you or @talldan make a start before I'm able to jump in properly, I'm happy to help review in the interim!

@andrewserong
Copy link
Contributor Author

I've updated the To-do list in the linked issue (#73261) to capture @oandregal's excellent list of follow-up tasks above. Thanks again!

@youknowriad
Copy link
Contributor

@oandregal for the "type" object, I think we should consider nesting fields.

{
	id: 'link',
	type: 'object',
	properties: {
		url: {
                      // The id is optional (it's the parent key, the rest is just a field object
                      // Alternatively, "properties" can be an array of fields.
                     type: 'string'
               }
	},
	Edit: 'link', // consider why the existing 'url' is enough? should we expand it?
}

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

Labels

[Feature] Patterns A collection of blocks that can be synced (previously reusable blocks) or unsynced [Type] Code Quality Issues or PRs that relate to code quality

Projects

None yet

Development

Successfully merging this pull request may close these issues.

contentOnly Pattern Editing: "[object Object] Options" title

5 participants