Skip to content

Commit

Permalink
Allow dynamic blocks to create loops
Browse files Browse the repository at this point in the history
Stores and restores the global post object around dynamic block callbacks. This allows dynamic blocks to create new `WP_Query` instances and set up its post data, without changing the currently edited post.

See #7427, #8035.
  • Loading branch information
obenland committed Aug 20, 2018
1 parent f631337 commit 5d8081f
Show file tree
Hide file tree
Showing 2 changed files with 58 additions and 0 deletions.
10 changes: 10 additions & 0 deletions lib/blocks.php
Original file line number Diff line number Diff line change
Expand Up @@ -151,11 +151,14 @@ function gutenberg_render_block( $block ) {
* Parses dynamic blocks out of `post_content` and re-renders them.
*
* @since 0.1.0
* @global WP_Post $post The post to edit.
*
* @param string $content Post content.
* @return string Updated post content.
*/
function do_blocks( $content ) {
global $post;

$rendered_content = '';
$dynamic_block_pattern = get_dynamic_blocks_regex();

Expand Down Expand Up @@ -213,8 +216,15 @@ function do_blocks( $content ) {
$content = substr( $content, $end_offset + strlen( $end_tag ) );
}

/*
* Back up global post, to restore after render callback.
* Allows callbacks to run new WP_Query instances without breaking the global post.
*/
$global_post = $post;

// Replace dynamic block with server-rendered output.
$rendered_content .= $block_type->render( $attributes, $inner_content );
$post = $global_post;
}

// Append remaining unmatched content.
Expand Down
48 changes: 48 additions & 0 deletions phpunit/class-dynamic-blocks-render-test.php
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,33 @@ function render_dummy_block_numeric() {
return 10;
}

/**
* Dummy block rendering function, creating a new WP_Query instance.
*
* @return string Block output.
*/
function render_dummy_block_wp_query() {
$content = '';
$recent = new WP_Query( array(
'numberposts' => 10,
'orderby' => 'ID',
'order' => 'DESC',
'post_type' => 'post',
'post_status' => 'draft, publish, future, pending, private',
'suppress_filters' => true,
) );

while ( $recent->have_posts() ) {
$recent->the_post();

$content .= get_the_title();
}

wp_reset_postdata();

return $content;
}

/**
* Tear down.
*/
Expand Down Expand Up @@ -87,6 +114,27 @@ function test_dynamic_block_rendering() {
);
}

/**
* Tests that do_blocks() maintains the global $post variable when dynamic
* blocks create new WP_Query instances in their callbacks.
*
* @covers ::do_blocks
*/
function test_global_post_persistence() {
global $post;

register_block_type( 'core/dummy', array(
'render_callback' => array( $this, 'render_dummy_block_wp_query' ),
) );

$posts = self::factory()->post->create_many( 5 );
$global_post = $post = get_post( end( $posts ) );

do_blocks( '<!-- wp:core/dummy /-->' );

$this->assertEquals( $global_post, $post );
}

/**
* Test dynamic blocks return string value from render, even if render
* callback does not.
Expand Down

0 comments on commit 5d8081f

Please sign in to comment.