Skip to content

Experimental - Add content attribute controls to "Content" sidebar in contentOnly#71567

Closed
getdave wants to merge 13 commits into
trunkfrom
feature/attribute-controls-system
Closed

Experimental - Add content attribute controls to "Content" sidebar in contentOnly#71567
getdave wants to merge 13 commits into
trunkfrom
feature/attribute-controls-system

Conversation

@getdave
Copy link
Copy Markdown
Contributor

@getdave getdave commented Sep 9, 2025

This PR has been co-authored by @jeryj.

What

This PR explores (this is a WIP/prototype!) an automatic approach to displaying standardized UI controls for attributes with role: 'content' in the block quick navigation sidebar. Unlike the alternative approach in #71577, this implementation requires no changes to existing block.json files and works automatically with all blocks (core and third-party).

@jeryj and I are not sure which approach is best so we felt that prototyping this might help contributors to decide on which approach is best.

Closes #71557: Add automatic content attribute controls to block quick navigation sidebar

Key Features

  • Automatic Control Inference: Automatically detects and renders appropriate UI controls based on attribute type and naming patterns
  • DataForm Integration: Uses @wordpress/dataviews DataForm components as suggested in #71577#issuecomment-3274658200 - cc @youknowriad
  • Smart "Drill Down" Navigation: Single-attribute blocks show inline controls; multi-attribute blocks use Navigator sub-views with drill-down functionality
  • Comprehensive Type Support: Handles string, boolean, rich-text, number, and URL attributes with intelligent field type mapping
  • Zero Configuration: Works immediately with all existing blocks without requiring block authors to update their block.json

Why

The current contentOnly mode lacks standardized controls for editing block content attributes in the sidebar. This creates an inconsistent user experience where users must switch between the canvas and sidebar to edit different aspects of their content.

This automatic approach addresses the core concern raised in #71577: ensuring write mode works for third-party blocks without requiring updates from block authors.

Comparison with Alternative Approach

Aspect This PR (Automatic) #71577 (Manual)
Configuration Zero - works automatically Requires control property in block.json
Third-party compatibility ✅ Works immediately ❌ Requires block updates
Maintenance Low - centralized logic High - per-block configuration
Customization Limited to inferred types Full control per attribute
Adoption barrier None High - requires ecosystem updates

We acknowledge that both approaches have merit and the optimal solution may be a hybrid approach that combines automatic inference with optional manual overrides.

How

Automatic Control Inference

The system automatically maps attribute types to appropriate DataForm field types:

  • String attributestext field
  • Boolean attributestoggle field
  • Rich-text attributestext field (with future RichText support)
  • Number attributestext field
  • URL attributesurl field (detected by name patterns: url, src, href, link)

Smart UI Layout

  • Single Content Attribute: Displays inline with block icon and custom label
  • Multiple Content Attributes: Shows navigation button with chevron arrow, leading to dedicated sub-view
  • Sub-view Navigation: Uses Navigator component with back button for seamless drill-down experience

DataForm Integration

Leverages @wordpress/dataviews DataForm components for:

  • Consistent styling and behavior
  • Built-in validation and error handling
  • Accessibility compliance
  • Future extensibility

Implementation Details

  • Location: packages/block-editor/src/components/block-quick-navigation/index.js
  • Dependencies: Added @wordpress/dataviews to block-editor package
  • Performance: Uses useMemo for attribute processing and useSelect for efficient data access
  • State Management: Integrates with existing block editor store for attribute updates

Testing

Manual Testing

  1. Enable contentOnly mode in Gutenberg settings
  2. Create a post with various block types (heading, paragraph, image, etc.)
  3. Select a pattern containing multiple blocks
  4. Open block quick navigation sidebar
  5. Verify controls appear for blocks with role: 'content' attributes
  6. Test single-attribute blocks show inline controls with block icons
  7. Test multi-attribute blocks show navigation buttons with chevrons
  8. Test sub-view navigation by clicking multi-attribute blocks
  9. Verify attribute updates are reflected in the canvas
  10. Test with third-party blocks to ensure automatic compatibility

Keyboard Testing

  1. Tab navigation through all controls
  2. Enter/Space to activate buttons and toggles
  3. Arrow keys for navigation between fields
  4. Escape to close popovers and return to main view
  5. Tab to navigate between single-attribute controls
  6. Enter to activate multi-attribute navigation buttons

Screenshots

Screenshot 2025-09-10 at 16 52 45
Screen.Capture.on.2025-09-10.at.16-58-21.mp4

Breaking Changes

None - this is purely additive functionality.

Uncertain Elements

  • RichText Integration: Currently renders as text field; full RichText support may require additional work
  • Custom Control Support: Future enhancement could allow block authors to override inferred controls
  • Performance: Large numbers of attributes may impact rendering; monitoring needed
  • Hybrid Approach: Whether to combine with manual configuration from #71577

Related Issues

  • Addresses #71557 - Patterns: standardize representation of controls
  • Alternative approach: #71577 - Manual control configuration
  • Related: #58233 - Features with limited control over block UI
  • Similar: #60779 - Block controls standardization

@github-actions
Copy link
Copy Markdown

github-actions Bot commented Sep 9, 2025

Size Change: +1.01 kB (+0.05%)

Total Size: 1.94 MB

Filename Size Change
build/block-editor/index.min.js 268 kB +1.01 kB (+0.38%)
ℹ️ 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/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/index.min.js 234 kB
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.6 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.24 kB
build/core-data/index.min.js 74.9 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 239 kB
build/edit-site/posts-rtl.css 9.37 kB
build/edit-site/posts.css 9.37 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 132 kB
build/editor/style-rtl.css 9.2 kB
build/editor/style.css 9.21 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.36 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

@github-actions
Copy link
Copy Markdown

github-actions Bot commented Sep 10, 2025

Flaky tests detected in 3f94064.
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/17612601792
📝 Reported issues:

@getdave getdave added [Type] Experimental Experimental feature or API. [Feature] Patterns A collection of blocks that can be synced (previously reusable blocks) or unsynced labels Sep 10, 2025
@getdave getdave changed the title WIP - Add content attribute controls to block quick navigation Experimental - Add content attribute controls to "Content" sidebar in contentOnly Sep 10, 2025
@getdave getdave requested a review from jasmussen September 10, 2025 16:00
@talldan
Copy link
Copy Markdown
Contributor

talldan commented Sep 11, 2025

Zero Configuration: Works immediately with all existing blocks without requiring block authors to update their block.json

Don't you need a label for the fields?

},
"id": {
"type": "number",
"role": "content"
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Do you know why id had the content attribute in the first place? 🤔

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I checked on the source of when it was added in #47936, and my best guess is that it was so early in the process that it was added because it was so unclear how to make something considered content. From where we are now, it feels safe to say that "id" should not be considered content.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I think this is the attachment id, and when replacing an image from the media library this will need to be updated (even in content only mode). We'll need a control in the inspector that can change this value. So I'd argue it could be considered as content. I think that's probably why the role was added.

In terms of inferring a control, we probably need to be able to detect the attachment id and the img/video element src attributes, and when present show a control that can update these values together. We might also want to match the logic around how the caption and alt text can be set from the attachment's caption.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

We were discussing identifying the media src and showing a media selection button. We haven't gotten there yet.

It feels like a bug to need id labeled as content. Hopefully using a media selector will set the fields we need.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

We'll need a control in the inspector that can change this value. So I'd argue it could be considered as content. I think that's probably why the role was added.

Do we need the attribute to be exposed in the inspector? Could we just update it when the media item itself changes?

Comment on lines +94 to +138
if ( attrDef.role === 'content' ) {
attributes.push( {
name: attrName,
definition: attrDef,
value: block.attributes?.[ attrName ],
} );
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Very clever!

Just checking my skim-reading assumptions: any block attribute could opt-in or opt-out of having content-only editable fields by:

  1. Using attributes[ someAttr ].role = 'content'
  2. The attribute having a supported type.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Yup! That's the idea.

@Mamaduka
Copy link
Copy Markdown
Member

From the screenshot/screencast, it seems we're just duplicating fields that are already in Canvas.

This seems to be going in the opposite direction to what we've been advocating with the block editor - in canvas editing is better than filling out forms. It also looks like what many "block builder" plugins are doing, using the sidebar to edit attributes, instead of the canvas.

@talldan
Copy link
Copy Markdown
Contributor

talldan commented Sep 11, 2025

@Mamaduka this is to try the proposal in Pattern Editing and contentOnly interactivity. That's probably a good place to leave feedback, I expert more people are reading than the PRs.

@talldan
Copy link
Copy Markdown
Contributor

talldan commented Sep 11, 2025

A lot to digest here. I like the idea of inferring the controls, but from testing the PR there are a lot of problems to solve, and I'm not sure it's a good idea to opt-in every attribute straight away.

An example is that it's very easy to break image blocks by disconnecting the id from the url. From my experience working on and reviewing block bindings PR I think the discovery was that the source / selector / attribute are better properties to do any inference from, those props provide more semantic information. Otherwise you won't know whether a url is an href or a src.

I think links will present similar challenges, where there's rel, openInNewTab etc. that should be associated and part of the same control, and updating one attribute might change another.

I'm ok with the idea of trying this, but I think it should be iteratively introduced rather than allowing everything from the start (and I realize that goes against the point of making everything work out of the box for third party blocks).

UI-wise, I think it'd be good to lean closer to what was described in the issue too. So no drill down, instead something more like ToolsPanel. If we can achieve that with DataForms that's ideal, but I think we might need to gradually implement that. We need to consider things like having proper labels and only showing some fields by default as well.

I also wish we'd focus efforts on one PR rather than creating alternate diverging approaches so early. Things will go very slowly if we constantly duplicate what we're working on. I could've done better on this as well, maybe I should've assigned the issue. Let's try to better coordinate efforts in the future.

@ramonjd
Copy link
Copy Markdown
Member

ramonjd commented Sep 11, 2025

Let's try to better coordinate efforts in the future.

I think it's okay to try out different directions for Core work, but this is an unusual project in that it was proposed late in the cycle. I guess we have the luxury of working behind an experiment and iterating until we get things right.

If the goal is to prototype with a view to request more fine-grained feedback, what can we work on in parallel?

@ramonjd
Copy link
Copy Markdown
Member

ramonjd commented Sep 11, 2025

@jeryj
Copy link
Copy Markdown
Contributor

jeryj commented Sep 11, 2025

I think it's okay to try out different directions for Core work, but this is an unusual project in that it was proposed late in the cycle. I guess we have the luxury of working behind an experiment and iterating until we get things right.

I think this is the central issue. We're trying to quickly figure out a thing that we're not sure what the end looks like. We're not trying to step on toes, but quickly iterate sketches so we can find what works. I can confidently say @getdave and I are NOT confident that this PR is the right direction. We are using this PR to see if it might be the right direction. This is very much a POC sketch of the idea to see if it breaks down.

UI-wise, I think it'd be good to lean closer to what was described in the issue too. So no drill down, instead something more like ToolsPanel.

In #71517 it says:

When we have more than one editable attribute (like alt text or captions on images) we collapse into an item group with a flyout menu or drilldown.

I'm not saying it's the right move, but that's how we're building the sidebar in this PR to see how it works.

@getdave getdave force-pushed the feature/attribute-controls-system branch from 0f030f7 to 25d4c67 Compare September 11, 2025 09:55
@jeryj
Copy link
Copy Markdown
Contributor

jeryj commented Sep 11, 2025

@talldan - thanks for testing this out! We're very much learning as we go here.

An example is that it's very easy to break image blocks by disconnecting the id from the url

I didn't know this - could you explain how to reproduce this?

I think links will present similar challenges, where there's rel, openInNewTab etc. that should be associated and part of the same control, and updating one attribute might change another.

I think those should be excluded from the content editing experience. Those are more advanced functionality than baseline experience IMO.

@talldan
Copy link
Copy Markdown
Contributor

talldan commented Sep 12, 2025

I didn't know this - could you explain how to reproduce this?

When adding a media library image to the block normally, both the id and url attributes are set to the correct value for the attachment. If I then change image to an external one (a non-media library image) the id is unset to reflect the image isn't sourced from an attachment.

In this PR you can change the image's url to something different, but the block's id always remains the same, so you can have a mismatch. Some parts of the code might think the attachment is still being used. Hard to say what kind of issues it might cause having a mismatch like that. I recall there's some dynamic PHP code somewhere in WordPress to add the srcset attribute to images on the frontend and it uses the id, so I think it's best to ensure it matches correctly.

I think what you'll need is a single control that manages both the id and the url. So you wouldn't just infer a single control per attribute, but sometimes you might need one control for multiple attributes. To determine which attribute represents the image src you could use these properties:

"selector": "img",
"attribute": "src",

Why? Because the video block needs to work the same way, but there the attribute is src instead of url.

Then I don't how you'd determine which is the id, it's just called id, which doesn't tell you much. It could be an html id on a different block:

"id": {
"type": "number",
"role": "content"
},

@talldan
Copy link
Copy Markdown
Contributor

talldan commented Sep 12, 2025

I'm not saying it's the right move, but that's how we're building the sidebar in this PR to see how it works.

I was leaning more towards ToolsPanel based on past sentiment when this kind of UI has been discussed. For example:
#57911 (comment). It's not the only place I've seen it mentioned, just the first one I found.

I did also ask a clarifying question about this in #71517 and this was the answer (#71517 (comment)):

The existing ToolsPanel UI could be a good fit. It's still not the perfect experience, but it's the closest fit I think we have if we want to re-use (and possibly improve) existing parts.

Yes, I think we can start there and see how it scales.

It was a somewhat closed question rather than an open one though.

Then there was a little bit extra about possibly using drilldown for complex blocks with hierarchy like List, but it still feels quite unclear to me how that will work. Maybe it'll be unusual having some blocks that drill down and others that don't, but I think it will already be the case no matter what.

I'm also thinking that we have ToolsPanel on every core block now as the default Inspector UI, so it might make sense from that perspective too.

@jeryj
Copy link
Copy Markdown
Contributor

jeryj commented Sep 12, 2025

I'm all in favor of reusing existing UI and components. This is very much a sketch to see if we can infer controls more than what UI we go with.

getdave and others added 13 commits September 17, 2025 08:42
- Display standardized UI controls for attributes with role: 'content'
- Support string, boolean, and rich-text attribute types
- String and rich-text render as TextControl
- Boolean renders as ToggleControl
- Controls appear under blockTitle in the sidebar
- Maintains block selection while editing attributes
- Implement Navigator component with home screen and block-specific sub-screens
- Add smart attribute display logic: inline for single attributes, navigation for multiple
- Show chevron arrow for blocks with >1 content attribute to indicate drill-down capability
- Create BlockContentAttributesView for detailed attribute editing in sub-view
- Add SingleContentAttributeControl component for reusable single attribute handling
- Maintain LinkControl with popover functionality for URL attributes
- Ensure only one block sub-view can be open at a time
- Provide 'Back' button to return to main view from sub-view
- Preserve existing inline display behavior for single content attributes
…d not be write mode editable

I think these attributes were added early in on write mode (see PR# 47936) and incorrectly assigned role content to id, ref, and title attributes.
This is not working. When encountering a paragraph or list block, it creates a content group and passes these blocks to a standalone unstyled editor. The issue is this editor instance is tied to the main editor.
This can keep getting refactored further. The media selector is working though by inferring a selector of img and attribute of src. This can then be expanded for better UI when that is determined.
@jasmussen
Copy link
Copy Markdown
Contributor

I'm coming back to this a bit late, I had some AFK. Thanks for the ping. Quick GIF:

test

I guess this is some work that precedes #71730 yes? I also just reviewed that. Both work well, though I tend to think 71730 works slightly better. The drilldown in the content pattern is impressive, I think this pattern can work especially well with complex blocks in contentOnly mode, a la Query Loop or Navigation (think site links), but less so for patterns where arguably it is beneficial to lock things down to what the pattern author has done, and be a bit more limiting in the options.

The main goal is to provide a simplified editing interface for complex blocks or groups of blocks. For mostly static visual patterns, my instinct would go towards not needing the drilldown.

@scruffian
Copy link
Copy Markdown
Contributor

Closing in favour of #71730

@scruffian scruffian closed this Sep 24, 2025
@youknowriad youknowriad deleted the feature/attribute-controls-system branch September 24, 2025 11:54
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] Experimental Experimental feature or API.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Patterns: in the sidebar, standardize representation of edit controls across blocks and patterns

7 participants