Make WordPress Core

Changeset 57574


Ignore:
Timestamp:
02/09/2024 10:38:38 AM (3 months ago)
Author:
gziolo
Message:

Editor: Refactor block binding processing and attribute computation

Refactors the processing of block bindings into steps:

  • Gets the value for each "bound" attribute from the respective source.
  • Returns the computer attributes with values from the sources.
  • The computed attributes get injected into block's content.
  • The render_callback gets the updated list of attributes and processeded block content.

Fixes #60282.
Props czapla, gziolo, andraganescu, santosguillamot.

Location:
trunk
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/wp-includes/class-wp-block.php

    r57565 r57574  
    193193
    194194    /**
    195      * Processes the block bindings in block's attributes.
     195     * Processes the block bindings and updates the block attributes with the values from the sources.
    196196     *
    197197     * A block might contain bindings in its attributes. Bindings are mappings
     
    200200     * retrieve a value from outside the block, e.g. from post meta.
    201201     *
    202      * This function will process those bindings and replace the HTML with the value of the binding.
    203      * The value is retrieved from the source of the binding.
     202     * This function will process those bindings and update the block's attributes
     203     * with the values coming from the bindings.
    204204     *
    205205     * ### Example
     
    229229     * @since 6.5.0
    230230     *
    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      */
    235     private function process_block_bindings( $block_content ) {
     231     * @return array The computed block attributes for the provided block bindings.
     232     */
     233    private function process_block_bindings() {
    236234        $parsed_block = $this->parsed_block;
     235
     236        $computed_attributes = array();
    237237
    238238        // Allowed blocks that support block bindings.
     
    252252            ! is_array( $parsed_block['attrs']['metadata']['bindings'] )
    253253        ) {
    254             return $block_content;
    255         }
    256 
    257         $modified_block_content = $block_content;
     254            return $computed_attributes;
     255        }
     256
    258257        foreach ( $parsed_block['attrs']['metadata']['bindings'] as $attribute_name => $block_binding ) {
    259258            // If the attribute is not in the allowed list, process next attribute.
     
    276275            // If the value is not null, process the HTML based on the block and the attribute.
    277276            if ( ! is_null( $source_value ) ) {
    278                 $modified_block_content = $this->replace_html( $modified_block_content, $attribute_name, $source_value );
    279             }
    280         }
    281 
    282         return $modified_block_content;
     277                $computed_attributes[ $attribute_name ] = $source_value;
     278            }
     279        }
     280
     281        return $computed_attributes;
    283282    }
    284283
     
    392391     *
    393392     * @since 5.5.0
     393     * @since 6.5.0 Added block bindings processing.
    394394     *
    395395     * @global WP_Post $post Global post object.
     
    411411        );
    412412
     413        // Process the block bindings and get attributes updated with the values from the sources.
     414        $computed_attributes = $this->process_block_bindings();
     415        if ( ! empty( $computed_attributes ) ) {
     416            // Merge the computed attributes with the original attributes
     417            $this->attributes = array_merge( $this->attributes, $computed_attributes );
     418        }
     419
    413420        $is_dynamic    = $options['dynamic'] && $this->name && null !== $this->block_type && $this->block_type->is_dynamic();
    414421        $block_content = '';
     
    446453        }
    447454
     455        if ( ! empty( $computed_attributes ) && ! empty( $block_content ) ) {
     456            foreach ( $computed_attributes as $attribute_name => $source_value ) {
     457                $block_content = $this->replace_html( $block_content, $attribute_name, $source_value );
     458            }
     459        }
     460
    448461        if ( $is_dynamic ) {
    449462            $global_post = $post;
     
    488501            }
    489502        }
    490 
    491         // Process the block bindings for this block, if any are registered. This
    492         // will replace the block content with the value from a registered binding source.
    493         $block_content = $this->process_block_bindings( $block_content );
    494503
    495504        /**
  • trunk/tests/phpunit/tests/block-bindings/render.php

    r57526 r57574  
    5353
    5454        $block_content = <<<HTML
    55 <!-- wp:paragraph {"metadata":{"bindings":{"content":{"source":"test/source"}}}} --><p>This should not appear</p><!-- /wp:paragraph -->
     55<!-- wp:paragraph {"metadata":{"bindings":{"content":{"source":"test/source"}}}} -->
     56<p>This should not appear</p>
     57<!-- /wp:paragraph -->
    5658HTML;
    57 
    5859        $parsed_blocks = parse_blocks( $block_content );
    5960        $block         = new WP_Block( $parsed_blocks[0] );
     61        $result        = $block->render();
    6062
    61         $expected = '<p>test source value</p>';
    62         $result   = $block->render();
    63 
    64         $this->assertEquals( $expected, $result, 'The block content should be updated with the value returned by the source.' );
     63        $this->assertSame(
     64            'test source value',
     65            $block->attributes['content'],
     66            "The 'content' attribute should be updated with the value returned by the source."
     67        );
     68        $this->assertSame(
     69            '<p>test source value</p>',
     70            trim( $result ),
     71            'The block content should be updated with the value returned by the source.'
     72        );
    6573    }
    6674
     
    8694        );
    8795
    88         $value         = 'test';
    8996        $block_content = <<<HTML
    90 <!-- wp:paragraph {"metadata":{"bindings":{"content":{"source":"test/source", "args": {"key": "$value"}}}}} --><p>This should not appear</p><!-- /wp:paragraph -->
     97<!-- wp:paragraph {"metadata":{"bindings":{"content":{"source":"test/source", "args": {"key": "test"}}}}} -->
     98<p>This should not appear</p>
     99<!-- /wp:paragraph -->
    91100HTML;
    92 
    93101        $parsed_blocks = parse_blocks( $block_content );
    94102        $block         = new WP_Block( $parsed_blocks[0] );
     103        $result        = $block->render();
    95104
    96         $expected = "<p>The attribute name is 'content' and its binding has argument 'key' with value '$value'.</p>";
    97         $result   = $block->render();
     105        $this->assertSame(
     106            "The attribute name is 'content' and its binding has argument 'key' with value 'test'.",
     107            $block->attributes['content'],
     108            "The 'content' attribute should be updated with the value returned by the source."
     109        );
     110        $this->assertSame(
     111            "<p>The attribute name is 'content' and its binding has argument 'key' with value 'test'.</p>",
     112            trim( $result ),
     113            'The block content should be updated with the value returned by the source.'
     114        );
     115    }
    98116
    99         $this->assertEquals( $expected, $result, 'The block content should be updated with the value returned by the source.' );
     117    /**
     118     * Tests if the block content is updated with the value returned by the source
     119     * for the Image block in the placeholder state.
     120     *
     121     * @ticket 60282
     122     *
     123     * @covers ::register_block_bindings_source
     124     */
     125    public function test_update_block_with_value_from_source_image_placeholder() {
     126        $get_value_callback = function () {
     127            return 'https://example.com/image.jpg';
     128        };
     129
     130        register_block_bindings_source(
     131            self::SOURCE_NAME,
     132            array(
     133                'label'              => self::SOURCE_LABEL,
     134                'get_value_callback' => $get_value_callback,
     135            )
     136        );
     137
     138        $block_content = <<<HTML
     139<!-- wp:image {"metadata":{"bindings":{"url":{"source":"test/source"}}}} -->
     140<figure class="wp-block-image"><img alt=""/></figure>
     141<!-- /wp:image -->
     142HTML;
     143        $parsed_blocks = parse_blocks( $block_content );
     144        $block         = new WP_Block( $parsed_blocks[0] );
     145        $result        = $block->render();
     146
     147        $this->assertSame(
     148            'https://example.com/image.jpg',
     149            $block->attributes['url'],
     150            "The 'url' attribute should be updated with the value returned by the source."
     151        );
     152        $this->assertSame(
     153            '<figure class="wp-block-image"><img src="https://example.com/image.jpg" alt=""/></figure>',
     154            trim( $result ),
     155            'The block content should be updated with the value returned by the source.'
     156        );
    100157    }
    101158}
Note: See TracChangeset for help on using the changeset viewer.