From 691f11d6db8542ede22b4603a32f7ac312151f25 Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Mon, 6 Oct 2025 12:07:37 +0200 Subject: [PATCH 01/10] Block Bindings: Remove 'Bindings' panel from e2e test plugin --- .../e2e-tests/plugins/block-bindings/index.js | 45 +------------------ 1 file changed, 1 insertion(+), 44 deletions(-) diff --git a/packages/e2e-tests/plugins/block-bindings/index.js b/packages/e2e-tests/plugins/block-bindings/index.js index c0bd9d67d6f901..c0812c99a3d69e 100644 --- a/packages/e2e-tests/plugins/block-bindings/index.js +++ b/packages/e2e-tests/plugins/block-bindings/index.js @@ -1,9 +1,5 @@ const { registerBlockBindingsSource } = wp.blocks; -const { InspectorControls } = wp.blockEditor; -const { PanelBody, TextControl } = wp.components; -const { createHigherOrderComponent } = wp.compose; -const { createElement: el, Fragment } = wp.element; -const { addFilter } = wp.hooks; +const { createElement: el } = wp.element; const { fieldsList } = window.testingBindings || {}; const getValues = ( { bindings } ) => { @@ -64,42 +60,3 @@ registerBlockBindingsSource( { getValues, canUserEditValue: () => true, } ); - -const withBlockBindingsInspectorControl = createHigherOrderComponent( - ( BlockEdit ) => { - return ( props ) => { - if ( ! props.attributes?.metadata?.bindings?.content ) { - return el( BlockEdit, props ); - } - - return el( - Fragment, - {}, - el( BlockEdit, props ), - el( - InspectorControls, - {}, - el( - PanelBody, - { title: 'Bindings' }, - el( TextControl, { - __next40pxDefaultSize: true, - label: 'Content', - value: props.attributes.content, - onChange: ( content ) => - props.setAttributes( { - content, - } ), - } ) - ) - ) - ); - }; - } -); - -addFilter( - 'editor.BlockEdit', - 'testing/bindings-inspector-control', - withBlockBindingsInspectorControl -); From 5b492af9d1e483b45d416c7849ebdca756eef791 Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Thu, 20 Nov 2025 17:58:55 +0100 Subject: [PATCH 02/10] Remove e2e test that was using custom component --- .../various/block-bindings/post-meta.spec.js | 40 ------------------- 1 file changed, 40 deletions(-) diff --git a/test/e2e/specs/editor/various/block-bindings/post-meta.spec.js b/test/e2e/specs/editor/various/block-bindings/post-meta.spec.js index 5506f9b2ded7dc..e45899b42887d5 100644 --- a/test/e2e/specs/editor/various/block-bindings/post-meta.spec.js +++ b/test/e2e/specs/editor/various/block-bindings/post-meta.spec.js @@ -536,46 +536,6 @@ test.describe( 'Post Meta source', () => { ).toHaveText( 'new value' ); } ); - test( 'should be possible to edit the value of the connected custom fields in the inspector control registered by the plugin', async ( { - editor, - page, - } ) => { - await editor.insertBlock( { - name: 'core/paragraph', - attributes: { - anchor: 'connected-paragraph', - content: 'fallback content', - metadata: { - bindings: { - content: { - source: 'core/post-meta', - args: { - key: 'movie_field', - }, - }, - }, - }, - }, - } ); - const contentInput = page.getByRole( 'textbox', { - name: 'Content', - } ); - await expect( contentInput ).toHaveValue( - 'Movie field default value' - ); - await contentInput.fill( 'new value' ); - // Check that the paragraph content attribute didn't change. - const [ paragraphBlockObject ] = await editor.getBlocks(); - expect( paragraphBlockObject.attributes.content ).toBe( - 'fallback content' - ); - // Check the value of the custom field is being updated by visiting the frontend. - const previewPage = await editor.openPreviewPage(); - await expect( - previewPage.locator( '#connected-paragraph' ) - ).toHaveText( 'new value' ); - } ); - test( 'should be possible to connect movie fields through the attributes panel', async ( { editor, page, From 69782e175677007a556d4f1517e5ed2949153074 Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Thu, 20 Nov 2025 18:00:27 +0100 Subject: [PATCH 03/10] Remove el variable --- packages/e2e-tests/plugins/block-bindings/index.js | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/e2e-tests/plugins/block-bindings/index.js b/packages/e2e-tests/plugins/block-bindings/index.js index c0812c99a3d69e..d87198c04fe8da 100644 --- a/packages/e2e-tests/plugins/block-bindings/index.js +++ b/packages/e2e-tests/plugins/block-bindings/index.js @@ -1,5 +1,4 @@ const { registerBlockBindingsSource } = wp.blocks; -const { createElement: el } = wp.element; const { fieldsList } = window.testingBindings || {}; const getValues = ( { bindings } ) => { From 29e17116f2bc6c24d8f8bf0b359195ab70113412 Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Thu, 8 Jan 2026 14:47:12 +0100 Subject: [PATCH 04/10] Remove now-obsolete dependencies --- packages/e2e-tests/plugins/block-bindings.php | 5 ----- 1 file changed, 5 deletions(-) diff --git a/packages/e2e-tests/plugins/block-bindings.php b/packages/e2e-tests/plugins/block-bindings.php index 944bfc332c447e..92331d2b654d27 100644 --- a/packages/e2e-tests/plugins/block-bindings.php +++ b/packages/e2e-tests/plugins/block-bindings.php @@ -46,11 +46,6 @@ function gutenberg_test_block_bindings_registration() { plugins_url( 'block-bindings/index.js', __FILE__ ), array( 'wp-blocks', - 'wp-block-editor', - 'wp-components', - 'wp-compose', - 'wp-element', - 'wp-hooks', ), filemtime( plugin_dir_path( __FILE__ ) . 'block-bindings/index.js' ), true From 85720c2285a3446748964da86e12a6c7b8adf702 Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Thu, 8 Jan 2026 14:47:46 +0100 Subject: [PATCH 05/10] Revert "Remove e2e test that was using custom component" This reverts commit 1983b5ca8e1351d351ad28883f660bde09f1c11f. --- .../various/block-bindings/post-meta.spec.js | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/test/e2e/specs/editor/various/block-bindings/post-meta.spec.js b/test/e2e/specs/editor/various/block-bindings/post-meta.spec.js index e45899b42887d5..5506f9b2ded7dc 100644 --- a/test/e2e/specs/editor/various/block-bindings/post-meta.spec.js +++ b/test/e2e/specs/editor/various/block-bindings/post-meta.spec.js @@ -536,6 +536,46 @@ test.describe( 'Post Meta source', () => { ).toHaveText( 'new value' ); } ); + test( 'should be possible to edit the value of the connected custom fields in the inspector control registered by the plugin', async ( { + editor, + page, + } ) => { + await editor.insertBlock( { + name: 'core/paragraph', + attributes: { + anchor: 'connected-paragraph', + content: 'fallback content', + metadata: { + bindings: { + content: { + source: 'core/post-meta', + args: { + key: 'movie_field', + }, + }, + }, + }, + }, + } ); + const contentInput = page.getByRole( 'textbox', { + name: 'Content', + } ); + await expect( contentInput ).toHaveValue( + 'Movie field default value' + ); + await contentInput.fill( 'new value' ); + // Check that the paragraph content attribute didn't change. + const [ paragraphBlockObject ] = await editor.getBlocks(); + expect( paragraphBlockObject.attributes.content ).toBe( + 'fallback content' + ); + // Check the value of the custom field is being updated by visiting the frontend. + const previewPage = await editor.openPreviewPage(); + await expect( + previewPage.locator( '#connected-paragraph' ) + ).toHaveText( 'new value' ); + } ); + test( 'should be possible to connect movie fields through the attributes panel', async ( { editor, page, From 140d730aef49984be45696aa6d5c94548e0d7a66 Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Thu, 8 Jan 2026 17:17:40 +0100 Subject: [PATCH 06/10] Use textbox added by contentOnly experiments for test --- .../various/block-bindings/post-meta.spec.js | 22 ++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/test/e2e/specs/editor/various/block-bindings/post-meta.spec.js b/test/e2e/specs/editor/various/block-bindings/post-meta.spec.js index 5506f9b2ded7dc..3122110be66d11 100644 --- a/test/e2e/specs/editor/various/block-bindings/post-meta.spec.js +++ b/test/e2e/specs/editor/various/block-bindings/post-meta.spec.js @@ -367,6 +367,13 @@ test.describe( 'Post Meta source', () => { } ); test.describe( 'Movie CPT post', () => { + test.beforeAll( async ( { requestUtils } ) => { + await requestUtils.setGutenbergExperiments( [ + 'gutenberg-content-only-pattern-insertion', + 'gutenberg-content-only-inspector-fields', + ] ); + } ); + test.beforeEach( async ( { admin } ) => { // CHECK HOW TO CREATE A MOVIE. await admin.createNewPost( { @@ -375,6 +382,11 @@ test.describe( 'Post Meta source', () => { } ); } ); + test.afterAll( async ( { requestUtils } ) => { + // Ensure experiments are disabled after test. + await requestUtils.setGutenbergExperiments( [] ); + } ); + test( 'should show the custom field value of that specific post', async ( { editor, } ) => { @@ -536,7 +548,7 @@ test.describe( 'Post Meta source', () => { ).toHaveText( 'new value' ); } ); - test( 'should be possible to edit the value of the connected custom fields in the inspector control registered by the plugin', async ( { + test( 'should be possible to edit the value of the connected custom fields in the inspector control registered by contentOnly experiments', async ( { editor, page, } ) => { @@ -557,12 +569,14 @@ test.describe( 'Post Meta source', () => { }, }, } ); + const contentInput = page.getByRole( 'textbox', { - name: 'Content', + label: 'Content', } ); - await expect( contentInput ).toHaveValue( + await expect( contentInput ).toHaveText( 'Movie field default value' ); + await contentInput.fill( 'new value' ); // Check that the paragraph content attribute didn't change. const [ paragraphBlockObject ] = await editor.getBlocks(); @@ -583,6 +597,7 @@ test.describe( 'Post Meta source', () => { await editor.insertBlock( { name: 'core/paragraph', } ); + await page.getByRole( 'tab', { name: 'Settings' } ).click(); await page.getByLabel( 'Attributes options' ).click(); await page .getByRole( 'menuitemcheckbox', { @@ -611,6 +626,7 @@ test.describe( 'Post Meta source', () => { await editor.insertBlock( { name: 'core/paragraph', } ); + await page.getByRole( 'tab', { name: 'Settings' } ).click(); await page.getByLabel( 'Attributes options' ).click(); await page .getByRole( 'menuitemcheckbox', { From 3210d8cc98cc67e02c0a54c47390a9dccc8bd7fd Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Mon, 12 Jan 2026 13:29:56 +0100 Subject: [PATCH 07/10] Enable gutenberg-content-only-inspector-fields experiment only --- test/e2e/specs/editor/various/block-bindings/post-meta.spec.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/test/e2e/specs/editor/various/block-bindings/post-meta.spec.js b/test/e2e/specs/editor/various/block-bindings/post-meta.spec.js index 3122110be66d11..901ace24f2fdc2 100644 --- a/test/e2e/specs/editor/various/block-bindings/post-meta.spec.js +++ b/test/e2e/specs/editor/various/block-bindings/post-meta.spec.js @@ -369,7 +369,6 @@ test.describe( 'Post Meta source', () => { test.describe( 'Movie CPT post', () => { test.beforeAll( async ( { requestUtils } ) => { await requestUtils.setGutenbergExperiments( [ - 'gutenberg-content-only-pattern-insertion', 'gutenberg-content-only-inspector-fields', ] ); } ); @@ -548,7 +547,7 @@ test.describe( 'Post Meta source', () => { ).toHaveText( 'new value' ); } ); - test( 'should be possible to edit the value of the connected custom fields in the inspector control registered by contentOnly experiments', async ( { + test( 'should be possible to edit the value of the connected custom fields in the inspector control registered by Block Fields experiment', async ( { editor, page, } ) => { From 0a8a932b2b5fc545197c7063a6f5939e1525168f Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Thu, 5 Feb 2026 18:57:13 +0100 Subject: [PATCH 08/10] Add fix --- .../src/hooks/block-fields/index.js | 28 +++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/packages/block-editor/src/hooks/block-fields/index.js b/packages/block-editor/src/hooks/block-fields/index.js index 72fac94ee1ac27..b56c4d17c857f0 100644 --- a/packages/block-editor/src/hooks/block-fields/index.js +++ b/packages/block-editor/src/hooks/block-fields/index.js @@ -4,6 +4,7 @@ import { privateApis as blocksPrivateApis, getBlockType, + store as blocksStore, } from '@wordpress/blocks'; import { __experimentalHStack as HStack, @@ -19,6 +20,7 @@ import { __ } from '@wordpress/i18n'; */ import { store as blockEditorStore } from '../../store'; import { unlock } from '../../lock-unlock'; +import BlockContext from '../../components/block-context'; import BlockIcon from '../../components/block-icon'; import useBlockDisplayTitle from '../../components/block-title/use-block-display-title'; import useBlockDisplayInformation from '../../components/use-block-display-information'; @@ -72,9 +74,31 @@ function BlockFields( { const blockTypeFields = blockType?.[ fieldsKey ]; + const blockContext = useContext( BlockContext ); + const attributes = useSelect( - ( select ) => select( blockEditorStore ).getBlockAttributes( clientId ), - [ clientId ] + ( select ) => { + const _attributes = + select( blockEditorStore ).getBlockAttributes( clientId ); + if ( ! _attributes?.metadata?.bindings ) { + return _attributes; + } + + const { getBlockBindingsSource } = unlock( select( blocksStore ) ); + return Object.entries( _attributes.metadata.bindings ).reduce( + ( acc, [ attribute, binding ] ) => { + const source = getBlockBindingsSource( binding.source ); + const values = source.getValues( { + select, + context: blockContext, + bindings: { [ attribute ]: binding }, + } ); + return { ...acc, ...values }; + }, + _attributes + ); + }, + [ blockContext, clientId ] ); const computedForm = useMemo( () => { From 2571fd53750145b7673c32efb66150cde6e42c48 Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Thu, 5 Feb 2026 18:59:07 +0100 Subject: [PATCH 09/10] Remove excess newlines --- test/e2e/specs/editor/various/block-bindings/post-meta.spec.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/test/e2e/specs/editor/various/block-bindings/post-meta.spec.js b/test/e2e/specs/editor/various/block-bindings/post-meta.spec.js index 901ace24f2fdc2..9a8f591e0cc349 100644 --- a/test/e2e/specs/editor/various/block-bindings/post-meta.spec.js +++ b/test/e2e/specs/editor/various/block-bindings/post-meta.spec.js @@ -568,14 +568,12 @@ test.describe( 'Post Meta source', () => { }, }, } ); - const contentInput = page.getByRole( 'textbox', { label: 'Content', } ); await expect( contentInput ).toHaveText( 'Movie field default value' ); - await contentInput.fill( 'new value' ); // Check that the paragraph content attribute didn't change. const [ paragraphBlockObject ] = await editor.getBlocks(); From 82287fa008f217dacfdc00f8af5cc3c93542781d Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Mon, 9 Feb 2026 14:52:18 +0100 Subject: [PATCH 10/10] Guard against non-existing source --- packages/block-editor/src/hooks/block-fields/index.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/block-editor/src/hooks/block-fields/index.js b/packages/block-editor/src/hooks/block-fields/index.js index b56c4d17c857f0..01acb9db3031b6 100644 --- a/packages/block-editor/src/hooks/block-fields/index.js +++ b/packages/block-editor/src/hooks/block-fields/index.js @@ -88,6 +88,9 @@ function BlockFields( { return Object.entries( _attributes.metadata.bindings ).reduce( ( acc, [ attribute, binding ] ) => { const source = getBlockBindingsSource( binding.source ); + if ( ! source ) { + return acc; + } const values = source.getValues( { select, context: blockContext,