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

Render block preview on the server #55850

Closed
wants to merge 22 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
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
2 changes: 1 addition & 1 deletion docs/reference-guides/core-blocks.md
Original file line number Diff line number Diff line change
Expand Up @@ -630,7 +630,7 @@ Display a post's featured image. ([Source](https://github.com/WordPress/gutenber
- **Name:** core/post-featured-image
- **Category:** theme
- **Supports:** align (center, full, left, right, wide), color (~~background~~, ~~text~~), spacing (margin, padding), ~~html~~
- **Attributes:** aspectRatio, customGradient, customOverlayColor, dimRatio, gradient, height, isLink, linkTarget, overlayColor, rel, scale, sizeSlug, width
- **Attributes:** aspectRatio, customGradient, customOverlayColor, dimRatio, featured_image, gradient, height, isLink, linkTarget, overlayColor, rel, scale, sizeSlug, width

## Post Navigation Link

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
<?php
/**
* File description goes here.
*
* @package Gutenberg_Render_Blocks_Controller
*/

if ( ! class_exists( 'Gutenberg_Render_Blocks_Controller' ) ) {

/**
* Class Gutenberg_Render_Blocks_Controller
*
* Renders blocks from a REST API request.
*
* @package Gutenberg_Render_Blocks_Controller
*/
class Gutenberg_Render_Blocks_Controller extends WP_REST_Controller {

/**
* Constructor.
*/
public function __construct() {
$this->namespace = 'wp/v2';
$this->rest_base = 'render_blocks';
}

/**
* Registers the routes for the objects of the controller.
*/
public function register_routes() {
register_rest_route(
$this->namespace,
'/' . $this->rest_base,
array(
array(
'methods' => WP_REST_Server::CREATABLE,
'callback' => array( $this, 'render_blocks_from_request' ),
'permission_callback' => array( $this, 'get_permissions_check' ),
'args' => array(
'blocks' => array(
'required' => true,
'validate_callback' => array( $this, 'validate_blocks' ),
'sanitize_callback' => array( $this, 'sanitize_blocks' ),
),
),
'schema' => array( $this, 'get_item_schema' ),
),
)
);
}

/**
* Checks if a given request has access to create items.
*/
public function get_permissions_check() {
return true;
}

/**
* Checks if the blocks string is valid.
*
* @param string $blocks Full data about the request.
* @return WP_Error|bool True if the request has read access for the item, WP_Error object otherwise.
*/
public function validate_blocks( $blocks ) {
$blocks = parse_blocks( $blocks );
if ( ! is_array( $blocks ) ) {
// If parse_blocks does not return an array, it's not a valid block string.
return new WP_Error( 'rest_invalid_blocks', __( 'The blocks parameter is invalid.', 'gutenberg' ), array( 'status' => 400 ) );
}

return true;
}

/**
* Sanitizes the 'blocks' parameter.
*
* @param string $blocks The blocks string.
*/
public function sanitize_blocks( $blocks ) {
// Sanitize the blocks string to ensure it's a clean string.
return wp_kses_post( $blocks );
}

/**
* Renders blocks from a REST API request.
*
* @param WP_REST_Request $request Full data about the request.
*/
public function render_blocks_from_request( $request ) {
global $wp_query, $post;

$data = $request->get_json_params();

// We need to fake a global $wp_query and $post.
// This is because some blocks (e.g. Query block) rely on them,
// and we don't have them in the REST API context.
// Without them, the preview will be empty.
$fake_query = new WP_Query(
array(
'post_type' => 'post',
'posts_per_page' => get_option( 'posts_per_page' ),
'post_status' => 'publish',
)
);
$wp_query = $fake_query;
$post = $wp_query->posts[0];

$rendered_blocks = do_blocks( $data['blocks'] );

return rest_ensure_response( $rendered_blocks );
}

/**
* Retrieves the block renderer's schema, conforming to JSON Schema.
*/
public function get_item_schema() {
return array(
'$schema' => 'http://json-schema.org/draft-04/schema#',
'title' => 'block-render',
'type' => 'object',
'properties' => array(
'blocks' => array(
'description' => __( 'Serialized blocks to render', 'gutenberg' ),
'type' => 'string',
'context' => array( 'view', 'edit' ),
),
),
);
}
}
}
9 changes: 9 additions & 0 deletions lib/compat/wordpress-6.5/rest-api.php
Original file line number Diff line number Diff line change
Expand Up @@ -144,3 +144,12 @@ function _gutenberg_register_wp_templates_additional_fields() {
}

add_action( 'rest_api_init', '_gutenberg_register_wp_templates_additional_fields' );
/**
* Registers the Block Rederer REST API routes.
*/
function gutenberg_register_block_rederer_routes() {
$block_renderer_controller = new Gutenberg_Render_Blocks_Controller();
$block_renderer_controller->register_routes();
}

add_action( 'rest_api_init', 'gutenberg_register_block_rederer_routes' );
91 changes: 91 additions & 0 deletions lib/load.php
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ function gutenberg_is_experiment_enabled( $name ) {

// WordPress 6.5 compat.
require_once __DIR__ . '/compat/wordpress-6.5/class-gutenberg-rest-global-styles-revisions-controller-6-5.php';
require_once __DIR__ . '/compat/wordpress-6.5/class-gutenberg-render-blocks-controller.php';
require_once __DIR__ . '/compat/wordpress-6.5/rest-api.php';

// Plugin specific code.
Expand Down Expand Up @@ -258,3 +259,93 @@ function () {

// Data views.
require_once __DIR__ . '/experimental/data-views.php';

// Updates all blocks to use their example data, if they have it.
function modify_block_attributes_before_render( $block ) {
Comment on lines +263 to +264
Copy link
Contributor

Choose a reason for hiding this comment

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

I think we'll need to explain why this is being done 🙏



if ( ! isset( $_GET['block_preview'] ) ) {
return $block;
};

$block_type_registry = WP_Block_Type_Registry::get_instance();
$block_type = $block_type_registry->get_registered( $block['blockName'] );
// we should use the bindings API!
if ( isset( $block_type->example ) && isset( $block_type->example[ 'attributes' ] ) ) {
foreach( $block_type->example[ 'attributes' ] as $attribute_name => $attribute_value ) {
// Only replace attributes that are already set.
if ( isset( $block['attrs'][ $attribute_name ] ) ) {
$block['attrs'][ $attribute_name ] = $attribute_value;
}
$block['attrs'][ $attribute_name ] = $attribute_value;
if ( $block['blockName'] === 'core/cover' ) {
//var_dump( $block['attrs'] );
//var_dump( $attribute_name );
//var_dump( $attribute_value );
}

$attribute_definition = $block_type->attributes[ $attribute_name ];
// Is this attribute sourced from the block markup istead of the block json comment.
if ( isset( $attribute_definition['source'] ) && $attribute_definition['source'] === 'attribute' ) {
$processor = new WP_HTML_Tag_Processor( $block['innerHTML'] ); //Should this be innerContent?
if ( $processor->next_tag( $attribute_definition['selector'] ) ) {
$processor->set_attribute( $attribute_definition['attribute'], $attribute_value );
//$block['innerHTML'] = $processor->get_updated_html();
$block['innerContent'] = array( $processor->get_updated_html() );
}
}
}
}

return $block;
}

function modify_block_attributes_during_render( $block_content, $block ) {
//var_dump( $block['blockName'] );
$block_type_registry = WP_Block_Type_Registry::get_instance();
$block_type = $block_type_registry->get_registered( $block['blockName'] );
/*if ( isset( $block_type->example ) && isset( $block_type->example[ 'attributes' ] ) ) {

if ( $block['blockName'] === 'core/cover' ) {
if ( isset( $block['attrs']['useFeaturedImage'] ) ) {
$processor = new WP_HTML_Tag_Processor( $block_content );
$processor->next_tag();
$processor->set_attribute( 'style', 'background-image: url('. $block_type->example[ 'attributes' ]['url'] .');' );
$block_content = $processor->get_updated_html();
}
}
}*/

if ( $block['blockName'] === 'core/cover' ) {
//var_dump( $block_content );
/*$processor = new WP_HTML_Tag_Processor( $block_content );
if ( ! $processor->next_tag('img') ) {
if ( isset( $block['attrs']['useFeaturedImage'] ) && $block['attrs']['useFeaturedImage'] ) {
$inner_blocks_html = $block['innerBlocks'][0]['innerHTML'];
return str_replace( '[[INNER_BLOCKS]]', $inner_blocks_html, $block_type->example[ 'preview' ] );
}
}*/
}

/*if ( isset( $block_type->example[ 'preview' ] ) && $block_content === '' ) {
return $block_type->example[ 'preview' ];
}*/

return $block_content;
}

//add_filter( 'render_block_data', 'modify_block_attributes_before_render', 10, 2 );
//add_filter( 'render_block', 'modify_block_attributes_during_render', 10, 2 );


function modify_post_thumbnail_html( $html, $post_id, $post_thumbnail_id, $size, $attr ) {
$classes = isset( $attr['class'] ) ? $attr['class'] : '';
$style = isset( $attr['style'] ) ? $attr['style'] : '';
$placeholder_svg = "%3Csvg fill='none' xmlns='http://www.w3.org/2000/svg' viewBox='0 0 60 60' preserveAspectRatio='none' class='components-placeholder__illustration' aria-hidden='true' focusable='false' style='background: %23e1e1e1; stroke: %23000;'%3E%3Cpath vector-effect='non-scaling-stroke' d='M60 60 0 0'%3E%3C/path%3E%3C/svg%3E ";
if ( ! $html ) {
return '<img width="2000" height="2000" src="data:image/svg+xml;charset=UTF-8,' . $placeholder_svg . '" class="wp-post-image ' . $classes . '" alt="" style="' . $style . '" decoding="async" />';
}
return $html;

}
add_filter( 'post_thumbnail_html', 'modify_post_thumbnail_html', 10, 5 );
34 changes: 34 additions & 0 deletions packages/block-editor/src/components/block-preview/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,40 @@ export function BlockPreview( {
// Deprecated props:
__experimentalMinHeight,
__experimentalPadding,
} ) {
const settings = useSelect(
( select ) => select( blockEditorStore ).getSettings(),
[]
);

if ( settings.blockPreview ) {
return settings.blockPreview( {
blocks,
viewportWidth,
minHeight,
additionalStyles,
} );
}
return (
<DefaultBlockPreview
blocks={ blocks }
viewportWidth={ viewportWidth }
minHeight={ minHeight }
additionalStyles={ additionalStyles }
__experimentalMinHeight={ __experimentalMinHeight }
__experimentalPadding={ __experimentalPadding }
/>
);
}

function DefaultBlockPreview( {
blocks,
viewportWidth = 1200,
minHeight,
additionalStyles = [],
// Deprecated props:
__experimentalMinHeight,
__experimentalPadding,
} ) {
if ( __experimentalMinHeight ) {
minHeight = __experimentalMinHeight;
Expand Down
3 changes: 3 additions & 0 deletions packages/block-library/src/cover/block.json
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,9 @@
"default": "div"
}
},
"example": {
"preview": "<div class=\"wp-block-cover is-light\"><span aria-hidden=\"true\" class=\"wp-block-cover__background has-background-dim\" style=\"background-color:#FFF\"><div class=\"block-editor-media-placeholder\" style=\"overflow: auto\"><svg style=\"background: #e1e1e1; stroke: currentColor;stroke: currentColor;box-sizing: content-box;height: 100%;left: 50%;position: absolute;top: 50%;transform: translate(-50%, -50%);width: 100%;\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 60 60\" preserveAspectRatio=\"none\" class=\"components-placeholder__illustration\" aria-hidden=\"true\" focusable=\"false\"><path vector-effect=\"non-scaling-stroke\" d=\"M60 60 0 0\"></path></svg></div></span><div class=\"wp-block-cover__inner-container\">[[INNER_BLOCKS]]</div></div>"
},
"usesContext": [ "postId", "postType" ],
"supports": {
"anchor": true,
Expand Down
7 changes: 7 additions & 0 deletions packages/block-library/src/image/block.json
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,13 @@
"attribute": "target"
}
},
"example": {
"attributes": {
"sizeSlug": "large",
"url": "https://s.w.org/images/core/5.3/MtBlanc1.jpg",
"caption": "Mont Blanc appears—still, snowy, and serene."
}
},
"supports": {
"interactivity": true,
"align": [ "left", "center", "right", "wide", "full" ],
Expand Down
8 changes: 0 additions & 8 deletions packages/block-library/src/image/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,6 @@ export { metadata, name };

export const settings = {
icon,
example: {
attributes: {
sizeSlug: 'large',
url: 'https://s.w.org/images/core/5.3/MtBlanc1.jpg',
// translators: Caption accompanying an image of the Mont Blanc, which serves as an example for the Image block.
caption: __( 'Mont Blanc appears—still, snowy, and serene.' ),
},
},
__experimentalLabel( attributes, { context } ) {
if ( context === 'accessibility' ) {
const { caption, alt, url } = attributes;
Expand Down
11 changes: 11 additions & 0 deletions packages/block-library/src/post-featured-image/block.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,15 @@
"category": "theme",
"description": "Display a post's featured image.",
"textdomain": "default",
"example": {
"attributes": {
"featured_image": "<figure style=\"margin-bottom:var(--wp--preset--spacing--40);\" class=\"wp-block-post-featured-image\"><img src=\"https://images.pexels.com/photos/14850795/pexels-photo-14850795.jpeg?auto=compress&cs=tinysrgb&w=1260&h=750&dpr=1\" class=\"attachment-post-thumbnail size-post-thumbnail wp-post-image\" alt=\"\" style=\"object-fit:cover;\" decoding=\"async\"></figure>"
}
},
"attributes": {
"featured_image": {
"type": "string"
},
"isLink": {
"type": "boolean",
"default": false
Expand Down Expand Up @@ -53,6 +61,9 @@
"type": "string"
}
},
"example": {
"preview": "<figure class=\"wp-block-post-featured-image\"><div class=\"block-editor-media-placeholder\" style=\"overflow: auto\"><svg style=\"background: #e1e1e1; stroke: currentColor;\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 60 60\" preserveAspectRatio=\"none\" class=\"components-placeholder__illustration\" aria-hidden=\"true\" focusable=\"false\"><path vector-effect=\"non-scaling-stroke\" d=\"M60 60 0 0\"></path></svg></div></figure>"
},
"usesContext": [ "postId", "postType", "queryId" ],
"supports": {
"align": [ "left", "right", "center", "wide", "full" ],
Expand Down
Loading
Loading