-
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
Experiment: Auto-inserting blocks on the frontend #50103
Conversation
Originally, I wanted to experiment with auto-inserting the Log-in/out block as the last child of the Navigation block. But of course, it's not that easy 😬 The Navigation block, if unmodified by the user, defaults to the Page List block, or renders a previously created navigation menu. This means that the location where we'd want to insert the Log-in block becomes a moving target; and due to the mechanism used by the Navigation block, it also doesn't show up as the Page List blocks (or navigation menu's) parent block. tl;dr If we want a mechanism that auto-inserts blocks as the last (or first) child of a given parent block, it won't "just work" with the Navigation block; we'll have to manually tweak some of its internals. |
I chose the example of auto-inserting a Like button (of sorts) below each comment based on what this Jetpack Module does, using the |
Another thing that occurred to me while working on this is that we'll want a way to pass block context (from containing blocks) to auto-inserted blocks. Think of the example of an auto-inserted Like button for comments: That button will need to know which comment is being liked. That information ( Hopefully, block context is enough information for auto-inserted blocks to work in the desired settings. I'm somewhat optimistic, since each auto-inserted block will also have to work when manually inserted (or persisted) in the editor. The latter will also probably be a good guideline to look at when deciding which information a given auto-inserting block needs. |
P.S. to the above: Maybe we should make a minimal plugin with a real-world example (the Comments Like button block comes to mind; or maybe a "Share this comment on tumblr" or something) to test our explorations and tentative auto-inserting blocks code with. |
Regarding the block context, passing it to the auto-inserted block could be handled similarly, as we can observe it for the Post Template and Comment Template blocks. In there, the block context changes programmatically depending on the currently iterated entity:
It sounds like a great idea to exercise the assumptions with real-world examples 👍🏻 I don't know which block would be the vest to start with, so any option is fine based on your preference. |
I ended up using the Avatar block (instead of a newly written block) to experiment with (92c29fe). It conveniently uses
That was my initial thinking as well. However, it's not as straight-forward, unfortunately; I spent all afternoon trying to make it work; to no avail, so far 😕 While we can easily replace the (context-ignorant) way of rendering our auto-inserted block with the method you're suggesting... diff --git a/lib/experimental/blocks.php b/lib/experimental/blocks.php
index 018ae7d2cc..63565d9420 100644
--- a/lib/experimental/blocks.php
+++ b/lib/experimental/blocks.php
@@ -147,7 +147,12 @@ function gutenberg_auto_insert_blocks( $block_content, $block ) {
$inserted_block_markup = '<!-- wp:avatar {"size":40,"style":{"border":{"radius":"10px"}}} /-->';
$inserted_blocks = parse_blocks( $inserted_block_markup );
- $inserted_content = render_block( $inserted_blocks[0] );
+ $inserted_content = ( new WP_Block(
+ $inserted_blocks[0],
+ array(
+ 'commentId' => 1. // FIXME: Provide actual context!!!
+ )
+ ) )->render();
if ( isset( $block['parentBlock'] ) && $block_name === $block['parentBlock'] ) {
if ( 'last-child' === $block_position ) { ...we don't have any way of obtaining the 'right' context here: While we can access Alternatively, we could try to auto-insert the block from the diff --git a/lib/experimental/blocks.php b/lib/experimental/blocks.php
index 018ae7d2cc..2a714a3f93 100644
--- a/lib/experimental/blocks.php
+++ b/lib/experimental/blocks.php
@@ -112,6 +112,19 @@ function gutenberg_auto_insert_child_block( $parsed_block, $source_block, $paren
if ( isset( $parent_block ) ) {
$parsed_block['parentBlock'] = $parent_block->name;
}
+
+ if ( 'core/comment-template' === $parsed_block['blockName'] ) {
+ $inserted_block_markup = <<<END
+<!-- wp:social-links -->
+<ul class="wp-block-social-links"><!-- wp:social-link {"url":"https://wordpress.org","service":"wordpress"} /--></ul>
+<!-- /wp:social-links -->'
+END;
+ $inserted_blocks = parse_blocks( $inserted_block_markup );
+
+ $parsed_block['innerBlocks'][] = $inserted_blocks[0]; // last-child
+
+ // TODO: Implement first-child logic
+ }
return $parsed_block;
}
add_filter( 'render_block_data', 'gutenberg_auto_insert_child_block', 10, 3 );
@@ -168,4 +181,4 @@ function gutenberg_auto_insert_blocks( $block_content, $block ) {
return $block_content;
}
-add_filter( 'render_block', 'gutenberg_auto_insert_blocks', 10, 2 );
+//add_filter( 'render_block', 'gutenberg_auto_insert_blocks', 10, 2 ); ...would be ideal in a number of ways: The But alas, I've never managed to get this method to work; while I've verified that |
I now tried array_unshift( $parsed_block['innerBlocks'], $inserted_blocks[0] ); instead of $parsed_block['innerBlocks'][] = $inserted_blocks[0]; and that does indeed show the Social Icon -- but it removes the rest of each comment template 😬 So it seems to me that the number of elements in a |
I had some partial success: I think I managed to solve the context problem in #50279 🎉 (Note the auto-inserted avatar block under the first comment, which correctly displays Wapuu, as opposed to the screenshot in this comment.) |
92c29fe
to
6efe12a
Compare
Rebased on #50279. |
In the Comment Template block's render callback, instead of creating a new `WP_Block` instance with `commentId` context set, use the `render_block_context` filter to set that context and render the existing `WP_Block` instance. This approach arguably follows our established patterns with regard to handling block context better. Notably, with the previous approach, we were only setting block context for the Comment Template block itself. In this PR, we extend it to apply to all child blocks, including ones that are dynamically inserted, e.g. via the `render_block` filter. This is relevant for Auto-inserting blocks (see #50103).
6efe12a
to
f4d5f0c
Compare
Rebased on |
In the Post Template block's render callback, instead of creating a new `WP_Block` instance with `postId` and `postType` context set, use the `render_block_context` filter to set that context and render the existing `WP_Block` instance. This approach arguably follows our established patterns with regard to handling block context better. Notably, with the previous approach, we were only setting block context for the Post Template block itself. In this PR, we extend it to apply to all child blocks, including ones that are dynamically inserted, e.g. via the `render_block` filter. This is relevant for Auto-inserting blocks (see #50103). This follows the precedent of the Comment Template block, see #50279.
Recap of findings
To sum up:Block filters such as
In order to get things to work properly, we'll likely have to untangle why blocks that are appended to a parsed block's I don't believe that we need or should tackle auto-insertion right after parsing, i.e. by injecting into the tree of parsed blocks. The reason for that is that that tree doesn't seem to represent the markup on the frontend that well, especially if "template" blocks are involved: E.g. there might be only one Comments Template block in that tree, but on the frontend, its render callback renders comments recursively, passing the correct comment ID as block context each time. This doesn't seem to be something that can be easily represented by solely modifying the tree of parsed blocks. |
Hi @ockham! Could you please ping me as soon as this experiment is ready for testing? On WooCommerce we want to explore injecting the mini cart block to the header by relying on auto-inserting blocks. |
Hey @nefeline! Apologies for the late reply, I just came back from a 2-week vacation. |
No worries: I hope you enjoyed your time off!
Thank you! Looking forward to starting experimenting with those auto-inserting blocks on Woo. |
In the Post Template block's render callback, instead of creating a new `WP_Block` instance with `postId` and `postType` context set, use the `render_block_context` filter to set that context and render the existing `WP_Block` instance. This approach arguably follows our established patterns with regard to handling block context better. Notably, with the previous approach, we were only setting block context for the Post Template block itself. In this PR, we extend it to apply to all child blocks, including ones that are dynamically inserted, e.g. via the `render_block` filter. This is relevant for Auto-inserting blocks (see #50103). This follows the precedent of the Comment Template block, see #50279.
Yeah, exactly 👍
Yeah, I should've added a TODO for this. I didn't look into this right away since it didn't seem to impact auto-insertion, but I agree that we should be consistent here with what |
I’m becoming more and more convinced that the syntax we want for auto-insertion needs to involve block patterns rather than just blocks. I’ve just updated the PR to support a basic syntax in "autoInsert": {
"core/post-content": "after"
} The result really doesn’t look great: The reason is that blocks need at least a minor degree of customization by setting attributes — the defaults might be fine for inserting a new instance of the block in the editor, but they just about never cut it on the frontend. We had those attributes set at a previous stage of the PR, but it was hardwired (inside the $inserted_block = array(
'blockName' => 'core/avatar',
'attrs' => array(
'size' => 40,
'style' => array(
'border' => array( 'radius' => '10px' ),
),
),
'innerHTML' => '',
'innerContent' => array(),
); The ProblemsSpecifying Block AttributesDuring my call with @gziolo, we decided to provide attributes in the "autoInsert": {
"core/post-content": {
"position": "after",
"attrs": {
"size": 40,
"style": {
"border": {
"radius": "10px"
}
}
}
}
} Aside from getting annoyingly verbose for even the most basic of nested block-supports attributes, it's easy to think that these attributes are for the Post Content block -- when really they are for the Avatar block, whose Inner BlocksAttributes aren't the only issue with this approach: My original example in this PR was to insert a Social Icon block (rather than an Avatar) after Post Content. I discovered that for styling to be applied properly, I had to render it wrapped in its Social Links parent block: $inserted_block_markup = <<<END
<!-- wp:social-links -->
<ul class="wp-block-social-links"><!-- wp:social-link {"url":"https://wordpress.org","service":"wordpress"} /--></ul>
<!-- /wp:social-links -->'
END;
$inserted_blocks = parse_blocks( $inserted_block_markup );
$inserted_content = render_block( $inserted_blocks[0] ); Once again, a fairly basic example -- but one that cannot be carried over to the above Static BlocksFinally, as discussed earlier, this approach was never going to work for static blocks -- as we cannot know on the server side what they serialize to, as this requires saving them on the client side. ProposalAll of the above problems are solved by block patterns, where we simply specify the serialized block markup anyway. I'm thus thinking to experiment with auto-inserting block patterns as a next step. We already have the concept of contextual block types there -- a concept that can take on different roles (a pattern to transform a block to, or a destination template area). Maybe we can extend that concept further to also encompass anchor blocks (or add a separate field, if that's again too prone to confusion). register_block_pattern(
'my-plugin/wordpress-logo',
array(
'title' => __( 'WordPress Logo', 'my-plugin' ),
'autoInsert' => 'after',
'blockTypes' => array( 'core/post-content' ),
'content' => '<!-- wp:social-links --><ul class="wp-block-social-links"><!-- wp:social-link {"url":"https://wordpress.org","service":"wordpress"} /--></ul><!-- /wp:social-links -->'',
)
); cc/ @mtias |
2b196b0
to
46e30e5
Compare
Spin-off PR to explore block auto-insertion in the editor via the REST API: #51449. |
@ockham I don't think this API should deal directly with patterns. You should always be able to leverage |
Closing in favor of #51449, which also auto-inserts blocks into the editor. |
* Post Template Block: Set block context via filter In the Post Template block's render callback, use the `render_block_context` filter to set `postId` and `postType` context, rather than passing that context directly to the `WP_Block` constructor. This approach arguably follows our established patterns with regard to handling block context better. Notably, with the previous approach, we were only setting block context for the Post Template block itself. In this PR, we extend it to apply to all child blocks, including ones that are dynamically inserted, e.g. via the `render_block` filter. This is relevant for Auto-inserting blocks (see WordPress#50103). This follows the precedent of the Comment Template block, see WordPress#50279. Furthermore, add some test coverage to guard against duplicated block-supports class names, which was an issue in a previous iteration of this PR.
What?
Early-stages experiment to explore concepts discussed in #39439.
Why?
See #39439. In short, block themes are currently lacking extensibility; the concept of hooks and filters from PHP themes doesn't carry over to them, so we need a more block-centric concept instead.
How?
Per discussion in #39349, we'd likely want blocks to be auto-inserted as the (previous or next) sibling of a given block, or as its (first or last) child. In this PR, we're demonstrating one example of each sibling and child insertion:
render_block
hook to insert the Social Icons block as the next sibling of the Post Content block.render_block_data
hook (which -- unlike therender_block
hook -- conveniently gives us access to a given block's children) to insert the Avatar block as the last child of the Comment Template block.The latter example is chosen to also demonstrate that block context is successfully passed to auto-inserted blocks (as evidenced by the auto-inserted Avatar blocks showing each comment author's avatar).
This PR required some preparation in order to make the Comment Template block work with auto-inserted blocks, see in particular #50279, #50879, and #50883. (Similar modifications were applied to the Post Template block, see #50313.)
Testing Instructions
Screenshots or screencast