diff --git a/lib/compat/wordpress-6.5/block-bindings/block-bindings.php b/lib/compat/wordpress-6.5/block-bindings/block-bindings.php index 7ea0f1bab4683..1bcb23ccd6549 100644 --- a/lib/compat/wordpress-6.5/block-bindings/block-bindings.php +++ b/lib/compat/wordpress-6.5/block-bindings/block-bindings.php @@ -25,18 +25,19 @@ * @param array $source_properties { * The array of arguments that are used to register a source. * - * @type string $label The label of the source. - * @type callback $get_value_callback A callback executed when the source is processed during block rendering. - * The callback should have the following signature: + * @type string $label The label of the source. + * @type callback $get_value_callback A callback executed when the source is processed during block rendering. + * The callback should have the following signature: * - * `function ($source_args, $block_instance,$attribute_name): mixed` - * - @param array $source_args Array containing source arguments - * used to look up the override value, - * i.e. {"key": "foo"}. - * - @param WP_Block $block_instance The block instance. - * - @param string $attribute_name The name of an attribute . - * The callback has a mixed return type; it may return a string to override - * the block's original value, null, false to remove an attribute, etc. + * `function ($source_args, $block_instance,$attribute_name): mixed` + * - @param array $source_args Array containing source arguments + * used to look up the override value, + * i.e. {"key": "foo"}. + * - @param WP_Block $block_instance The block instance. + * - @param string $attribute_name The name of an attribute . + * The callback has a mixed return type; it may return a string to override + * the block's original value, null, false to remove an attribute, etc. + * @type array $uses_context (optional) Array of values to add to block `uses_context` needed by the source. * } * @return WP_Block_Bindings_Source|false Source when the registration was successful, or `false` on failure. */ diff --git a/lib/compat/wordpress-6.5/block-bindings/class-wp-block-bindings-registry.php b/lib/compat/wordpress-6.5/block-bindings/class-wp-block-bindings-registry.php index e60b9ac8fbd08..7f04820050a91 100644 --- a/lib/compat/wordpress-6.5/block-bindings/class-wp-block-bindings-registry.php +++ b/lib/compat/wordpress-6.5/block-bindings/class-wp-block-bindings-registry.php @@ -32,6 +32,31 @@ final class WP_Block_Bindings_Registry { */ private static $instance = null; + /** + * Supported source properties that can be passed to the registered source. + * + * @since 6.5.0 + * @var array + */ + private $allowed_source_properties = array( + 'label', + 'get_value_callback', + 'uses_context', + ); + + /** + * Supported blocks that can use the block bindings API. + * + * @since 6.5.0 + * @var array + */ + private $supported_blocks = array( + 'core/paragraph', + 'core/heading', + 'core/image', + 'core/button', + ); + /** * Registers a new block bindings source. * @@ -48,18 +73,19 @@ final class WP_Block_Bindings_Registry { * @param array $source_properties { * The array of arguments that are used to register a source. * - * @type string $label The label of the source. - * @type callback $get_value_callback A callback executed when the source is processed during block rendering. - * The callback should have the following signature: - * - * `function ($source_args, $block_instance,$attribute_name): mixed` - * - @param array $source_args Array containing source arguments - * used to look up the override value, - * i.e. {"key": "foo"}. - * - @param WP_Block $block_instance The block instance. - * - @param string $attribute_name The name of the target attribute. - * The callback has a mixed return type; it may return a string to override - * the block's original value, null, false to remove an attribute, etc. + * @type string $label The label of the source. + * @type callback $get_value_callback A callback executed when the source is processed during block rendering. + * The callback should have the following signature: + * + * `function ($source_args, $block_instance,$attribute_name): mixed` + * - @param array $source_args Array containing source arguments + * used to look up the override value, + * i.e. {"key": "foo"}. + * - @param WP_Block $block_instance The block instance. + * - @param string $attribute_name The name of the target attribute. + * The callback has a mixed return type; it may return a string to override + * the block's original value, null, false to remove an attribute, etc. + * @type array $uses_context (optional) Array of values to add to block `uses_context` needed by the source. * } * @return WP_Block_Bindings_Source|false Source when the registration was successful, or `false` on failure. */ @@ -102,7 +128,7 @@ public function register( string $source_name, array $source_properties ) { return false; } - /* Validate that the source properties contain the label */ + // Validate that the source properties contain the label. if ( ! isset( $source_properties['label'] ) ) { _doing_it_wrong( __METHOD__, @@ -112,7 +138,7 @@ public function register( string $source_name, array $source_properties ) { return false; } - /* Validate that the source properties contain the get_value_callback */ + // Validate that the source properties contain the get_value_callback. if ( ! isset( $source_properties['get_value_callback'] ) ) { _doing_it_wrong( __METHOD__, @@ -122,7 +148,7 @@ public function register( string $source_name, array $source_properties ) { return false; } - /* Validate that the get_value_callback is a valid callback */ + // Validate that the get_value_callback is a valid callback. if ( ! is_callable( $source_properties['get_value_callback'] ) ) { _doing_it_wrong( __METHOD__, @@ -132,6 +158,26 @@ public function register( string $source_name, array $source_properties ) { return false; } + // Validate that the uses_context parameter is an array. + if ( isset( $source_properties['uses_context'] ) && ! is_array( $source_properties['uses_context'] ) ) { + _doing_it_wrong( + __METHOD__, + __( 'The "uses_context" parameter must be an array.' ), + '6.5.0' + ); + return false; + } + + // Validate that the source properties contain only allowed properties. + if ( ! empty( array_diff( array_keys( $source_properties ), $this->allowed_source_properties ) ) ) { + _doing_it_wrong( + __METHOD__, + __( 'The $source_properties array contains invalid properties.' ), + '6.5.0' + ); + return false; + } + $source = new WP_Block_Bindings_Source( $source_name, $source_properties @@ -139,6 +185,22 @@ public function register( string $source_name, array $source_properties ) { $this->sources[ $source_name ] = $source; + // Add `uses_context` defined by block bindings sources. + add_filter( + 'register_block_type_args', + function ( $args, $block_name ) use ( $source ) { + if ( ! in_array( $block_name, $this->supported_blocks, true ) || empty( $source->uses_context ) ) { + return $args; + } + $original_use_context = isset( $args['uses_context'] ) ? $args['uses_context'] : array(); + // Use array_values to reset the array keys. + $args['uses_context'] = array_values( array_unique( array_merge( $original_use_context, $source->uses_context ) ) ); + + return $args; + }, + 10, + 2 + ); return $source; } diff --git a/lib/compat/wordpress-6.5/block-bindings/class-wp-block-bindings-source.php b/lib/compat/wordpress-6.5/block-bindings/class-wp-block-bindings-source.php index fa2bc53705fdc..1862f2af8bb11 100644 --- a/lib/compat/wordpress-6.5/block-bindings/class-wp-block-bindings-source.php +++ b/lib/compat/wordpress-6.5/block-bindings/class-wp-block-bindings-source.php @@ -46,6 +46,14 @@ final class WP_Block_Bindings_Source { */ private $get_value_callback; + /** + * The context added to the blocks needed by the source. + * + * @since 6.5.0 + * @var array|null + */ + public $uses_context = null; + /** * Constructor. * @@ -58,9 +66,10 @@ final class WP_Block_Bindings_Source { * @param array $source_properties The properties of the source. */ public function __construct( string $name, array $source_properties ) { - $this->name = $name; - $this->label = $source_properties['label']; - $this->get_value_callback = $source_properties['get_value_callback']; + $this->name = $name; + foreach ( $source_properties as $property_name => $property_value ) { + $this->$property_name = $property_value; + } } /** diff --git a/lib/compat/wordpress-6.5/block-bindings/pattern-overrides.php b/lib/compat/wordpress-6.5/block-bindings/pattern-overrides.php index 0e6d3fc94eeaa..76c3d49ca8085 100644 --- a/lib/compat/wordpress-6.5/block-bindings/pattern-overrides.php +++ b/lib/compat/wordpress-6.5/block-bindings/pattern-overrides.php @@ -35,6 +35,7 @@ function gutenberg_register_block_bindings_pattern_overrides_source() { array( 'label' => _x( 'Pattern Overrides', 'block bindings source' ), 'get_value_callback' => 'gutenberg_block_bindings_pattern_overrides_callback', + 'uses_context' => array( 'pattern/overrides' ), ) ); } diff --git a/lib/compat/wordpress-6.5/block-bindings/post-meta.php b/lib/compat/wordpress-6.5/block-bindings/post-meta.php index 655abd982663b..5ce8eb7ac56ee 100644 --- a/lib/compat/wordpress-6.5/block-bindings/post-meta.php +++ b/lib/compat/wordpress-6.5/block-bindings/post-meta.php @@ -8,23 +8,20 @@ /** * Gets value for Post Meta source. * - * @param array $source_args Array containing source arguments used to look up the override value. - * Example: array( "key" => "foo" ). + * @param array $source_args Array containing source arguments used to look up the override value. + * Example: array( "key" => "foo" ). + * @param WP_Block $block_instance The block instance. * @return mixed The value computed for the source. */ -function gutenberg_block_bindings_post_meta_callback( $source_attrs ) { - if ( ! isset( $source_attrs['key'] ) ) { +function gutenberg_block_bindings_post_meta_callback( $source_attrs, $block_instance ) { + if ( empty( $source_attrs['key'] ) ) { return null; } - // Use the postId attribute if available - if ( isset( $source_attrs['postId'] ) ) { - $post_id = $source_attrs['postId']; - } else { - // I tried using $block_instance->context['postId'] but it wasn't available in the image block. - $post_id = get_the_ID(); + if ( empty( $block_instance->context['postId'] ) ) { + return null; } - + $post_id = $block_instance->context['postId']; // If a post isn't public, we need to prevent unauthorized users from accessing the post meta. $post = get_post( $post_id ); if ( ( ! is_post_publicly_viewable( $post ) && ! current_user_can( 'read_post', $post_id ) ) || post_password_required( $post ) ) { @@ -47,6 +44,7 @@ function gutenberg_register_block_bindings_post_meta_source() { array( 'label' => _x( 'Post Meta', 'block bindings source' ), 'get_value_callback' => 'gutenberg_block_bindings_post_meta_callback', + 'uses_context' => array( 'postId', 'postType' ), ) ); } diff --git a/lib/compat/wordpress-6.5/blocks.php b/lib/compat/wordpress-6.5/blocks.php index c670e1363a7f8..d8c24b3772125 100644 --- a/lib/compat/wordpress-6.5/blocks.php +++ b/lib/compat/wordpress-6.5/blocks.php @@ -157,18 +157,16 @@ function gutenberg_block_bindings_replace_html( $block_content, $block_name, str * @param WP_Block $block_instance The block instance. */ function gutenberg_process_block_bindings( $block_content, $parsed_block, $block_instance ) { - // Allowed blocks that support block bindings. - // TODO: Look for a mechanism to opt-in for this. Maybe adding a property to block attributes? - $allowed_blocks = array( + $supported_block_attrs = array( 'core/paragraph' => array( 'content' ), 'core/heading' => array( 'content' ), 'core/image' => array( 'url', 'title', 'alt' ), 'core/button' => array( 'url', 'text', 'linkTarget', 'rel' ), ); - // If the block doesn't have the bindings property or isn't one of the allowed block types, return. + // If the block doesn't have the bindings property or isn't one of the supported block types, return. if ( - ! isset( $allowed_blocks[ $block_instance->name ] ) || + ! isset( $supported_block_attrs[ $block_instance->name ] ) || empty( $parsed_block['attrs']['metadata']['bindings'] ) || ! is_array( $parsed_block['attrs']['metadata']['bindings'] ) ) { @@ -192,8 +190,8 @@ function gutenberg_process_block_bindings( $block_content, $parsed_block, $block $modified_block_content = $block_content; foreach ( $parsed_block['attrs']['metadata']['bindings'] as $attribute_name => $block_binding ) { - // If the attribute is not in the allowed list, process next attribute. - if ( ! in_array( $attribute_name, $allowed_blocks[ $block_instance->name ], true ) ) { + // If the attribute is not in the supported list, process next attribute. + if ( ! in_array( $attribute_name, $supported_block_attrs[ $block_instance->name ], true ) ) { continue; } // If no source is provided, or that source is not registered, process next attribute. diff --git a/packages/block-editor/src/hooks/use-bindings-attributes.js b/packages/block-editor/src/hooks/use-bindings-attributes.js index a1873143c294a..33020bc5a40d2 100644 --- a/packages/block-editor/src/hooks/use-bindings-attributes.js +++ b/packages/block-editor/src/hooks/use-bindings-attributes.js @@ -112,24 +112,3 @@ addFilter( 'core/editor/custom-sources-backwards-compatibility/shim-attribute-source', shimAttributeSource ); - -// Add the context to all blocks. -addFilter( - 'blocks.registerBlockType', - 'core/block-bindings-ui', - ( settings, name ) => { - if ( ! ( name in BLOCK_BINDINGS_ALLOWED_BLOCKS ) ) { - return settings; - } - const contextItems = [ 'postId', 'postType', 'queryId' ]; - const usesContextArray = settings.usesContext; - const oldUsesContextArray = new Set( usesContextArray ); - contextItems.forEach( ( item ) => { - if ( ! oldUsesContextArray.has( item ) ) { - usesContextArray.push( item ); - } - } ); - settings.usesContext = usesContextArray; - return settings; - } -); diff --git a/packages/block-library/src/button/block.json b/packages/block-library/src/button/block.json index c3d51c61a0999..ec9f042cf5bcf 100644 --- a/packages/block-library/src/button/block.json +++ b/packages/block-library/src/button/block.json @@ -8,7 +8,6 @@ "description": "Prompt visitors to take action with a button-style link.", "keywords": [ "link" ], "textdomain": "default", - "usesContext": [ "pattern/overrides" ], "attributes": { "tagName": { "type": "string", diff --git a/packages/block-library/src/heading/block.json b/packages/block-library/src/heading/block.json index 90ef0d383af2c..9990ef582e2f4 100644 --- a/packages/block-library/src/heading/block.json +++ b/packages/block-library/src/heading/block.json @@ -7,7 +7,6 @@ "description": "Introduce new sections and organize content to help visitors (and search engines) understand the structure of your content.", "keywords": [ "title", "subtitle" ], "textdomain": "default", - "usesContext": [ "pattern/overrides" ], "attributes": { "textAlign": { "type": "string" diff --git a/packages/block-library/src/image/block.json b/packages/block-library/src/image/block.json index 7a46a34db591f..1076aad0f1798 100644 --- a/packages/block-library/src/image/block.json +++ b/packages/block-library/src/image/block.json @@ -4,12 +4,7 @@ "name": "core/image", "title": "Image", "category": "media", - "usesContext": [ - "allowResize", - "imageCrop", - "fixedHeight", - "pattern/overrides" - ], + "usesContext": [ "allowResize", "imageCrop", "fixedHeight" ], "description": "Insert an image to make a visual statement.", "keywords": [ "img", "photo", "picture" ], "textdomain": "default", diff --git a/packages/block-library/src/paragraph/block.json b/packages/block-library/src/paragraph/block.json index 2f23d41cd0372..7cfe785921b66 100644 --- a/packages/block-library/src/paragraph/block.json +++ b/packages/block-library/src/paragraph/block.json @@ -7,7 +7,7 @@ "description": "Start with the basic building block of all narrative.", "keywords": [ "text" ], "textdomain": "default", - "usesContext": [ "postId", "pattern/overrides" ], + "usesContext": [ "postId" ], "attributes": { "align": { "type": "string"