WordPress.org

Make WordPress Core

Changeset 49695


Ignore:
Timestamp:
11/25/2020 01:18:25 AM (10 months 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.