Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Revert "Extensibility: Make Block Bindings work with editor.BlockEdit hook" #67516

Merged
merged 1 commit into from
Dec 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 2 additions & 10 deletions packages/block-editor/src/components/block-edit/edit.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,6 @@ import { useContext, useMemo } from '@wordpress/element';
* Internal dependencies
*/
import BlockContext from '../block-context';
import { withBlockBindingsSupport } from './with-block-bindings-support';
import { canBindBlock } from '../../utils/block-bindings';

/**
* Default value used for blocks which do not define their own context needs,
Expand Down Expand Up @@ -49,8 +47,6 @@ const Edit = ( props ) => {

const EditWithFilters = withFilters( 'editor.BlockEdit' )( Edit );

const EditWithFiltersAndBindings = withBlockBindingsSupport( EditWithFilters );

const EditWithGeneratedProps = ( props ) => {
const { attributes = {}, name } = props;
const blockType = getBlockType( name );
Expand All @@ -71,12 +67,8 @@ const EditWithGeneratedProps = ( props ) => {
return null;
}

const EditComponent = canBindBlock( name )
? EditWithFiltersAndBindings
: EditWithFilters;

if ( blockType.apiVersion > 1 ) {
return <EditComponent { ...props } context={ context } />;
return <EditWithFilters { ...props } context={ context } />;
}

// Generate a class name for the block's editable form.
Expand All @@ -90,7 +82,7 @@ const EditWithGeneratedProps = ( props ) => {
);

return (
<EditComponent
<EditWithFilters
{ ...props }
context={ context }
className={ className }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ import { useBlockRefProvider } from './use-block-refs';
import { useIntersectionObserver } from './use-intersection-observer';
import { useScrollIntoView } from './use-scroll-into-view';
import { useFlashEditableBlocks } from '../../use-flash-editable-blocks';
import { canBindBlock } from '../../../utils/block-bindings';
import { canBindBlock } from '../../../hooks/use-bindings-attributes';
import { useFirefoxDraggableCompatibility } from './use-firefox-draggable-compatibility';

/**
Expand Down
2 changes: 1 addition & 1 deletion packages/block-editor/src/components/rich-text/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ import FormatEdit from './format-edit';
import { getAllowedFormats } from './utils';
import { Content, valueToHTMLString } from './content';
import { withDeprecations } from './with-deprecations';
import { canBindBlock } from '../../utils/block-bindings';
import { canBindBlock } from '../../hooks/use-bindings-attributes';
import BlockContext from '../block-context';

export const keyboardShortcutContext = createContext();
Expand Down
10 changes: 5 additions & 5 deletions packages/block-editor/src/hooks/block-bindings.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,15 +23,15 @@ import { useViewportMatch } from '@wordpress/compose';
/**
* Internal dependencies
*/
import {
canBindAttribute,
getBindableAttributes,
} from '../hooks/use-bindings-attributes';
import { unlock } from '../lock-unlock';
import InspectorControls from '../components/inspector-controls';
import BlockContext from '../components/block-context';
import { useBlockEditContext } from '../components/block-edit';
import {
canBindAttribute,
getBindableAttributes,
useBlockBindingsUtils,
} from '../utils/block-bindings';
import { useBlockBindingsUtils } from '../utils/block-bindings';
import { store as blockEditorStore } from '../store';

const { Menu } = unlock( componentsPrivateApis );
Expand Down
1 change: 1 addition & 0 deletions packages/block-editor/src/hooks/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import './metadata';
import blockHooks from './block-hooks';
import blockBindingsPanel from './block-bindings';
import './block-renaming';
import './use-bindings-attributes';
import './grid-visualizer';

createBlockEditFilter(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,31 @@ import { store as blocksStore } from '@wordpress/blocks';
import { createHigherOrderComponent } from '@wordpress/compose';
import { useRegistry, useSelect } from '@wordpress/data';
import { useCallback, useMemo, useContext } from '@wordpress/element';
import { addFilter } from '@wordpress/hooks';

/**
* Internal dependencies
*/
import isURLLike from '../link-control/is-url-like';
import { unlock } from '../../lock-unlock';
import BlockContext from '../block-context';
import {
BLOCK_BINDINGS_ALLOWED_BLOCKS,
canBindAttribute,
} from '../../utils/block-bindings';
import isURLLike from '../components/link-control/is-url-like';
import { unlock } from '../lock-unlock';
import BlockContext from '../components/block-context';

/** @typedef {import('@wordpress/compose').WPHigherOrderComponent} WPHigherOrderComponent */
/** @typedef {import('@wordpress/blocks').WPBlockSettings} WPBlockSettings */

/**
* Given a binding of block attributes, returns a higher order component that
* overrides its `attributes` and `setAttributes` props to sync any changes needed.
*
* @return {WPHigherOrderComponent} Higher-order component.
*/

const BLOCK_BINDINGS_ALLOWED_BLOCKS = {
'core/paragraph': [ 'content' ],
'core/heading': [ 'content' ],
'core/image': [ 'id', 'url', 'title', 'alt' ],
'core/button': [ 'url', 'text', 'linkTarget', 'rel' ],
};

const DEFAULT_ATTRIBUTE = '__default';

Expand Down Expand Up @@ -55,12 +67,36 @@ function replacePatternOverrideDefaultBindings( blockName, bindings ) {
}

/**
* Given a binding of block attributes, returns a higher order component that
* overrides its `attributes` and `setAttributes` props to sync any changes needed.
* Based on the given block name,
* check if it is possible to bind the block.
*
* @return {WPHigherOrderComponent} Higher-order component.
* @param {string} blockName - The block name.
* @return {boolean} Whether it is possible to bind the block to sources.
*/
export const withBlockBindingsSupport = createHigherOrderComponent(
export function canBindBlock( blockName ) {
return blockName in BLOCK_BINDINGS_ALLOWED_BLOCKS;
}

/**
* Based on the given block name and attribute name,
* check if it is possible to bind the block attribute.
*
* @param {string} blockName - The block name.
* @param {string} attributeName - The attribute name.
* @return {boolean} Whether it is possible to bind the block attribute.
*/
export function canBindAttribute( blockName, attributeName ) {
return (
canBindBlock( blockName ) &&
BLOCK_BINDINGS_ALLOWED_BLOCKS[ blockName ].includes( attributeName )
);
}

export function getBindableAttributes( blockName ) {
return BLOCK_BINDINGS_ALLOWED_BLOCKS[ blockName ];
}

export const withBlockBindingSupport = createHigherOrderComponent(
( BlockEdit ) => ( props ) => {
const registry = useRegistry();
const blockContext = useContext( BlockContext );
Expand All @@ -72,9 +108,9 @@ export const withBlockBindingsSupport = createHigherOrderComponent(
() =>
replacePatternOverrideDefaultBindings(
name,
props.attributes?.metadata?.bindings
props.attributes.metadata?.bindings
),
[ props.attributes?.metadata?.bindings, name ]
[ props.attributes.metadata?.bindings, name ]
);

// While this hook doesn't directly call any selectors, `useSelect` is
Expand Down Expand Up @@ -160,7 +196,7 @@ export const withBlockBindingsSupport = createHigherOrderComponent(

const hasParentPattern = !! updatedContext[ 'pattern/overrides' ];
const hasPatternOverridesDefaultBinding =
props.attributes?.metadata?.bindings?.[ DEFAULT_ATTRIBUTE ]
props.attributes.metadata?.bindings?.[ DEFAULT_ATTRIBUTE ]
?.source === 'core/pattern-overrides';

const _setAttributes = useCallback(
Expand Down Expand Up @@ -247,13 +283,40 @@ export const withBlockBindingsSupport = createHigherOrderComponent(
);

return (
<BlockEdit
{ ...props }
attributes={ { ...props.attributes, ...boundAttributes } }
setAttributes={ _setAttributes }
context={ { ...context, ...updatedContext } }
/>
<>
<BlockEdit
{ ...props }
attributes={ { ...props.attributes, ...boundAttributes } }
setAttributes={ _setAttributes }
context={ { ...context, ...updatedContext } }
/>
</>
);
},
'withBlockBindingSupport'
);

/**
* Filters a registered block's settings to enhance a block's `edit` component
* to upgrade bound attributes.
*
* @param {WPBlockSettings} settings - Registered block settings.
* @param {string} name - Block name.
* @return {WPBlockSettings} Filtered block settings.
*/
function shimAttributeSource( settings, name ) {
if ( ! canBindBlock( name ) ) {
return settings;
}

return {
...settings,
edit: withBlockBindingSupport( settings.edit ),
};
}

addFilter(
'blocks.registerBlockType',
'core/editor/custom-sources-backwards-compatibility/shim-attribute-source',
shimAttributeSource
);
37 changes: 0 additions & 37 deletions packages/block-editor/src/utils/block-bindings.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,43 +13,6 @@ function isObjectEmpty( object ) {
return ! object || Object.keys( object ).length === 0;
}

export const BLOCK_BINDINGS_ALLOWED_BLOCKS = {
'core/paragraph': [ 'content' ],
'core/heading': [ 'content' ],
'core/image': [ 'id', 'url', 'title', 'alt' ],
'core/button': [ 'url', 'text', 'linkTarget', 'rel' ],
};

/**
* Based on the given block name,
* check if it is possible to bind the block.
*
* @param {string} blockName - The block name.
* @return {boolean} Whether it is possible to bind the block to sources.
*/
export function canBindBlock( blockName ) {
return blockName in BLOCK_BINDINGS_ALLOWED_BLOCKS;
}

/**
* Based on the given block name and attribute name,
* check if it is possible to bind the block attribute.
*
* @param {string} blockName - The block name.
* @param {string} attributeName - The attribute name.
* @return {boolean} Whether it is possible to bind the block attribute.
*/
export function canBindAttribute( blockName, attributeName ) {
return (
canBindBlock( blockName ) &&
BLOCK_BINDINGS_ALLOWED_BLOCKS[ blockName ].includes( attributeName )
);
}

export function getBindableAttributes( blockName ) {
return BLOCK_BINDINGS_ALLOWED_BLOCKS[ blockName ];
}

/**
* Contains utils to update the block `bindings` metadata.
*
Expand Down
6 changes: 1 addition & 5 deletions packages/e2e-tests/plugins/block-bindings.php
Original file line number Diff line number Diff line change
Expand Up @@ -41,11 +41,7 @@ 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',
'wp-private-apis',
),
filemtime( plugin_dir_path( __FILE__ ) . 'block-bindings/index.js' ),
true
Expand Down
45 changes: 0 additions & 45 deletions packages/e2e-tests/plugins/block-bindings/index.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,4 @@
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 { fieldsList } = window.testingBindings || {};

const getValues = ( { bindings } ) => {
Expand Down Expand Up @@ -51,43 +46,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,
__nextHasNoMarginBottom: true,
label: 'Content',
value: props.attributes.content,
onChange: ( content ) =>
props.setAttributes( {
content,
} ),
} )
)
)
);
};
}
);

addFilter(
'editor.BlockEdit',
'testing/bindings-inspector-control',
withBlockBindingsInspectorControl
);
41 changes: 0 additions & 41 deletions test/e2e/specs/editor/various/block-bindings/post-meta.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -524,47 +524,6 @@ test.describe( 'Post Meta source', () => {
previewPage.locator( '#connected-paragraph' )
).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,
Expand Down
Loading