Make WordPress Core

Changeset 49695


Ignore:
Timestamp:
11/25/2020 01:18:25 AM (6 years ago)
Author:
noisysocks
Message:

Editor: Remove render_block hooks from WP_Block

Reverts the move of pre_render_block, render_block_data, and
render_block_context to WP_Block.

This change has more implications than first thought so will be revisted later
in 5.7.

Reverts [49609,49608].
See #51612.

Location:
trunk
Files:
3 edited

Legend:

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

    r49608 r49695  
    663663
    664664        /**
    665          * Allows render_block() or WP_Block::render() to be short-circuited, by
    666          * returning a non-null value.
     665         * Allows render_block() to be short-circuited, by returning a non-null value.
    667666         *
    668667         * @since 5.1.0
     
    675674                return $pre_render;
    676675        }
     676
     677        $source_block = $parsed_block;
     678
     679        /**
     680         * Filters the block being rendered in render_block(), before it's processed.
     681         *
     682         * @since 5.1.0
     683         *
     684         * @param array $parsed_block The block being rendered.
     685         * @param array $source_block An un-modified copy of $parsed_block, as it appeared in the source content.
     686         */
     687        $parsed_block = apply_filters( 'render_block_data', $parsed_block, $source_block );
    677688
    678689        $context = array();
     
    697708        }
    698709
     710        /**
     711         * Filters the default context provided to a rendered block.
     712         *
     713         * @since 5.5.0
     714         *
     715         * @param array $context      Default context.
     716         * @param array $parsed_block Block being rendered, filtered by `render_block_data`.
     717         */
     718        $context = apply_filters( 'render_block_context', $context, $parsed_block );
     719
    699720        $block = new WP_Block( $parsed_block, $context );
    700721
  • trunk/src/wp-includes/class-wp-block.php

    r49609 r49695  
    1212 * @since 5.5.0
    1313 * @property array $attributes
    14  * @property array $context
    15  * @property WP_Block[] $inner_blocks;
    16  * @property string $inner_html;
    17  * @property array $inner_content;
    1814 */
    1915class WP_Block {
     
    2824
    2925        /**
     26         * Name of block.
     27         *
     28         * @example "core/paragraph"
     29         *
     30         * @since 5.5.0
     31         * @var string
     32         */
     33        public $name;
     34
     35        /**
     36         * Block type associated with the instance.
     37         *
     38         * @since 5.5.0
     39         * @var WP_Block_Type
     40         */
     41        public $block_type;
     42
     43        /**
     44         * Block context values.
     45         *
     46         * @since 5.5.0
     47         * @var array
     48         */
     49        public $context = array();
     50
     51        /**
    3052         * All available context of the current hierarchy.
    3153         *
     
    3759
    3860        /**
    39          * Name of block.
    40          *
    41          * @example "core/paragraph"
     61         * List of inner blocks (of this same class)
     62         *
     63         * @since 5.5.0
     64         * @var WP_Block[]
     65         */
     66        public $inner_blocks = array();
     67
     68        /**
     69         * Resultant HTML from inside block comment delimiters after removing inner
     70         * blocks.
     71         *
     72         * @example "...Just <!-- wp:test /--> testing..." -> "Just testing..."
    4273         *
    4374         * @since 5.5.0
    4475         * @var string
    4576         */
    46         public $name;
    47 
    48         /**
    49          * Block type associated with the instance.
    50          *
    51          * @since 5.5.0
    52          * @var WP_Block_Type
    53          */
    54         public $block_type;
    55 
    56         /**
    57          * Map of block property names and their cached value.
    58          *
    59          * Some block properties are computed lazily using a getter function. The
    60          * result is then cached here for subsequent use.
    61          *
    62          * @since 5.6.0
    63          * @var array
    64          */
    65         protected $cached_properties = array();
    66 
    67         /**
    68          * Creates a block instance from a backing `$parsed_block` array and list of
    69          * `$available_context`. From these, the block's dynamic properties can be
    70          * derived.
     77        public $inner_html = '';
     78
     79        /**
     80         * List of string fragments and null markers where inner blocks were found
     81         *
     82         * @example array(
     83         *   'inner_html'    => 'BeforeInnerAfter',
     84         *   'inner_blocks'  => array( block, block ),
     85         *   'inner_content' => array( 'Before', null, 'Inner', null, 'After' ),
     86         * )
     87         *
     88         * @since 5.5.0
     89         * @var array
     90         */
     91        public $inner_content = array();
     92
     93        /**
     94         * Constructor.
     95         *
     96         * Populates object properties from the provided block instance argument.
    7197         *
    7298         * The given array of context values will not necessarily be available on
     
    78104         * @since 5.5.0
    79105         *
    80          * @param array                  $parsed_block      Array of parsed block properties.
     106         * @param array                  $block             Array of parsed block properties.
    81107         * @param array                  $available_context Optional array of ancestry context values.
    82108         * @param WP_Block_Type_Registry $registry          Optional block type registry.
    83109         */
    84         public function __construct( $parsed_block, $available_context = array(), $registry = null ) {
     110        public function __construct( $block, $available_context = array(), $registry = null ) {
     111                $this->parsed_block = $block;
     112                $this->name         = $block['blockName'];
     113
    85114                if ( is_null( $registry ) ) {
    86                         $this->registry = WP_Block_Type_Registry::get_instance();
    87                 } else {
    88                         $this->registry = $registry;
    89                 }
    90 
    91                 $this->reset( $parsed_block, $available_context );
    92         }
    93 
    94         /**
    95          * Changes the backing `$parsed_block` and `$available_context` used to
    96          * derive the block's dynamic properties.
    97          *
    98          * @since 5.6.0
    99 
    100          * @param array $parsed_block      Array of parsed block properties.
    101          * @param array $available_context Optional array of ancestry context values.
    102          * @param array $cached_properties Optional cache of dynamic properties to use.
    103          */
    104         protected function reset(
    105                 $parsed_block,
    106                 $available_context = array(),
    107                 $cached_properties = array()
    108         ) {
    109                 $this->parsed_block      = $parsed_block;
     115                        $registry = WP_Block_Type_Registry::get_instance();
     116                }
     117
     118                $this->block_type = $registry->get_registered( $this->name );
     119
    110120                $this->available_context = $available_context;
    111                 $this->name              = $parsed_block['blockName'];
    112                 $this->block_type        = $this->registry->get_registered( $this->name );
    113                 $this->cached_properties = $cached_properties;
    114         }
    115 
    116         /**
    117          * Getter used for the block's dynamic properties:
    118          *
    119          * - `$block->attributes`
    120          * - `$block->context`
    121          * - `$block->inner_blocks`
    122          * - `$block->inner_html`
    123          * - `$block->inner_content`
    124          *
    125          * Each dynamic property is obtained by calling the associated getter
    126          * function (e.g. `this->get_attributes()`). The result is then cached in
    127          * `$this->cached_attributes` for subsequent calls.
    128          *
    129          * @since 5.5.0
    130          *
    131          * @param string $name Property name.
    132          * @return array|null Prepared attributes, or null.
    133          */
    134         public function __get( $name ) {
    135                 if ( method_exists( $this, "get_$name" ) ) {
    136                         if ( ! isset( $this->cached_properties[ $name ] ) ) {
    137                                 $this->cached_properties[ $name ] = $this->{"get_$name"}();
    138                         }
    139 
    140                         return $this->cached_properties[ $name ];
    141                 }
    142 
    143                 return null;
    144         }
    145 
    146         /**
    147          * Block attributes.
    148          *
    149          * Use `$block->attributes` to access this.
    150          *
    151          * @since 5.6.0
    152          * @return array
    153          */
    154         protected function get_attributes() {
    155                 $attributes = isset( $this->parsed_block['attrs'] ) ?
    156                         $this->parsed_block['attrs'] :
    157                         array();
    158 
    159                 if ( ! is_null( $this->block_type ) ) {
    160                         return $this->block_type->prepare_attributes_for_render( $attributes );
    161                 }
    162 
    163                 return $attributes;
    164         }
    165 
    166         /**
    167          * Block context values.
    168          *
    169          * Use `$block->context` to access this.
    170          *
    171          * @since 5.6.0
    172          * @return array
    173          */
    174         protected function get_context() {
    175                 $context = array();
    176121
    177122                if ( ! empty( $this->block_type->uses_context ) ) {
    178123                        foreach ( $this->block_type->uses_context as $context_name ) {
    179124                                if ( array_key_exists( $context_name, $this->available_context ) ) {
    180                                         $context[ $context_name ] = $this->available_context[ $context_name ];
     125                                        $this->context[ $context_name ] = $this->available_context[ $context_name ];
    181126                                }
    182127                        }
    183128                }
    184129
    185                 return $context;
    186         }
    187 
    188         /**
    189          * List of inner blocks (of this same class).
    190          *
    191          * Use `$block->inner_blocks` to access this.
    192          *
    193          * @since 5.6.0
    194          * @return WP_Block[]
    195          */
    196         protected function get_inner_blocks() {
    197                 if ( ! empty( $this->parsed_block['innerBlocks'] ) ) {
     130                if ( ! empty( $block['innerBlocks'] ) ) {
    198131                        $child_context = $this->available_context;
    199132
     
    206139                        }
    207140
    208                         return new WP_Block_List(
    209                                 $this->parsed_block['innerBlocks'],
    210                                 $child_context,
    211                                 $this->registry
    212                         );
    213                 }
    214 
    215                 return array();
     141                        $this->inner_blocks = new WP_Block_List( $block['innerBlocks'], $child_context, $registry );
     142                }
     143
     144                if ( ! empty( $block['innerHTML'] ) ) {
     145                        $this->inner_html = $block['innerHTML'];
     146                }
     147
     148                if ( ! empty( $block['innerContent'] ) ) {
     149                        $this->inner_content = $block['innerContent'];
     150                }
    216151        }
    217152
    218153        /**
    219          * Resultant HTML from inside block comment delimiters after removing inner
    220          * blocks.
    221          *
    222          * Use `$block->inner_html` to access this.
    223          *
    224          * @example "...Just <!-- wp:test /--> testing..." -> "Just testing..."
    225          *
    226          * @since 5.6.0
    227          * @return string
    228          */
    229         protected function get_inner_html() {
    230                 if ( ! empty( $this->parsed_block['innerHTML'] ) ) {
    231                         return $this->parsed_block['innerHTML'];
    232                 }
    233 
    234                 return '';
    235         }
    236 
    237         /**
    238          * List of string fragments and null markers where inner blocks were found
    239          *
    240          * Use `$block->inner_content` to access this.
    241          *
    242          * @example array(
    243          *   'inner_html'    => 'BeforeInnerAfter',
    244          *   'inner_blocks'  => array( block, block ),
    245          *   'inner_content' => array( 'Before', null, 'Inner', null, 'After' ),
    246          * )
    247          *
    248          * @since 5.6.0
    249          * @return array
    250          */
    251         protected function get_inner_content() {
    252                 if ( ! empty( $this->parsed_block['innerContent'] ) ) {
    253                         return $this->parsed_block['innerContent'];
    254                 }
    255 
    256                 return array();
     154         * Returns a value from an inaccessible property.
     155         *
     156         * This is used to lazily initialize the `attributes` property of a block,
     157         * such that it is only prepared with default attributes at the time that
     158         * the property is accessed. For all other inaccessible properties, a `null`
     159         * value is returned.
     160         *
     161         * @since 5.5.0
     162         *
     163         * @param string $name Property name.
     164         * @return array|null Prepared attributes, or null.
     165         */
     166        public function __get( $name ) {
     167                if ( 'attributes' === $name ) {
     168                        $this->attributes = isset( $this->parsed_block['attrs'] ) ?
     169                                $this->parsed_block['attrs'] :
     170                                array();
     171
     172                        if ( ! is_null( $this->block_type ) ) {
     173                                $this->attributes = $this->block_type->prepare_attributes_for_render( $this->attributes );
     174                        }
     175
     176                        return $this->attributes;
     177                }
     178
     179                return null;
    257180        }
    258181
     
    271194        public function render( $options = array() ) {
    272195                global $post;
    273 
    274                 /** This filter is documented in wp-includes/blocks.php */
    275                 $pre_render = apply_filters( 'pre_render_block', null, $this->parsed_block );
    276                 if ( ! is_null( $pre_render ) ) {
    277                         return $pre_render;
    278                 }
    279 
    280196                $options = wp_parse_args(
    281197                        $options,
     
    285201                );
    286202
    287                 $initial_parsed_block      = $this->parsed_block;
    288                 $initial_available_context = $this->available_context;
    289                 $initial_cached_properties = $this->cached_properties;
    290 
    291                 /**
    292                  * Filters a block which is to be rendered by render_block() or
    293                  * WP_Block::render().
    294                  *
    295                  * @since 5.1.0
    296                  *
    297                  * @param array $parsed_block The block being rendered.
    298                  * @param array $source_block An un-modified copy of $parsed_block, as it appeared in the source content.
    299                  */
    300                 $parsed_block = apply_filters(
    301                         'render_block_data',
    302                         $this->parsed_block,
    303                         $initial_parsed_block
    304                 );
    305 
    306                 /**
    307                  * Filters the default context of a block which is to be rendered by
    308                  * render_block() or WP_Block::render().
    309                  *
    310                  * @since 5.5.0
    311                  *
    312                  * @param array $available_context Default context.
    313                  * @param array $parsed_block      Block being rendered, filtered by `render_block_data`.
    314                  */
    315                 $available_context = apply_filters(
    316                         'render_block_context',
    317                         $this->available_context,
    318                         $this->parsed_block
    319                 );
    320 
    321                 $this->reset( $parsed_block, $available_context );
    322 
    323                 $is_dynamic = $options['dynamic']
    324                         && $this->name
    325                         && null !== $this->block_type
    326                         && $this->block_type->is_dynamic();
    327 
     203                $is_dynamic    = $options['dynamic'] && $this->name && null !== $this->block_type && $this->block_type->is_dynamic();
    328204                $block_content = '';
    329205
     
    343219                        WP_Block_Supports::$block_to_render = $this->parsed_block;
    344220
    345                         $block_content = (string) call_user_func(
    346                                 $this->block_type->render_callback,
    347                                 $this->attributes,
    348                                 $block_content,
    349                                 $this
    350                         );
     221                        $block_content = (string) call_user_func( $this->block_type->render_callback, $this->attributes, $block_content, $this );
    351222
    352223                        WP_Block_Supports::$block_to_render = $parent;
     
    371242                 * @param array  $block         The full block, including name and attributes.
    372243                 */
    373                 $block_content = apply_filters( 'render_block', $block_content, $this->parsed_block );
    374 
    375                 $this->reset(
    376                         $initial_parsed_block,
    377                         $initial_available_context,
    378                         $initial_cached_properties
    379                 );
    380 
    381                 return $block_content;
     244                return apply_filters( 'render_block', $block_content, $this->parsed_block );
    382245        }
    383246
  • trunk/tests/phpunit/tests/blocks/block.php

    r49608 r49695  
    4646        }
    4747
    48         function filter_pre_render_block( $pre_render, $parsed_block ) {
    49                 if ( 'core/skip' === $parsed_block['blockName'] ) {
    50                         return 'Hello world!';
    51                 }
    52                 return null;
    53         }
    54 
    55         function filter_render_block_data( $parsed_block, $source_block ) {
    56                 $parsed_block['attrs']['tag'] = $parsed_block['attrs']['tag'] . '-filtered';
    57                 return $parsed_block;
    58         }
    59 
    60         function filter_render_block_context( $available_context, $parsed_block ) {
    61                 $available_context['core/recordId'] += 1;
    62                 return $available_context;
    63         }
    64 
    6548        /**
    6649         * @ticket 49927
     
    412395        }
    413396
    414         /**
    415          * @ticket 51612
    416          */
    417         function test_applies_pre_render_block_filter() {
    418                 $this->registry->register( 'core/skip', array() );
    419 
    420                 add_filter( 'pre_render_block', array( $this, 'filter_pre_render_block' ), 10, 2 );
    421 
    422                 $parsed_blocks = parse_blocks( '<!-- wp:skip /-->' );
    423                 $parsed_block  = $parsed_blocks[0];
    424                 $context       = array();
    425                 $block         = new WP_Block( $parsed_block, $context, $this->registry );
    426 
    427                 $rendered_content = $block->render();
    428 
    429                 remove_filter( 'pre_render_block', array( $this, 'filter_pre_render_block' ) );
    430 
    431                 $this->assertSame( 'Hello world!', $rendered_content );
    432         }
    433 
    434         /**
    435          * @ticket 51612
    436          */
    437         function test_applies_pre_render_block_filter_to_inner_blocks() {
    438                 $this->registry->register( 'core/outer', array() );
    439                 $this->registry->register( 'core/skip', array() );
    440 
    441                 add_filter( 'pre_render_block', array( $this, 'filter_pre_render_block' ), 10, 2 );
    442 
    443                 $parsed_blocks = parse_blocks( '<!-- wp:outer --><!-- wp:skip /--> How are you?<!-- /wp:outer -->' );
    444                 $parsed_block  = $parsed_blocks[0];
    445                 $context       = array();
    446                 $block         = new WP_Block( $parsed_block, $context, $this->registry );
    447 
    448                 $rendered_content = $block->render();
    449 
    450                 remove_filter( 'pre_render_block', array( $this, 'filter_pre_render_block' ) );
    451 
    452                 $this->assertSame( 'Hello world! How are you?', $rendered_content );
    453         }
    454 
    455         /**
    456          * @ticket 51612
    457          */
    458         function test_applies_render_block_data_filter() {
    459                 $this->registry->register(
    460                         'core/wrapper',
    461                         array(
    462                                 'attributes'      => array(
    463                                         'tag' => array(
    464                                                 'type' => 'string',
    465                                         ),
    466                                 ),
    467                                 'render_callback' => function( $block_attributes, $content ) {
    468                                         return sprintf(
    469                                                 '<%1$s>%2$s</%1$s>',
    470                                                 $block_attributes['tag'],
    471                                                 $content
    472                                         );
    473                                 },
    474                         )
    475                 );
    476 
    477                 add_filter( 'render_block_data', array( $this, 'filter_render_block_data' ), 10, 2 );
    478 
    479                 $parsed_blocks = parse_blocks( '<!-- wp:wrapper {"tag":"outer"} --><!-- wp:wrapper {"tag":"inner"} -->Hello!<!-- /wp:wrapper --><!-- /wp:wrapper -->' );
    480                 $parsed_block  = $parsed_blocks[0];
    481                 $context       = array();
    482                 $block         = new WP_Block( $parsed_block, $context, $this->registry );
    483 
    484                 $rendered_content = $block->render();
    485 
    486                 remove_filter( 'render_block_data', array( $this, 'filter_render_block_data' ) );
    487 
    488                 $this->assertSame( '<outer-filtered><inner-filtered>Hello!</inner-filtered></outer-filtered>', $rendered_content );
    489         }
    490 
    491         /**
    492          * @ticket 51612
    493          */
    494         function test_applies_render_block_context_filter() {
    495                 $this->registry->register(
    496                         'core/provider',
    497                         array(
    498                                 'attributes'       => array(
    499                                         'recordId' => array(
    500                                                 'type' => 'number',
    501                                         ),
    502                                 ),
    503                                 'uses_context'     => array( 'core/recordId' ),
    504                                 'provides_context' => array(
    505                                         'core/recordId' => 'recordId',
    506                                 ),
    507                         )
    508                 );
    509                 $this->registry->register(
    510                         'core/consumer',
    511                         array(
    512                                 'uses_context'    => array( 'core/recordId' ),
    513                                 'render_callback' => function( $block_attributes, $content, $block ) {
    514                                         return sprintf( 'Record ID: %d ', $block->context['core/recordId'] );
    515                                 },
    516                         )
    517                 );
    518 
    519                 add_filter( 'render_block_context', array( $this, 'filter_render_block_context' ), 10, 2 );
    520 
    521                 $parsed_blocks = parse_blocks( '<!-- wp:consumer /--><!-- wp:provider {"recordId":20} --><!-- wp:consumer /--><!-- /wp:provider -->' );
    522                 $context       = array( 'core/recordId' => 10 );
    523 
    524                 $rendered_content = '';
    525 
    526                 foreach ( $parsed_blocks as $parsed_block ) {
    527                         $block = new WP_Block( $parsed_block, $context, $this->registry );
    528 
    529                         $rendered_content .= $block->render();
    530                 }
    531 
    532                 remove_filter( 'render_block_context', array( $this, 'filter_render_block_context' ) );
    533 
    534                 $this->assertSame( 'Record ID: 11 Record ID: 21 ', $rendered_content );
    535         }
    536 
    537397}
Note: See TracChangeset for help on using the changeset viewer.