diff --git a/wp-includes/post.php b/wp-includes/post.php index d8ccf05ffb..5cda6bd5b6 100644 --- a/wp-includes/post.php +++ b/wp-includes/post.php @@ -255,18 +255,21 @@ function create_initial_post_types() { register_post_type( 'wp_block', array( - 'labels' => array( + 'labels' => array( 'name' => __( 'Blocks' ), 'singular_name' => __( 'Block' ), 'search_items' => __( 'Search Blocks' ), ), - 'public' => false, - '_builtin' => true, /* internal use only. don't use this when registering your own post type. */ - 'show_ui' => true, - 'show_in_menu' => false, - 'rewrite' => false, - 'capability_type' => 'block', - 'capabilities' => array( + 'public' => false, + '_builtin' => true, /* internal use only. don't use this when registering your own post type. */ + 'show_ui' => true, + 'show_in_menu' => false, + 'rewrite' => false, + 'show_in_rest' => true, + 'rest_base' => 'blocks', + 'rest_controller_class' => 'WP_REST_Blocks_Controller', + 'capability_type' => 'block', + 'capabilities' => array( // You need to be able to edit posts, in order to read blocks in their raw form. 'read' => 'edit_posts', // You need to be able to publish posts, in order to create blocks. @@ -276,8 +279,8 @@ function create_initial_post_types() { 'edit_others_posts' => 'edit_others_posts', 'delete_others_posts' => 'delete_others_posts', ), - 'map_meta_cap' => true, - 'supports' => array( + 'map_meta_cap' => true, + 'supports' => array( 'title', 'editor', ), diff --git a/wp-includes/rest-api.php b/wp-includes/rest-api.php index 5ab3857cd2..f8e97065a9 100644 --- a/wp-includes/rest-api.php +++ b/wp-includes/rest-api.php @@ -249,6 +249,10 @@ function create_initial_rest_routes() { $controller = new WP_REST_Search_Controller( $search_handlers ); $controller->register_routes(); + // Block Renderer. + $controller = new WP_REST_Block_Renderer_Controller; + $controller->register_routes(); + // Settings. $controller = new WP_REST_Settings_Controller; $controller->register_routes(); @@ -256,6 +260,7 @@ function create_initial_rest_routes() { // Themes. $controller = new WP_REST_Themes_Controller; $controller->register_routes(); + } /** diff --git a/wp-includes/rest-api/endpoints/class-wp-rest-block-renderer-controller.php b/wp-includes/rest-api/endpoints/class-wp-rest-block-renderer-controller.php new file mode 100644 index 0000000000..f0e1e7db47 --- /dev/null +++ b/wp-includes/rest-api/endpoints/class-wp-rest-block-renderer-controller.php @@ -0,0 +1,177 @@ +namespace = 'wp/v2'; + $this->rest_base = 'block-renderer'; + } + + /** + * Registers the necessary REST API routes, one for each dynamic block. + * + * @since 5.0.0 + */ + public function register_routes() { + $block_types = WP_Block_Type_Registry::get_instance()->get_all_registered(); + + foreach ( $block_types as $block_type ) { + if ( ! $block_type->is_dynamic() ) { + continue; + } + + register_rest_route( + $this->namespace, + '/' . $this->rest_base . '/(?P' . $block_type->name . ')', + array( + 'args' => array( + 'name' => array( + 'description' => __( 'Unique registered name for the block.' ), + 'type' => 'string', + ), + ), + array( + 'methods' => WP_REST_Server::READABLE, + 'callback' => array( $this, 'get_item' ), + 'permission_callback' => array( $this, 'get_item_permissions_check' ), + 'args' => array( + 'context' => $this->get_context_param( array( 'default' => 'view' ) ), + 'attributes' => array( + /* translators: %s is the name of the block */ + 'description' => sprintf( __( 'Attributes for %s block' ), $block_type->name ), + 'type' => 'object', + 'additionalProperties' => false, + 'properties' => $block_type->get_attributes(), + ), + 'post_id' => array( + 'description' => __( 'ID of the post context.' ), + 'type' => 'integer', + ), + ), + ), + 'schema' => array( $this, 'get_public_item_schema' ), + ) + ); + } + } + + /** + * Checks if a given request has access to read blocks. + * + * @since 5.0.0 + * + * @param WP_REST_Request $request Request. + * @return true|WP_Error True if the request has read access, WP_Error object otherwise. + */ + public function get_item_permissions_check( $request ) { + global $post; + + $post_id = isset( $request['post_id'] ) ? intval( $request['post_id'] ) : 0; + + if ( 0 < $post_id ) { + $post = get_post( $post_id ); + + if ( ! $post || ! current_user_can( 'edit_post', $post->ID ) ) { + return new WP_Error( + 'block_cannot_read', + __( 'Sorry, you are not allowed to read blocks of this post.' ), + array( + 'status' => rest_authorization_required_code(), + ) + ); + } + } else { + if ( ! current_user_can( 'edit_posts' ) ) { + return new WP_Error( + 'block_cannot_read', + __( 'Sorry, you are not allowed to read blocks as this user.' ), + array( + 'status' => rest_authorization_required_code(), + ) + ); + } + } + + return true; + } + + /** + * Returns block output from block's registered render_callback. + * + * @since 5.0.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 get_item( $request ) { + global $post; + + $post_id = isset( $request['post_id'] ) ? intval( $request['post_id'] ) : 0; + + if ( 0 < $post_id ) { + $post = get_post( $post_id ); + + // Set up postdata since this will be needed if post_id was set. + setup_postdata( $post ); + } + $registry = WP_Block_Type_Registry::get_instance(); + $block = $registry->get_registered( $request['name'] ); + + if ( null === $block ) { + return new WP_Error( + 'block_invalid', + __( 'Invalid block.' ), + array( + 'status' => 404, + ) + ); + } + + $data = array( + 'rendered' => $block->render( $request->get_param( 'attributes' ) ), + ); + return rest_ensure_response( $data ); + } + + /** + * Retrieves block's output schema, conforming to JSON Schema. + * + * @since 5.0.0 + * + * @return array Item schema data. + */ + public function get_item_schema() { + return array( + '$schema' => 'http://json-schema.org/schema#', + 'title' => 'rendered-block', + 'type' => 'object', + 'properties' => array( + 'rendered' => array( + 'description' => __( 'The rendered block.' ), + 'type' => 'string', + 'required' => true, + 'context' => array( 'edit' ), + ), + ), + ); + } +} diff --git a/wp-includes/rest-api/endpoints/class-wp-rest-blocks-controller.php b/wp-includes/rest-api/endpoints/class-wp-rest-blocks-controller.php new file mode 100644 index 0000000000..66a2e7adad --- /dev/null +++ b/wp-includes/rest-api/endpoints/class-wp-rest-blocks-controller.php @@ -0,0 +1,39 @@ +post_type ); + if ( ! current_user_can( $post_type->cap->read_post, $post->ID ) ) { + return false; + } + + return parent::check_read_permission( $post ); + } +} diff --git a/wp-includes/version.php b/wp-includes/version.php index 5684332b34..1f2b32241d 100644 --- a/wp-includes/version.php +++ b/wp-includes/version.php @@ -13,7 +13,7 @@ * * @global string $wp_version */ -$wp_version = '5.1-alpha-44149'; +$wp_version = '5.1-alpha-44150'; /** * Holds the WordPress DB revision, increments when changes are made to the WordPress DB schema. diff --git a/wp-settings.php b/wp-settings.php index 9b1d9f5445..4f15f0edc2 100644 --- a/wp-settings.php +++ b/wp-settings.php @@ -236,6 +236,8 @@ require( ABSPATH . WPINC . '/rest-api/endpoints/class-wp-rest-terms-controller.p require( ABSPATH . WPINC . '/rest-api/endpoints/class-wp-rest-users-controller.php' ); require( ABSPATH . WPINC . '/rest-api/endpoints/class-wp-rest-comments-controller.php' ); require( ABSPATH . WPINC . '/rest-api/endpoints/class-wp-rest-search-controller.php' ); +require( ABSPATH . WPINC . '/rest-api/endpoints/class-wp-rest-blocks-controller.php' ); +require( ABSPATH . WPINC . '/rest-api/endpoints/class-wp-rest-block-renderer-controller.php' ); require( ABSPATH . WPINC . '/rest-api/endpoints/class-wp-rest-settings-controller.php' ); require( ABSPATH . WPINC . '/rest-api/endpoints/class-wp-rest-themes-controller.php' ); require( ABSPATH . WPINC . '/rest-api/fields/class-wp-rest-meta-fields.php' );