Changeset 57526
- Timestamp:
- 02/02/2024 08:22:11 PM (8 months ago)
- Location:
- trunk
- Files:
-
- 2 added
- 1 deleted
- 5 edited
- 1 moved
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/wp-includes/block-bindings.php
r57514 r57526 20 20 * @since 6.5.0 21 21 * 22 * @param string 23 * 24 * 25 * @param array 22 * @param string $source_name The name of the source. It must be a string containing a namespace prefix, i.e. 23 * `my-plugin/my-custom-source`. It must only contain lowercase alphanumeric 24 * characters, the forward slash `/` and dashes. 25 * @param array $source_properties { 26 26 * The array of arguments that are used to register a source. 27 27 * … … 41 41 * @return array|false Source when the registration was successful, or `false` on failure. 42 42 */ 43 function register_block_bindings_source( $source_name, array $source_properties ) {43 function register_block_bindings_source( string $source_name, array $source_properties ) { 44 44 return WP_Block_Bindings_Registry::get_instance()->register( $source_name, $source_properties ); 45 45 } … … 53 53 * @return array|false The unregistered block bindings source on success and `false` otherwise. 54 54 */ 55 function unregister_block_bindings_source( $source_name ) {55 function unregister_block_bindings_source( string $source_name ) { 56 56 return WP_Block_Bindings_Registry::get_instance()->unregister( $source_name ); 57 57 } … … 67 67 return WP_Block_Bindings_Registry::get_instance()->get_all_registered(); 68 68 } 69 70 /** 71 * Retrieves a registered block bindings source. 72 * 73 * @since 6.5.0 74 * 75 * @param string $source_name The name of the source. 76 * @return array|null The registered block bindings source, or `null` if it is not registered. 77 */ 78 function get_block_bindings_source( string $source_name ) { 79 return WP_Block_Bindings_Registry::get_instance()->get_registered( $source_name ); 80 } -
trunk/src/wp-includes/class-wp-block-bindings-registry.php
r57514 r57526 58 58 * i.e. {"key": "foo"}. 59 59 * - @param WP_Block $block_instance The block instance. 60 * - @param string $attribute_name The name of an attribute.60 * - @param string $attribute_name The name of the target attribute. 61 61 * The callback has a mixed return type; it may return a string to override 62 62 * the block's original value, null, false to remove an attribute, etc. … … 64 64 * @return array|false Source when the registration was successful, or `false` on failure. 65 65 */ 66 public function register( $source_name, array $source_properties ) {66 public function register( string $source_name, array $source_properties ) { 67 67 if ( ! is_string( $source_name ) ) { 68 68 _doing_it_wrong( … … 121 121 * @return array|false The unregistered block bindings source on success and `false` otherwise. 122 122 */ 123 public function unregister( $source_name ) {123 public function unregister( string $source_name ) { 124 124 if ( ! $this->is_registered( $source_name ) ) { 125 125 _doing_it_wrong( … … 157 157 * @return array|null The registered block bindings source, or `null` if it is not registered. 158 158 */ 159 public function get_registered( $source_name ) {159 public function get_registered( string $source_name ) { 160 160 if ( ! $this->is_registered( $source_name ) ) { 161 161 return null; -
trunk/src/wp-includes/class-wp-block.php
r57514 r57526 212 212 * "bindings": { 213 213 * "title": { 214 * "source": " post_meta",214 * "source": "core/post-meta", 215 215 * "args": { "key": "text_custom_field" } 216 216 * }, 217 217 * "url": { 218 * "source": " post_meta",218 * "source": "core/post-meta", 219 219 * "args": { "key": "url_custom_field" } 220 220 * } … … 227 227 * block with the values of the `text_custom_field` and `url_custom_field` post meta. 228 228 * 229 * @access private230 229 * @since 6.5.0 231 230 * 232 * @param string $block_content Block content. 233 * @param array $block The full block, including name and attributes. 231 * @param string $block_content Block content. 232 * @param array $block The full block, including name and attributes. 233 * @return string The modified block content. 234 234 */ 235 235 private function process_block_bindings( $block_content ) { 236 $ block = $this->parsed_block;236 $parsed_block = $this->parsed_block; 237 237 238 238 // Allowed blocks that support block bindings. … … 247 247 // If the block doesn't have the bindings property, isn't one of the allowed 248 248 // block types, or the bindings property is not an array, return the block content. 249 if ( ! isset( $block['attrs']['metadata']['bindings'] ) || 250 ! is_array( $block['attrs']['metadata']['bindings'] ) || 251 ! isset( $allowed_blocks[ $this->name ] ) 252 ) { 249 if ( 250 ! isset( $allowed_blocks[ $this->name ] ) || 251 empty( $parsed_block['attrs']['metadata']['bindings'] ) || 252 ! is_array( $parsed_block['attrs']['metadata']['bindings'] ) 253 ) { 253 254 return $block_content; 254 255 } 255 256 256 $block_bindings_sources = get_all_registered_block_bindings_sources();257 257 $modified_block_content = $block_content; 258 foreach ( $ block['attrs']['metadata']['bindings'] as $binding_attribute => $binding_source) {259 // If the attribute is not in the list, process next attribute.260 if ( ! in_array( $ binding_attribute, $allowed_blocks[ $this->name ], true ) ) {258 foreach ( $parsed_block['attrs']['metadata']['bindings'] as $attribute_name => $block_binding ) { 259 // If the attribute is not in the allowed list, process next attribute. 260 if ( ! in_array( $attribute_name, $allowed_blocks[ $this->name ], true ) ) { 261 261 continue; 262 262 } 263 263 // If no source is provided, or that source is not registered, process next attribute. 264 if ( ! isset( $b inding_source['source'] ) || ! is_string( $binding_source['source'] ) || ! isset( $block_bindings_sources[ $binding_source['source']] ) ) {264 if ( ! isset( $block_binding['source'] ) || ! is_string( $block_binding['source'] ) ) { 265 265 continue; 266 266 } 267 267 268 $source_callback = $block_bindings_sources[ $binding_source['source'] ]['get_value_callback']; 269 // Get the value based on the source. 270 if ( ! isset( $binding_source['args'] ) ) { 271 $source_args = array(); 272 } else { 273 $source_args = $binding_source['args']; 274 } 275 $source_value = call_user_func_array( $source_callback, array( $source_args, $this, $binding_attribute ) ); 276 // If the value is null, process next attribute. 277 if ( is_null( $source_value ) ) { 268 $block_binding_source = get_block_bindings_source( $block_binding['source'] ); 269 if ( null === $block_binding_source ) { 278 270 continue; 279 271 } 280 272 281 // Process the HTML based on the block and the attribute. 282 $modified_block_content = $this->replace_html( $modified_block_content, $this->name, $binding_attribute, $source_value ); 283 } 273 $source_callback = $block_binding_source['get_value_callback']; 274 $source_args = ! empty( $block_binding['args'] ) && is_array( $block_binding['args'] ) ? $block_binding['args'] : array(); 275 $source_value = call_user_func_array( $source_callback, array( $source_args, $this, $attribute_name ) ); 276 277 // If the value is not null, process the HTML based on the block and the attribute. 278 if ( ! is_null( $source_value ) ) { 279 $modified_block_content = $this->replace_html( $modified_block_content, $attribute_name, $source_value ); 280 } 281 } 282 284 283 return $modified_block_content; 285 284 } 286 285 287 286 /** 288 * Depending on the block attribute s, replace the HTML based on the value returned by the source.287 * Depending on the block attribute name, replace its value in the HTML based on the value provided. 289 288 * 290 289 * @since 6.5.0 291 290 * 292 * @param string $block_content Block content.293 * @param string $ block_name The name of the block to process.294 * @param string $block_attr The attribute of the block we want to process.295 * @ param string $source_value The value used to replace the HTML.296 */ 297 private function replace_html( string $block_content, string $ block_name, string $block_attr, string$source_value ) {291 * @param string $block_content Block content. 292 * @param string $attribute_name The attribute name to replace. 293 * @param mixed $source_value The value used to replace in the HTML. 294 * @return string The modified block content. 295 */ 296 private function replace_html( string $block_content, string $attribute_name, $source_value ) { 298 297 $block_type = $this->block_type; 299 if ( null === $block_type || ! isset( $block_type->attributes[ $block_attr] ) ) {298 if ( ! isset( $block_type->attributes[ $attribute_name ] ) ) { 300 299 return $block_content; 301 300 } 302 301 303 302 // Depending on the attribute source, the processing will be different. 304 switch ( $block_type->attributes[ $ block_attr]['source'] ) {303 switch ( $block_type->attributes[ $attribute_name ]['source'] ) { 305 304 case 'html': 306 305 case 'rich-text': … … 309 308 // TODO: Support for CSS selectors whenever they are ready in the HTML API. 310 309 // In the meantime, support comma-separated selectors by exploding them into an array. 311 $selectors = explode( ',', $block_type->attributes[ $ block_attr]['selector'] );310 $selectors = explode( ',', $block_type->attributes[ $attribute_name ]['selector'] ); 312 311 // Add a bookmark to the first tag to be able to iterate over the selectors. 313 312 $block_reader->next_tag(); … … 317 316 // Store the parent tag and its attributes to be able to restore them later in the button. 318 317 // The button block has a wrapper while the paragraph and heading blocks don't. 319 if ( 'core/button' === $ block_name ) {318 if ( 'core/button' === $this->name ) { 320 319 $button_wrapper = $block_reader->get_tag(); 321 320 $button_wrapper_attribute_names = $block_reader->get_attribute_names_with_prefix( '' ); … … 349 348 $amended_content->set_attribute( $attribute_key, $attribute_value ); 350 349 } 351 if ( 'core/paragraph' === $ block_name || 'core/heading' === $block_name ) {350 if ( 'core/paragraph' === $this->name || 'core/heading' === $this->name ) { 352 351 return $amended_content->get_updated_html(); 353 352 } 354 if ( 'core/button' === $ block_name ) {353 if ( 'core/button' === $this->name ) { 355 354 $button_markup = "<$button_wrapper>{$amended_content->get_updated_html()}</$button_wrapper>"; 356 355 $amended_button = new WP_HTML_Tag_Processor( $button_markup ); … … 373 372 array( 374 373 // TODO: build the query from CSS selector. 375 'tag_name' => $block_type->attributes[ $ block_attr]['selector'],374 'tag_name' => $block_type->attributes[ $attribute_name ]['selector'], 376 375 ) 377 376 ) ) { 378 377 return $block_content; 379 378 } 380 $amended_content->set_attribute( $block_type->attributes[ $ block_attr]['attribute'], esc_attr( $source_value ) );379 $amended_content->set_attribute( $block_type->attributes[ $attribute_name ]['attribute'], esc_attr( $source_value ) ); 381 380 return $amended_content->get_updated_html(); 382 381 break; -
trunk/src/wp-settings.php
r57514 r57526 345 345 require ABSPATH . WPINC . '/class-wp-navigation-fallback.php'; 346 346 require ABSPATH . WPINC . '/block-bindings.php'; 347 require ABSPATH . WPINC . '/block-bindings/pattern-overrides.php'; 348 require ABSPATH . WPINC . '/block-bindings/post-meta.php'; 347 349 require ABSPATH . WPINC . '/blocks.php'; 348 350 require ABSPATH . WPINC . '/blocks/index.php'; … … 377 379 require ABSPATH . WPINC . '/class-wp-script-modules.php'; 378 380 require ABSPATH . WPINC . '/script-modules.php'; 379 require ABSPATH . WPINC . '/block-bindings/sources/post-meta.php';380 require ABSPATH . WPINC . '/block-bindings/sources/pattern.php';381 381 require ABSPATH . WPINC . '/interactivity-api.php'; 382 382 -
trunk/tests/phpunit/tests/block-bindings/register.php
r57514 r57526 18 18 19 19 /** 20 * Set up before each test.21 *22 * @since 6.5.023 */24 public function set_up() {25 foreach ( get_all_registered_block_bindings_sources() as $source_name => $source_properties ) {26 unregister_block_bindings_source( $source_name );27 }28 29 parent::set_up();30 }31 32 /**33 20 * Tear down after each test. 34 21 * … … 37 24 public function tear_down() { 38 25 foreach ( get_all_registered_block_bindings_sources() as $source_name => $source_properties ) { 39 unregister_block_bindings_source( $source_name ); 26 if ( str_starts_with( $source_name, 'test/' ) ) { 27 unregister_block_bindings_source( $source_name ); 28 } 40 29 } 41 30 … … 50 39 * @covers ::register_block_bindings_source 51 40 * @covers ::get_all_registered_block_bindings_sources 41 * @covers ::get_block_bindings_source 52 42 */ 53 43 public function test_get_all_registered() { … … 65 55 66 56 $expected = array( 67 $source_one_name => array_merge( array( 'name' => $source_one_name ), $source_one_properties ), 68 $source_two_name => array_merge( array( 'name' => $source_two_name ), $source_two_properties ), 69 $source_three_name => array_merge( array( 'name' => $source_three_name ), $source_three_properties ), 57 $source_one_name => array_merge( array( 'name' => $source_one_name ), $source_one_properties ), 58 $source_two_name => array_merge( array( 'name' => $source_two_name ), $source_two_properties ), 59 $source_three_name => array_merge( array( 'name' => $source_three_name ), $source_three_properties ), 60 'core/post-meta' => get_block_bindings_source( 'core/post-meta' ), 61 'core/pattern-overrides' => get_block_bindings_source( 'core/pattern-overrides' ), 70 62 ); 71 63 72 64 $registered = get_all_registered_block_bindings_sources(); 73 $this->assert Same( $expected, $registered );65 $this->assertEquals( $expected, $registered ); 74 66 } 75 67 -
trunk/tests/phpunit/tests/block-bindings/render.php
r57525 r57526 1 1 <?php 2 2 /** 3 * Unit tests covering the Block Bindings public API.3 * Tests for Block Bindings integration with block rendering. 4 4 * 5 5 * @package WordPress … … 9 9 * @group blocks 10 10 * @group block-bindings 11 *12 * @covers register_block_bindings_source13 11 */ 14 class WP_Block_Bindings_ Testextends WP_UnitTestCase {12 class WP_Block_Bindings_Render extends WP_UnitTestCase { 15 13 16 14 const SOURCE_NAME = 'test/source'; … … 20 18 21 19 /** 22 * Set up beforeeach test.20 * Tear down after each test. 23 21 * 24 22 * @since 6.5.0 25 23 */ 26 public function set_up() {24 public function tear_down() { 27 25 foreach ( get_all_registered_block_bindings_sources() as $source_name => $source_properties ) { 28 26 if ( str_starts_with( $source_name, 'test/' ) ) { … … 31 29 } 32 30 33 parent:: set_up();31 parent::tear_down(); 34 32 } 35 33 … … 39 37 * @ticket 60282 40 38 * 41 * @covers register_block_bindings_source39 * @covers ::register_block_bindings_source 42 40 */ 43 41 public function test_update_block_with_value_from_source() { … … 64 62 $result = $block->render(); 65 63 66 // Check if the block content was updated correctly.67 64 $this->assertEquals( $expected, $result, 'The block content should be updated with the value returned by the source.' ); 68 65 } … … 73 70 * @ticket 60282 74 71 * 75 * @covers register_block_bindings_source72 * @covers ::register_block_bindings_source 76 73 */ 77 74 public function test_passing_arguments_to_source() { … … 89 86 ); 90 87 91 $key = 'test'; 92 88 $value = 'test'; 93 89 $block_content = <<<HTML 94 <!-- wp:paragraph {"metadata":{"bindings":{"content":{"source":"test/source", "args": {"key": "$ key"}}}}} --><p>This should not appear</p><!-- /wp:paragraph -->90 <!-- wp:paragraph {"metadata":{"bindings":{"content":{"source":"test/source", "args": {"key": "$value"}}}}} --><p>This should not appear</p><!-- /wp:paragraph --> 95 91 HTML; 96 92 … … 98 94 $block = new WP_Block( $parsed_blocks[0] ); 99 95 100 $expected = "<p>The attribute name is 'content' and its binding has argument 'key' with value ' test'.</p>";96 $expected = "<p>The attribute name is 'content' and its binding has argument 'key' with value '$value'.</p>"; 101 97 $result = $block->render(); 102 98 103 // Check if the block content was updated correctly.104 99 $this->assertEquals( $expected, $result, 'The block content should be updated with the value returned by the source.' ); 105 100 }
Note: See TracChangeset
for help on using the changeset viewer.