From e9936fb5bf5f7660f3afdf0f2de0bee851c72644 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dami=C3=A1n=20Su=C3=A1rez?= Date: Mon, 1 Apr 2024 08:45:06 +0100 Subject: [PATCH 1/9] rename constant name --- .../block-editor/src/hooks/use-bindings-attributes.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/packages/block-editor/src/hooks/use-bindings-attributes.js b/packages/block-editor/src/hooks/use-bindings-attributes.js index 5cd8cb46b3b7e7..81fed0bc4b2293 100644 --- a/packages/block-editor/src/hooks/use-bindings-attributes.js +++ b/packages/block-editor/src/hooks/use-bindings-attributes.js @@ -23,7 +23,7 @@ import { unlock } from '../lock-unlock'; * @return {WPHigherOrderComponent} Higher-order component. */ -const BLOCK_BINDINGS_ALLOWED_BLOCKS = { +const DEFAULT_BLOCK_BINDINGS_ALLOWED_BLOCKS = { 'core/paragraph': [ 'content' ], 'core/heading': [ 'content' ], 'core/image': [ 'url', 'title', 'alt' ], @@ -38,7 +38,7 @@ const BLOCK_BINDINGS_ALLOWED_BLOCKS = { * @return {boolean} Whether it is possible to bind the block to sources. */ export function canBindBlock( blockName ) { - return blockName in BLOCK_BINDINGS_ALLOWED_BLOCKS; + return blockName in DEFAULT_BLOCK_BINDINGS_ALLOWED_BLOCKS; } /** @@ -52,7 +52,9 @@ export function canBindBlock( blockName ) { export function canBindAttribute( blockName, attributeName ) { return ( canBindBlock( blockName ) && - BLOCK_BINDINGS_ALLOWED_BLOCKS[ blockName ].includes( attributeName ) + DEFAULT_BLOCK_BINDINGS_ALLOWED_BLOCKS[ blockName ].includes( + attributeName + ) ); } From 10ee3e6435a5e12f9f96052f0fb6e2d2893c42be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dami=C3=A1n=20Su=C3=A1rez?= Date: Mon, 1 Apr 2024 10:47:15 +0100 Subject: [PATCH 2/9] introduce settings object to source handler API --- packages/editor/src/bindings/post-meta.js | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/packages/editor/src/bindings/post-meta.js b/packages/editor/src/bindings/post-meta.js index 0d0c737d0eaf77..4e9c043904822e 100644 --- a/packages/editor/src/bindings/post-meta.js +++ b/packages/editor/src/bindings/post-meta.js @@ -41,4 +41,12 @@ export default { updateValue: updateMetaValue, }; }, + settings: { + blocks: { + 'core/paragraph': [ 'content' ], + 'core/heading': [ 'content' ], + 'core/image': [ 'url', 'title', 'alt' ], + 'core/button': [ 'url', 'text', 'linkTarget' ], + }, + }, }; From d3e993a37e1de9c9aed6305fa598175b7d44262f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dami=C3=A1n=20Su=C3=A1rez?= Date: Mon, 1 Apr 2024 10:47:51 +0100 Subject: [PATCH 3/9] add settings when registering source handler --- packages/blocks/src/store/private-actions.js | 1 + packages/blocks/src/store/reducer.js | 1 + 2 files changed, 2 insertions(+) diff --git a/packages/blocks/src/store/private-actions.js b/packages/blocks/src/store/private-actions.js index d609f70b91b55d..fa5e6ae4eafe03 100644 --- a/packages/blocks/src/store/private-actions.js +++ b/packages/blocks/src/store/private-actions.js @@ -52,6 +52,7 @@ export function registerBlockBindingsSource( source ) { sourceName: source.name, sourceLabel: source.label, useSource: source.useSource, + settings: source.settings, lockAttributesEditing: source.lockAttributesEditing, }; } diff --git a/packages/blocks/src/store/reducer.js b/packages/blocks/src/store/reducer.js index f92fb376b530a7..bf70fd3dffbbd7 100644 --- a/packages/blocks/src/store/reducer.js +++ b/packages/blocks/src/store/reducer.js @@ -390,6 +390,7 @@ export function blockBindingsSources( state = {}, action ) { [ action.sourceName ]: { label: action.sourceLabel, useSource: action.useSource, + settings: action.settings || {}, lockAttributesEditing: action.lockAttributesEditing ?? true, }, }; From 420a824f337827baf7ee1c67f02ee543a22b2d7d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dami=C3=A1n=20Su=C3=A1rez?= Date: Mon, 1 Apr 2024 10:49:16 +0100 Subject: [PATCH 4/9] check attr bindibility based on handler settings --- .../src/hooks/use-bindings-attributes.js | 80 ++++++++++++------- 1 file changed, 49 insertions(+), 31 deletions(-) diff --git a/packages/block-editor/src/hooks/use-bindings-attributes.js b/packages/block-editor/src/hooks/use-bindings-attributes.js index 81fed0bc4b2293..97e7caf1ef04e0 100644 --- a/packages/block-editor/src/hooks/use-bindings-attributes.js +++ b/packages/block-editor/src/hooks/use-bindings-attributes.js @@ -34,11 +34,15 @@ const DEFAULT_BLOCK_BINDINGS_ALLOWED_BLOCKS = { * Based on the given block name, * check if it is possible to bind the block. * - * @param {string} blockName - The block name. + * @param {string} blockName - The block name. + * @param {Object} allowBlocks - The allowed blocks settings. * @return {boolean} Whether it is possible to bind the block to sources. */ -export function canBindBlock( blockName ) { - return blockName in DEFAULT_BLOCK_BINDINGS_ALLOWED_BLOCKS; +export function canBindBlock( + blockName, + allowBlocks = DEFAULT_BLOCK_BINDINGS_ALLOWED_BLOCKS +) { + return blockName in allowBlocks; } /** @@ -47,14 +51,17 @@ export function canBindBlock( blockName ) { * * @param {string} blockName - The block name. * @param {string} attributeName - The attribute name. + * @param {Object} allowBlocks - The allowed blocks settings. * @return {boolean} Whether it is possible to bind the block attribute. */ -export function canBindAttribute( blockName, attributeName ) { +export function canBindAttribute( + blockName, + attributeName, + allowBlocks = DEFAULT_BLOCK_BINDINGS_ALLOWED_BLOCKS +) { return ( - canBindBlock( blockName ) && - DEFAULT_BLOCK_BINDINGS_ALLOWED_BLOCKS[ blockName ].includes( - attributeName - ) + canBindBlock( blockName, allowBlocks ) && + allowBlocks[ blockName ]?.includes( attributeName ) ); } @@ -65,7 +72,7 @@ export function canBindAttribute( blockName, attributeName ) { * @param {Object} props - The component props. * @param {string} props.attrName - The attribute name. * @param {Object} props.blockProps - The block props with bound attribute. - * @param {Object} props.source - Source handler. + * @param {Object} props.sourceHandler - Source handler. * @param {Object} props.args - The arguments to pass to the source. * @param {Function} props.onPropValueChange - The function to call when the attribute value changes. * @return {null} Data-handling component. Render nothing. @@ -74,10 +81,10 @@ const BindingConnector = ( { args, attrName, blockProps, - source, + sourceHandler, onPropValueChange, } ) => { - const { placeholder, value: propValue } = source.useSource( + const { placeholder, value: propValue } = sourceHandler.useSource( blockProps, args ); @@ -167,24 +174,43 @@ function BlockBindingBridge( { blockProps, bindings, onPropValueChange } ) { useSelect( blocksStore ) ).getAllBlockBindingsSources(); + /* + * Create binding object filtering + * only the attributes that can be bound. + */ + const allowBindings = Object.entries( bindings ).reduce( + ( acc, [ attrName, settings ] ) => { + const source = blockBindingsSources[ settings.source ]; + // Check if the block has a valid source handler. + if ( ! source?.useSource ) { + return false; + } + + // Check if the attribute can be bound. + const allowBlocks = source?.settings?.blocks; + if ( canBindAttribute( blockProps.name, attrName, allowBlocks ) ) { + acc[ attrName ] = { + ...settings, + handler: source, // populate the source handler. + }; + } + + return acc; + }, + {} + ); + return ( <> - { Object.entries( bindings ).map( - ( [ attrName, boundAttribute ] ) => { - // Bail early if the block doesn't have a valid source handler. - const source = - blockBindingsSources[ boundAttribute.source ]; - if ( ! source?.useSource ) { - return null; - } - + { Object.entries( allowBindings ).map( + ( [ attrName, settings ] ) => { return ( ); @@ -210,15 +236,7 @@ const withBlockBindingSupport = createHigherOrderComponent( [] ); - /* - * Create binding object filtering - * only the attributes that can be bound. - */ - const bindings = Object.fromEntries( - Object.entries( props.attributes.metadata?.bindings || {} ).filter( - ( [ attrName ] ) => canBindAttribute( props.name, attrName ) - ) - ); + const bindings = props.attributes.metadata?.bindings || {}; return ( <> From a61047d4c4461ddd2de70d47fb70e2aeec23a84f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dami=C3=A1n=20Su=C3=A1rez?= Date: Mon, 1 Apr 2024 11:12:49 +0100 Subject: [PATCH 5/9] do not extend when not bindings metadata attr --- .../src/hooks/use-bindings-attributes.js | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/packages/block-editor/src/hooks/use-bindings-attributes.js b/packages/block-editor/src/hooks/use-bindings-attributes.js index 97e7caf1ef04e0..565a196fd69d9a 100644 --- a/packages/block-editor/src/hooks/use-bindings-attributes.js +++ b/packages/block-editor/src/hooks/use-bindings-attributes.js @@ -236,17 +236,19 @@ const withBlockBindingSupport = createHigherOrderComponent( [] ); + // Bail early if the block has no bindings metadata attribute. const bindings = props.attributes.metadata?.bindings || {}; + if ( ! Object.keys( bindings ).length ) { + return ; + } return ( <> - { Object.keys( bindings ).length > 0 && ( - - ) } + Date: Mon, 1 Apr 2024 11:38:34 +0100 Subject: [PATCH 6/9] refact canBindBlock based on source handler settings --- .../src/hooks/use-bindings-attributes.js | 32 ++++++++++++------- 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/packages/block-editor/src/hooks/use-bindings-attributes.js b/packages/block-editor/src/hooks/use-bindings-attributes.js index 565a196fd69d9a..bcf43478989ff9 100644 --- a/packages/block-editor/src/hooks/use-bindings-attributes.js +++ b/packages/block-editor/src/hooks/use-bindings-attributes.js @@ -3,7 +3,7 @@ */ import { getBlockType, store as blocksStore } from '@wordpress/blocks'; import { createHigherOrderComponent } from '@wordpress/compose'; -import { useSelect } from '@wordpress/data'; +import { useSelect, select } from '@wordpress/data'; import { useLayoutEffect, useCallback, useState } from '@wordpress/element'; import { addFilter } from '@wordpress/hooks'; import { RichTextData } from '@wordpress/rich-text'; @@ -34,15 +34,26 @@ const DEFAULT_BLOCK_BINDINGS_ALLOWED_BLOCKS = { * Based on the given block name, * check if it is possible to bind the block. * - * @param {string} blockName - The block name. - * @param {Object} allowBlocks - The allowed blocks settings. + * @param {string} blockName - The block name. * @return {boolean} Whether it is possible to bind the block to sources. */ -export function canBindBlock( - blockName, - allowBlocks = DEFAULT_BLOCK_BINDINGS_ALLOWED_BLOCKS -) { - return blockName in allowBlocks; +export function canBindBlock( blockName ) { + // Pick blocks list from all source handlers settings. + const blockBindingsSources = unlock( + select( blocksStore ) + ).getAllBlockBindingsSources(); + + let blockNames = Object.keys( DEFAULT_BLOCK_BINDINGS_ALLOWED_BLOCKS ); + Object.keys( blockBindingsSources ).forEach( ( sourceName ) => { + const blocks = blockBindingsSources[ sourceName ].settings?.blocks; + if ( blocks ) { + blockNames.push( ...Object.keys( blocks ) ); + } + } ); + + blockNames = [ ...new Set( blockNames ) ]; + + return blockNames.includes( blockName ); } /** @@ -59,10 +70,7 @@ export function canBindAttribute( attributeName, allowBlocks = DEFAULT_BLOCK_BINDINGS_ALLOWED_BLOCKS ) { - return ( - canBindBlock( blockName, allowBlocks ) && - allowBlocks[ blockName ]?.includes( attributeName ) - ); + return allowBlocks[ blockName ]?.includes( attributeName ); } /** From cf6e1b131cd16987df41a3c1487b44f0e0df8f41 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dami=C3=A1n=20Su=C3=A1rez?= Date: Mon, 1 Apr 2024 11:41:30 +0100 Subject: [PATCH 7/9] update doc comments --- packages/block-editor/src/hooks/use-bindings-attributes.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/block-editor/src/hooks/use-bindings-attributes.js b/packages/block-editor/src/hooks/use-bindings-attributes.js index bcf43478989ff9..ab310ac5b8b47b 100644 --- a/packages/block-editor/src/hooks/use-bindings-attributes.js +++ b/packages/block-editor/src/hooks/use-bindings-attributes.js @@ -183,8 +183,9 @@ function BlockBindingBridge( { blockProps, bindings, onPropValueChange } ) { ).getAllBlockBindingsSources(); /* - * Create binding object filtering - * only the attributes that can be bound. + * Create allow binding object, + * filtering only the valid bindings, + * and populating the source handler. */ const allowBindings = Object.entries( bindings ).reduce( ( acc, [ attrName, settings ] ) => { From a9119f653c1d417a6bd485aad3c1ad1b075380e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dami=C3=A1n=20Su=C3=A1rez?= Date: Mon, 1 Apr 2024 11:44:10 +0100 Subject: [PATCH 8/9] rename const name --- .../block-editor/src/hooks/use-bindings-attributes.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/block-editor/src/hooks/use-bindings-attributes.js b/packages/block-editor/src/hooks/use-bindings-attributes.js index ab310ac5b8b47b..dbfe958bd75f7a 100644 --- a/packages/block-editor/src/hooks/use-bindings-attributes.js +++ b/packages/block-editor/src/hooks/use-bindings-attributes.js @@ -189,18 +189,18 @@ function BlockBindingBridge( { blockProps, bindings, onPropValueChange } ) { */ const allowBindings = Object.entries( bindings ).reduce( ( acc, [ attrName, settings ] ) => { - const source = blockBindingsSources[ settings.source ]; + const handler = blockBindingsSources[ settings.source ]; // Check if the block has a valid source handler. - if ( ! source?.useSource ) { + if ( ! handler?.useSource ) { return false; } // Check if the attribute can be bound. - const allowBlocks = source?.settings?.blocks; + const allowBlocks = handler?.settings?.blocks; if ( canBindAttribute( blockProps.name, attrName, allowBlocks ) ) { acc[ attrName ] = { ...settings, - handler: source, // populate the source handler. + handler, // populate the source handler. }; } From 3278a354eee39470f098d5674d1e284da57335a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dami=C3=A1n=20Su=C3=A1rez?= Date: Sat, 13 Apr 2024 11:59:14 +0100 Subject: [PATCH 9/9] fix typo --- .../block-editor/src/hooks/use-bindings-attributes.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/block-editor/src/hooks/use-bindings-attributes.js b/packages/block-editor/src/hooks/use-bindings-attributes.js index dbfe958bd75f7a..ff7a1409f3334c 100644 --- a/packages/block-editor/src/hooks/use-bindings-attributes.js +++ b/packages/block-editor/src/hooks/use-bindings-attributes.js @@ -100,7 +100,7 @@ const BindingConnector = ( { const { name: blockName } = blockProps; const attrValue = blockProps.attributes[ attrName ]; - const updateBoundAttibute = useCallback( + const updateBoundAttribute = useCallback( ( newAttrValue, prevAttrValue ) => { /* * If the attribute is a RichTextData instance, @@ -134,7 +134,7 @@ const BindingConnector = ( { useLayoutEffect( () => { if ( typeof propValue !== 'undefined' ) { - updateBoundAttibute( propValue, attrValue ); + updateBoundAttribute( propValue, attrValue ); } else if ( placeholder ) { /* * Placeholder fallback. @@ -147,14 +147,14 @@ const BindingConnector = ( { getBlockType( blockName ).attributes[ attrName ].attribute; if ( htmlAttribute === 'src' || htmlAttribute === 'href' ) { - updateBoundAttibute( null ); + updateBoundAttribute( null ); return; } - updateBoundAttibute( placeholder ); + updateBoundAttribute( placeholder ); } }, [ - updateBoundAttibute, + updateBoundAttribute, propValue, attrValue, placeholder,