From f17f82d344f042f633d2622e1211dbcf0d2c29f0 Mon Sep 17 00:00:00 2001 From: Kai Hao Date: Mon, 18 Mar 2024 22:24:39 +0800 Subject: [PATCH 1/3] Use name only as the hint for pattern overrides --- lib/compat/wordpress-6.6/blocks.php | 51 ++++++++ lib/load.php | 1 + packages/block-library/src/block/edit.js | 12 +- .../editor/src/hooks/pattern-overrides.js | 21 +-- .../components/use-set-pattern-bindings.js | 120 ------------------ packages/patterns/src/private-apis.js | 2 - .../editor/various/pattern-overrides.spec.js | 25 ++-- 7 files changed, 64 insertions(+), 168 deletions(-) create mode 100644 lib/compat/wordpress-6.6/blocks.php delete mode 100644 packages/patterns/src/components/use-set-pattern-bindings.js diff --git a/lib/compat/wordpress-6.6/blocks.php b/lib/compat/wordpress-6.6/blocks.php new file mode 100644 index 00000000000000..c9f109e230f6d1 --- /dev/null +++ b/lib/compat/wordpress-6.6/blocks.php @@ -0,0 +1,51 @@ + array( 'content' ), + 'core/heading' => array( 'content' ), + 'core/image' => array( 'id', 'url', 'title', 'alt' ), + 'core/button' => array( 'url', 'text', 'linkTarget', 'rel' ), + ); + + // If the block isn't one of the supported block types or isn't inside a pattern, return. + if ( + ! isset( $supported_block_attrs[ $block_instance->name ] ) || + ! isset( $block_instance->context['pattern/overrides'] ) + ) { + return $block_content; + } + + $modified_block_content = $block_content; + foreach ( $supported_block_attrs[ $block_instance->name ] as $attribute_name ) { + $source_value = $pattern_overrides_source->get_value( array(), $block_instance, $attribute_name ); + + // If the value is not null, process the HTML based on the block and the attribute. + if ( ! is_null( $source_value ) ) { + $modified_block_content = gutenberg_block_bindings_replace_html( $modified_block_content, $block_instance->name, $attribute_name, $source_value ); + } + } + + return $modified_block_content; +} + +add_filter( 'render_block', 'gutenberg_process_pattern_overrides_bindings', 20, 3 ); diff --git a/lib/load.php b/lib/load.php index a9ce52385ab48f..7a4da1e10774a9 100644 --- a/lib/load.php +++ b/lib/load.php @@ -125,6 +125,7 @@ function gutenberg_is_experiment_enabled( $name ) { require __DIR__ . '/compat/wordpress-6.5/script-loader.php'; // WordPress 6.6 compat. +require __DIR__ . '/compat/wordpress-6.6/blocks.php'; require __DIR__ . '/compat/wordpress-6.6/block-bindings/pattern-overrides.php'; // Experimental features. diff --git a/packages/block-library/src/block/edit.js b/packages/block-library/src/block/edit.js index 6e6379571cc9e3..799df20a6ace56 100644 --- a/packages/block-library/src/block/edit.js +++ b/packages/block-library/src/block/edit.js @@ -94,11 +94,7 @@ function hasOverridableAttributes( block ) { return ( Object.keys( PARTIAL_SYNCING_SUPPORTED_BLOCKS ).includes( block.name - ) && - !! block.attributes.metadata?.bindings && - Object.values( block.attributes.metadata.bindings ).some( - ( binding ) => binding.source === 'core/pattern-overrides' - ) + ) && !! block.attributes.metadata?.name ); } @@ -110,11 +106,7 @@ function hasOverridableBlocks( blocks ) { } function getOverridableAttributes( block ) { - return Object.entries( block.attributes.metadata.bindings ) - .filter( - ( [ , binding ] ) => binding.source === 'core/pattern-overrides' - ) - .map( ( [ attributeKey ] ) => attributeKey ); + return PARTIAL_SYNCING_SUPPORTED_BLOCKS[ block.name ]; } function applyInitialContentValuesToInnerBlocks( diff --git a/packages/editor/src/hooks/pattern-overrides.js b/packages/editor/src/hooks/pattern-overrides.js index 442ce70a2bf71c..ecbbcce56d9477 100644 --- a/packages/editor/src/hooks/pattern-overrides.js +++ b/packages/editor/src/hooks/pattern-overrides.js @@ -14,7 +14,6 @@ import { store as editorStore } from '../store'; import { unlock } from '../lock-unlock'; const { - useSetPatternBindings, ResetOverridesControl, PATTERN_TYPES, PARTIAL_SYNCING_SUPPORTED_BLOCKS, @@ -38,7 +37,6 @@ const withPatternOverrideControls = createHigherOrderComponent( return ( <> - { isSupportedBlock && } { props.isSelected && isSupportedBlock && ( ) } @@ -47,15 +45,6 @@ const withPatternOverrideControls = createHigherOrderComponent( } ); -function BindingUpdater( props ) { - const postType = useSelect( - ( select ) => select( editorStore ).getCurrentPostType(), - [] - ); - useSetPatternBindings( props, postType ); - return null; -} - // Split into a separate component to avoid a store subscription // on every block. function ControlsWithStoreSubscription( props ) { @@ -66,18 +55,10 @@ function ControlsWithStoreSubscription( props ) { [] ); - const bindings = props.attributes.metadata?.bindings; - const hasPatternBindings = - !! bindings && - Object.values( bindings ).some( - ( binding ) => binding.source === 'core/pattern-overrides' - ); - const shouldShowResetOverridesControl = ! isEditingPattern && !! props.attributes.metadata?.name && - blockEditingMode !== 'disabled' && - hasPatternBindings; + blockEditingMode !== 'disabled'; return ( <> diff --git a/packages/patterns/src/components/use-set-pattern-bindings.js b/packages/patterns/src/components/use-set-pattern-bindings.js deleted file mode 100644 index 261187a91088c1..00000000000000 --- a/packages/patterns/src/components/use-set-pattern-bindings.js +++ /dev/null @@ -1,120 +0,0 @@ -/** - * WordPress dependencies - */ -import { usePrevious } from '@wordpress/compose'; -import { store as blocksStore } from '@wordpress/blocks'; -import { useEffect } from '@wordpress/element'; -import { useSelect } from '@wordpress/data'; - -/** - * Internal dependencies - */ -import { PARTIAL_SYNCING_SUPPORTED_BLOCKS } from '../constants'; - -import { unlock } from '../lock-unlock'; - -function removeBindings( bindings, syncedAttributes ) { - let updatedBindings = {}; - for ( const attributeName of syncedAttributes ) { - // Omit any pattern override bindings from the `updatedBindings` object. - if ( - bindings?.[ attributeName ]?.source !== 'core/pattern-overrides' && - bindings?.[ attributeName ]?.source !== undefined - ) { - updatedBindings[ attributeName ] = bindings[ attributeName ]; - } - } - if ( ! Object.keys( updatedBindings ).length ) { - updatedBindings = undefined; - } - return updatedBindings; -} - -function addBindings( bindings, syncedAttributes ) { - const updatedBindings = { ...bindings }; - for ( const attributeName of syncedAttributes ) { - if ( ! bindings?.[ attributeName ] ) { - updatedBindings[ attributeName ] = { - source: 'core/pattern-overrides', - }; - } - } - return updatedBindings; -} - -export default function useSetPatternBindings( - { name, attributes, setAttributes }, - currentPostType -) { - const hasPatternOverridesSource = useSelect( ( select ) => { - const { getBlockBindingsSource } = unlock( select( blocksStore ) ); - - // For editing link to the site editor if the theme and user permissions support it. - return !! getBlockBindingsSource( 'core/pattern-overrides' ); - }, [] ); - - const metadataName = attributes?.metadata?.name ?? ''; - const prevMetadataName = usePrevious( metadataName ) ?? ''; - const bindings = attributes?.metadata?.bindings; - - useEffect( () => { - // Bindings should only be created when editing a wp_block post type, - // and also when there's a change to the user-given name for the block. - // Also check that the pattern overrides source is registered. - if ( - ! hasPatternOverridesSource || - currentPostType !== 'wp_block' || - metadataName === prevMetadataName - ) { - return; - } - - const syncedAttributes = PARTIAL_SYNCING_SUPPORTED_BLOCKS[ name ]; - const attributeSources = syncedAttributes.map( - ( attributeName ) => - attributes.metadata?.bindings?.[ attributeName ]?.source - ); - const isConnectedToOtherSources = attributeSources.every( - ( source ) => source && source !== 'core/pattern-overrides' - ); - - // Avoid overwriting other (e.g. meta) bindings. - if ( isConnectedToOtherSources ) { - return; - } - - // The user-given name for the block was deleted, remove the bindings. - if ( ! metadataName?.length && prevMetadataName?.length ) { - const updatedBindings = removeBindings( - bindings, - syncedAttributes - ); - setAttributes( { - metadata: { - ...attributes.metadata, - bindings: updatedBindings, - }, - } ); - } - - // The user-given name for the block was set, set the bindings. - if ( ! prevMetadataName?.length && metadataName.length ) { - const updatedBindings = addBindings( bindings, syncedAttributes ); - setAttributes( { - metadata: { - ...attributes.metadata, - bindings: updatedBindings, - }, - } ); - } - }, [ - hasPatternOverridesSource, - bindings, - prevMetadataName, - metadataName, - currentPostType, - name, - attributes.metadata, - setAttributes, - ] ); -} diff --git a/packages/patterns/src/private-apis.js b/packages/patterns/src/private-apis.js index 54ad5a4aa47d1b..164e644b70f56f 100644 --- a/packages/patterns/src/private-apis.js +++ b/packages/patterns/src/private-apis.js @@ -13,7 +13,6 @@ import { import RenamePatternModal from './components/rename-pattern-modal'; import PatternsMenuItems from './components'; import RenamePatternCategoryModal from './components/rename-pattern-category-modal'; -import useSetPatternBindings from './components/use-set-pattern-bindings'; import ResetOverridesControl from './components/reset-overrides-control'; import { useAddPatternCategory } from './private-hooks'; import { @@ -34,7 +33,6 @@ lock( privateApis, { RenamePatternModal, PatternsMenuItems, RenamePatternCategoryModal, - useSetPatternBindings, ResetOverridesControl, useAddPatternCategory, PATTERN_TYPES, diff --git a/test/e2e/specs/editor/various/pattern-overrides.spec.js b/test/e2e/specs/editor/various/pattern-overrides.spec.js index b4f32e26df87af..63859a2392e17e 100644 --- a/test/e2e/specs/editor/various/pattern-overrides.spec.js +++ b/test/e2e/specs/editor/various/pattern-overrides.spec.js @@ -93,14 +93,7 @@ test.describe( 'Pattern Overrides', () => { name: 'core/paragraph', attributes: { content: 'This paragraph can be edited', - metadata: { - name: editableParagraphName, - bindings: { - content: { - source: 'core/pattern-overrides', - }, - }, - }, + metadata: { name: editableParagraphName }, }, }, { @@ -225,7 +218,7 @@ test.describe( 'Pattern Overrides', () => { const paragraphId = 'paragraph-id'; const { id } = await requestUtils.createBlock( { title: 'Pattern', - content: ` + content: `

Editable

`, status: 'publish', @@ -257,7 +250,7 @@ test.describe( 'Pattern Overrides', () => { name: 'core/paragraph', attributes: { content: 'edited Editable', - metadata: undefined, + metadata: { name: paragraphId }, }, }, ] ); @@ -274,7 +267,7 @@ test.describe( 'Pattern Overrides', () => { const { id } = await requestUtils.createBlock( { title: 'Button with target', content: ` -
+ `, @@ -384,14 +377,14 @@ test.describe( 'Pattern Overrides', () => { const headingName = 'Editable heading'; const innerPattern = await requestUtils.createBlock( { title: 'Inner Pattern', - content: ` + content: `

Inner paragraph

`, status: 'publish', } ); const outerPattern = await requestUtils.createBlock( { title: 'Outer Pattern', - content: ` + content: `

Outer heading

`, @@ -501,10 +494,10 @@ test.describe( 'Pattern Overrides', () => { const paragraphName = 'Editable paragraph'; const { id } = await requestUtils.createBlock( { title: 'Pattern', - content: ` + content: `

Heading

- +

Paragraph

`, status: 'publish', @@ -596,7 +589,7 @@ test.describe( 'Pattern Overrides', () => { ); const { id } = await requestUtils.createBlock( { title: 'Pattern', - content: ` + content: `
`, status: 'publish', From e9858fe63e644474eead2e0e1cc276f627781d17 Mon Sep 17 00:00:00 2001 From: Kai Hao Date: Wed, 20 Mar 2024 15:30:19 +0800 Subject: [PATCH 2/3] Add check for metadata.name --- lib/compat/wordpress-6.6/blocks.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/compat/wordpress-6.6/blocks.php b/lib/compat/wordpress-6.6/blocks.php index c9f109e230f6d1..5d0b2cfda47af0 100644 --- a/lib/compat/wordpress-6.6/blocks.php +++ b/lib/compat/wordpress-6.6/blocks.php @@ -30,7 +30,8 @@ function gutenberg_process_pattern_overrides_bindings( $block_content, $parsed_b // If the block isn't one of the supported block types or isn't inside a pattern, return. if ( ! isset( $supported_block_attrs[ $block_instance->name ] ) || - ! isset( $block_instance->context['pattern/overrides'] ) + ! isset( $block_instance->context['pattern/overrides'] ) || + empty( $parsed_block['attrs']['metadata']['name'] ) ) { return $block_content; } From 7fba5e9e5d4610b8e2e067ec24d46b2adc603b3f Mon Sep 17 00:00:00 2001 From: Kai Hao Date: Mon, 25 Mar 2024 10:29:46 +0800 Subject: [PATCH 3/3] Add bindings attribute --- lib/compat/wordpress-6.6/blocks.php | 52 ---------------------- lib/load.php | 1 - packages/block-library/src/block/index.php | 32 ++++++++++++- 3 files changed, 31 insertions(+), 54 deletions(-) delete mode 100644 lib/compat/wordpress-6.6/blocks.php diff --git a/lib/compat/wordpress-6.6/blocks.php b/lib/compat/wordpress-6.6/blocks.php deleted file mode 100644 index 5d0b2cfda47af0..00000000000000 --- a/lib/compat/wordpress-6.6/blocks.php +++ /dev/null @@ -1,52 +0,0 @@ - array( 'content' ), - 'core/heading' => array( 'content' ), - 'core/image' => array( 'id', 'url', 'title', 'alt' ), - 'core/button' => array( 'url', 'text', 'linkTarget', 'rel' ), - ); - - // If the block isn't one of the supported block types or isn't inside a pattern, return. - if ( - ! isset( $supported_block_attrs[ $block_instance->name ] ) || - ! isset( $block_instance->context['pattern/overrides'] ) || - empty( $parsed_block['attrs']['metadata']['name'] ) - ) { - return $block_content; - } - - $modified_block_content = $block_content; - foreach ( $supported_block_attrs[ $block_instance->name ] as $attribute_name ) { - $source_value = $pattern_overrides_source->get_value( array(), $block_instance, $attribute_name ); - - // If the value is not null, process the HTML based on the block and the attribute. - if ( ! is_null( $source_value ) ) { - $modified_block_content = gutenberg_block_bindings_replace_html( $modified_block_content, $block_instance->name, $attribute_name, $source_value ); - } - } - - return $modified_block_content; -} - -add_filter( 'render_block', 'gutenberg_process_pattern_overrides_bindings', 20, 3 ); diff --git a/lib/load.php b/lib/load.php index 7a4da1e10774a9..a9ce52385ab48f 100644 --- a/lib/load.php +++ b/lib/load.php @@ -125,7 +125,6 @@ function gutenberg_is_experiment_enabled( $name ) { require __DIR__ . '/compat/wordpress-6.5/script-loader.php'; // WordPress 6.6 compat. -require __DIR__ . '/compat/wordpress-6.6/blocks.php'; require __DIR__ . '/compat/wordpress-6.6/block-bindings/pattern-overrides.php'; // Experimental features. diff --git a/packages/block-library/src/block/index.php b/packages/block-library/src/block/index.php index 9403205c186596..6f0c3465687c02 100644 --- a/packages/block-library/src/block/index.php +++ b/packages/block-library/src/block/index.php @@ -78,13 +78,42 @@ function render_block_core_block( $attributes ) { * filter so that it is available when a pattern's inner blocks are * rendering via do_blocks given it only receives the inner content. */ - $has_pattern_overrides = isset( $attributes['content'] ); + $has_pattern_overrides = isset( $attributes['content'] ) && null !== get_block_bindings_source( 'core/pattern-overrides' ); if ( $has_pattern_overrides ) { $filter_block_context = static function ( $context ) use ( $attributes ) { $context['pattern/overrides'] = $attributes['content']; return $context; }; add_filter( 'render_block_context', $filter_block_context, 1 ); + + $filter_pattern_overrides_bindings = static function ( $parsed_block ) { + $supported_block_attrs = array( + 'core/paragraph' => array( 'content' ), + 'core/heading' => array( 'content' ), + 'core/image' => array( 'id', 'url', 'title', 'alt' ), + 'core/button' => array( 'url', 'text', 'linkTarget', 'rel' ), + ); + + if ( + // Return early if the block isn't one of the supported block types, + ! isset( $supported_block_attrs[ $parsed_block['blockName'] ] ) || + // or doesn't have a name, + empty( $parsed_block['attrs']['metadata']['name'] ) || + // or already has bindings. + ! empty( $parsed_block['attrs']['metadata']['bindings'] ) + ) { + return $parsed_block; + } + + $bindings = array(); + foreach ( $supported_block_attrs[ $parsed_block['blockName'] ] as $attribute_name ) { + $bindings[ $attribute_name ] = array( 'source' => 'core/pattern-overrides' ); + } + $parsed_block['attrs']['metadata']['bindings'] = $bindings; + + return $parsed_block; + }; + add_filter( 'render_block_data', $filter_pattern_overrides_bindings, 10, 1 ); } $content = do_blocks( $content ); @@ -92,6 +121,7 @@ function render_block_core_block( $attributes ) { if ( $has_pattern_overrides ) { remove_filter( 'render_block_context', $filter_block_context, 1 ); + remove_filter( 'render_block_data', $filter_pattern_overrides_bindings, 10 ); } return $content;