diff --git a/backport-changelog/6.7/7258.md b/backport-changelog/6.7/7258.md
new file mode 100644
index 00000000000000..6714b13b70b8d2
--- /dev/null
+++ b/backport-changelog/6.7/7258.md
@@ -0,0 +1,3 @@
+https://github.com/WordPress/wordpress-develop/pull/7258
+
+* https://github.com/WordPress/gutenberg/pull/64570
\ No newline at end of file
diff --git a/lib/compat/wordpress-6.7/block-bindings.php b/lib/compat/wordpress-6.7/block-bindings.php
index 398b53b340673b..9e82c1843f35a0 100644
--- a/lib/compat/wordpress-6.7/block-bindings.php
+++ b/lib/compat/wordpress-6.7/block-bindings.php
@@ -38,3 +38,18 @@ function gutenberg_add_server_block_bindings_sources_to_editor_settings( $editor
}
add_filter( 'block_editor_settings_all', 'gutenberg_add_server_block_bindings_sources_to_editor_settings', 10 );
+
+/**
+ * Initialize `canUpdateBlockBindings` editor setting if it doesn't exist. By default, it is `true` only for admin users.
+ *
+ * @param array $settings The block editor settings from the `block_editor_settings_all` filter.
+ * @return array The editor settings including `canUpdateBlockBindings`.
+ */
+function gutenberg_add_can_update_block_bindings_editor_setting( $editor_settings ) {
+ if ( empty( $editor_settings['canUpdateBlockBindings'] ) ) {
+ $editor_settings['canUpdateBlockBindings'] = current_user_can( 'manage_options' );
+ }
+ return $editor_settings;
+}
+
+add_filter( 'block_editor_settings_all', 'gutenberg_add_can_update_block_bindings_editor_setting', 10 );
diff --git a/lib/experimental/editor-settings.php b/lib/experimental/editor-settings.php
index c6bd99a18bf4c7..cb9fddbb056a12 100644
--- a/lib/experimental/editor-settings.php
+++ b/lib/experimental/editor-settings.php
@@ -34,9 +34,6 @@ function gutenberg_enable_experiments() {
if ( $gutenberg_experiments && array_key_exists( 'gutenberg-quick-edit-dataviews', $gutenberg_experiments ) ) {
wp_add_inline_script( 'wp-block-editor', 'window.__experimentalQuickEditDataViews = true', 'before' );
}
- if ( $gutenberg_experiments && array_key_exists( 'gutenberg-block-bindings-ui', $gutenberg_experiments ) ) {
- wp_add_inline_script( 'wp-block-editor', 'window.__experimentalBlockBindingsUI = true', 'before' );
- }
if ( $gutenberg_experiments && array_key_exists( 'gutenberg-media-processing', $gutenberg_experiments ) ) {
wp_add_inline_script( 'wp-block-editor', 'window.__experimentalMediaProcessing = true', 'before' );
}
diff --git a/lib/experiments-page.php b/lib/experiments-page.php
index f76dcdca7d18cb..cccbab263c44fd 100644
--- a/lib/experiments-page.php
+++ b/lib/experiments-page.php
@@ -175,18 +175,6 @@ function gutenberg_initialize_experiments_settings() {
)
);
- add_settings_field(
- 'gutenberg-block-bindings-ui',
- __( 'UI to create block bindings', 'gutenberg' ),
- 'gutenberg_display_experiment_field',
- 'gutenberg-experiments',
- 'gutenberg_experiments_section',
- array(
- 'label' => __( 'Add UI to create and update block bindings in block inspector controls.', 'gutenberg' ),
- 'id' => 'gutenberg-block-bindings-ui',
- )
- );
-
add_settings_field(
'gutenberg-media-processing',
__( 'Client-side media processing', 'gutenberg' ),
diff --git a/packages/block-editor/src/components/block-inspector/index.js b/packages/block-editor/src/components/block-inspector/index.js
index 9daf29f8043bba..9c610e9e8c2d46 100644
--- a/packages/block-editor/src/components/block-inspector/index.js
+++ b/packages/block-editor/src/components/block-inspector/index.js
@@ -307,6 +307,7 @@ const BlockInspectorSingleBlock = ( { clientId, blockName } ) => {
/>
+
diff --git a/packages/block-editor/src/components/inspector-controls-tabs/settings-tab.js b/packages/block-editor/src/components/inspector-controls-tabs/settings-tab.js
index ec34035b754a91..ea2f45114bf9cf 100644
--- a/packages/block-editor/src/components/inspector-controls-tabs/settings-tab.js
+++ b/packages/block-editor/src/components/inspector-controls-tabs/settings-tab.js
@@ -9,6 +9,7 @@ const SettingsTab = ( { showAdvancedControls = false } ) => (
<>
+
{ showAdvancedControls && (
diff --git a/packages/block-editor/src/components/inspector-controls-tabs/use-inspector-controls-tabs.js b/packages/block-editor/src/components/inspector-controls-tabs/use-inspector-controls-tabs.js
index ff68be82a829f1..6a80d47f024816 100644
--- a/packages/block-editor/src/components/inspector-controls-tabs/use-inspector-controls-tabs.js
+++ b/packages/block-editor/src/components/inspector-controls-tabs/use-inspector-controls-tabs.js
@@ -32,6 +32,7 @@ function getShowTabs( blockName, tabSettings = {} ) {
export default function useInspectorControlsTabs( blockName ) {
const tabs = [];
const {
+ bindings: bindingsGroup,
border: borderGroup,
color: colorGroup,
default: defaultGroup,
@@ -64,8 +65,10 @@ export default function useInspectorControlsTabs( blockName ) {
// (i.e. both list view and styles), check only the default and position
// InspectorControls slots. If we have multiple tabs, we'll need to check
// the advanced controls slot as well to ensure they are rendered.
- const advancedFills =
- useSlotFills( InspectorAdvancedControls.slotName ) || [];
+ const advancedFills = [
+ ...( useSlotFills( InspectorAdvancedControls.slotName ) || [] ),
+ ...( useSlotFills( bindingsGroup.Slot.__unstableName ) || [] ),
+ ];
const settingsFills = [
...( useSlotFills( defaultGroup.Slot.__unstableName ) || [] ),
diff --git a/packages/block-editor/src/components/inspector-controls/groups.js b/packages/block-editor/src/components/inspector-controls/groups.js
index 9ca1a72b9918a6..34ec49a5e1cb41 100644
--- a/packages/block-editor/src/components/inspector-controls/groups.js
+++ b/packages/block-editor/src/components/inspector-controls/groups.js
@@ -5,6 +5,7 @@ import { createSlotFill } from '@wordpress/components';
const InspectorControlsDefault = createSlotFill( 'InspectorControls' );
const InspectorControlsAdvanced = createSlotFill( 'InspectorAdvancedControls' );
+const InspectorControlsBindings = createSlotFill( 'InspectorControlsBindings' );
const InspectorControlsBackground = createSlotFill(
'InspectorControlsBackground'
);
@@ -26,6 +27,7 @@ const groups = {
default: InspectorControlsDefault,
advanced: InspectorControlsAdvanced,
background: InspectorControlsBackground,
+ bindings: InspectorControlsBindings,
border: InspectorControlsBorder,
color: InspectorControlsColor,
dimensions: InspectorControlsDimensions,
diff --git a/packages/block-editor/src/hooks/block-bindings.js b/packages/block-editor/src/hooks/block-bindings.js
index 961a34f6f858fc..d015eca5af9926 100644
--- a/packages/block-editor/src/hooks/block-bindings.js
+++ b/packages/block-editor/src/hooks/block-bindings.js
@@ -13,7 +13,7 @@ import {
__experimentalVStack as VStack,
privateApis as componentsPrivateApis,
} from '@wordpress/components';
-import { useRegistry } from '@wordpress/data';
+import { useRegistry, useSelect } from '@wordpress/data';
import { useContext, Fragment } from '@wordpress/element';
import { useViewportMatch } from '@wordpress/compose';
@@ -28,6 +28,7 @@ import { unlock } from '../lock-unlock';
import InspectorControls from '../components/inspector-controls';
import BlockContext from '../components/block-context';
import { useBlockBindingsUtils } from '../utils/block-bindings';
+import { store as blockEditorStore } from '../store';
const { DropdownMenuV2 } = unlock( componentsPrivateApis );
@@ -201,6 +202,13 @@ export const BlockBindingsPanel = ( { name: blockName, metadata } ) => {
}
} );
+ const { canUpdateBlockBindings } = useSelect( ( select ) => {
+ return {
+ canUpdateBlockBindings:
+ select( blockEditorStore ).getSettings().canUpdateBlockBindings,
+ };
+ }, [] );
+
if ( ! bindableAttributes || bindableAttributes.length === 0 ) {
return null;
}
@@ -236,17 +244,16 @@ export const BlockBindingsPanel = ( { name: blockName, metadata } ) => {
}
} );
- // Lock the UI when the experiment is not enabled or there are no fields to connect to.
+ // Lock the UI when the user can't update bindings or there are no fields to connect to.
const readOnly =
- ! window.__experimentalBlockBindingsUI ||
- ! Object.keys( fieldsList ).length;
+ ! canUpdateBlockBindings || ! Object.keys( fieldsList ).length;
if ( readOnly && Object.keys( filteredBindings ).length === 0 ) {
return null;
}
return (
-
+
{
@@ -268,9 +275,13 @@ export const BlockBindingsPanel = ( { name: blockName, metadata } ) => {
/>
) }
-
- { __( 'Attributes connected to various sources.' ) }
-
+
+
+ { __(
+ 'Attributes connected to custom fields or other dynamic data.'
+ ) }
+
+
);
diff --git a/packages/editor/src/components/provider/use-block-editor-settings.js b/packages/editor/src/components/provider/use-block-editor-settings.js
index 6aa2763cf9db06..48290caefc158e 100644
--- a/packages/editor/src/components/provider/use-block-editor-settings.js
+++ b/packages/editor/src/components/provider/use-block-editor-settings.js
@@ -47,6 +47,7 @@ const BLOCK_EDITOR_SETTINGS = [
'allowedMimeTypes',
'bodyPlaceholder',
'canLockBlocks',
+ 'canUpdateBlockBindings',
'capabilities',
'clearBlockSelection',
'codeEditingEnabled',
diff --git a/test/e2e/specs/editor/various/block-bindings.spec.js b/test/e2e/specs/editor/various/block-bindings.spec.js
index d0e1f079ce8439..5feda2bdc3334a 100644
--- a/test/e2e/specs/editor/various/block-bindings.spec.js
+++ b/test/e2e/specs/editor/various/block-bindings.spec.js
@@ -1394,20 +1394,10 @@ test.describe( 'Block bindings', () => {
editor,
page,
} ) => {
- // Activate the block bindings UI experiment.
- await page.evaluate( () => {
- window.__experimentalBlockBindingsUI = true;
- } );
-
await editor.insertBlock( {
name: 'core/paragraph',
} );
- await page
- .getByRole( 'tabpanel', {
- name: 'Settings',
- } )
- .getByLabel( 'Attributes options' )
- .click();
+ await page.getByLabel( 'Attributes options' ).click();
const contentAttribute = page.getByRole( 'menuitemcheckbox', {
name: 'Show content',
} );
@@ -1417,11 +1407,6 @@ test.describe( 'Block bindings', () => {
editor,
page,
} ) => {
- // Activate the block bindings UI experiment.
- await page.evaluate( () => {
- window.__experimentalBlockBindingsUI = true;
- } );
-
await editor.insertBlock( {
name: 'core/paragraph',
attributes: {
@@ -1436,12 +1421,7 @@ test.describe( 'Block bindings', () => {
},
},
} );
- await page
- .getByRole( 'tabpanel', {
- name: 'Settings',
- } )
- .getByRole( 'button', { name: 'content' } )
- .click();
+ await page.getByRole( 'button', { name: 'content' } ).click();
await page
.getByRole( 'menuitemradio' )
@@ -1539,20 +1519,10 @@ test.describe( 'Block bindings', () => {
editor,
page,
} ) => {
- // Activate the block bindings UI experiment.
- await page.evaluate( () => {
- window.__experimentalBlockBindingsUI = true;
- } );
-
await editor.insertBlock( {
name: 'core/heading',
} );
- await page
- .getByRole( 'tabpanel', {
- name: 'Settings',
- } )
- .getByLabel( 'Attributes options' )
- .click();
+ await page.getByLabel( 'Attributes options' ).click();
const contentAttribute = page.getByRole( 'menuitemcheckbox', {
name: 'Show content',
} );
@@ -1739,11 +1709,6 @@ test.describe( 'Block bindings', () => {
editor,
page,
} ) => {
- // Activate the block bindings UI experiment.
- await page.evaluate( () => {
- window.__experimentalBlockBindingsUI = true;
- } );
-
await editor.insertBlock( {
name: 'core/buttons',
innerBlocks: [
@@ -2074,11 +2039,6 @@ test.describe( 'Block bindings', () => {
editor,
page,
} ) => {
- // Activate the block bindings UI experiment.
- await page.evaluate( () => {
- window.__experimentalBlockBindingsUI = true;
- } );
-
await editor.insertBlock( {
name: 'core/image',
} );
@@ -2367,11 +2327,9 @@ test.describe( 'Block bindings', () => {
},
} );
- const bindingsPanel = page
- .getByRole( 'tabpanel', {
- name: 'Settings',
- } )
- .locator( '.block-editor-bindings__panel' );
+ const bindingsPanel = page.locator(
+ '.block-editor-bindings__panel'
+ );
await expect( bindingsPanel ).toContainText( 'Server Source' );
} );
} );