-
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
Templates perf: resolve patterns server side #60349
Changes from all commits
243f72a
19136e0
a5fdfc7
b159d95
1ad5980
7f09e52
0bfe0d6
a65767e
7ba871e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,97 @@ | ||
<?php | ||
|
||
/** | ||
* Replaces pattern blocks with their content. | ||
* | ||
* @param array $blocks Array of blocks. | ||
* @param array $inner_content Optional array of inner content. | ||
* @return array Array of blocks with patterns replaced. | ||
*/ | ||
function gutenberg_replace_pattern_blocks( $blocks, &$inner_content = null ) { | ||
// Keep track of seen references to avoid infinite loops. | ||
static $seen_refs = array(); | ||
$i = 0; | ||
while ( $i < count( $blocks ) ) { | ||
if ( 'core/pattern' === $blocks[ $i ]['blockName'] ) { | ||
$slug = $blocks[ $i ]['attrs']['slug']; | ||
|
||
if ( isset( $seen_refs[ $slug ] ) ) { | ||
// Skip recursive patterns. | ||
array_splice( $blocks, $i, 1 ); | ||
Comment on lines
+19
to
+20
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. A downside (but not a blocker) of this simple skipping is that recursion violations become silent in the editor, reducing users' ability to spot and fix them, but they will still be flagged in the front end by a different mechanism. In a production environment (with There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, but we don't have mechanism to "store" errors in block markup. You just injected some text, but that doesn't work in the editor. We can't just inject a paragraph block that is then editable. 🤔 Maybe set an attribute and error in the editor if that's present? Anyway, I think we could explore this separately if needed. I guess the main thing is preventing an infinite loop. :) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Like I said, not a blocker. :)
Could be as simple as a special block, no? Inject: [
'blockName' => 'core/error',
'attrs' => [
'type' => 'recursion',
'details' => $pattern_slug,
],
'innerBlocks' => [],
'innerHTML' => '',
'innerContent' => [],
]; There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We could also try to use the |
||
continue; | ||
} | ||
|
||
$registry = WP_Block_Patterns_Registry::get_instance(); | ||
$pattern = $registry->get_registered( $slug ); | ||
$blocks_to_insert = parse_blocks( $pattern['content'] ); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I had the same issue fwiw, and wp-admin wasn't even loading for me but pretty sure the version I was on was 6.5-alpha-something. Destroying my env and upgrading to 6.6-alpha fixed it, but we do need to make sure the plugin works on 6.4 and 6.5. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks, I created #60464 |
||
$seen_refs[ $slug ] = true; | ||
$blocks_to_insert = gutenberg_replace_pattern_blocks( $blocks_to_insert ); | ||
unset( $seen_refs[ $slug ] ); | ||
array_splice( $blocks, $i, 1, $blocks_to_insert ); | ||
|
||
// If we have inner content, we need to insert nulls in the | ||
// inner content array, otherwise serialize_blocks will skip | ||
// blocks. | ||
if ( $inner_content ) { | ||
$null_indices = array_keys( $inner_content, null, true ); | ||
$content_index = $null_indices[ $i ]; | ||
$nulls = array_fill( 0, count( $blocks_to_insert ), null ); | ||
array_splice( $inner_content, $content_index, 1, $nulls ); | ||
} | ||
|
||
// Skip inserted blocks. | ||
$i += count( $blocks_to_insert ); | ||
} else { | ||
if ( ! empty( $blocks[ $i ]['innerBlocks'] ) ) { | ||
$blocks[ $i ]['innerBlocks'] = gutenberg_replace_pattern_blocks( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is it possible to guard against recursions. Like a pattern block containing the same pattern block or something like that. cc @mcsf has some experience here. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Right, I guess we can pass down the parent pattern name and check |
||
$blocks[ $i ]['innerBlocks'], | ||
$blocks[ $i ]['innerContent'] | ||
); | ||
} | ||
++$i; | ||
} | ||
} | ||
return $blocks; | ||
} | ||
|
||
function gutenberg_replace_pattern_blocks_get_block_templates( $templates ) { | ||
foreach ( $templates as $template ) { | ||
$blocks = parse_blocks( $template->content ); | ||
$blocks = gutenberg_replace_pattern_blocks( $blocks ); | ||
$template->content = serialize_blocks( $blocks ); | ||
} | ||
return $templates; | ||
} | ||
|
||
function gutenberg_replace_pattern_blocks_get_block_template( $template ) { | ||
$blocks = parse_blocks( $template->content ); | ||
$blocks = gutenberg_replace_pattern_blocks( $blocks ); | ||
$template->content = serialize_blocks( $blocks ); | ||
return $template; | ||
} | ||
|
||
function gutenberg_replace_pattern_blocks_patterns_endpoint( $result, $server, $request ) { | ||
if ( $request->get_route() !== '/wp/v2/block-patterns/patterns' ) { | ||
return $result; | ||
} | ||
|
||
$data = $result->get_data(); | ||
|
||
foreach ( $data as $index => $pattern ) { | ||
$blocks = parse_blocks( $pattern['content'] ); | ||
$blocks = gutenberg_replace_pattern_blocks( $blocks ); | ||
$data[ $index ]['content'] = serialize_blocks( $blocks ); | ||
} | ||
|
||
$result->set_data( $data ); | ||
|
||
return $result; | ||
} | ||
|
||
// For core merge, we should avoid the double parse and replace the patterns in templates here: | ||
// https://github.com/WordPress/wordpress-develop/blob/02fb53498f1ce7e63d807b9bafc47a7dba19d169/src/wp-includes/block-template-utils.php#L558 | ||
add_filter( 'get_block_templates', 'gutenberg_replace_pattern_blocks_get_block_templates' ); | ||
add_filter( 'get_block_template', 'gutenberg_replace_pattern_blocks_get_block_template' ); | ||
// Similarly, for patterns, we can avoid the double parse here: | ||
// https://github.com/WordPress/wordpress-develop/blob/02fb53498f1ce7e63d807b9bafc47a7dba19d169/src/wp-includes/class-wp-block-patterns-registry.php#L175 | ||
add_filter( 'rest_post_dispatch', 'gutenberg_replace_pattern_blocks_patterns_endpoint', 10, 3 ); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @youknowriad @Mamaduka I added some comments here regarding the double parse and core merge. |
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.
I'm not sure I ever used a static variable before but I guess this works.
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.
I shamelessly copied @mcsf #56511.
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.
I approve this technique