Make WordPress Core

Opened 4 weeks ago

Closed 4 weeks ago

#65609 closed defect (bug) (duplicate)

Plugin-registered block templates are merged with string keys in get_block_templates(), breaking $current_template[0] access in wp_get_post_content_block_attributes()

Reported by: misulicus Owned by:
Priority: normal Milestone:
Component: Editor Version:
Severity: normal Keywords: needs-patch php81
Cc: Focuses:

Description

Summary

When a plugin registers a page-type block template via register_block_template() (introduced in 6.7) and the active block theme has no theme file for that slug, editing any page in the block editor logs PHP warnings and deprecations on every editor load:

PHP Warning: Undefined array key 0 in wp-includes/block-editor.php on line 469 PHP Warning: Attempt to read property "content" on null in wp-includes/block-editor.php on line 469 PHP Deprecated: preg_match(): Passing null to parameter #2 ($subject) of type string is deprecated in wp-includes/class-wp-block-parser.php on line 247 PHP Deprecated: strlen(): Passing null to parameter #1 ($string) of type string is deprecated in wp-includes/class-wp-block-parser.php on line 324

Reproduced on 6.7 through 7.0.1 and current trunk (7.1-alpha).

Root cause

wp_get_post_content_block_attributes() in wp-includes/block-editor.php calls get_block_templates( array( 'slugin' => array( $template_slug ) ) ) and then reads $current_template[0]->content (guarded only by ! empty( $current_template )).

Inside get_block_templates() in wp-includes/block-template-utils.php, plugin-registered templates come from WP_Block_Templates_Registry::get_by_query(), which returns an array keyed by the full template name string (e.g. 'my-pluginpage-checkout') — see $matching_templates[ $template_name ] = $template; in class-wp-block-templates-registry.php.

Those results are merged with array_merge( $query_result, $matching_registered_templates ). array_merge() preserves string keys. When the theme provides no file for the queried slug, $query_result is empty, so the final return value is:

array( 'my-plugin//page-checkout' => WP_Block_Template )

— non-empty, but with no index 0.

Back in wp_get_post_content_block_attributes(), ! empty( $current_template ) passes, $current_template[0] is undefined (→ the two warnings), and parse_blocks( null ) feeds null into WP_Block_Parser (→ the two deprecations on PHP 8.1+).
The same string-keyed return value is also surfaced to every other consumer of get_block_templates() and its filter, which document the return type as WP_Block_Template[] and generally assume a list.

Steps to reproduce

Activate a block theme (e.g. Twenty Twenty-Five), WP_DEBUG + WP_DEBUG_LOG enabled, PHP 8.1+.
In a plugin (or mu-plugin), register a page template with a slug the theme does not provide: {{{ add_action( 'init', function () { register_block_template( 'my-pluginpage-checkout', array( 'title' => 'Page: Checkout', 'content' => '
Hi

', 'post_types' => array( 'page' ), ) ); } ); }}}
Edit any page in the block editor.
Observe the four log entries above on every editor load.

Suggested fix

Either (or both):

In get_block_templates(), normalize the merged result before returning / applying the get_block_templates filter: $query_result = array_values( array_merge( $query_result, $matching_registered_templates ) );

Defensively, in wp_get_post_content_block_attributes(), avoid relying on index 0: {{{ $current_template = get_block_templates( array( 'slugin' => array( $template_slug ) ) );

if ( ! empty( $current_template ) ) { $first_template = reset( $current_template ); $template_blocks = parse_blocks( $first_template->content ); ... }}}

The array_values() normalization in get_block_templates() seems preferable since the documented return type is WP_Block_Template[] (a list), and string keys also leak into the get_block_templates filter and REST responses' JSON encoding for any other consumer.

Related (but distinct)

Gutenberg issue #72786 / PR #72795 fixed a similar "Undefined array key" symptom for WooCommerce-registered templates, but in the Gutenberg plugin's lib/compat/wordpress-6.9/template-activate.php (template-activate flow) — it does not change get_block_templates()'s array_merge() behavior in core, and this bug reproduces with the Gutenberg plugin deactivated.

Change History (1)

#1 @misulicus
4 weeks ago

  • Milestone Awaiting Review
  • Resolutionduplicate
  • Status newclosed

Duplicate of #62407.

Note: See TracTickets for help on using tickets.