From b4bda6800297f1dbd3efb7a3eb506225c07ee9c4 Mon Sep 17 00:00:00 2001 From: Dennis Snell Date: Mon, 12 Nov 2018 12:35:37 -0500 Subject: [PATCH 1/7] Block Rendering: Add pre-render and post-render filteres Allows for blocks to be structurally and textually filtered during the rendering process. The pre-filter provides the parsed block object for transformation while the post-filter provides the rendered output of the block. These filters can be used in unison to perform a variety of operations on blocks. They are applied in a depth-first manner when rendering a block tree so that deeper-nested blocks are processed before their parents. > Caveat: Inner blocks aren't structurally filtered in this patch yet before their parent. Actually this needs a lot of work still... --- lib/blocks.php | 28 ++++++++++++++++++++-------- 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/lib/blocks.php b/lib/blocks.php index 0b11041d0576d..3b7f20bfd9e2c 100644 --- a/lib/blocks.php +++ b/lib/blocks.php @@ -142,25 +142,37 @@ function get_dynamic_blocks_regex() { function gutenberg_render_block( $block ) { global $post; - $block_type = WP_Block_Type_Registry::get_instance()->get_registered( $block['blockName'] ); - $is_dynamic = $block['blockName'] && null !== $block_type && $block_type->is_dynamic(); + $global_post = $post; + $pre_render = apply_filters( 'block_pre_render', $block ); + $post = $global_post; + + if ( null === $pre_render ) { + return ''; + } + + $block_type = WP_Block_Type_Registry::get_instance()->get_registered( $pre_render['blockName'] ); + $is_dynamic = $pre_render['blockName'] && null !== $block_type && $block_type->is_dynamic(); $inner_content = ''; $index = 0; - foreach ( $block['innerContent'] as $chunk ) { - $inner_content .= is_string( $chunk ) ? $chunk : gutenberg_render_block( $block['innerBlocks'][ $index++ ] ); + foreach ( $pre_render['innerContent'] as $chunk ) { + $inner_content .= is_string( $chunk ) ? $chunk : gutenberg_render_block( $pre_render['innerBlocks'][ $index++ ] ); } if ( $is_dynamic ) { - $attributes = is_array( $block['attrs'] ) ? (array) $block['attrs'] : array(); + $attributes = is_array( $pre_render['attrs'] ) ? (array) $pre_render['attrs'] : array(); $global_post = $post; $output = $block_type->render( $attributes, $inner_content ); $post = $global_post; - - return $output; + } else { + $output = $inner_content; } - return $inner_content; + $global_post = $post; + $post_render = apply_filters( 'block_post_render', $output ); + $post = $global_post; + + return $post_render; } if ( ! function_exists( 'do_blocks' ) ) { From 9df5f866404cf4a608c397061576821a361fce8b Mon Sep 17 00:00:00 2001 From: Dennis Snell Date: Fri, 16 Nov 2018 14:03:01 -0500 Subject: [PATCH 2/7] change the interface --- lib/blocks.php | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/lib/blocks.php b/lib/blocks.php index 3b7f20bfd9e2c..1e7e24713bba2 100644 --- a/lib/blocks.php +++ b/lib/blocks.php @@ -139,28 +139,25 @@ function get_dynamic_blocks_regex() { * @param array $block A single parsed block object. * @return string String of rendered HTML. */ -function gutenberg_render_block( $block ) { +function gutenberg_render_block( $source_block ) { global $post; $global_post = $post; - $pre_render = apply_filters( 'block_pre_render', $block ); + $pre_render = apply_filters( 'block_pre_render', null, $source_block ); $post = $global_post; + $block = isset( $pre_render ) ? $pre_render : $source_block; - if ( null === $pre_render ) { - return ''; - } - - $block_type = WP_Block_Type_Registry::get_instance()->get_registered( $pre_render['blockName'] ); - $is_dynamic = $pre_render['blockName'] && null !== $block_type && $block_type->is_dynamic(); + $block_type = WP_Block_Type_Registry::get_instance()->get_registered( $block['blockName'] ); + $is_dynamic = $block['blockName'] && null !== $block_type && $block_type->is_dynamic(); $inner_content = ''; $index = 0; - foreach ( $pre_render['innerContent'] as $chunk ) { - $inner_content .= is_string( $chunk ) ? $chunk : gutenberg_render_block( $pre_render['innerBlocks'][ $index++ ] ); + foreach ( $block['innerContent'] as $chunk ) { + $inner_content .= is_string( $chunk ) ? $chunk : gutenberg_render_block( $block['innerBlocks'][ $index++ ] ); } if ( $is_dynamic ) { - $attributes = is_array( $pre_render['attrs'] ) ? (array) $pre_render['attrs'] : array(); + $attributes = is_array( $block['attrs'] ) ? (array) $block['attrs'] : array(); $global_post = $post; $output = $block_type->render( $attributes, $inner_content ); $post = $global_post; @@ -169,7 +166,7 @@ function gutenberg_render_block( $block ) { } $global_post = $post; - $post_render = apply_filters( 'block_post_render', $output ); + $post_render = apply_filters( 'block_post_render', $output, $block ); $post = $global_post; return $post_render; From e74095ca6615a51e35969ca5a720a10d4f50cf4f Mon Sep 17 00:00:00 2001 From: Dennis Snell Date: Tue, 27 Nov 2018 17:14:08 -0700 Subject: [PATCH 3/7] add filter comment for "block_pre_render" --- lib/blocks.php | 69 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) diff --git a/lib/blocks.php b/lib/blocks.php index 1e7e24713bba2..24ed2b2c80951 100644 --- a/lib/blocks.php +++ b/lib/blocks.php @@ -134,6 +134,7 @@ function get_dynamic_blocks_regex() { * * @since 1.9.0 * @since 4.4.0 renders full nested tree of blocks before reassembling into HTML string + * @since 4.6.0 filters blocks structurally before rendering and as text afterwards * @global WP_Post $post The post to edit. * * @param array $block A single parsed block object. @@ -143,6 +144,74 @@ function gutenberg_render_block( $source_block ) { global $post; $global_post = $post; + /** + * Filter to process a block structurally before rendering + * + * Use this filter if you want to modify a block's attributes or rearrange + * its inner blocks or change its block type - anything which might govern + * the way the block gets rendered in the next step. + * + * @example + * function block_rot13( $prev, $source_block ) { + * $block = $prev ?: $source_block; + * + * return isset( $block['attrs']['do_rot13'] ) + * ? array_merge( $block, array( 'innerContent' => array_map( 'str_rot13', $block['innerContent'] ) ) ) + * : $prev; + * } + * add_filter( 'block_pre_render', 'block_rot13' ); + * + * @example + * function hide_hidden_inner_blocks( $prev, $source_block ) { + * if ( 'my-plugin/hider' !== $source_block['blockName'] ) { + * return $prev; + * } + * + * $block = $prev ?: $source_block; + * $block['innerBlocks'] = array(); + * $inner_content = array(); + * $block_index = 0; + * $html = ''; + * foreach ( $block['innerContent'] as $chunk ) { + * if ( is_string( $chunk ) ) { + * $html .= $chunk; + * continue; + * } + * + * if ( ! can_see_block( $inner ) ) { + * continue; + * } + * + * $inner = $block['innerBlocks'][$block_index++]; + * $block['innerBlocks'][] = $inner; + * if ( ! empty( $html ) ) { + * $inner_content[] = $html; + * } + * $inner_content[] = null; + * } + * + * return $block; + * } + * add_filter( 'block_pre_render', 'hide_hidden_inner_blocks' ); + * + * @example + * function un_markdownify_block( $prev, $source_block ) { + * $block = $prev ?: $source_block; + * return 'my-plugin/markdown' === $block['blockName'] + * ? array_merge( $block, array( 'blockName' => 'core/paragraph' ) ) + * : $prev; + * } + * if ( show_markdown_source() ) { + * add_filter( 'block_pre_render', 'un_markdownify_block' ); + * } + * + * @since 4.6.0 + * + * @param array|null $prev transformed block from previous filter or null + * @param array $source_block original block passed through all filters + * + * @return array|null transformed version of block or previous $block if not transformation is needed + */ $pre_render = apply_filters( 'block_pre_render', null, $source_block ); $post = $global_post; $block = isset( $pre_render ) ? $pre_render : $source_block; From 92a2d09c2bd46a35d42a58943b5d18192383e6ae Mon Sep 17 00:00:00 2001 From: Dennis Snell Date: Tue, 27 Nov 2018 18:26:06 -0700 Subject: [PATCH 4/7] add filter comment for "block_post_render" and update other one --- lib/blocks.php | 83 ++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 77 insertions(+), 6 deletions(-) diff --git a/lib/blocks.php b/lib/blocks.php index 24ed2b2c80951..267c331aa8765 100644 --- a/lib/blocks.php +++ b/lib/blocks.php @@ -145,21 +145,26 @@ function gutenberg_render_block( $source_block ) { $global_post = $post; /** - * Filter to process a block structurally before rendering + * Filter to process a block structurally before rendering. * * Use this filter if you want to modify a block's attributes or rearrange * its inner blocks or change its block type - anything which might govern * the way the block gets rendered in the next step. * * @example - * function block_rot13( $prev, $source_block ) { + * function replace_with_translation( $prev, $source_block ) { * $block = $prev ?: $source_block; * - * return isset( $block['attrs']['do_rot13'] ) - * ? array_merge( $block, array( 'innerContent' => array_map( 'str_rot13', $block['innerContent'] ) ) ) - * : $prev; + * if ( ! isset( $block['attrs']['translation_id'] ) ) { + * return $prev; + * } + * + * $locale = get_current_locale(); + * $translation = get_translated_block( $block['attrs']['translation_id'], $locale ); + * + * return $translation ?: $prev; * } - * add_filter( 'block_pre_render', 'block_rot13' ); + * add_filter( 'block_pre_render', 'replace_with_translation' ); * * @example * function hide_hidden_inner_blocks( $prev, $source_block ) { @@ -235,6 +240,72 @@ function gutenberg_render_block( $source_block ) { } $global_post = $post; + /** + * Filter to process a block textually after rendering. + * + * Use this filter if you want to apply string or HTML transformations + * on a block after it and its inner blocks have already been rendered + * and into HTML. Inner blocks will have been fully rendered into the + * parent block by this point, so if you want to process the inner blocks + * themselves you should look at `block_pre_render`. + * + * This filter is particularly useful if you want to process the output + * from other blocks which might be substantially different from their + * original raw `post_content` content. + * + * @example + * function rot13_block( $output, $block ) { + * return isset( $block['attrs']['do_rot13'] ) + * ? str_rot13( $output ) + * : $output; + * } + * add_filter( 'block_post_render', 'rot13_block' ); + * + * @example + * function add_return_to_top_link( $output ) { + * return $output . 'Top'; + * } + * add_filter( 'block_post_render', 'add_return_to_top_link' ); + * + * @example + * class Matcher { + * public $count = 0; + * public $pattern; + * + * function __construct( $pattern ) { + * $this->pattern = $pattern; + * } + * + * function block_post_render( $output ) { + * if ( 1 !== preg_match( $this->pattern, $output ) ) { + * return $output; + * } + * + * $this->count++; + * + * return '
' . $output . '
' + * } + * + * function the_content( $html ) { + * $count = $this->count; + * $this->count = 0; + * + * return $count > 0 + * ? $html . '
Found ' . $count . ' blocks with a match!
' + * : $html; + * } + * } + * $matcher = new Matcher( '/new editor/i' ); + * add_filter( 'block_post_render', array( $matcher, 'block_post_render' ) ); + * add_filter( 'the_content', array( $matcher, 'the_content' ), 10 ); + * + * @since 4.6.0 + * + * @param string $output rendered HTML from block or previous filters + * @param array $block original block that was rendered + * + * @return string processed HTML to display + */ $post_render = apply_filters( 'block_post_render', $output, $block ); $post = $global_post; From 29c62f70a70d86aea8cfd2c71c31543a43daec22 Mon Sep 17 00:00:00 2001 From: Dennis Snell Date: Wed, 28 Nov 2018 10:40:17 -0700 Subject: [PATCH 5/7] fix linting issues --- lib/blocks.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/blocks.php b/lib/blocks.php index 267c331aa8765..e20869f86a4e3 100644 --- a/lib/blocks.php +++ b/lib/blocks.php @@ -137,7 +137,7 @@ function get_dynamic_blocks_regex() { * @since 4.6.0 filters blocks structurally before rendering and as text afterwards * @global WP_Post $post The post to edit. * - * @param array $block A single parsed block object. + * @param array $source_block A single parsed block object. * @return string String of rendered HTML. */ function gutenberg_render_block( $source_block ) { @@ -217,9 +217,9 @@ function gutenberg_render_block( $source_block ) { * * @return array|null transformed version of block or previous $block if not transformation is needed */ - $pre_render = apply_filters( 'block_pre_render', null, $source_block ); - $post = $global_post; - $block = isset( $pre_render ) ? $pre_render : $source_block; + $pre_render = apply_filters( 'block_pre_render', null, $source_block ); + $post = $global_post; + $block = isset( $pre_render ) ? $pre_render : $source_block; $block_type = WP_Block_Type_Registry::get_instance()->get_registered( $block['blockName'] ); $is_dynamic = $block['blockName'] && null !== $block_type && $block_type->is_dynamic(); From bbb7a3c3cf3940abf9d9c218faa645212234e49f Mon Sep 17 00:00:00 2001 From: Dennis Snell Date: Wed, 28 Nov 2018 10:40:43 -0700 Subject: [PATCH 6/7] switch to 4.7.0 --- lib/blocks.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/blocks.php b/lib/blocks.php index e20869f86a4e3..7e264293c83fb 100644 --- a/lib/blocks.php +++ b/lib/blocks.php @@ -134,7 +134,7 @@ function get_dynamic_blocks_regex() { * * @since 1.9.0 * @since 4.4.0 renders full nested tree of blocks before reassembling into HTML string - * @since 4.6.0 filters blocks structurally before rendering and as text afterwards + * @since 4.7.0 filters blocks structurally before rendering and as text afterwards * @global WP_Post $post The post to edit. * * @param array $source_block A single parsed block object. @@ -210,7 +210,7 @@ function gutenberg_render_block( $source_block ) { * add_filter( 'block_pre_render', 'un_markdownify_block' ); * } * - * @since 4.6.0 + * @since 4.7.0 * * @param array|null $prev transformed block from previous filter or null * @param array $source_block original block passed through all filters @@ -299,7 +299,7 @@ function gutenberg_render_block( $source_block ) { * add_filter( 'block_post_render', array( $matcher, 'block_post_render' ) ); * add_filter( 'the_content', array( $matcher, 'the_content' ), 10 ); * - * @since 4.6.0 + * @since 4.7.0 * * @param string $output rendered HTML from block or previous filters * @param array $block original block that was rendered From 7bf127db59fb5faa60b53760f6bfde6119a3946d Mon Sep 17 00:00:00 2001 From: Dennis Snell Date: Thu, 29 Nov 2018 10:46:53 -0700 Subject: [PATCH 7/7] bump target version --- lib/blocks.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/blocks.php b/lib/blocks.php index 7e264293c83fb..799026c928eec 100644 --- a/lib/blocks.php +++ b/lib/blocks.php @@ -134,7 +134,7 @@ function get_dynamic_blocks_regex() { * * @since 1.9.0 * @since 4.4.0 renders full nested tree of blocks before reassembling into HTML string - * @since 4.7.0 filters blocks structurally before rendering and as text afterwards + * @since 4.8.0 filters blocks structurally before rendering and as text afterwards * @global WP_Post $post The post to edit. * * @param array $source_block A single parsed block object. @@ -210,7 +210,7 @@ function gutenberg_render_block( $source_block ) { * add_filter( 'block_pre_render', 'un_markdownify_block' ); * } * - * @since 4.7.0 + * @since 4.8.0 * * @param array|null $prev transformed block from previous filter or null * @param array $source_block original block passed through all filters @@ -299,7 +299,7 @@ function gutenberg_render_block( $source_block ) { * add_filter( 'block_post_render', array( $matcher, 'block_post_render' ) ); * add_filter( 'the_content', array( $matcher, 'the_content' ), 10 ); * - * @since 4.7.0 + * @since 4.8.0 * * @param string $output rendered HTML from block or previous filters * @param array $block original block that was rendered