Make WordPress Core


Ignore:
Timestamp:
01/19/2024 08:52:06 PM (18 months ago)
Author:
joemcgill
Message:

Editor: Support deferred block variation initialization on the server.

When registering blocks on the server using register_block_type() or similar functions, a set of block type variations can also be registered. However, in some cases building this variation data during block registration can be an expensive process, which is not needed in most contexts.

To address this problem, this adds support to the WP_Block_Type object for a new property, variation_callback, which can be used to register a callback for building variation data only when the block variations data is needed. The WP_Block_Type::variations property has been changed to a private property that is now accessed through the magic __get() method. The magic getter makes use of a new public method, WP_Block_Type::get_variations which will build variations from a registered callback if variations have not already been built.

Props spacedmonkey, thekt12, Mamaduka, gaambo, gziolo, mukesh27, joemcgill.
Fixes #59969.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/tests/phpunit/tests/blocks/wpBlockType.php

    r57068 r57315  
    461461        );
    462462    }
     463
     464    /**
     465     * @ticket 59969
     466     */
     467    public function test_variation_callback() {
     468        $block_type = new WP_Block_Type(
     469            'test/block',
     470            array(
     471                'title'              => 'Test title',
     472                'variation_callback' => array( $this, 'mock_variation_callback' ),
     473            )
     474        );
     475
     476        $this->assertSameSets( $this->mock_variation_callback(), $block_type->variations );
     477    }
     478
     479    /**
     480     * @ticket 59969
     481     * @covers WP_Block_Type::get_variations
     482     */
     483    public function test_get_variations() {
     484        $block_type = new WP_Block_Type(
     485            'test/block',
     486            array(
     487                'title'              => 'Test title',
     488                'variation_callback' => array( $this, 'mock_variation_callback' ),
     489            )
     490        );
     491
     492        $this->assertSameSets( $this->mock_variation_callback(), $block_type->get_variations() );
     493    }
     494
     495    /**
     496     * @ticket 59969
     497     */
     498    public function test_variations_precedence_over_callback() {
     499        $test_variations = array( 'name' => 'test1' );
     500
     501        $block_type = new WP_Block_Type(
     502            'test/block',
     503            array(
     504                'title'              => 'Test title',
     505                'variations'         => $test_variations,
     506                'variation_callback' => array( $this, 'mock_variation_callback' ),
     507            )
     508        );
     509
     510        // If the variations are defined, the callback should not be used.
     511        $this->assertSameSets( $test_variations, $block_type->variations );
     512    }
     513
     514    /**
     515     * @ticket 59969
     516     */
     517    public function test_variations_callback_are_lazy_loaded() {
     518        $callback_called = false;
     519
     520        $block_type = new WP_Block_Type(
     521            'test/block',
     522            array(
     523                'title'              => 'Test title',
     524                'variation_callback' => function () use ( &$callback_called ) {
     525                    $callback_called = true;
     526                    return $this->mock_variation_callback();
     527                },
     528            )
     529        );
     530
     531        $this->assertSame( false, $callback_called, 'The callback should not be called before the variations are accessed.' );
     532        $block_type->variations; // access the variations.
     533        $this->assertSame( true, $callback_called, 'The callback should be called when the variations are accessed.' );
     534    }
     535
     536    /**
     537     * @ticket 59969
     538     * @covers WP_Block_Type::get_variations
     539     */
     540    public function test_variations_precedence_over_callback_post_registration() {
     541        $test_variations = array( 'name' => 'test1' );
     542        $callback_called = false;
     543
     544        $block_type             = new WP_Block_Type(
     545            'test/block',
     546            array(
     547                'title'              => 'Test title',
     548                'variation_callback' => function () use ( &$callback_called ) {
     549                    $callback_called = true;
     550                    return $this->mock_variation_callback();
     551                },
     552            )
     553        );
     554        $block_type->variations = $test_variations;
     555
     556        // If the variations are defined after registration but before first access, the callback should not override it.
     557        $this->assertSameSets( $test_variations, $block_type->get_variations(), 'Variations are same as variations set' );
     558        $this->assertSame( false, $callback_called, 'The callback was never called.' );
     559    }
     560
     561    /**
     562     * @ticket 59969
     563     * @covers WP_Block_Type::get_variations
     564     */
     565    public function test_variations_callback_happens_only_once() {
     566        $callback_count = 0;
     567
     568        $block_type = new WP_Block_Type(
     569            'test/block',
     570            array(
     571                'title'              => 'Test title',
     572                'variation_callback' => function () use ( &$callback_count ) {
     573                    $callback_count++;
     574                    return $this->mock_variation_callback();
     575                },
     576            )
     577        );
     578
     579        $this->assertSame( 0, $callback_count, 'The callback should not be called before the variations are accessed.' );
     580        $block_type->get_variations(); // access the variations.
     581        $this->assertSame( 1, $callback_count, 'The callback should be called when the variations are accessed.' );
     582        $block_type->get_variations(); // access the variations again.
     583        $this->assertSame( 1, $callback_count, 'The callback should not be called again.' );
     584    }
     585
     586    /**
     587     * Test filter function for get_block_type_variations filter.
     588     *
     589     * @param array $variations Block variations before filter.
     590     * @param WP_Block_Type $block_type Block type.
     591     *
     592     * @return array Block variations after filter.
     593     */
     594    public function filter_test_variations( $variations, $block_type ) {
     595        return array( array( 'name' => 'test1' ) );
     596    }
     597
     598    /**
     599     * @ticket 59969
     600     */
     601    public function test_get_block_type_variations_filter_with_variation_callback() {
     602        // Filter will override the variations obtained from the callback.
     603        add_filter( 'get_block_type_variations', array( $this, 'filter_test_variations' ), 10, 2 );
     604        $expected_variations = array( array( 'name' => 'test1' ) );
     605
     606        $callback_called = false;
     607        $block_type      = new WP_Block_Type(
     608            'test/block',
     609            array(
     610                'title'              => 'Test title',
     611                'variation_callback' => function () use ( &$callback_called ) {
     612                    $callback_called = true;
     613                    return $this->mock_variation_callback();
     614                },
     615            )
     616        );
     617
     618        $obtained_variations = $block_type->variations; // access the variations.
     619
     620        $this->assertSame( true, $callback_called, 'The callback should be called when the variations are accessed.' );
     621        $this->assertSameSets( $obtained_variations, $expected_variations, 'The variations obtained from the callback should be filtered.' );
     622    }
     623
     624    /**
     625     * @ticket 59969
     626     */
     627    public function test_get_block_type_variations_filter_variations() {
     628        // Filter will override the variations set during registration.
     629        add_filter( 'get_block_type_variations', array( $this, 'filter_test_variations' ), 10, 2 );
     630        $expected_variations = array( array( 'name' => 'test1' ) );
     631
     632        $block_type = new WP_Block_Type(
     633            'test/block',
     634            array(
     635                'title'      => 'Test title',
     636                'variations' => $this->mock_variation_callback(),
     637            )
     638        );
     639
     640        $obtained_variations = $block_type->variations; // access the variations.
     641        $this->assertSameSets( $obtained_variations, $expected_variations, 'The variations that was initially set should be filtered.' );
     642    }
     643
     644    /**
     645     * Mock variation callback.
     646     *
     647     * @return array
     648     */
     649    public function mock_variation_callback() {
     650        return array(
     651            array( 'name' => 'var1' ),
     652            array( 'name' => 'var2' ),
     653        );
     654    }
    463655}
Note: See TracChangeset for help on using the changeset viewer.