Skip to content

Blocks: Add support for variations in block.json file - #1499

Closed
gziolo wants to merge 13 commits into
WordPress:masterfrom
gziolo:update/block-json-variations
Closed

Blocks: Add support for variations in block.json file#1499
gziolo wants to merge 13 commits into
WordPress:masterfrom
gziolo:update/block-json-variations

Conversation

@gziolo

@gziolo gziolo commented Jul 15, 2021

Copy link
Copy Markdown
Member

Trac ticket: https://core.trac.wordpress.org/ticket/53238

/cc @gwwar

This PR also ports the implementation used in JavaScript for translatable fields that works with the schema making future changes a simple change in the function that defines translatable fields:

https://github.com/WordPress/gutenberg/blob/4ff70e6f3ad45cd0e77d7cbb77f7912e5844cba7/packages/blocks/src/api/registration.js#L384-L425

Implementation Details

As part of unifying i18n handling for theme.json and block.json I extracted two new methods for shared logic:

wp_json_file_decode

Reads and decodes a JSON file.

Params:

  • $filename (string) – path to the JSON file.
  • $options (array) – optional, options to be used with json_decode().
  • associative (bool) – optionalwhen true, JSON objects will be returned as associative arrays, when false, JSON objects will be returned as objects.

Returns:
(mixed) Returns the value encoded in JSON in appropriate PHP type. null is returned if the file is not found, or its content can't be decoded.

translate_settings_using_i18n_schema

Translates the provided settings value using its i18n schema.

Params:

  • $i18n_schema (string|string[]|array[]|object) – i18n schema for the setting.
  • $settings (string|string[]|array[]) – value for the settings.
  • $textdomain (string) – textdomain to use with translations.

Returns:
(string|string[]|array[]) Translated settings.

Testing

It turns out testing is quite straightforward because block.json is handled by PHP only. I applied the following diff:

diff --git a/src/wp-includes/blocks/heading/block.json b/src/wp-includes/blocks/heading/block.json
index 69ec1ba374..01b815d2fc 100644
--- a/src/wp-includes/blocks/heading/block.json
+++ b/src/wp-includes/blocks/heading/block.json
@@ -41,5 +41,13 @@
 		"__unstablePasteTextInline": true
 	},
 	"editorStyle": "wp-block-heading-editor",
-	"style": "wp-block-heading"
+	"style": "wp-block-heading",
+	"variations": [
+		{
+			"name": "heading-1",
+			"title": "Heading 1",
+			"description": "Heading level one.",
+			"attributes": { "level": 1 }
+		}
+	]
 }

Please note that running npm run build:dev or npm run build will override the changes because block.json files are synced from node_modules folder.

When you open a page or post for modification, you should be able to find "Heading 1" block variation and it should have H1 selected after it gets inserted in the post.

Screen Shot 2021-07-22 at 09 44 51

Screen Shot 2021-07-22 at 09 44 59

Follow-up in Gutenberg

It looks like i18n schema is covered in Gutenberg:

https://github.com/WordPress/gutenberg/blob/9a9e709f7fe0984ed0f1eb3c8679a88350234766/packages/blocks/src/api/i18n-block.json#L10-L16

It's also added to the list of allowed fields:

https://github.com/WordPress/gutenberg/blob/9a9e709f7fe0984ed0f1eb3c8679a88350234766/packages/blocks/src/api/registration.js#L218

It only requires follow-up changes in the Gutenberg repository to document variations in the block metadata document: https://github.com/WordPress/gutenberg/blob/trunk/docs/reference-guides/block-api/block-metadata.md


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.

@gziolo gziolo self-assigned this Jul 15, 2021
Comment thread src/wp-includes/blocks.php Outdated
@swissspidy
swissspidy requested a review from ocean90 July 20, 2021 17:09
@gwwar

gwwar commented Jul 20, 2021

Copy link
Copy Markdown

@gziolo happy to take a look here. Would it be possible to add some manual testing instructions?

@gziolo

gziolo commented Jul 21, 2021

Copy link
Copy Markdown
Member Author

happy to take a look here. Would it be possible to add some manual testing instructions?

Good point. I put too much trust in unit tests and I forgot that you can test this change manually, too. I will do a quick round of testing and share the instructions later today.

@gziolo

gziolo commented Jul 22, 2021

Copy link
Copy Markdown
Member Author

Testing

It turns out testing is quite straightforward because block.json is handled by PHP only. I applied the following diff:

diff --git a/src/wp-includes/blocks/heading/block.json b/src/wp-includes/blocks/heading/block.json
index 69ec1ba374..01b815d2fc 100644
--- a/src/wp-includes/blocks/heading/block.json
+++ b/src/wp-includes/blocks/heading/block.json
@@ -41,5 +41,13 @@
 		"__unstablePasteTextInline": true
 	},
 	"editorStyle": "wp-block-heading-editor",
-	"style": "wp-block-heading"
+	"style": "wp-block-heading",
+	"variations": [
+		{
+			"name": "heading-1",
+			"title": "Heading 1",
+			"description": "Heading level one.",
+			"attributes": { "level": 1 }
+		}
+	]
 }

Please note that running npm run build:dev or npm run build will override the changes because block.json files are synced from node_modules folder.

When you open a page or post for modification, you should be able to find "Heading 1" block variation and it should have H1 selected after it gets inserted in the post.

Screen Shot 2021-07-22 at 09 44 51

Screen Shot 2021-07-22 at 09 44 59

Note: I also updated the description with the same details.

@gwwar

gwwar commented Jul 22, 2021

Copy link
Copy Markdown

Background context

So if I'm understanding changes here correctly, we're giving folks another way of declaring block variations (not to be confused with style variations) in the block.json file.

Previously this was defined either in the block index.js file OR server side with register_block_type_from_metadata See #1015

In WordPress/gutenberg#31120 @gziolo also added support for moving translatable fields to block.json files

Out of the defined properties of variations, two props are problematic: isActive and icon which were expected to be functions. Icon will not be supported here since an acceptable serialization approach hasn't been found yet. isActive had some work in WordPress/gutenberg#30913 but not sure if we're supporting this yet from the server side.

Manual Testing with Heading block

I gave this a try with the Heading block. If other folks are manually testing, be sure to deactivate the Gutenberg plugin, and make sure that a recent npm run build or dev has not wiped out the block.json file we're hand-editing.

I verified that attributes, label, title, keyword, and scope work ✅

I tried to get the example field to work, but wasn't able to. ❓

variations2.mp4

I'm not sure if the string array form of isActive works since Gutenberg isn't active while testing. If we set this field to something like "isActive":[ "level" ]. We'll see a JS error of:

Screen Shot 2021-07-22 at 9 22 32 AM

Next Steps

Overall, I think this manually tests well for me but it'd be lovely to document what expected behaviors we expect for the existing variation properties (and what still needs more work).

If possible I'd feel more comfortable if we could get 👀 on:

  • a ✅ on the overall i18n approach from component owners
  • There's a new utility function of wp_json_file_decode. I'm thinking this may need a lookover from folks more familiar with code here, and maybe a quick SIRT check.

@gziolo

gziolo commented Jul 23, 2021

Copy link
Copy Markdown
Member Author

Thanks for the detailed testing @gwwar 💯

I tried to get the example field to work, but wasn't able to. ❓

It should pick up the example:

https://github.com/WordPress/gutenberg/blob/ece5560abd945279530bd58f80f74f06b904a293/packages/block-editor/src/store/selectors.js#L1440-L1443

I will investigate it. There might be some issue with type conversion when passing the data between JSON, PHP and JavaScript.

I'm not sure if the string array form of isActive works since Gutenberg isn't active while testing. If we set this field to something like "isActive":[ "level" ]. We'll see a JS error of:

This feature was added in WordPress/gutenberg#30913 that was part of Gutenberg 10.6 and therefore it is included in WordPress 5.8 so it should work. I will do some more testing on that front, too.

Comment thread src/wp-includes/blocks.php Outdated
Comment thread src/wp-includes/functions.php
Comment thread src/wp-includes/functions.php Outdated
Comment thread src/wp-includes/functions.php
Comment thread src/wp-includes/blocks.php Outdated
@johnbillion johnbillion changed the title Blocks: Add support for variations in block.json` file Blocks: Add support for variations in block.json file Jul 23, 2021
@gziolo

gziolo commented Jul 27, 2021

Copy link
Copy Markdown
Member Author

@gwwar, I tested the following changes to block.json file in Heading block:

diff --git a/src/wp-includes/blocks/heading/block.json b/src/wp-includes/blocks/heading/block.json
index 69ec1ba374..7ac8e01841 100644
--- a/src/wp-includes/blocks/heading/block.json
+++ b/src/wp-includes/blocks/heading/block.json
@@ -41,5 +41,23 @@
 		"__unstablePasteTextInline": true
 	},
 	"editorStyle": "wp-block-heading-editor",
-	"style": "wp-block-heading"
+	"style": "wp-block-heading",
+	"variations": [
+		{
+			"name": "heading-1",
+			"title": "Heading 1",
+			"description": "Heading level one.",
+			"attributes": { "level": 1, "content": "Example heading 1" },
+			"isActive": [ "level" ],
+			"scope": [ "inserter", "transform" ]
+		},
+		{
+			"name": "heading-3",
+			"title": "Heading 3",
+			"description": "Heading level three.",
+			"attributes": { "level": 3, "content": "Example heading 3" },
+			"isActive": [ "level" ],
+			"scope": [ "inserter", "transform" ]
+		}
+	]
 }

Everything works as expected:

  • isActive is properly processed
  • example is used as intended tricky, it overrides attributes passed in example with attributes passed in the variation in the preview
  • scope gets applied correctly, too
Screen.Recording.2021-07-27.at.18.50.19.mov

I'm not sure if the string array form of isActive works since Gutenberg isn't active while testing. If we set this field to something like "isActive":[ "level" ]. We'll see a JS error of:

Screen Shot 2021-07-22 at 9 22 32 AM

I can't reproduce the same issue when using this branch.

I did some more digging into how the example works. When I have in the variation:

"attributes": { "level": 3, "content": "Heading 3 - attributes" },
"example": {
	"attributes": { "level": 3, "content": "Heading 3 - example" }
},

then the inserter overrides attributes defined in the example with the initial attributes set for the variation.

Screen Shot 2021-07-27 at 19 17 38

It looks like at the moment it's taking an example from the block type or the variation and overrides "attributes" passed in the "example" with initial attributes when set for the variation. We should add a case that favors attributes passed in the example from the variation - it's another issue in the @wordpress/block-editor package.

Comment thread src/wp-includes/blocks.php Outdated

@gwwar gwwar left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Thanks @gziolo! I'll go ahead and give tentative approval since manual testing looks good. Ideally it'd be nice if we can get another +1 since I'm less familiar with code here.

I can't reproduce the same issue when using this branch.

I can't reproduce the error with isActive now either 👍 I wonder if I had a stale JS dist file.

We should add a case that favors attributes passed in the example from the variation - it's another issue in the @wordpress/block-editor package.

Let's maybe add a tracking issue for this one.

Comment thread src/wp-includes/class-wp-theme-json-resolver.php
@@ -188,50 +90,12 @@ private static function translate_theme_json_chunk( array $array_to_translate, $
* @return array Returns the modified $theme_json_structure.
*/
private static function translate( $theme_json, $domain = 'default' ) {

@gziolo gziolo Jul 30, 2021

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

This PR replaces the existing logic to translate theme.json so it would be great to confirm that everything works as before. All existing unit tests pass for processing theme.json are still green. New tests were added to cover new cases in the extracted general-purpose translate_settings_using_i18n_schema method (it works with block.json, too) that no longer use the intermediate step to run get_fields_to_translate which collects an alist of fields to translate.

@jorgefilipecosta and @nosolosw, I would appreciate your feedback.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I tested theme.json translation and things are working well 👍 Nice work! We should probably also update plugin code right?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

We could update the plugin, although it works exactly the same so I consider it a low priority. I'll have to explore what is necessary to bring variations handling to block.json for older versions of WordPress supported by the Gutenberg plugin. If we need to polyfill translate_settings_using_i18n_schema then we can refactor the logic for theme.json as well.

Comment thread src/wp-includes/l10n.php
*
* @return string|string[]|array[] Translated settings.
*/
function translate_settings_using_i18n_schema( $i18n_schema, $settings, $textdomain ) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

It seems the value of this function for general plugin authors is very limited. And the function is very dependent on the way we translate things now. I think it would be safer to mark this function as internal.

@@ -188,50 +90,12 @@ private static function translate_theme_json_chunk( array $array_to_translate, $
* @return array Returns the modified $theme_json_structure.
*/
private static function translate( $theme_json, $domain = 'default' ) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I tested theme.json translation and things are working well 👍 Nice work! We should probably also update plugin code right?

Comment thread src/wp-includes/l10n.php
Comment thread src/wp-includes/l10n.php Outdated
@gziolo

gziolo commented Aug 11, 2021

Copy link
Copy Markdown
Member Author

Committed with https://core.trac.wordpress.org/changeset/51599.

@gziolo gziolo closed this Aug 11, 2021
@gziolo
gziolo deleted the update/block-json-variations branch August 11, 2021 09:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants