Usage of pre_render_block
filter without returning value
#11077
Comments
Hey @danieliser, With the current snippet:
Blocks are still visible on the page. With
the blocks are not visible. I'm unsure how adding To ensure that your filter is applied, you have to ensure it has the highest priority. Am I missing something? |
In general A filter is used to manipulate a value, as such apply_filters expects every callback to return a value that will then be passed to the next hooked callback. In this case though WooCommerce is not touching the data being filtered, but instead treating it like an action, and doing side-effects based on the block attributes/type. But by not returning the value passed in, it effectively breaks the functionality. As such yes, priority of higher does solve our problem, but its not the right solution to this issue, our fix is kinda irrelevant (see examples at bottom). Consider the following example using add_filter( 'the_content', function ( $content ) {
// Log that content was viewed.
some_function_call(); // irrelevant to the $content variable.
}, 10 ); When I call However if I do the following, it works as expected. add_filter( 'the_content', function ( $content ) {
// Log that content was viewed.
some_function_call(); // irrelevant to the $content variable.
return $content;
}, 10 ); The callbacks in question here should look like this, in effort to always return a valid value. public function update_query( $pre_render, $parsed_block ) {
if ( 'core/query' !== $parsed_block['blockName'] ) {
return $pre_render;
}
$this->parsed_block = $parsed_block;
if ( self::is_woocommerce_variation( $parsed_block ) ) {
// Set this so that our product filters can detect if it's a PHP template.
$this->asset_data_registry->add( 'hasFilterableProducts', true, true );
$this->asset_data_registry->add( 'isRenderingPhpTemplate', true, true );
add_filter(
'query_loop_block_query_vars',
array( $this, 'build_query' ),
10,
1
);
}
return $pre_render;
} The reason this seems like a non-issue on the face of it, is that Not returning anything essentially sets it back to null. So this flaw in WooCommerce filter callback only presents if something is actively changing outputs of a block. Some examples of why this needs to be fixed, and likely optimized further than the fix: A site might overload the image block with custom output, they might do so on Further optimizing might bail (return) early if public function update_query( $pre_render, $parsed_block ) {
// Bail early if pre_render isset & empty or if this isn't core/query block.
if ( 'core/query' !== $parsed_block['blockName'] || '' === $pre_render ) {
return $pre_render;
}
$this->parsed_block = $parsed_block;
if ( self::is_woocommerce_variation( $parsed_block ) ) {
// Set this so that our product filters can detect if it's a PHP template.
$this->asset_data_registry->add( 'hasFilterableProducts', true, true );
$this->asset_data_registry->add( 'isRenderingPhpTemplate', true, true );
add_filter(
'query_loop_block_query_vars',
array( $this, 'build_query' ),
10,
1
);
}
return $pre_render;
} |
All of this said, might be worth using phpstan or similar to find any uses of apply_filters that has callbacks that don't return a value. These should all be addressed as they fundamentally break how WP is intended to function. |
Hey @danieliser, I will open a PR for WooCommerce Blocks, but this will not fix the issue. |
@gigitux - Thanks for the patch. I see you caught an additional case I didn't mention above, thanks. As for your findings about core.. Good catch, and after reading over their code there, I will be filing issues with WP Core as well. During my test this is what I found, when I hook in at That is because my filter might be coming after core & before WooCommerce, since all were set to the same When that oocurs, and only on WooCommerce pages, this fix does work. So since the docs on that filter show a Per the docs
IE all filters hooked in there should respect an existing non-nullish value, even those in core, especially since they are not hooked in at priority 0. |
Describe the bug
Seems that somebody used
add_filter
to handle action like code, but didn't return anything, so filtering before WooCommerce results in corrupted values.Add filter & callback. This is done in 2 different files in that directory.
The other file is RelatedProducts.php
Impact on
pre_render_block
in this way means that if you returned '' (to remove a block), at priority 9 or 10 , WooCommerce's filters will void that out by not returning anything.Hook in at 11 and the issue is gone (for us).
But I know we aren't the only plugin using that filter, so this is likely mucking up other things without any real indication its happening.
I should add this only occurs on WooCommerce pages.
To reproduce
Steps to reproduce the behavior:
pre_render_block
at priority 9 and return '' for any block to remove it from the page.Expected behavior
These 2 callbacks should at minimum
return $pre_render;
, and should ideally be optimized to bail early in cases where$pre_render
is set but to empty-ish values.If the item was removed from page, no need to run additional checks for loading assets etc.
Environment
WordPress (please complete the following information):
The text was updated successfully, but these errors were encountered: