Make WordPress Core

Opened 13 months ago

Closed 8 months ago

Last modified 6 months ago

#57566 closed defect (bug) (fixed)

Issue registering blocks within a parent theme

Reported by: jacknotman's profile jacknotman Owned by: audrasjb's profile audrasjb
Milestone: 6.3 Priority: normal
Severity: major Version: 6.1.1
Component: Editor Keywords: has-patch has-testing-info commit
Focuses: Cc:

Description

Registering a block type using

register_block_type('./path/to/block/block.json')

does not work when called from a parent theme. Currently, any existing instances of the block added prior to enabling the child theme will show the

'Your site doesn’t include support for the "..." block.'

message. With

define( 'SCRIPT_DEBUG', true );

multiple errors are outputted to the dev console, indicating that the necessary CSS / JS files could not be loaded; this is due to the necessary files returning 404 errors as a result of WordPress appending the paths with the plugin directory URI.

This appears to be happening due to how WordPress handles registering blocks from themes. At

lines 137, and 234

of

wp-includes/blocks.php

when enqueuing necessary block assets from block.json the function

get_theme_file_path()

is used with an empty string ie:

get_theme_file_path('')

When passed an empty string this function returns the path to the currently active theme, which in this case is a child theme, therefor causing the subsequent

$is_theme_block

at

line 141

to equal

false

This causes the function to incorrectly use the

plugins_url(...)

path, rather than also checking the parent theme directory as would be expected.

Attachments (5)

parent.zip (144.8 KB) - added by leprincenoir 8 months ago.
child.zip (590 bytes) - added by leprincenoir 8 months ago.
19aff00807ed30e2662a3bd6398e4411.gif (132.5 KB) - added by audrasjb 8 months ago.
First step: the block is available when activating the parent theme
33862fbc582124b1bdc0dbfbf32068b8.gif (177.4 KB) - added by audrasjb 8 months ago.
Third step: after applying the patch, the block is now available again
3bb76664232a37d964ad947de5af7ed6.gif (187.6 KB) - added by audrasjb 8 months ago.
Second step: bug reproduced - the block is not available anymore when the child theme is activated

Download all attachments as: .zip

Change History (26)

This ticket was mentioned in PR #3921 on WordPress/wordpress-develop by jack-h2ml.


13 months ago
#1

  • Keywords has-patch added

Fixes for both the register_block_script_handle() and register_block_style_handle() functions within wp-includes/blocks.js , allowing for child themes to access and utilise blocks defined in parent themes.

Previously these functions could not handle blocks registered in Parent themes, however the above changes fix this by determining whether the given asset path belongs to either of the template or stylesheet directories (Parent and Child themes respectively) as opposed to just checking using get_theme_file_path('') as is currently the case, thus mitigating this issue.

An issue was raised under the WordPress / gutenberg Repo, however as wp-includes/blocks.js is included in the WordPress / wordpress-develop repo I have created the PR here instead. That original ticket can be found here.

Trac ticket: Ticket

@jacknotman commented on PR #3921:


13 months ago
#2

## Temporary Workaround

I have created a filter based workaround for the above issue, just incase anyone lands here!

Tested and working on my local dev server [MacOS 13.1, NGINX, PHP 8.0] and SiteGround Hosting [Linux, Apache, PHP 7.4.33] without issue thus far.

I do have some reservations with regards to other Plugins filtering theme_file_path / possibly with Windows based environments - use with caution and test on a dev server before adding to production._

### Commented

/**
 *
 * If registering a block which is solely defined in the current themes parent,
 * then add the `overrideThemeFilePath` filter to `theme_file_path`, this serves 
 * as a temporary workaround for https://github.com/WordPress/wordpress-develop/pull/3921
 * 
 */

add_action('init', function() {
	//
	// The filter function for overriding `get_theme_file_path()`
	//
	function overrideThemeFilePath($_, $file) {
		$path = get_template_directory() . '/' . $file;
		return $path;
	}
	//
	// Add the filter where appropriate.
	//
	add_filter('block_type_metadata', function($metadata) {
		if(array_key_exists('file', $metadata)) {
			// Normalize the block path
			$blockPathNorm = wp_normalize_path($metadata['file']);
			// Cache the $templatePathNorm and $stylesheetPathNorm to avoid unnecessary additional calls.
			static $templatePathNorm   = '';
			static $stylesheetPathNorm = '';
			if (!$templatePathNorm || !$stylesheetPathNorm) {
				$templatePathNorm   = wp_normalize_path(get_template_directory());
				$stylesheetPathNorm = wp_normalize_path(get_stylesheet_directory());
			}
			// If looking at a block which is only defined in the parent theme then add the filter.
			$isTemplateBlock     = str_starts_with($blockPathNorm, $templatePathNorm);
			$isStylesheetBlock   = str_starts_with($blockPathNorm, $stylesheetPathNorm);
			if($isTemplateBlock && !$isStylesheetBlock) {
				add_filter('theme_file_path', 'overrideThemeFilePath', 10, 2);
			}
		}
		return $metadata;
	}, 10, 1);
	//
	// Ensure the filter is removed as soon as possible
	//
	add_filter('block_type_metadata_settings', function($settings, $metadata) {
		remove_filter('theme_file_path', 'overrideThemeFilePath', 10);
		return $settings;
	}, 10, 2);
}, 10);

### Compacted

Note the three add_filter calls are nested within the add_action call, so do not split these lines or add code in between them.

/**
 *
 * If registering a block which is solely defined in the current themes parent,
 * then add the `overrideThemeFilePath` filter to `theme_file_path`, this serves 
 * as a temporary workaround for https://github.com/WordPress/wordpress-develop/pull/3921
 * 
 */

add_action('init',function(){function overrideThemeFilePath($_,$file){$path=get_template_directory().'/'.$file;return $path;}
add_filter('block_type_metadata',function($metadata){if(array_key_exists('file',$metadata)){$blockPathNorm=wp_normalize_path($metadata['file']);static $templatePathNorm='';static $stylesheetPathNorm='';if(!$templatePathNorm||!$stylesheetPathNorm){$templatePathNorm=wp_normalize_path(get_template_directory());$stylesheetPathNorm=wp_normalize_path(get_stylesheet_directory());}$isTemplateBlock=str_starts_with($blockPathNorm,$templatePathNorm);$isStylesheetBlock=str_starts_with($blockPathNorm,$stylesheetPathNorm);if($isTemplateBlock&&!$isStylesheetBlock){
add_filter('theme_file_path','overrideThemeFilePath',10,2);}} return $metadata;},10,1);
add_filter('block_type_metadata_settings',function($settings,$metadata){remove_filter('theme_file_path','overrideThemeFilePath',10);return $settings;},10,2);},10);

@jacknotman commented on PR #3921:


13 months ago
#3

A note on the above workaround, ensure that the workaround is called before you register your blocks or it won't work, so for example call the above init filter with a priority of 1, and then register your blocks in a separate init filter with a priority >= 2.

#4 @Levdbas
12 months ago

  • Severity changed from normal to major

I ran into the same issue as you and glad I found this issue. I would like to raise this to a major issue, since without jumping through hoops described above, blocks registered by parent themes aren't working because of this.

Last edited 12 months ago by Levdbas (previous) (diff)

#6 @audrasjb
8 months ago

  • Keywords needs-testing needs-testing-info added
  • Milestone changed from Awaiting Review to 6.3
  • Owner set to audrasjb
  • Status changed from new to accepted

Moving for 6.3 consideration.

@audrasjb commented on PR #3921:


8 months ago
#7

Closing in favor of #4788

@leprincenoir
8 months ago

@leprincenoir
8 months ago

#8 @leprincenoir
8 months ago

Hello,

Here's how to reproduce the bug.

You need :

  • a parent theme with blocks made with block.json
  • then a child theme: with nothing in it (that's enough)
  • activate the child theme and check whether the parent's blocks work

For the example, I've added 2 zips: parent.zip and child.zip 2 themes to reproduce the bug.

Simply download the 2 themes and activate the child theme.

Then test adding the "Todo List" block to see the errors in the console. (script errors, block not found).
And if you activate the parent theme, everything works correctly.

With @guillaumeturpin's PR, the problem is correctly corrected.

#9 @whaze
8 months ago

Hi,

I was able to reproduce the bug thanks to the themes provided by @leprincenoir.

and I also tested with the PR patch from @guillaumeturpin and it corrects the problem.

#10 @audrasjb
8 months ago

  • Keywords needs-testing-info removed

#11 @audrasjb
8 months ago

  • Keywords has-testing-info added

I tested the patch against trunk and it works fine on my side.

  1. First, I activated the parent test theme proposed by @leprincenoir in parent.zip:

🆗 the Todolist block is available

  1. Then, I activated the child test theme located in child.zip:

❌ the Todolist block is not available anymore

  1. Then, I applied the patch:

✅ the Todolist block is available again

Conclusion: the proposed patch works fine.

@audrasjb
8 months ago

First step: the block is available when activating the parent theme

@audrasjb
8 months ago

Third step: after applying the patch, the block is now available again

#12 @audrasjb
8 months ago

I messed up with the second step GIF. Uploading a new image :D

@audrasjb
8 months ago

Second step: bug reproduced - the block is not available anymore when the child theme is activated

#13 @audrasjb
8 months ago

Pinging @isabel_brison as Editor Tech lead for final review before commit :)

#14 @isabel_brison
8 months ago

Thanks for the ping @audrasjb! I reviewed and tested the PR and LGTM.

#15 @audrasjb
8 months ago

  • Keywords commit added; needs-testing removed

#16 @audrasjb
8 months ago

  • Resolution set to fixed
  • Status changed from accepted to closed

In 56183:

Editor: Ensure blocks registered within parent theme are available when child theme is activated.

This changeset fixes both register_block_script_handle() and register_block_style_handle() functions, allowing for child themes to access and utilise
blocks defined in parent themes.

Previously these functions could not handle blocks registered in Parent themes. This changeset fixes the issue by determining whether the given asset path
belongs to either of the template or stylesheet directories (Parent and Child themes respectively) as opposed to just checking using
get_theme_file_path('').

Props jacknotman, Levdbas, audrasjb, guillaumeturpin, leprincenoir, whaze, isabel_brison.
Fixes #57566.

--Cette ligne, et les suivantes ci-dessous, seront ignorées--

M trunk/src/wp-includes/blocks.php

#18 @audrasjb
8 months ago

Manually added missed props to @mukesh27 who reviewed and proposed changes to the PR.

#19 @spacedmonkey
8 months ago

@audrasjb I wish we would have tackled these as part of #58525.

The current implementation takes 2 static variables that will take up memory. Moving betweens share logic and caches, should be the goal.

#20 @audrasjb
8 months ago

@spacedmonkey we can still improve caching in #58525, this ticket was focused on fixing the major bug where blocks declared in parent theme were not available when the child theme is activated.

Improvements to caching can go in a follow-up ticket/commit in 6.4 (as beta cycle is only focused on bugs, not enhancements), but we had to fix the bug before the end of the beta cycle :)

Last edited 8 months ago by audrasjb (previous) (diff)

This ticket was mentioned in Slack in #core by masteradhoc. View the logs.


6 months ago

Note: See TracTickets for help on using tickets.