Skip to content
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

Fix presets data for themes that do not provide any preset #36054

Merged
merged 5 commits into from
Nov 2, 2021

Conversation

oandregal
Copy link
Member

@oandregal oandregal commented Oct 28, 2021

This is a dormant bug that was uncovered by #35970 (comment)

The bug

In the core/block-editor store, we have the presets keyed by origin (core, theme, user). For example, the color palette is stored under __experimentalFeatures.color.palette as:

{
  core: [ { slug: 'value', color: 'value', name: 'value' } ],
  preset: [ { slug: 'value', color: 'value', name: 'value' } ],
  user: [ { slug: 'value', color: 'value', name: 'value' } ]
}

If a given origin has not provided data, there's no key for them. For themes that do not provide any preset and the user hasn't either, the presets are expected to have this shape:

{
  core: [ { slug: 'value', color: 'value', name: 'value' } ]
}

Storefront is one of those themes that do not provide any preset so should be expected to have the above shape. The same can be reproduced for any theme that has a theme.json by removing the settings.color.palette contents. By testing #35970 (comment) we found that these themes included in the theme origin the same data that already was in the core one:

{
  core: [ { slug: 'value', color: 'value', name: 'value' } ],
  theme: [ { slug: 'value', color: 'value', name: 'value' } ] // The values here are the same than core's.
}

How to test

  • Activate Storefront. You can also use the empty theme and remove the settings.color.palette property.
  • Inspect the contents of the core/block-editor store, specifically the settings.__experimentalFeatures.color.palette key.
  • The expected result is that you'll find only a core origin but instead there're core and theme.

Why it happens

WordPress 5.8 does the following (see get_block_editor_settings):

1.1. Takes the data from the theme (either from theme supports or theme.json).
1.2 It stores under settings.__experimentalFeatures the theme.json settings.
1.3. For backward compatibility, it also retrofits the data to the legacy settings mechanism (settings.colors for the palette, settings.gradients for the gradients, and so on). At this point, all themes have stored presets in the old legacy settings mechanism, whether it's core presets or presets coming from the theme.
1.4. Then, it fires the block editor settings filter, so 3rd parties can filter them.

The Gutenberg plugin hooks into that filter to reorganize the settings.__experimentalFeatures with the new schema and then retrofit again the data to the legacy settings mechanism. The bug is here, in the plugin. Because we use the filtered legacy settings (settings.color) to create the new ones (settings.__experimentalFeatures.color.palette) there's always data coming from settings.color that we interpret as coming from the "theme origin".

The fix is not taking into account the filtered legacy settings (settings.color).

The drawback to this fix is that the legacy settings can be filtered no longer, because the plugin will ignored them anyway.

For reference, there're less than a dozen, see here.

@oandregal oandregal self-assigned this Oct 28, 2021
@oandregal oandregal added [Type] Bug An existing feature does not function as intended Global Styles Anything related to the broader Global Styles efforts, including Styles Engine and theme.json labels Oct 28, 2021
lib/global-styles.php Outdated Show resolved Hide resolved
@oandregal
Copy link
Member Author

I've got this thought: for the backward-compatible theme settings we retrofit plugins can still filter them via after_theme_setup. So we're not stopping them from being filterable. We need to communicate that so plugins can adapt, if necessary.

Copy link
Contributor

@youknowriad youknowriad left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I'm not wrong, this change means that all add_theme_support calls are ignored when constructing the "theme" global styles.

For me, it seems that it's not the right approach. My expectation is the following:

  • add_theme_support calls should be taken into consideration when building the "theme" global styles.
  • block_editor_settings should not be taken into consideration.

I tried following the code but I think the issue comes from the fact that the current code base is optimized for this flow:

theme-supports ----(transform)----> block-editor-settings -----( merge with raw theme.json )------> theme global styles

It seems that the solution should be that we do this instead

theme-supports --------( merge with raw theme.json ) -----> theme global styles.

Does that make sense?

@youknowriad
Copy link
Contributor

I guess in other words, WP_Theme_JSON_Gutenberg::get_merged_data shouldn't be receiving any "block editor settings" in all situations but it should take into consideration the add_theme_support calls.

@oandregal
Copy link
Member Author

I've just merged two PRs I had on top of this #36075 and #36081

@oandregal
Copy link
Member Author

I guess in other words, WP_Theme_JSON_Gutenberg::get_merged_data shouldn't be receiving any "block editor settings" in all situations but it should take into consideration the add_theme_support calls.

Yeah, exactly, that's what this PR should do.

It is a change from how it worked until now but we need it to make the UI color control work as we want (show all origins but only if they have data). Plugins that were filtering the theme support settings we retrofit in theme.json via the block_editor_settings will need to be updated to do it via after_theme_setup instead.

Before this is ready, I still need to understand why some tests needed changing.

* @param string $origin To what level should we merge data.
* Valid values are 'theme' or 'user'.
* Default is 'user'.
*
* @return WP_Theme_JSON_Gutenberg
*/
public static function get_merged_data( $settings = array(), $origin = 'user' ) {
public static function get_merged_data( $origin = 'user' ) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change is great :)

* So we take theme supports, transform it to theme.json shape
* and merge the self::$theme upon that.
*/
$theme_support_data = WP_Theme_JSON_Gutenberg::get_from_editor_settings( gutenberg_get_default_block_editor_settings() );
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you help me understand what this line does? My understanding is the following: it uses the "add_theme_support" calls to build something like a "theme.json" tree based on these.

If that's correct, then we're aligned here. The thing that bother me though is that it still says "editor settings", it should be more something like:

$theme_support_data  = WP_Theme_JSON_Gutenberg::get_from_theme_supports();

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, that's exactly what it does.

The current name is actually representative of what this function does at the moment, as gutenberg_get_default_block_editor_settings returns editor settings. However, I understand your point is that you'd rather inline the call to theme supports into WP_Theme_JSON.

This makes me think of the conversation about the endpoint and whether to allow getting data for the non-active themes. How can we retrieve the theme supports data of a non-active theme? Does the REST API request load the theme being requested? Or we won't have access to that data?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point, I guess for now, we'll limit that endpoint to the active theme. I think it's fine for our current usage.

@@ -142,7 +111,7 @@ function_exists( 'gutenberg_is_edit_site_page' ) &&
}

// Copied from get_block_editor_settings() at wordpress-develop/block-editor.php.
$settings['__experimentalFeatures'] = $consolidated->get_settings();
$settings['__experimentalFeatures'] = gutenberg_get_global_settings();

if ( isset( $settings['__experimentalFeatures']['color']['palette'] ) ) {
$colors_by_origin = $settings['__experimentalFeatures']['color']['palette'];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All the changes here make things a lot simpler, it's cool and also validates these higher level APIs.

@oandregal oandregal force-pushed the fix/settings-themes-no-theme-json branch from 0ec76f8 to 6d9098c Compare November 2, 2021 12:13
Copy link
Contributor

@youknowriad youknowriad left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is looking good to me, I think we should be looking at removing the get_from_editor_settings function in favor of a get_from_theme_supports for clarity. But that's not a blocker.

Do not read them from the filtered block settings.
This has the side-effect of not taking into account changes
3rd parties may have done to theme supports data.
For example, adding support for link color,
or changing the theme editor palette.
* Use gutenberg_get_global_* functions (#36075)

* Remove settings as an argument from `WP_Theme_JSON_Resolver` (#36081)
@oandregal oandregal force-pushed the fix/settings-themes-no-theme-json branch from 6d9098c to 76f61ab Compare November 2, 2021 16:06
'color' => array(
'palette' => array(
'color' => array(
'custom' => false,
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These tests now get the defaults for color.custom, color.customGradients, typography.customFontSize, typography.customLineHeight, spacing.units, and spacing.customPadding.

The reason is that the (legacy) theme supports are now pulled from the WP_Theme_JSON_Resolver_Gutenberg::get_theme_data() method directly, while, before, these were passed via an argument (and it was empty for the tests).

@oandregal oandregal merged commit d5d524d into trunk Nov 2, 2021
@oandregal oandregal deleted the fix/settings-themes-no-theme-json branch November 2, 2021 16:53
@github-actions github-actions bot added this to the Gutenberg 11.9 milestone Nov 2, 2021
@oandregal
Copy link
Member Author

Apparently, some PRs got merged in parallel and not all the uses of get_merged_data were migrated #36173

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Global Styles Anything related to the broader Global Styles efforts, including Styles Engine and theme.json [Type] Bug An existing feature does not function as intended
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants