Skip to content

Commit d10c203

Browse files
SantosGuillamotgzioloartemiomorales
authored
Block Bindings: Bootstrap sources defined in the server (#63470)
* Move bindings registration to editor provider * Remove sources from editor provider * Create `registerCoreBlockBindingsSources` function * Add `updateBlockBindingsSource` action * Bootstrap sources defined in the server * Change registration to allow server bootstrap * Remove label from post meta and pattern overrides * Remove `updateBlockBindingsSource` * Use `bootstrapBlockBindingsSource` instead * Wrap server registration in the same function * Ensure label is provided when source is not bootstrapped * Remove old import * Add compat filter to expose server sources * Add e2e test * Check if the sources are already added * Change how label is managed * Remove type from object * Use blockBindingsSources name * Fixes from rebase * Add return back and warning * Add backport * Improve comments * Fix getValues/setValues after rebase * Adapt reducer and fixes * Revert args used in `addBlockBindingsSource` Co-authored-by: SantosGuillamot <santosguillamot@git.wordpress.org> Co-authored-by: gziolo <gziolo@git.wordpress.org> Co-authored-by: artemiomorales <artemiosans@git.wordpress.org>
1 parent d0b82da commit d10c203

File tree

15 files changed

+189
-17
lines changed

15 files changed

+189
-17
lines changed

backport-changelog/6.7/7020.md

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
https://github.com/WordPress/wordpress-develop/pull/7020
2+
3+
* https://github.com/WordPress/gutenberg/pull/63470
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
<?php
2+
/**
3+
* Temporary compatibility code for new functionalitites/changes related to block bindings APIs present in Gutenberg.
4+
*
5+
* @package gutenberg
6+
*/
7+
8+
/**
9+
* Adds the block bindings sources registered in the server to the editor settings.
10+
*
11+
* This allows them to be bootstrapped in the editor.
12+
*
13+
* @param array $settings The block editor settings from the `block_editor_settings_all` filter.
14+
* @return array The editor settings including the block bindings sources.
15+
*/
16+
function gutenberg_add_server_block_bindings_sources_to_editor_settings( $editor_settings ) {
17+
// Check if the sources are already exposed in the editor settings.
18+
if ( isset( $editor_settings['blockBindingsSources'] ) ) {
19+
return $editor_settings;
20+
}
21+
22+
$registered_block_bindings_sources = get_all_registered_block_bindings_sources();
23+
if ( ! empty( $registered_block_bindings_sources ) ) {
24+
// Initialize array.
25+
$editor_settings['blockBindingsSources'] = array();
26+
foreach ( $registered_block_bindings_sources as $source_name => $source_properties ) {
27+
// Add source with the label to editor settings.
28+
$editor_settings['blockBindingsSources'][ $source_name ] = array(
29+
'label' => $source_properties->label,
30+
);
31+
// Add `usesContext` property if exists.
32+
if ( ! empty( $source_properties->uses_context ) ) {
33+
$editor_settings['blockBindingsSources'][ $source_name ]['usesContext'] = $source_properties->uses_context;
34+
}
35+
}
36+
}
37+
return $editor_settings;
38+
}
39+
40+
add_filter( 'block_editor_settings_all', 'gutenberg_add_server_block_bindings_sources_to_editor_settings', 10 );

lib/load.php

+1
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,7 @@ function gutenberg_is_experiment_enabled( $name ) {
169169

170170
// WordPress 6.7 compat.
171171
require __DIR__ . '/compat/wordpress-6.7/blocks.php';
172+
require __DIR__ . '/compat/wordpress-6.7/block-bindings.php';
172173

173174
// Experimental features.
174175
require __DIR__ . '/experimental/block-editor-settings-mobile.php';

packages/blocks/src/api/registration.js

+18-5
Original file line numberDiff line numberDiff line change
@@ -769,7 +769,7 @@ export const unregisterBlockVariation = ( blockName, variationName ) => {
769769
*
770770
* @param {Object} source Properties of the source to be registered.
771771
* @param {string} source.name The unique and machine-readable name.
772-
* @param {string} source.label Human-readable label.
772+
* @param {string} [source.label] Human-readable label.
773773
* @param {Function} [source.getValues] Function to get the values from the source.
774774
* @param {Function} [source.setValues] Function to update multiple values connected to the source.
775775
* @param {Function} [source.getPlaceholder] Function to get the placeholder when the value is undefined.
@@ -800,11 +800,15 @@ export const registerBlockBindingsSource = ( source ) => {
800800
canUserEditValue,
801801
} = source;
802802

803-
// Check if the source is already registered.
804803
const existingSource = unlock(
805804
select( blocksStore )
806805
).getBlockBindingsSource( name );
807-
if ( existingSource ) {
806+
807+
/*
808+
* Check if the source has been already registered on the client.
809+
* If the `getValues` property is defined, it could be assumed the source is already registered.
810+
*/
811+
if ( existingSource?.getValues ) {
808812
warning(
809813
'Block bindings source "' + name + '" is already registered.'
810814
);
@@ -844,12 +848,21 @@ export const registerBlockBindingsSource = ( source ) => {
844848
}
845849

846850
// Check the `label` property is correct.
847-
if ( ! label ) {
851+
if ( label && existingSource?.label ) {
852+
warning(
853+
'Block bindings "' +
854+
name +
855+
'" source label is already defined in the server.'
856+
);
857+
return;
858+
}
859+
860+
if ( ! label && ! existingSource?.label ) {
848861
warning( 'Block bindings source must contain a label.' );
849862
return;
850863
}
851864

852-
if ( typeof label !== 'string' ) {
865+
if ( label && typeof label !== 'string' ) {
853866
warning( 'Block bindings source label must be a string.' );
854867
return;
855868
}

packages/blocks/src/api/test/registration.js

+17
Original file line numberDiff line numberDiff line change
@@ -1512,6 +1512,22 @@ describe( 'blocks', () => {
15121512
expect( getBlockBindingsSource( 'core/testing' ) ).toBeUndefined();
15131513
} );
15141514

1515+
it( 'should not override label from the server', () => {
1516+
// Simulate bootstrapping a source from the server registration.
1517+
registerBlockBindingsSource( {
1518+
name: 'core/server',
1519+
label: 'Server label',
1520+
} );
1521+
// Override the source with a different label in the client.
1522+
registerBlockBindingsSource( {
1523+
name: 'core/server',
1524+
label: 'Client label',
1525+
} );
1526+
expect( console ).toHaveWarnedWith(
1527+
'Block bindings "core/server" source label is already defined in the server.'
1528+
);
1529+
} );
1530+
15151531
// Check the `getValues` callback is correct.
15161532
it( 'should reject invalid getValues callback', () => {
15171533
registerBlockBindingsSource( {
@@ -1600,6 +1616,7 @@ describe( 'blocks', () => {
16001616
const source = {
16011617
name: 'core/test-source',
16021618
label: 'Test Source',
1619+
getValues: () => 'value',
16031620
};
16041621
registerBlockBindingsSource( source );
16051622
registerBlockBindingsSource( source );

packages/blocks/src/store/private-actions.js

+14
Original file line numberDiff line numberDiff line change
@@ -69,3 +69,17 @@ export function removeBlockBindingsSource( name ) {
6969
name,
7070
};
7171
}
72+
73+
/**
74+
* Add bootstrapped block bindings sources, usually initialized from the server.
75+
*
76+
* @param {string} source Name of the source to bootstrap.
77+
*/
78+
export function addBootstrappedBlockBindingsSource( source ) {
79+
return {
80+
type: 'ADD_BOOTSTRAPPED_BLOCK_BINDINGS_SOURCE',
81+
name: source.name,
82+
label: source.label,
83+
usesContext: source.usesContext,
84+
};
85+
}

packages/blocks/src/store/reducer.js

+10-1
Original file line numberDiff line numberDiff line change
@@ -377,13 +377,22 @@ export function blockBindingsSources( state = {}, action ) {
377377
return {
378378
...state,
379379
[ action.name ]: {
380-
label: action.label,
380+
// Don't override the label if it's already set.
381+
label: state[ action.name ]?.label || action.label,
381382
getValues: action.getValues,
382383
setValues: action.setValues,
383384
getPlaceholder: action.getPlaceholder,
384385
canUserEditValue: action.canUserEditValue,
385386
},
386387
};
388+
case 'ADD_BOOTSTRAPPED_BLOCK_BINDINGS_SOURCE':
389+
return {
390+
...state,
391+
[ action.name ]: {
392+
label: action.label,
393+
usesContext: action.usesContext,
394+
},
395+
};
387396
case 'REMOVE_BLOCK_BINDINGS_SOURCE':
388397
return omit( state, action.name );
389398
}

packages/e2e-tests/plugins/block-bindings.php

+13-3
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,19 @@
88
*/
99

1010
/**
11-
* Register custom fields.
11+
* Register custom fields and custom block bindings sources.
1212
*/
13-
function gutenberg_test_block_bindings_register_custom_fields() {
13+
function gutenberg_test_block_bindings_registration() {
14+
// Register custom block bindings sources.
15+
register_block_bindings_source(
16+
'core/server-source',
17+
array(
18+
'label' => 'Server Source',
19+
'get_value_callback' => function () {},
20+
)
21+
);
22+
23+
// Register custom fields.
1424
register_meta(
1525
'post',
1626
'text_custom_field',
@@ -51,4 +61,4 @@ function gutenberg_test_block_bindings_register_custom_fields() {
5161
)
5262
);
5363
}
54-
add_action( 'init', 'gutenberg_test_block_bindings_register_custom_fields' );
64+
add_action( 'init', 'gutenberg_test_block_bindings_registration' );

packages/edit-post/src/index.js

+2
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ const {
2929
BackButton: __experimentalMainDashboardButton,
3030
registerDefaultActions,
3131
registerCoreBlockBindingsSources,
32+
bootstrapBlockBindingsSourcesFromServer,
3233
} = unlock( editorPrivateApis );
3334

3435
/**
@@ -87,6 +88,7 @@ export function initializeEditor(
8788
}
8889

8990
registerCoreBlocks();
91+
bootstrapBlockBindingsSourcesFromServer( settings?.blockBindingsSources );
9092
registerCoreBlockBindingsSources();
9193
registerLegacyWidgetBlock( { inserter: false } );
9294
registerWidgetGroupBlock( { inserter: false } );

packages/edit-site/src/index.js

+6-2
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,11 @@ import { store as editSiteStore } from './store';
2828
import { unlock } from './lock-unlock';
2929
import App from './components/app';
3030

31-
const { registerDefaultActions, registerCoreBlockBindingsSources } =
32-
unlock( editorPrivateApis );
31+
const {
32+
registerDefaultActions,
33+
registerCoreBlockBindingsSources,
34+
bootstrapBlockBindingsSourcesFromServer,
35+
} = unlock( editorPrivateApis );
3336

3437
/**
3538
* Initializes the site editor screen.
@@ -46,6 +49,7 @@ export function initializeEditor( id, settings ) {
4649
( { name } ) => name !== 'core/freeform'
4750
);
4851
registerCoreBlocks( coreBlocks );
52+
bootstrapBlockBindingsSourcesFromServer( settings?.blockBindingsSources );
4953
registerCoreBlockBindingsSources();
5054
dispatch( blocksStore ).setFreeformFallbackBlockName( 'core/html' );
5155
registerLegacyWidgetBlock( { inserter: false } );

packages/editor/src/bindings/api.js

+31-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
11
/**
22
* WordPress dependencies
33
*/
4-
import { privateApis as blocksPrivateApis } from '@wordpress/blocks';
4+
import {
5+
privateApis as blocksPrivateApis,
6+
store as blocksStore,
7+
} from '@wordpress/blocks';
8+
import { dispatch } from '@wordpress/data';
59

610
/**
711
* Internal dependencies
@@ -25,3 +29,29 @@ export function registerCoreBlockBindingsSources() {
2529
registerBlockBindingsSource( patternOverrides );
2630
registerBlockBindingsSource( postMeta );
2731
}
32+
33+
/**
34+
* Function to bootstrap core block bindings sources defined in the server.
35+
*
36+
* @param {Object} sources Object containing the sources to bootstrap.
37+
*
38+
* @example
39+
* ```js
40+
* import { bootstrapBlockBindingsSourcesFromServer } from '@wordpress/editor';
41+
*
42+
* bootstrapBlockBindingsSourcesFromServer( sources );
43+
* ```
44+
*/
45+
export function bootstrapBlockBindingsSourcesFromServer( sources ) {
46+
if ( sources ) {
47+
const { addBootstrappedBlockBindingsSource } = unlock(
48+
dispatch( blocksStore )
49+
);
50+
for ( const [ name, args ] of Object.entries( sources ) ) {
51+
addBootstrappedBlockBindingsSource( {
52+
name,
53+
...args,
54+
} );
55+
}
56+
}
57+
}

packages/editor/src/bindings/pattern-overrides.js

-2
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,12 @@
11
/**
22
* WordPress dependencies
33
*/
4-
import { _x } from '@wordpress/i18n';
54
import { store as blockEditorStore } from '@wordpress/block-editor';
65

76
const CONTENT = 'content';
87

98
export default {
109
name: 'core/pattern-overrides',
11-
label: _x( 'Pattern Overrides', 'block bindings source' ),
1210
getValues( { registry, clientId, context, bindings } ) {
1311
const patternOverridesContent = context[ 'pattern/overrides' ];
1412
const { getBlockAttributes } = registry.select( blockEditorStore );

packages/editor/src/bindings/post-meta.js

-2
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
* WordPress dependencies
33
*/
44
import { store as coreDataStore } from '@wordpress/core-data';
5-
import { _x } from '@wordpress/i18n';
65

76
/**
87
* Internal dependencies
@@ -11,7 +10,6 @@ import { store as editorStore } from '../store';
1110

1211
export default {
1312
name: 'core/post-meta',
14-
label: _x( 'Post Meta', 'block bindings source' ),
1513
getPlaceholder( { args } ) {
1614
return args.key;
1715
},

packages/editor/src/private-apis.js

+5-1
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,10 @@ import {
2424
GlobalStylesProvider,
2525
} from './components/global-styles-provider';
2626
import registerDefaultActions from './dataviews/actions';
27-
import { registerCoreBlockBindingsSources } from './bindings/api';
27+
import {
28+
registerCoreBlockBindingsSources,
29+
bootstrapBlockBindingsSourcesFromServer,
30+
} from './bindings/api';
2831

2932
const { store: interfaceStore, ...remainingInterfaceApis } = interfaceApis;
3033

@@ -45,6 +48,7 @@ lock( privateApis, {
4548
ResizableEditor,
4649
registerDefaultActions,
4750
registerCoreBlockBindingsSources,
51+
bootstrapBlockBindingsSourcesFromServer,
4852

4953
// This is a temporary private API while we're updating the site editor to use EditorProvider.
5054
useBlockEditorSettings,

test/e2e/specs/editor/various/block-bindings.spec.js

+29
Original file line numberDiff line numberDiff line change
@@ -2172,4 +2172,33 @@ test.describe( 'Block bindings', () => {
21722172
} );
21732173
} );
21742174
} );
2175+
2176+
test.describe( 'Sources registration', () => {
2177+
test.beforeEach( async ( { admin } ) => {
2178+
await admin.createNewPost( { title: 'Test bindings' } );
2179+
} );
2180+
2181+
test( 'should show the label of a source only registered in the server', async ( {
2182+
editor,
2183+
page,
2184+
} ) => {
2185+
await editor.insertBlock( {
2186+
name: 'core/paragraph',
2187+
attributes: {
2188+
metadata: {
2189+
bindings: {
2190+
content: {
2191+
source: 'core/server-source',
2192+
},
2193+
},
2194+
},
2195+
},
2196+
} );
2197+
2198+
const bindingLabel = page.locator(
2199+
'.components-item__block-bindings-source'
2200+
);
2201+
await expect( bindingLabel ).toHaveText( 'Server Source' );
2202+
} );
2203+
} );
21752204
} );

0 commit comments

Comments
 (0)