From 94fd308e3325bd260e1cb620b092c06091b1085f Mon Sep 17 00:00:00 2001 From: Mario Santos Date: Tue, 25 Jun 2024 12:29:05 +0200 Subject: [PATCH 01/10] Remove only supported attributes --- .../src/hooks/use-bindings-attributes.js | 31 ++++++++++++++----- 1 file changed, 24 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 7bd5df05d31eb..e09149b0be391 100644 --- a/packages/block-editor/src/hooks/use-bindings-attributes.js +++ b/packages/block-editor/src/hooks/use-bindings-attributes.js @@ -216,13 +216,30 @@ export const withBlockBindingSupport = createHigherOrderComponent( } } - // Only apply normal attribute updates to blocks - // that have partial bindings. Currently this is - // only skipped for pattern overrides sources. - if ( - ! hasPatternOverridesDefaultBinding && - Object.keys( keptAttributes ).length - ) { + // Don't update block attributes connected to pattern overrides. + if ( hasPatternOverridesDefaultBinding ) { + // Skip caption and href until they are supported. + const attributesToSkip = [ 'caption', 'href' ]; + // Skip supported attributes that are not bound to other sources. + BLOCK_BINDINGS_ALLOWED_BLOCKS[ name ].forEach( + ( attr ) => { + // Ensure it is bound to pattern overrides. + if ( + bindings?.[ attr ]?.source === + 'core/pattern-overrides' + ) { + attributesToSkip.push( attr ); + } + } + ); + + // Remove attributes from the list. + attributesToSkip.forEach( + ( attr ) => delete keptAttributes[ attr ] + ); + } + + if ( Object.keys( keptAttributes ).length ) { setAttributes( keptAttributes ); } } ); From 61eb825cd7910381243c427e1fe0cf2aa5c33bfd Mon Sep 17 00:00:00 2001 From: Mario Santos Date: Tue, 25 Jun 2024 13:01:32 +0200 Subject: [PATCH 02/10] Try alternative approach --- .../src/hooks/use-bindings-attributes.js | 60 ++++++++++--------- 1 file changed, 33 insertions(+), 27 deletions(-) diff --git a/packages/block-editor/src/hooks/use-bindings-attributes.js b/packages/block-editor/src/hooks/use-bindings-attributes.js index e09149b0be391..17222f0dc9380 100644 --- a/packages/block-editor/src/hooks/use-bindings-attributes.js +++ b/packages/block-editor/src/hooks/use-bindings-attributes.js @@ -11,6 +11,7 @@ import { addFilter } from '@wordpress/hooks'; * Internal dependencies */ import { unlock } from '../lock-unlock'; +import { store as blockEditorStore } from '../store'; /** @typedef {import('@wordpress/compose').WPHigherOrderComponent} WPHigherOrderComponent */ /** @typedef {import('@wordpress/blocks').WPBlockSettings} WPBlockSettings */ @@ -93,10 +94,25 @@ export function canBindAttribute( blockName, attributeName ) { export const withBlockBindingSupport = createHigherOrderComponent( ( BlockEdit ) => ( props ) => { const registry = useRegistry(); - const sources = useSelect( ( select ) => - unlock( select( blocksStore ) ).getAllBlockBindingsSources() - ); const { name, clientId, context } = props; + const { sources, hasParentPattern } = useSelect( + ( select ) => { + const { getAllBlockBindingsSources } = unlock( + select( blocksStore ) + ); + const { getBlockParentsByBlockName } = unlock( + select( blockEditorStore ) + ); + + return { + sources: getAllBlockBindingsSources(), + hasParentPattern: + getBlockParentsByBlockName( clientId, 'core/block' ) + .length > 0, + }; + }, + [ clientId ] + ); const hasPatternOverridesDefaultBinding = props.attributes.metadata?.bindings?.[ DEFAULT_ATTRIBUTE ] ?.source === 'core/pattern-overrides'; @@ -216,30 +232,20 @@ export const withBlockBindingSupport = createHigherOrderComponent( } } - // Don't update block attributes connected to pattern overrides. - if ( hasPatternOverridesDefaultBinding ) { - // Skip caption and href until they are supported. - const attributesToSkip = [ 'caption', 'href' ]; - // Skip supported attributes that are not bound to other sources. - BLOCK_BINDINGS_ALLOWED_BLOCKS[ name ].forEach( - ( attr ) => { - // Ensure it is bound to pattern overrides. - if ( - bindings?.[ attr ]?.source === - 'core/pattern-overrides' - ) { - attributesToSkip.push( attr ); - } - } - ); - - // Remove attributes from the list. - attributesToSkip.forEach( - ( attr ) => delete keptAttributes[ attr ] - ); - } - - if ( Object.keys( keptAttributes ).length ) { + if ( + // Don't update non-connected attributes when using if the block is overriden + // and the editing is happening while using the pattern (not editing the original). + ! ( + hasPatternOverridesDefaultBinding && + hasParentPattern + ) && + Object.keys( keptAttributes ).length + ) { + // Don't update caption and href until they are supported. + if ( hasPatternOverridesDefaultBinding ) { + delete keptAttributes?.caption; + delete keptAttributes?.href; + } setAttributes( keptAttributes ); } } ); From 1980e79b79b7df97f52d0cdb5e0aad950ac53e52 Mon Sep 17 00:00:00 2001 From: Mario Santos Date: Tue, 25 Jun 2024 13:03:15 +0200 Subject: [PATCH 03/10] Update comment --- packages/block-editor/src/hooks/use-bindings-attributes.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/block-editor/src/hooks/use-bindings-attributes.js b/packages/block-editor/src/hooks/use-bindings-attributes.js index 17222f0dc9380..e7ec06117c611 100644 --- a/packages/block-editor/src/hooks/use-bindings-attributes.js +++ b/packages/block-editor/src/hooks/use-bindings-attributes.js @@ -233,7 +233,7 @@ export const withBlockBindingSupport = createHigherOrderComponent( } if ( - // Don't update non-connected attributes when using if the block is overriden + // Don't update non-connected attributes if the block is using pattern overrides // and the editing is happening while using the pattern (not editing the original). ! ( hasPatternOverridesDefaultBinding && From fff77d4fbffc154ad0f11862bfa9545793b2086e Mon Sep 17 00:00:00 2001 From: Mario Santos Date: Tue, 25 Jun 2024 15:03:40 +0200 Subject: [PATCH 04/10] Return early while editing the original pattern --- .../src/hooks/use-bindings-attributes.js | 29 ++++++++++++------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/packages/block-editor/src/hooks/use-bindings-attributes.js b/packages/block-editor/src/hooks/use-bindings-attributes.js index e7ec06117c611..98fbfe4ceb974 100644 --- a/packages/block-editor/src/hooks/use-bindings-attributes.js +++ b/packages/block-editor/src/hooks/use-bindings-attributes.js @@ -176,6 +176,20 @@ export const withBlockBindingSupport = createHigherOrderComponent( } const keptAttributes = { ...nextAttributes }; + + // Don't update caption and href in pattern overrides until they are supported. + if ( hasPatternOverridesDefaultBinding ) { + delete keptAttributes?.caption; + delete keptAttributes?.href; + } + + // Don't run bindings logic when a block is using pattern overrides but + // the user is editing the original pattern. + if ( ! hasParentPattern ) { + setAttributes( keptAttributes ); + return; + } + const updatesBySource = new Map(); // Loop only over the updated attributes to avoid modifying the bound ones that haven't changed. @@ -232,20 +246,13 @@ export const withBlockBindingSupport = createHigherOrderComponent( } } + // Only apply normal attribute updates to blocks + // that have partial bindings. Currently this is + // only skipped for pattern overrides sources. if ( - // Don't update non-connected attributes if the block is using pattern overrides - // and the editing is happening while using the pattern (not editing the original). - ! ( - hasPatternOverridesDefaultBinding && - hasParentPattern - ) && + ! hasPatternOverridesDefaultBinding && Object.keys( keptAttributes ).length ) { - // Don't update caption and href until they are supported. - if ( hasPatternOverridesDefaultBinding ) { - delete keptAttributes?.caption; - delete keptAttributes?.href; - } setAttributes( keptAttributes ); } } ); From 4faa8bb6c9e14b01a6c09e83a98b948884117a80 Mon Sep 17 00:00:00 2001 From: Mario Santos Date: Tue, 25 Jun 2024 15:06:26 +0200 Subject: [PATCH 05/10] Move conditional inside conditional --- .../block-editor/src/hooks/use-bindings-attributes.js | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/packages/block-editor/src/hooks/use-bindings-attributes.js b/packages/block-editor/src/hooks/use-bindings-attributes.js index 98fbfe4ceb974..004603f1e2d92 100644 --- a/packages/block-editor/src/hooks/use-bindings-attributes.js +++ b/packages/block-editor/src/hooks/use-bindings-attributes.js @@ -177,15 +177,13 @@ export const withBlockBindingSupport = createHigherOrderComponent( const keptAttributes = { ...nextAttributes }; - // Don't update caption and href in pattern overrides until they are supported. - if ( hasPatternOverridesDefaultBinding ) { - delete keptAttributes?.caption; - delete keptAttributes?.href; - } - // Don't run bindings logic when a block is using pattern overrides but // the user is editing the original pattern. if ( ! hasParentPattern ) { + // Don't update caption and href in pattern overrides until they are supported. + delete keptAttributes?.caption; + delete keptAttributes?.href; + setAttributes( keptAttributes ); return; } From 46d01adfddf8a44f5b5fa3382778108a5a5573bd Mon Sep 17 00:00:00 2001 From: Mario Santos Date: Tue, 25 Jun 2024 15:45:33 +0200 Subject: [PATCH 06/10] Add missing check --- packages/block-editor/src/hooks/use-bindings-attributes.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/block-editor/src/hooks/use-bindings-attributes.js b/packages/block-editor/src/hooks/use-bindings-attributes.js index 004603f1e2d92..e991e519ebb42 100644 --- a/packages/block-editor/src/hooks/use-bindings-attributes.js +++ b/packages/block-editor/src/hooks/use-bindings-attributes.js @@ -179,7 +179,10 @@ export const withBlockBindingSupport = createHigherOrderComponent( // Don't run bindings logic when a block is using pattern overrides but // the user is editing the original pattern. - if ( ! hasParentPattern ) { + if ( + ! hasParentPattern && + hasPatternOverridesDefaultBinding + ) { // Don't update caption and href in pattern overrides until they are supported. delete keptAttributes?.caption; delete keptAttributes?.href; From e1bdd7e0f6f998fb235b688795ca29b4bd6b59ed Mon Sep 17 00:00:00 2001 From: Mario Santos Date: Tue, 25 Jun 2024 16:10:56 +0200 Subject: [PATCH 07/10] Go back to running always bindings --- .../src/hooks/use-bindings-attributes.js | 29 +++++++------------ 1 file changed, 11 insertions(+), 18 deletions(-) diff --git a/packages/block-editor/src/hooks/use-bindings-attributes.js b/packages/block-editor/src/hooks/use-bindings-attributes.js index e991e519ebb42..a0757bbb6d386 100644 --- a/packages/block-editor/src/hooks/use-bindings-attributes.js +++ b/packages/block-editor/src/hooks/use-bindings-attributes.js @@ -177,20 +177,6 @@ export const withBlockBindingSupport = createHigherOrderComponent( const keptAttributes = { ...nextAttributes }; - // Don't run bindings logic when a block is using pattern overrides but - // the user is editing the original pattern. - if ( - ! hasParentPattern && - hasPatternOverridesDefaultBinding - ) { - // Don't update caption and href in pattern overrides until they are supported. - delete keptAttributes?.caption; - delete keptAttributes?.href; - - setAttributes( keptAttributes ); - return; - } - const updatesBySource = new Map(); // Loop only over the updated attributes to avoid modifying the bound ones that haven't changed. @@ -247,13 +233,20 @@ export const withBlockBindingSupport = createHigherOrderComponent( } } - // Only apply normal attribute updates to blocks - // that have partial bindings. Currently this is - // only skipped for pattern overrides sources. if ( - ! hasPatternOverridesDefaultBinding && + // Don't update non-connected attributes if the block is using pattern overrides + // and the editing is happening while overriding the pattern (not editing the original). + ! ( + hasPatternOverridesDefaultBinding && + hasParentPattern + ) && Object.keys( keptAttributes ).length ) { + // Don't update caption and href until they are supported. + if ( hasPatternOverridesDefaultBinding ) { + delete keptAttributes?.caption; + delete keptAttributes?.href; + } setAttributes( keptAttributes ); } } ); From 9ee6ad33aecce663ffce256f69cb23ba5030382c Mon Sep 17 00:00:00 2001 From: Daniel Richards Date: Wed, 26 Jun 2024 19:42:35 +0800 Subject: [PATCH 08/10] Use block context to detect presence of parent pattern for overrides (#62861) * Use block context to detect presence of parent pattern * Regenerate fixtures * Update image block to use context for checking a parent pattern block exists * Rename context to `pattern/overrides` to be consistent with php code * Move pattern overrides context shim to pattern overrides hooks * Remove shim Co-authored-by: talldan Co-authored-by: ellatrix Co-authored-by: SantosGuillamot --- .../src/hooks/use-bindings-attributes.js | 32 ++++++------------- packages/block-library/src/block/block.json | 6 +++- packages/block-library/src/image/image.js | 13 ++++---- .../editor/src/bindings/pattern-overrides.js | 19 ++++++----- .../editor/src/hooks/pattern-overrides.js | 5 ++- .../fixtures/blocks/core__block.json | 3 +- 6 files changed, 37 insertions(+), 41 deletions(-) diff --git a/packages/block-editor/src/hooks/use-bindings-attributes.js b/packages/block-editor/src/hooks/use-bindings-attributes.js index a0757bbb6d386..e3ff6436ebea3 100644 --- a/packages/block-editor/src/hooks/use-bindings-attributes.js +++ b/packages/block-editor/src/hooks/use-bindings-attributes.js @@ -11,7 +11,6 @@ import { addFilter } from '@wordpress/hooks'; * Internal dependencies */ import { unlock } from '../lock-unlock'; -import { store as blockEditorStore } from '../store'; /** @typedef {import('@wordpress/compose').WPHigherOrderComponent} WPHigherOrderComponent */ /** @typedef {import('@wordpress/blocks').WPBlockSettings} WPBlockSettings */ @@ -95,24 +94,12 @@ export const withBlockBindingSupport = createHigherOrderComponent( ( BlockEdit ) => ( props ) => { const registry = useRegistry(); const { name, clientId, context } = props; - const { sources, hasParentPattern } = useSelect( - ( select ) => { - const { getAllBlockBindingsSources } = unlock( - select( blocksStore ) - ); - const { getBlockParentsByBlockName } = unlock( - select( blockEditorStore ) - ); - - return { - sources: getAllBlockBindingsSources(), - hasParentPattern: - getBlockParentsByBlockName( clientId, 'core/block' ) - .length > 0, - }; - }, - [ clientId ] + const sources = useSelect( + ( select ) => + unlock( select( blocksStore ) ).getAllBlockBindingsSources(), + [] ); + const hasParentPattern = !! props.context[ 'pattern/overrides' ]; const hasPatternOverridesDefaultBinding = props.attributes.metadata?.bindings?.[ DEFAULT_ATTRIBUTE ] ?.source === 'core/pattern-overrides'; @@ -254,12 +241,13 @@ export const withBlockBindingSupport = createHigherOrderComponent( [ registry, bindings, - name, - clientId, - context, + hasPatternOverridesDefaultBinding, + hasParentPattern, setAttributes, + name, sources, - hasPatternOverridesDefaultBinding, + context, + clientId, ] ); diff --git a/packages/block-library/src/block/block.json b/packages/block-library/src/block/block.json index 34dcb9a396ac6..fdce3bcc02e07 100644 --- a/packages/block-library/src/block/block.json +++ b/packages/block-library/src/block/block.json @@ -12,9 +12,13 @@ "type": "number" }, "content": { - "type": "object" + "type": "object", + "default": {} } }, + "providesContext": { + "pattern/overrides": "content" + }, "supports": { "customClassName": false, "html": false, diff --git a/packages/block-library/src/image/image.js b/packages/block-library/src/image/image.js index c96eb4e45117d..abddd724f4705 100644 --- a/packages/block-library/src/image/image.js +++ b/packages/block-library/src/image/image.js @@ -443,16 +443,12 @@ export default function Image( { return {}; } const { getBlockBindingsSource } = unlock( select( blocksStore ) ); - const { getBlockParentsByBlockName } = unlock( - select( blockEditorStore ) - ); const { url: urlBinding, alt: altBinding, title: titleBinding, } = metadata?.bindings || {}; - const hasParentPattern = - getBlockParentsByBlockName( clientId, 'core/block' ).length > 0; + const hasParentPattern = !! context[ 'pattern/overrides' ]; const urlBindingSource = getBlockBindingsSource( urlBinding?.source ); @@ -508,7 +504,12 @@ export default function Image( { : __( 'Connected to dynamic data' ), }; }, - [ clientId, isSingleSelected, metadata?.bindings ] + [ + arePatternOverridesEnabled, + context, + isSingleSelected, + metadata?.bindings, + ] ); const showUrlInput = diff --git a/packages/editor/src/bindings/pattern-overrides.js b/packages/editor/src/bindings/pattern-overrides.js index 107ed72e722ba..54ca77650a5fe 100644 --- a/packages/editor/src/bindings/pattern-overrides.js +++ b/packages/editor/src/bindings/pattern-overrides.js @@ -9,23 +9,22 @@ const CONTENT = 'content'; export default { name: 'core/pattern-overrides', label: _x( 'Pattern Overrides', 'block bindings source' ), - getValue( { registry, clientId, attributeName } ) { - const { getBlockAttributes, getBlockParentsByBlockName } = - registry.select( blockEditorStore ); + getValue( { registry, clientId, context, attributeName } ) { + const patternOverridesContent = context[ 'pattern/overrides' ]; + const { getBlockAttributes } = registry.select( blockEditorStore ); const currentBlockAttributes = getBlockAttributes( clientId ); - const [ patternClientId ] = getBlockParentsByBlockName( - clientId, - 'core/block', - true - ); + + if ( ! patternOverridesContent ) { + return currentBlockAttributes[ attributeName ]; + } const overridableValue = - getBlockAttributes( patternClientId )?.[ CONTENT ]?.[ + patternOverridesContent?.[ currentBlockAttributes?.metadata?.name ]?.[ attributeName ]; // If there is no pattern client ID, or it is not overwritten, return the default value. - if ( ! patternClientId || overridableValue === undefined ) { + if ( overridableValue === undefined ) { return currentBlockAttributes[ attributeName ]; } diff --git a/packages/editor/src/hooks/pattern-overrides.js b/packages/editor/src/hooks/pattern-overrides.js index 36a67bb9c5d24..426bc4d357f0b 100644 --- a/packages/editor/src/hooks/pattern-overrides.js +++ b/packages/editor/src/hooks/pattern-overrides.js @@ -14,6 +14,8 @@ import { store as blocksStore } from '@wordpress/blocks'; import { store as editorStore } from '../store'; import { unlock } from '../lock-unlock'; +/** @typedef {import('@wordpress/blocks').WPBlockSettings} WPBlockSettings */ + const { PatternOverridesControls, ResetOverridesControl, @@ -46,7 +48,8 @@ const withPatternOverrideControls = createHigherOrderComponent( { isSupportedBlock && } ); - } + }, + 'withPatternOverrideControls' ); // Split into a separate component to avoid a store subscription diff --git a/test/integration/fixtures/blocks/core__block.json b/test/integration/fixtures/blocks/core__block.json index a4ce0bf8c9545..d7c28bacfe137 100644 --- a/test/integration/fixtures/blocks/core__block.json +++ b/test/integration/fixtures/blocks/core__block.json @@ -3,7 +3,8 @@ "name": "core/block", "isValid": true, "attributes": { - "ref": 123 + "ref": 123, + "content": {} }, "innerBlocks": [] } From 7ed761ada3ab7a67de78508395f8033398a0cf36 Mon Sep 17 00:00:00 2001 From: Mario Santos Date: Wed, 26 Jun 2024 13:48:48 +0200 Subject: [PATCH 09/10] Reduce diff --- .../block-editor/src/hooks/use-bindings-attributes.js | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/packages/block-editor/src/hooks/use-bindings-attributes.js b/packages/block-editor/src/hooks/use-bindings-attributes.js index e3ff6436ebea3..ed69fb564fa04 100644 --- a/packages/block-editor/src/hooks/use-bindings-attributes.js +++ b/packages/block-editor/src/hooks/use-bindings-attributes.js @@ -93,12 +93,10 @@ export function canBindAttribute( blockName, attributeName ) { export const withBlockBindingSupport = createHigherOrderComponent( ( BlockEdit ) => ( props ) => { const registry = useRegistry(); - const { name, clientId, context } = props; - const sources = useSelect( - ( select ) => - unlock( select( blocksStore ) ).getAllBlockBindingsSources(), - [] + const sources = useSelect( ( select ) => + unlock( select( blocksStore ) ).getAllBlockBindingsSources() ); + const { name, clientId, context } = props; const hasParentPattern = !! props.context[ 'pattern/overrides' ]; const hasPatternOverridesDefaultBinding = props.attributes.metadata?.bindings?.[ DEFAULT_ATTRIBUTE ] @@ -163,7 +161,6 @@ export const withBlockBindingSupport = createHigherOrderComponent( } const keptAttributes = { ...nextAttributes }; - const updatesBySource = new Map(); // Loop only over the updated attributes to avoid modifying the bound ones that haven't changed. From 47f554ecf770d22b5662659c03afb6274ff860d9 Mon Sep 17 00:00:00 2001 From: Mario Santos Date: Wed, 26 Jun 2024 13:54:43 +0200 Subject: [PATCH 10/10] Change array order --- .../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 ed69fb564fa04..7fb0793ed09c4 100644 --- a/packages/block-editor/src/hooks/use-bindings-attributes.js +++ b/packages/block-editor/src/hooks/use-bindings-attributes.js @@ -238,13 +238,13 @@ export const withBlockBindingSupport = createHigherOrderComponent( [ registry, bindings, - hasPatternOverridesDefaultBinding, - hasParentPattern, - setAttributes, name, - sources, - context, clientId, + context, + setAttributes, + sources, + hasPatternOverridesDefaultBinding, + hasParentPattern, ] );