Make WordPress Core


Ignore:
Timestamp:
09/21/2023 08:32:52 AM (10 months ago)
Author:
Bernhard Reiter
Message:

Blocks: Change traverse_and_serialize_block(s)'s callback signature.

During work on #59399, it was discovered that sibling block insertion wasn't likely going to work the way it was planned, which required devising an alternative solution. This new solution requires some changes to traverse_and_serialize_block(s):

  • Change the signature of the existing callback such that:
    • the return value is a string that will be prepended to the result of the inner block traversal and serialization;
    • the function arguments are: a reference to the current block (so it can be modified inline, which is important e.g. for theme attribute insertion), the parent block, and the previous block (instead of the block index and chunk index).
  • Add a second callback argument to traverse_and_serialize_block(s), which is called after the block is traversed and serialized.
    • Its function arguments are a reference to the current block, the parent block, and the next block.

Props gziolo.
Fixes #59412. See #59313.

File:
1 edited

Legend:

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

    r56634 r56644  
    887887
    888888/**
    889  * Traverses the block applying transformations using the callback provided and returns the content of a block,
    890  * including comment delimiters, serializing all attributes from the given parsed block.
    891  *
    892  * This should be used when there is a need to modify the saved block.
    893  * Prefer `serialize_block` when preparing a block to be saved to post content.
     889 * Traverses a parsed block tree and applies callbacks before and after serializing it.
     890 *
     891 * Recursively traverses the block and its inner blocks and applies the two callbacks provided as
     892 * arguments, the first one before serializing the block, and the second one after serializing it.
     893 * If either callback returns a string value, it will be prepended and appended to the serialized
     894 * block markup, respectively.
     895 *
     896 * The callbacks will receive a reference to the current block as their first argument, so that they
     897 * can also modify it, and the current block's parent block as second argument. Finally, the
     898 * `$pre_callback` receives the previous block, whereas the `$post_callback` receives
     899 * the next block as third argument.
     900 *
     901 * Serialized blocks are returned including comment delimiters, and with all attributes serialized.
     902 *
     903 * This function should be used when there is a need to modify the saved block, or to inject markup
     904 * into the return value. Prefer `serialize_block` when preparing a block to be saved to post content.
    894905 *
    895906 * @since 6.4.0
     
    897908 * @see serialize_block()
    898909 *
    899  * @param array    $block    A representative array of a single parsed block object. See WP_Block_Parser_Block.
    900  * @param callable $callback Callback to run on each block in the tree before serialization.
    901  *                           It is called with the following arguments: $block, $parent_block, $block_index, $chunk_index.
    902  * @return string String of rendered HTML.
    903  */
    904 function traverse_and_serialize_block( $block, $callback ) {
     910 * @param array    $block         A representative array of a single parsed block object. See WP_Block_Parser_Block.
     911 * @param callable $pre_callback  Callback to run on each block in the tree before it is traversed and serialized.
     912 *                                It is called with the following arguments: &$block, $parent_block, $previous_block.
     913 *                                Its string return value will be prepended to the serialized block markup.
     914 * @param callable $post_callback Callback to run on each block in the tree after it is traversed and serialized.
     915 *                                It is called with the following arguments: &$block, $parent_block, $next_block.
     916 *                                Its string return value will be appended to the serialized block markup.
     917 * @return string Serialized block markup.
     918 */
     919function traverse_and_serialize_block( $block, $pre_callback = null, $post_callback = null ) {
    905920    $block_content = '';
    906921    $block_index   = 0;
    907922
    908     foreach ( $block['innerContent'] as $chunk_index => $chunk ) {
     923    foreach ( $block['innerContent'] as $chunk ) {
    909924        if ( is_string( $chunk ) ) {
    910925            $block_content .= $chunk;
    911926        } else {
    912             $inner_block = call_user_func(
    913                 $callback,
    914                 $block['innerBlocks'][ $block_index ],
    915                 $block,
    916                 $block_index,
    917                 $chunk_index
    918             );
     927            $inner_block = $block['innerBlocks'][ $block_index ];
     928
     929            if ( is_callable( $pre_callback ) ) {
     930                $prev = 0 === $block_index
     931                    ? null
     932                    : $block['innerBlocks'][ $block_index - 1 ];
     933                $block_content .= call_user_func_array(
     934                    $pre_callback,
     935                    array( &$inner_block, $block, $prev )
     936                );
     937            }
     938
     939            $block_content .= traverse_and_serialize_block( $inner_block, $pre_callback, $post_callback );
     940
     941            if ( is_callable( $post_callback ) ) {
     942                $next = count( $block['innerBlocks'] ) - 1 === $block_index
     943                    ? null
     944                    : $block['innerBlocks'][ $block_index + 1 ];
     945                $block_content .= call_user_func_array(
     946                    $post_callback,
     947                    array( &$inner_block, $block, $next )
     948                );
     949            }
    919950            $block_index++;
    920             $block_content .= traverse_and_serialize_block( $inner_block, $callback );
    921951        }
    922952    }
     
    934964
    935965/**
    936  * Traverses the blocks applying transformations using the callback provided,
    937  * and returns a joined string of the aggregate serialization of the given parsed blocks.
    938  *
    939  * This should be used when there is a need to modify the saved blocks.
    940  * Prefer `serialize_blocks` when preparing blocks to be saved to post content.
     966 * Given an array of parsed block trees, applies callbacks before and after serializing them and
     967 * returns their concatenated output.
     968 *
     969 * Recursively traverses the blocks and their inner blocks and applies the two callbacks provided as
     970 * arguments, the first one before serializing a block, and the second one after serializing.
     971 * If either callback returns a string value, it will be prepended and appended to the serialized
     972 * block markup, respectively.
     973 *
     974 * The callbacks will receive a reference to the current block as their first argument, so that they
     975 * can also modify it, and the current block's parent block as second argument. Finally, the
     976 * `$pre_callback` receives the previous block, whereas the `$post_callback` receives
     977 * the next block as third argument.
     978 *
     979 * Serialized blocks are returned including comment delimiters, and with all attributes serialized.
     980 *
     981 * This function should be used when there is a need to modify the saved blocks, or to inject markup
     982 * into the return value. Prefer `serialize_blocks` when preparing blocks to be saved to post content.
    941983 *
    942984 * @since 6.4.0
     
    944986 * @see serialize_blocks()
    945987 *
    946  * @param array[]  $blocks   An array of representative arrays of parsed block objects. See serialize_block().
    947  * @param callable $callback Callback to run on each block in the tree before serialization.
    948  *                           It is called with the following arguments: $block, $parent_block, $block_index, $chunk_index.
    949  * @return string String of rendered HTML.
    950  */
    951 function traverse_and_serialize_blocks( $blocks, $callback ) {
     988 * @param array[]  $blocks        An array of parsed blocks. See WP_Block_Parser_Block.
     989 * @param callable $pre_callback  Callback to run on each block in the tree before it is traversed and serialized.
     990 *                                It is called with the following arguments: &$block, $parent_block, $previous_block.
     991 *                                Its string return value will be prepended to the serialized block markup.
     992 * @param callable $post_callback Callback to run on each block in the tree after it is traversed and serialized.
     993 *                                It is called with the following arguments: &$block, $parent_block, $next_block.
     994 *                                Its string return value will be appended to the serialized block markup.
     995 * @return string Serialized block markup.
     996 */
     997function traverse_and_serialize_blocks( $blocks, $pre_callback = null, $post_callback = null ) {
    952998    $result = '';
    953     foreach ( $blocks as $block ) {
    954         // At the top level, there is no parent block, block index, or chunk index to pass to the callback.
    955         $block = call_user_func( $callback, $block );
    956         $result .= traverse_and_serialize_block( $block, $callback );
     999    foreach ( $blocks as $index => $block ) {
     1000        if ( is_callable( $pre_callback ) ) {
     1001            $prev = 0 === $index
     1002                ? null
     1003                : $blocks[ $index - 1 ];
     1004            $result .= call_user_func_array(
     1005                $pre_callback,
     1006                array( &$block, null, $prev ) // At the top level, there is no parent block to pass to the callback.
     1007            );
     1008        }
     1009        $result .= traverse_and_serialize_block( $block, $pre_callback, $post_callback );
     1010        if ( is_callable( $post_callback ) ) {
     1011            $next = count( $blocks ) - 1 === $index
     1012                ? null
     1013                : $blocks[ $index + 1 ];
     1014            $result .= call_user_func_array(
     1015                $post_callback,
     1016                array( &$block, null, $next ) // At the top level, there is no parent block to pass to the callback.
     1017            );
     1018        }
    9571019    }
    9581020    return $result;
Note: See TracChangeset for help on using the changeset viewer.