Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add block data to REST API #2649

Open
wants to merge 69 commits into
base: trunk
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 33 commits
Commits
Show all changes
69 commits
Select commit Hold shift + click to select a range
d45e15c
first pass
Sep 1, 2017
09a8e51
it works, second pass
Sep 1, 2017
f70f6bb
add gutenburg block class
Sep 1, 2017
6f73d88
remove logging, add inline docs, clean up
Sep 2, 2017
97d282b
add rendered block content when available
Sep 2, 2017
30d12b9
restore register.php
Sep 2, 2017
488690d
restore register.php
Sep 2, 2017
632a07d
restore register.php
Sep 2, 2017
9ce9ca4
dry out block parsing code, remove unused prepare_item_for_response
Sep 2, 2017
148469e
Remap response fields to match #2503
Sep 4, 2017
96f1fa2
Remove WP_Gutenberg_Block_Controller class
Sep 4, 2017
2023901
Attach the block data to the rest api post response
Sep 4, 2017
b4a3a92
remove unused $request parameter from callback
Sep 4, 2017
4c00931
whitespace cleanup
Sep 4, 2017
5a17b33
remove extraneous extra loop
Sep 4, 2017
dff3f0b
Clean up data response
Sep 4, 2017
cfd2f5e
fix rendered data setup
Sep 4, 2017
36f1000
rename get_block_data_for_api_from_post_content -> get_block_data_for…
Sep 7, 2017
d990979
Skip block if we didn’t get a valid block name.
Sep 7, 2017
5937d1a
use already set up $block_name
Sep 7, 2017
862bccc
attributes: use $attributes and return even if null
Sep 7, 2017
a5756f5
return `rendered`, even if null
Sep 7, 2017
8340341
ensure $post_type IS an array
Sep 7, 2017
957dc7e
Always attach blocks, even if null.
Sep 7, 2017
bc5f31e
use get_data/set_data to adjust response
Sep 7, 2017
5509c1b
Code clean up, improve documentation blocks
Sep 7, 2017
822ffe2
Fixes for phpcs
Sep 7, 2017
6cf7a5f
Clean up data setup
Sep 8, 2017
23a5565
revert unreleated changes
Sep 8, 2017
36f5df1
Add tests for the rest api block data in posts->content
Sep 10, 2017
37513d1
attach block data to pages and posts
Sep 10, 2017
daece40
Add a filter for whether to add block data to api response: gutenberg…
Sep 10, 2017
1eb5331
fixes for phpcs
Sep 10, 2017
728e725
Merge branch 'master' of github.com:WordPress/gutenberg
Sep 16, 2017
8117871
Merge branch 'master' of github.com:WordPress/gutenberg
Sep 25, 2017
7e8a823
Merge branch 'master' of github.com:WordPress/gutenberg
Sep 28, 2017
bc2600d
Merge branch 'master' into add-block-rest-endpoints
Sep 28, 2017
d395197
Fix data return setup for blocks data
Sep 28, 2017
08cdb15
Merge branch 'master' of github.com:WordPress/gutenberg
Oct 19, 2017
9d6b95c
Merge branch 'master' of github.com:WordPress/gutenberg
Oct 27, 2017
1e9572c
Merge branch 'master' of github.com:WordPress/gutenberg
Nov 16, 2017
b82fa9d
Merge branch 'master' of github.com:WordPress/gutenberg
Nov 26, 2017
cbd0c62
Merge branch 'master' of github.com:WordPress/gutenberg
Dec 8, 2017
9374837
Merge branch 'master' of github.com:WordPress/gutenberg
Dec 18, 2017
218299c
Merge branch 'master' of github.com:WordPress/gutenberg
Dec 20, 2017
8d75bb7
Merge branch 'master' of github.com:WordPress/gutenberg
Dec 28, 2017
b7ae85a
Merge branch 'master' of github.com:WordPress/gutenberg
Dec 29, 2017
d82bfa9
Merge branch 'master' of github.com:WordPress/gutenberg
Jan 2, 2018
951b8d6
Merge branch 'master' into add-block-rest-endpoints
Jan 2, 2018
f0355f0
restore api code after merge
Jan 2, 2018
55732b8
readd gutenberg_add_blocks_to_post_resource after merge
Jan 2, 2018
5e4db00
alignment for phpcs
Jan 2, 2018
bd638d1
update tests for new demo data
Jan 2, 2018
0098344
fix test_delete_item expected
Jan 2, 2018
4f5c72f
Merge branch 'master' of github.com:WordPress/gutenberg
Mar 13, 2019
1573cc4
Merge branch 'master' of github.com:WordPress/gutenberg
Mar 13, 2019
391c0ec
Merge branch 'master' of github.com:WordPress/gutenberg
Mar 13, 2019
7afbe67
Merge branch 'master' of github.com:WordPress/gutenberg
Mar 25, 2019
2b37f93
Merge branch 'master' of github.com:WordPress/gutenberg
Mar 25, 2019
b71ef00
Merge branch 'master' of github.com:WordPress/gutenberg
Mar 26, 2019
989f0ca
Merge branch 'master' of github.com:WordPress/gutenberg
Apr 8, 2019
74092df
Merge branch 'master' of github.com:WordPress/gutenberg
Apr 11, 2019
2144d20
Merge branch 'master' into add-block-rest-endpoints
Apr 11, 2019
63de8af
restore after merge conflict resolution
Apr 11, 2019
131dd90
Update parser use
Apr 11, 2019
1c6b213
merge
adamsilverstein Nov 5, 2020
546fb81
Cleanup for PHPCS.
adamsilverstein Nov 5, 2020
812af84
Simplify data construction approach.
adamsilverstein Nov 5, 2020
8258cb6
Remove unrelated changes.
adamsilverstein Nov 5, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
101 changes: 101 additions & 0 deletions lib/blocks.php
Original file line number Diff line number Diff line change
Expand Up @@ -93,3 +93,104 @@ function do_blocks( $content ) {
return $content_after_blocks;
}
add_filter( 'the_content', 'do_blocks', 9 ); // BEFORE do_shortcode() and wpautop().

/**
* Extract the blocks from post content for the REST API post response.
*
* @since 1.1.0
*
* @param string $content The post content.
*
* @return array Array of block data.
*/
function gutenberg_add_blocks_to_post_resource( $content ) {
adamsilverstein marked this conversation as resolved.
Show resolved Hide resolved
$registry = WP_Block_Type_Registry::get_instance();
$blocks = gutenberg_parse_blocks( $content );
$data = array();

// Loop thru the blocks, adding rendered content when available.
foreach ( $blocks as $block ) {
$block_name = isset( $block['blockName'] ) ? $block['blockName'] : null;
$attributes = is_array( $block['attrs'] ) ? $block['attrs'] : null;
$raw_content = isset( $block['rawContent'] ) ? $block['rawContent'] : null;

// Skip block if we didn’t get a valid block name.
if ( null === $block_name ) {
continue;
}

// Set up rendered content, if available.
$block['renderedContent'] = null;
$block_type = $registry->get_registered( $block_name );
if ( null !== $block_type ) {
$block['renderedContent'] = $block_type->render( $attributes, $raw_content );
}

// Add the item data.
$data[] = array(
'type' => $block_name,
'attributes' => $attributes,
adamsilverstein marked this conversation as resolved.
Show resolved Hide resolved
'content' => $block['rawContent'],
'rendered' => $block['renderedContent'],
);
}

return $data;
}

/**
* Attach a post's block data callback to the REST API response.
*
* @since 1.1.0
*
* @param string | array $post_types Post type, or array of post types.
*/
function gutenberg_attach_block_response_callback( $post_types ) {
if ( empty( $post_types ) ) {
$post_types = 'post';
}
if ( ! is_array( $post_types ) ) {
$post_types = array( $post_types );
}
foreach ( $post_types as $post_type ) {

/**
* Filter whether a post type has its blocks data added the REST API response content.
*
* @since 1.1.0
*
* @param bool $blocks_show_in_rest Whether to show blocks in the REST API response.
* @param string $post_type The post type.
*/
if ( apply_filters( 'gutenberg_add_blocks_to_rest_for_post_type', true, $post_type ) ) {
add_filter( 'rest_prepare_' . $post_type, 'gutenberg_extract_blocks_from_post_content', 10, 3 );
}
}
}
adamsilverstein marked this conversation as resolved.
Show resolved Hide resolved
gutenberg_attach_block_response_callback( array( 'post', 'page' ) );

/**
* Attach a post's block data to the REST API response.
*
* @since 1.1.0
*
* @param WP_REST_Response $response The response object.
* @param WP_Post $post The Post object.
*
* @return WP_REST_Response $response The filtered response object.
*/
function gutenberg_extract_blocks_from_post_content( $response, $post ) {
if ( ! $post ) {
return $response;
}

// Extract the block data from the post content.
$blocks = gutenberg_add_blocks_to_post_resource( $post->post_content );

// Add block data to the response as part of 'content'.
$content = $response->get_data( 'content' );
$content['blocks'] = $blocks;
$response->set_data( array( 'content' => $content ) );
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe related to my previous content, I'm seeing that the post entity is now wrapped inside a content key in the REST response:

response

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the feedback & testing @aduth, I'll review these issues.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@aduth Oops! fixed that in d395197


return $response;
}
95 changes: 95 additions & 0 deletions phpunit/class-rest-blocks-api-test.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
<?php
/**
* WP_REST_BlockAPI tests.
*
* @package gutenberg
*/

/**
* Tests for WP_REST_BlockAPI.
*/
class WP_REST_BlockAPI_Test extends WP_UnitTestCase {

/**
* Our fake reusable block's post ID.
*
* @var int
*/
protected static $test_block_post_id;

/**
* Our fake reusable block's post ID.
*
* @var int
*/
protected static $demo_post_content;

/**
* Our fake editor's user ID.
*
* @var int
*/
protected static $editor_id;

/**
* Create fake data before our tests run.
*
* @param WP_UnitTest_Factory $factory Helper that lets us create fake data.
*/
public static function wpSetUpBeforeClass( $factory ) {
global $wp_rest_server;
$wp_rest_server = new WP_REST_Server;
do_action( 'rest_api_init' );

self::$demo_post_content = file_get_contents(
dirname( __FILE__ ) . '/fixtures/long-content.html'
);

self::$test_block_post_id = wp_insert_post( array(
'post_type' => 'post',
'post_status' => 'publish',
'post_name' => 'gutenberg-block-test',
'post_title' => 'My cool block',
'post_content' => self::$demo_post_content,
) );

self::$editor_id = $factory->user->create( array(
'role' => 'editor',
) );
}

/**
* Delete our fake data after our tests run.
*/
public static function wpTearDownAfterClass() {
wp_delete_post( self::$test_block_post_id );

self::delete_user( self::$editor_id );
}

/**
* Check that we can GET blocks from a post request.
*/
public function test_get_items() {
global $wp_rest_server;
wp_set_current_user( self::$editor_id );

$request = new WP_REST_Request( 'GET', '/wp/v2/posts/' . self::$test_block_post_id );
$this->assertNotEquals( null, $request );

$response = $wp_rest_server->dispatch( $request );

$this->assertEquals( 200, $response->get_status() );
$response->get_data();

$blocks = isset( $response->data['content']['blocks'] ) ? $response->data['content']['blocks'] : false;

$first_block_url_attribute = wp_unslash( $blocks[0]['attributes']['url'] );
$first_block_type = wp_unslash( $blocks[0]['type'] );

$this->assertEquals( count( $blocks ), 43, 'The demo post content api call should contain 43 blocks.' );
$this->assertEquals( 'https://cldup.com/GCwahb3aOb.jpg', $first_block_url_attribute, 'Block attributes should be returned correctly.' );
$this->assertEquals( 'core/cover-image', $first_block_type, 'Block type should be returned correctly.' );
}

}