-
Notifications
You must be signed in to change notification settings - Fork 4.2k
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
Closed
Changes from 15 commits
Commits
Show all changes
22 commits
Select commit
Hold shift + click to select a range
c5d0207
trying out API calls to render
draganescu 44f6213
first try at static render
draganescu 175da44
lint
draganescu be94067
add a public permission for now
draganescu 136a92d
lint
draganescu 64eed79
not functional commit - refactor the implementation
draganescu 096d399
serialize blocks before sending them to render
draganescu 4ed76e3
fix the rendering of blocks that require global context
draganescu aa9bc10
revert the pattern list component edits
draganescu 6e2511e
adjustments after trunk rebase
draganescu aeae741
updates for edtitor implementation refactoring
draganescu 611fb31
allow the blockPreview setting to get to the block editor provider
draganescu cee067f
add REST class for render blocks endpoint
draganescu d991d0a
remove debugging error reporting
draganescu 23f3b41
rebase cleanup
draganescu 5b56232
add prototype for prerendering data
scruffian 19c78fd
source example data and update all attributes with it
scruffian 1634772
Update packages/block-library/src/site-logo/block.json
scruffian 1dd19b1
im sorry
scruffian c177616
example of block attribute convention for dynamic rendering
draganescu a8fd9e0
merge
scruffian cf78236
use embedded svg
scruffian File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
132 changes: 132 additions & 0 deletions
132
lib/compat/wordpress-6.5/class-gutenberg-render-blocks-controller.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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' ), | ||
), | ||
), | ||
); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
128 changes: 128 additions & 0 deletions
128
packages/edit-site/src/components/block-preview/editor-styles.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,128 @@ | ||
/** | ||
* External dependencies | ||
*/ | ||
import { colord, extend } from 'colord'; | ||
import namesPlugin from 'colord/plugins/names'; | ||
import a11yPlugin from 'colord/plugins/a11y'; | ||
|
||
/** | ||
* WordPress dependencies | ||
*/ | ||
import { SVG } from '@wordpress/components'; | ||
import { useCallback, useMemo } from '@wordpress/element'; | ||
import { useSelect } from '@wordpress/data'; | ||
import { | ||
transformStyles, | ||
store as blockEditorStore, | ||
} from '@wordpress/block-editor'; | ||
|
||
/** | ||
* Internal dependencies | ||
*/ | ||
import { unlock } from '../../lock-unlock'; | ||
|
||
extend( [ namesPlugin, a11yPlugin ] ); | ||
|
||
function useDarkThemeBodyClassName( styles, scope ) { | ||
return useCallback( | ||
( node ) => { | ||
if ( ! node ) { | ||
return; | ||
} | ||
|
||
const { ownerDocument } = node; | ||
const { defaultView, body } = ownerDocument; | ||
const canvas = scope ? ownerDocument.querySelector( scope ) : body; | ||
|
||
let backgroundColor; | ||
|
||
if ( ! canvas ) { | ||
// The real .editor-styles-wrapper element might not exist in the | ||
// DOM, so calculate the background color by creating a fake | ||
// wrapper. | ||
const tempCanvas = ownerDocument.createElement( 'div' ); | ||
tempCanvas.classList.add( 'editor-styles-wrapper' ); | ||
body.appendChild( tempCanvas ); | ||
|
||
backgroundColor = defaultView | ||
?.getComputedStyle( tempCanvas, null ) | ||
.getPropertyValue( 'background-color' ); | ||
|
||
body.removeChild( tempCanvas ); | ||
} else { | ||
backgroundColor = defaultView | ||
?.getComputedStyle( canvas, null ) | ||
.getPropertyValue( 'background-color' ); | ||
} | ||
const colordBackgroundColor = colord( backgroundColor ); | ||
// If background is transparent, it should be treated as light color. | ||
if ( | ||
colordBackgroundColor.luminance() > 0.5 || | ||
colordBackgroundColor.alpha() === 0 | ||
) { | ||
body.classList.remove( 'is-dark-theme' ); | ||
} else { | ||
body.classList.add( 'is-dark-theme' ); | ||
} | ||
}, | ||
[ styles, scope ] | ||
); | ||
} | ||
|
||
export default function EditorStyles( { styles, scope } ) { | ||
const overrides = useSelect( | ||
( select ) => unlock( select( blockEditorStore ) ).getStyleOverrides(), | ||
[] | ||
); | ||
const [ transformedStyles, transformedSvgs ] = useMemo( () => { | ||
const _styles = Object.values( styles ?? [] ); | ||
|
||
for ( const [ id, override ] of overrides ) { | ||
const index = _styles.findIndex( ( { id: _id } ) => id === _id ); | ||
const overrideWithId = { ...override, id }; | ||
if ( index === -1 ) { | ||
_styles.push( overrideWithId ); | ||
} else { | ||
_styles[ index ] = overrideWithId; | ||
} | ||
} | ||
|
||
return [ | ||
transformStyles( | ||
_styles.filter( ( style ) => style?.css ), | ||
scope | ||
), | ||
_styles | ||
.filter( ( style ) => style.__unstableType === 'svgs' ) | ||
.map( ( style ) => style.assets ) | ||
.join( '' ), | ||
]; | ||
}, [ styles, overrides, scope ] ); | ||
|
||
return ( | ||
<> | ||
{ /* Use an empty style element to have a document reference, | ||
but this could be any element. */ } | ||
<style | ||
ref={ useDarkThemeBodyClassName( transformedStyles, scope ) } | ||
/> | ||
{ transformedStyles.map( ( css, index ) => ( | ||
<style key={ index }>{ css }</style> | ||
) ) } | ||
<SVG | ||
xmlns="http://www.w3.org/2000/svg" | ||
viewBox="0 0 0 0" | ||
width="0" | ||
height="0" | ||
role="none" | ||
style={ { | ||
visibility: 'hidden', | ||
position: 'absolute', | ||
left: '-9999px', | ||
overflow: 'hidden', | ||
} } | ||
dangerouslySetInnerHTML={ { __html: transformedSvgs } } | ||
/> | ||
</> | ||
); | ||
} |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is duplicated from the block editor package,