Skip to content

Commit

Permalink
REST API: Use posts endpoint for reusable blocks (WordPress#10751)
Browse files Browse the repository at this point in the history
* REST API: Use posts endpoint for reusable blocks

* REST: Restore WP_REST_Blocks_Controller for permissions check

* Reusable Blocks: Enable post listing edit

* Reusable Blocks: Trash on delete action

* List Reusable Blocks: Provide context to post request

* Reusable Blocks: Verify edit capability on export action

* List Reusable Blocks: Import as published
  • Loading branch information
aduth authored and antpb committed Oct 26, 2018
1 parent a56aafa commit 18e46f2
Show file tree
Hide file tree
Showing 8 changed files with 50 additions and 276 deletions.
9 changes: 8 additions & 1 deletion gutenberg.php
Original file line number Diff line number Diff line change
Expand Up @@ -266,8 +266,15 @@ function gutenberg_add_edit_link( $actions, $post ) {
$title = _draft_or_post_title( $post->ID );

if ( 'wp_block' === $post->post_type ) {
unset( $actions['edit'] );
unset( $actions['inline hide-if-no-js'] );

// Export uses block raw content, which is only returned from the post
// REST endpoint via `context=edit`, requiring edit capability.
$post_type = get_post_type_object( $post->post_type );
if ( ! current_user_can( $post_type->cap->edit_post, $post->ID ) ) {
return $actions;
}

$actions['export'] = sprintf(
'<button type="button" class="wp-list-reusable-blocks__export button-link" data-id="%s" aria-label="%s">%s</button>',
$post->ID,
Expand Down
87 changes: 0 additions & 87 deletions lib/class-wp-rest-blocks-controller.php
Original file line number Diff line number Diff line change
Expand Up @@ -33,91 +33,4 @@ public function check_read_permission( $post ) {

return parent::check_read_permission( $post );
}

/**
* Handle a DELETE request.
*
* @since 1.10.0
*
* @param WP_REST_Request $request Full details about the request.
* @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure.
*/
public function delete_item( $request ) {
// Always hard-delete a block.
$request->set_param( 'force', true );

return parent::delete_item( $request );
}

/**
* Given an update or create request, build the post object that is saved to
* the database.
*
* @since 1.10.0
*
* @param WP_REST_Request $request Request object.
* @return stdClass|WP_Error Post object or WP_Error.
*/
public function prepare_item_for_database( $request ) {
$prepared_post = parent::prepare_item_for_database( $request );

// Force blocks to always be published.
$prepared_post->post_status = 'publish';

return $prepared_post;
}

/**
* Given a block from the database, build the array that is returned from an
* API response.
*
* @since 1.10.0
*
* @param WP_Post $post Post object that backs the block.
* @param WP_REST_Request $request Request object.
* @return WP_REST_Response Response object.
*/
public function prepare_item_for_response( $post, $request ) {
$data = array(
'id' => $post->ID,
'title' => $post->post_title,
'content' => $post->post_content,
);

$response = rest_ensure_response( $data );

return apply_filters( "rest_prepare_{$this->post_type}", $response, $post, $request );
}

/**
* Builds the block's schema, conforming to JSON Schema.
*
* @since 1.10.0
*
* @return array Item schema data.
*/
public function get_item_schema() {
return array(
'$schema' => 'http://json-schema.org/schema#',
'title' => $this->post_type,
'type' => 'object',
'properties' => array(
'id' => array(
'description' => __( 'Unique identifier for the block.', 'gutenberg' ),
'type' => 'integer',
'readonly' => true,
),
'title' => array(
'description' => __( 'The block’s title.', 'gutenberg' ),
'type' => 'string',
'required' => true,
),
'content' => array(
'description' => __( 'The block’s HTML content.', 'gutenberg' ),
'type' => 'string',
'required' => true,
),
),
);
}
}
5 changes: 4 additions & 1 deletion lib/register.php
Original file line number Diff line number Diff line change
Expand Up @@ -461,7 +461,10 @@ function gutenberg_register_post_types() {
'create_posts' => 'create_blocks',
),
'map_meta_cap' => true,
'supports' => false,
'supports' => array(
'title',
'editor',
),
)
);

Expand Down
31 changes: 17 additions & 14 deletions packages/editor/src/store/effects/reusable-blocks.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ import {
getBlocks,
getBlocksByClientId,
} from '../selectors';
import { getPostRawValue } from '../reducer';

/**
* Module Constants
Expand All @@ -61,26 +62,25 @@ export const fetchReusableBlocks = async ( action, store ) => {

let result;
if ( id ) {
result = apiFetch( { path: `/wp/v2/${ postType.rest_base }/${ id }` } );
result = apiFetch( { path: `/wp/v2/${ postType.rest_base }/${ id }?context=edit` } );
} else {
result = apiFetch( { path: `/wp/v2/${ postType.rest_base }?per_page=-1` } );
result = apiFetch( { path: `/wp/v2/${ postType.rest_base }?per_page=-1&context=edit` } );
}

try {
const reusableBlockOrBlocks = await result;
dispatch( receiveReusableBlocksAction( map(
castArray( reusableBlockOrBlocks ),
( reusableBlock ) => {
const parsedBlocks = parse( reusableBlock.content );
if ( parsedBlocks.length === 1 ) {
return {
reusableBlock,
parsedBlock: parsedBlocks[ 0 ],
};
}
( post ) => {
const parsedBlocks = parse( post.content.raw );
return {
reusableBlock,
parsedBlock: createBlock( 'core/template', {}, parsedBlocks ),
reusableBlock: {
id: post.id,
title: getPostRawValue( post.title ),
},
parsedBlock: parsedBlocks.length === 1 ?
parsedBlocks[ 0 ] :
createBlock( 'core/template', {}, parsedBlocks ),
};
}
) ) );
Expand Down Expand Up @@ -119,7 +119,7 @@ export const saveReusableBlocks = async ( action, store ) => {
const reusableBlock = getBlock( state, clientId );
const content = serialize( reusableBlock.name === 'core/template' ? reusableBlock.innerBlocks : reusableBlock );

const data = isTemporary ? { title, content } : { id, title, content };
const data = isTemporary ? { title, content, status: 'publish' } : { id, title, content, status: 'publish' };
const path = isTemporary ? `/wp/v2/${ postType.rest_base }` : `/wp/v2/${ postType.rest_base }/${ id }`;
const method = isTemporary ? 'POST' : 'PUT';

Expand Down Expand Up @@ -184,7 +184,10 @@ export const deleteReusableBlocks = async ( action, store ) => {
] ) );

try {
await apiFetch( { path: `/wp/v2/${ postType.rest_base }/${ id }`, method: 'DELETE' } );
await apiFetch( {
path: `/wp/v2/${ postType.rest_base }/${ id }`,
method: 'DELETE',
} );
dispatch( {
type: 'DELETE_REUSABLE_BLOCK_SUCCESS',
id,
Expand Down
18 changes: 12 additions & 6 deletions packages/editor/src/store/effects/test/reusable-blocks.js
Original file line number Diff line number Diff line change
Expand Up @@ -70,8 +70,12 @@ describe( 'reusable blocks effects', () => {
const blockPromise = Promise.resolve( [
{
id: 123,
title: 'My cool block',
content: '<!-- wp:test-block {"name":"Big Bird"} /-->',
title: {
raw: 'My cool block',
},
content: {
raw: '<!-- wp:test-block {"name":"Big Bird"} /-->',
},
},
] );
const postTypePromise = Promise.resolve( {
Expand All @@ -97,7 +101,6 @@ describe( 'reusable blocks effects', () => {
reusableBlock: {
id: 123,
title: 'My cool block',
content: '<!-- wp:test-block {"name":"Big Bird"} /-->',
},
parsedBlock: expect.objectContaining( {
name: 'core/test-block',
Expand All @@ -115,8 +118,12 @@ describe( 'reusable blocks effects', () => {
it( 'should fetch a single reusable block', async () => {
const blockPromise = Promise.resolve( {
id: 123,
title: 'My cool block',
content: '<!-- wp:test-block {"name":"Big Bird"} /-->',
title: {
raw: 'My cool block',
},
content: {
raw: '<!-- wp:test-block {"name":"Big Bird"} /-->',
},
} );
const postTypePromise = Promise.resolve( {
slug: 'wp_block', rest_base: 'blocks',
Expand All @@ -141,7 +148,6 @@ describe( 'reusable blocks effects', () => {
reusableBlock: {
id: 123,
title: 'My cool block',
content: '<!-- wp:test-block {"name":"Big Bird"} /-->',
},
parsedBlock: expect.objectContaining( {
name: 'core/test-block',
Expand Down
11 changes: 7 additions & 4 deletions packages/list-reusable-blocks/src/utils/export.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/**
* External dependencies
*/
import { pick, kebabCase } from 'lodash';
import { kebabCase } from 'lodash';

/**
* WordPress dependencies
Expand All @@ -20,12 +20,15 @@ import { download } from './file';
*/
async function exportReusableBlock( id ) {
const postType = await apiFetch( { path: `/wp/v2/types/wp_block` } );
const reusableBlock = await apiFetch( { path: `/wp/v2/${ postType.rest_base }/${ id }` } );
const post = await apiFetch( { path: `/wp/v2/${ postType.rest_base }/${ id }?context=edit` } );
const title = post.title.raw;
const content = post.content.raw;
const fileContent = JSON.stringify( {
__file: 'wp_block',
...pick( reusableBlock, [ 'title', 'content' ] ),
title,
content,
}, null, 2 );
const fileName = kebabCase( reusableBlock.title ) + '.json';
const fileName = kebabCase( title ) + '.json';

download( fileName, fileContent, 'application/json' );
}
Expand Down
1 change: 1 addition & 0 deletions packages/list-reusable-blocks/src/utils/import.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ async function importReusableBlock( file ) {
data: {
title: parsedContent.title,
content: parsedContent.content,
status: 'publish',
},
method: 'POST',
} );
Expand Down
Loading

0 comments on commit 18e46f2

Please sign in to comment.