-
Notifications
You must be signed in to change notification settings - Fork 2.6k
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
Block Hooks: Pass correct context to filters #6254
Conversation
cc/ @tjcafferkey |
$context = $args[0][3]; | ||
|
||
$this->assertSame( 'tests/anchor-block', $anchor_block_type ); | ||
$this->assertInstanceOf( 'WP_Block_Template', $context ); // FIXME: Currently failing :/ |
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 one threw me off; it's currently failing, saying $context
is null
.
$this->assertSame( | ||
$changes->post_content, | ||
$context->post_content, | ||
'The context passed to the hooked_block_types filter doesn\'t match the template changes.' | ||
); |
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 one is expected to fail currently; I'd expect the actual argument to be Content
(which is the post_content
set up in the test's template object fixtures).
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 test will always fail unless changed to $context->content
since WP_Block_Template
doesn't have a post_content
property which is the expected context here.
Test using WordPress PlaygroundThe changes in this pull request can previewed and tested using a WordPress Playground instance. WordPress Playground is an experimental project that creates a full WordPress instance entirely within the browser. Some things to be aware of
For more details about these limitations and more, check out the Limitations page in the WordPress Playground documentation. |
@@ -412,7 +412,7 @@ public function test_wp_generate_block_templates_export_file() { | |||
public function test_inject_ignored_hooked_blocks_metadata_attributes_into_template() { | |||
global $wp_current_filter; | |||
// Mock currently set filter. The $wp_current_filter global is reset during teardown by | |||
// WP_UnitTestCase_Base::_restore_hooks() in tests/phpunit/includes/abstract-testcase.php. | |||
// the unit test base class. |
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 in response to this comment:
Nit for [57799]: don't see a reason for mentioning the
tests/phpunit/includes/abstract-testcase.php
file path in the new comment there. That will just become stale with any refactor, and any IDE will allow you to quickly jump to the definition. But it is what it is :)
TypeCasting Block template utils Potential solution One solution I think we could do is build the template using $post_to_template_key_map = array(
'post_content' => 'content',
'post_title' => 'title',
'post_excerpt' => 'description',
'post_type' => 'type',
'post_status' => 'status',
);
// We need to overwrite the built template object with the incoming one from the request.
// This is so we can provide the correct context with up-to-date data on it to the Block Hooks API which expects the `WP_Block_Template` object.
foreach ( $post_to_template_key_map as $post_key => $template_key ) {
if ( isset( $post->$post_key ) ) {
$template->{$template_key} = $post->$post_key;
}
} |
@@ -1468,6 +1468,22 @@ function inject_ignored_hooked_blocks_metadata_attributes( $post, $request ) { | |||
$template = $request['id'] ? get_block_template( $request['id'], $post_type ) : null; |
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 call to get_block_template
results in an extra invocation of the hooked_block_types
filter.
As @tjcafferkey has mentioned in DM to me, this is visible in the newly added unit test, where the mock filter is run by the Block Hooks logic which is attempting insertion of hooked blocks into the mock template's content (which is just a Content
string literal, i.e. no blocks).
Thank you for your investigation! Good stuff 😄
This makes sense. I wish we didn't need to call Plus, ironically, when the |
@@ -24,7 +24,7 @@ public static function wpSetUpBeforeClass( WP_UnitTest_Factory $factory ) { | |||
'post_type' => 'wp_template', | |||
'post_name' => 'my_template', | |||
'post_title' => 'My Template', | |||
'post_content' => 'Content', | |||
'post_content' => '<!-- wp:tests/anchor-block -->Hello<!-- /wp:tests/anchor-block -->', |
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'd like to keep these distinct from the updated value that "comes in from the wire" in the new unit test. Otherwise, the test loses some value, as we won't be able to tell if the correct template object was given to the filter (i.e. one that's based on the $changes
or the one that was already present in the DB).
If we really need a block here to make sure it's traversed, we can maybe add a different one; although I'd hope we can maybe just revert to Content
and instead change the test (so it uses end( $args )
to look at the arguments from the last function call, rather than $args[0]
).
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.
instead change the test (so it uses end( $args ) to look at the arguments from the last function call, rather than $args[0]).
This would work and satisfy the test.
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.
Done in d5d8b9a
I gave this some more thought. I think your approach (6de2de8) is fine; the one thing I'm still a bit worried about is that we might miss some data. The crux is that we want a Now preparing those changes is exactly what Creating a We can then look at all the fields in the Finally, for the |
This comment was marked as resolved.
This comment was marked as resolved.
@@ -1468,6 +1468,37 @@ function inject_ignored_hooked_blocks_metadata_attributes( $post, $request ) { | |||
$template = $request['id'] ? get_block_template( $request['id'], $post_type ) : null; | |||
remove_filter( 'hooked_block_types', '__return_empty_array', 99999 ); | |||
|
|||
if ( $template ) { | |||
// TODO: Should maybe make this static. E.g. in the Templates Controller? |
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.
Hmm, for my own benefit can you explain how you see this TODO being implemented a little more please? I'm not quite following.
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 mostly meant that it'd be nice if the mappings were (more) publicly available, since I ended up duplicating them in the unit test.
(Making them static
was a poor choice of words on my part, where I conflated the means with the end.)
I realize now that a publicly available mappings array is probably not totally what we'd want, since there are some fields for which there isn't a 1:1 mapping from our $changes
object to WP_Block_Template
, so it'd have to be a function at least.
In the long run, this might be something we could use inside of _build_block_template_result_from_post
(it'd need some adjusting though to account for the differences between mapping from WP_Post
-- rather than from our $changes
stdClass
-- to WP_Block_Template
). This also means that it should not be a static member of the Templates controller after all, as functions such as _build_block_template_result_from_post
are clearly lower-level than the controller.
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'll rephrase the TODO comment accordingly.
// We also need to mimic terms and meta for the post based on the corresponding | ||
// `terms_input` and `meta_input` properties in the changes object. | ||
|
||
$terms_filter = function( $terms, $post_id, $taxonomy ) use ( $changes ) { | ||
if ( 'wp_theme' !== $taxonomy || ! isset( $changes->tax_input['wp_theme'] ) ) { | ||
return $terms; | ||
} | ||
|
||
// TODO: Verify it's not an error object. | ||
// TODO: Verify that $post_id matches (or isn't set). | ||
$term = new stdClass; | ||
$term->name = $changes->tax_input['wp_theme']; | ||
|
||
$term = new WP_Term( $term ); | ||
return array( $term ); | ||
}; | ||
|
||
$meta_filter = function( $value, $post_id, $meta_key, $single ) use ( $changes ) { | ||
if ( 'origin' === $meta_key && isset( $changes->meta_input['origin'] ) ) { | ||
return $single ? $changes->meta_input['origin'] : array( $changes->meta_input['origin'] ); | ||
} | ||
|
||
if ( 'is_wp_suggestion' === $meta_key && isset( $changes->meta_input['is_wp_suggestion'] ) ) { | ||
return $single ? $changes->meta_input['is_wp_suggestion'] : array( $changes->meta_input['is_wp_suggestion'] ); | ||
} | ||
|
||
return $value; | ||
}; | ||
|
||
add_filter( 'get_the_terms', $terms_filter, 10, 3 ); | ||
add_filter( 'get_post_metadata', $meta_filter, 10, 4 ); |
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 a bit too wild, and I don’t think I want to land it like this. However, it has helped inform a strategy in that it has made clear that a WP_Block_Template
needs more information than is solely contained in a WP_Post
(which it fetches from meta and terms). This becomes a problem when we try to pass $changes
to _build_block_template_result_from_post
, as it doesn’t have that meta and terms in the DB available yet; instead, it uses the meta_input
and tax_input
fields to set those upon insertion into the DB.
Let’s extract a helper function from _build_block_template_result_from_post
that acknowledges this and accepts as its arguments a WP_Post
, and additionally, all the required information that’s not included in it, i.e. a $theme
, an $origin
, an $is_wp_suggestion
, etc. That way, we’ll have a function that accurately represents the mapping from WP_Post
object to WP_Block_Template
; and in our inject_ignored_hooked_blocks_metadata_attributes
, we can provide the additional required arguments by reading them from meta_input
and tax_input
.
$post = get_post( $changes->ID ); | ||
} else { | ||
// This means that there's not post for this template in the DB yet. | ||
$post = new stdClass; // Is this correct? Might instead want to init a WP_Post with some fields set. |
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.
In the post editor it’s being set to the post object with some initial data. Let me find the code.
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 think this is what gets called to create a new draft post:
$post = get_default_post_to_edit( $post_type, true ); |
I was thinking about the following logic that is rather unrelated:
wordpress-develop/src/wp-admin/edit-form-blocks.php
Lines 91 to 105 in 3d3d510
if ( 'auto-draft' === $post->post_status ) { | |
$is_new_post = true; | |
// Override "(Auto Draft)" new post default title with empty string, or filtered value. | |
if ( post_type_supports( $post->post_type, 'title' ) ) { | |
$initial_edits['title'] = $post->post_title; | |
} | |
if ( post_type_supports( $post->post_type, 'editor' ) ) { | |
$initial_edits['content'] = $post->post_content; | |
} | |
if ( post_type_supports( $post->post_type, 'excerpt' ) ) { | |
$initial_edits['excerpt'] = $post->post_excerpt; | |
} | |
} |
I don't know if the get_default_post_to_edit
is a good way to go here.
Closing in favor of #6278. |
castingbuilding.$changes
toWP_Block_Template
WP_Block_Template
object from$changes
).$request
(whose missing fields will be set by the controller), rather than a "full"$changes
object, as we have to do in theblock-template-utils.php
unit test.$changes
into the existing$template
. (Done in ac59c76.)block-template-utils.php
. (Cover setting ofarea
!)Trac ticket: https://core.trac.wordpress.org/ticket/60754
This Pull Request is for code review only. Please keep all other discussion in the Trac ticket. Do not merge this Pull Request. See GitHub Pull Requests for Code Review in the Core Handbook for more details.