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

Update theme.json shape: make settings & style top-level keys #28110

Merged
merged 65 commits into from
Jan 27, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
65 commits
Select commit Hold shift + click to select a range
b7f859d
Switch key hierarchy
oandregal Jan 11, 2021
7c4a474
Update docs
oandregal Jan 11, 2021
7e3e2dd
Update tests
oandregal Jan 11, 2021
2db32c6
Filters out invalide top-level keys & block selectors
oandregal Jan 14, 2021
f5241a6
Filters out top-level keys within settings/styles subtrees
oandregal Jan 14, 2021
9eb5f54
Recursively iterate over schema
oandregal Jan 14, 2021
b1318e6
Refactor to compact the code
oandregal Jan 14, 2021
b99380c
Prepare code & test for get_settings
oandregal Jan 14, 2021
bb8af54
Improve test clarity
oandregal Jan 14, 2021
9efc1dc
Fix test_get_settings
oandregal Jan 14, 2021
8fcd1d5
Delete any subtree that is empty
oandregal Jan 14, 2021
1f6ea63
Remove styles & settings if they are not arrays
oandregal Jan 14, 2021
7079ce5
Improve readibility
oandregal Jan 14, 2021
02f6b64
Remove block selectors if they are not arrays
oandregal Jan 14, 2021
c9fa0a3
Remove styles&settinsg if they are empty at the end of the processing
oandregal Jan 14, 2021
ce754eb
Expand test not array
oandregal Jan 14, 2021
252d40b
Improve readibility, add comments
oandregal Jan 14, 2021
1970ba9
Remove unused method
oandregal Jan 14, 2021
d82bbcb
Prepare test
oandregal Jan 14, 2021
ee63972
Rename test
oandregal Jan 15, 2021
6f545aa
Adapt remove insecure props test to new theme.json shape
oandregal Jan 15, 2021
6d56160
Adapt to section/styles being top-level
oandregal Jan 15, 2021
c7332d5
Add failing test to demonstrate bug
oandregal Jan 15, 2021
bafc56b
Simplify merge method
oandregal Jan 15, 2021
5fdf7d0
Fix merge algorithm for leafs that have arrays as values
oandregal Jan 15, 2021
e4aca1b
Uncomment tests
oandregal Jan 15, 2021
50d7c0a
Fix get_stylesheet( css_variables )
oandregal Jan 18, 2021
3120447
Fix get_stylesheet( block_styles )
oandregal Jan 18, 2021
79d400d
Fix get_stylesheet
oandregal Jan 18, 2021
fa14cb5
No need to remove contexts as it was already done by the constructor
oandregal Jan 18, 2021
12c6fb9
Create a escape_styles function
oandregal Jan 18, 2021
2dcdc15
Another tests that can be removed
oandregal Jan 18, 2021
7b1c07a
Remove tests that are duplicated
oandregal Jan 18, 2021
8eb12b6
Create new schema validation test
oandregal Jan 18, 2021
02adbee
Remove style properties that are not supported by the block
oandregal Jan 21, 2021
af15f17
Remove unsafe styles
oandregal Jan 21, 2021
99d237b
Remove unsafe styles sub-properties
oandregal Jan 21, 2021
5162f3e
Fix settings
oandregal Jan 21, 2021
63655ae
Uncomment passing test
oandregal Jan 21, 2021
f27105b
Consolidate back keys
oandregal Jan 21, 2021
ddeb87a
Rename context to block
oandregal Jan 21, 2021
d14d14d
Test for custom css vars as well
oandregal Jan 21, 2021
8b3acf7
Fix custom
oandregal Jan 21, 2021
716c912
Update comments
oandregal Jan 21, 2021
0d41973
Adapt translation logic to new shape
oandregal Jan 22, 2021
138092f
Adapt preset defaults to new shape
oandregal Jan 22, 2021
d863d6c
Adapt preset defaults to new shape
oandregal Jan 22, 2021
a1cb0e4
Protect against theme.json with different shape or empty settings
oandregal Jan 22, 2021
2f395f4
Protect against different theme.json shapes
oandregal Jan 22, 2021
00d5db1
Fix block styles
oandregal Jan 22, 2021
d3195a6
add task/todo
oandregal Jan 25, 2021
523d62d
Update getSetting / setSetting
oandregal Jan 25, 2021
d153174
Update getStyle / setStyle
oandregal Jan 25, 2021
471a19b
Update global styles rendered function
oandregal Jan 25, 2021
2d037ba
Update presets processing
oandregal Jan 25, 2021
9e17373
Pass only the merged settings
oandregal Jan 25, 2021
a6cba44
Format for i18n
oandregal Jan 25, 2021
4ea5f33
Add comment
oandregal Jan 25, 2021
0078b35
Adapt path to new i18-theme.json shape
oandregal Jan 25, 2021
710953a
Fix rebase issues
oandregal Jan 25, 2021
7097e43
Fix rebase issues
oandregal Jan 25, 2021
158491b
fix lint issues in class-wp-theme-json-test.php
oandregal Jan 25, 2021
ba940aa
fix lint issues in class-wp-theme-json.php
oandregal Jan 25, 2021
aaa3edb
fix lint issues in class-wp-theme-json-resolver.php
oandregal Jan 25, 2021
7f99119
Adapt phpunit/class-wp-theme-json-legacy-settings-test.php
oandregal Jan 25, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
77 changes: 24 additions & 53 deletions docs/designers-developers/developers/themes/theme-json.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,53 +34,27 @@ By providing the block style properties in a structured way, the Block Editor ca

## Specification

The `experimental-theme.json` file is divided into sections known as "contexts", that represent a different CSS selector. For example, the `core/paragraph` context maps to `p` while `core/group` maps to `.wp-block-group`. In general, one block will map to a single context as in the cases mentioned. There are cases where one block can generate multiple contexts (different CSS selectors). For example, the heading block generates six different contexts (`core/heading/h1`, `core/heading/h2`, etc), one for each different selector (h1, h2, etc).
The `experimental-theme.json` file declares how a theme wants the editor configured (`settings`) as well as the style properties it sets (`styles`).

```
{
"global": { ... },
"core/paragraph": { ... },
"core/group": { ... },
"core/heading/h1": { ... },
"core/heading/h2": { ... },
"core/heading/h3": { ... },
"core/heading/h4": { ... },
"core/heading/h5": { ... },
"core/heading/h6": { ... }
"settings": { ... },
"styles": { ... }
}
```

Every context has the same structure, divided in two sections: `settings` and `styles`. The `settings` are used to control the editor (enable/disable certain features, declare presets), taking over what was previously declared via `add_theme_support`. The `styles` will be used to create new style rules to be appended to a new stylesheet `global-styles-inline-css` enqueued in the front-end and post editor.
Each one of these sections is sub-divided into "contexts" that loosely map to a block. In general, one block will create one single context ―the paragraph block can be addressed via `core/paragraph`― but there are also cases where one block will create multiple contexts ―the heading block represents different HTML elements, h1 to h6, so it creates one context for each such `core/heading/h1`, `core/heading/h2`, etc. Every context has the same inner structure.

```
{
"some/context": {
"settings": {
"border": [ ... ],
"color": [ ... ],
"custom": [ ... ],
"spacing": [ ... ],
"typography": [ ... ]
},
"styles": {
"border": { ... },
"color": { ... },
"typography": { ... }
}
}
}
```

This structure is the same for the three different origins that exist: core, themes, and users. Themes can override core's defaults by creating a file called `experimental-theme.json`. Users, via the site editor, will also be also to override theme's or core's preferences via an user interface that is being worked on.
This specification is the same for the three different origins that use this format: core, themes, and users. Themes can override core's defaults by creating a file called `experimental-theme.json`. Users, via the site editor, will also be also to override theme's or core's preferences via an user interface that is being worked on.

### Settings

The settings section has the following structure and default values:

```
{
"some/context": {
"settings": {
"settings": {
"some/context": {
"border": {
"customRadius": false /* true to opt-in */
},
Expand Down Expand Up @@ -114,26 +88,25 @@ The settings section has the following structure and default values:
}
```

To retain backward compatibility, `add_theme_support` declarations are retrofit in the proper categories. If a theme uses `add_theme_support('disable-custom-colors')`, it'll be the same as set `global.settings.color.custom` to `false`. If the `experimental-theme.json` contains any settings, these will take precedence over the values declared via `add_theme_support`.
To retain backward compatibility, `add_theme_support` declarations are retrofit in the proper categories. If a theme uses `add_theme_support('disable-custom-colors')`, it'll be the same as set `settings.global.color.custom` to `false`. If the `experimental-theme.json` contains any settings, these will take precedence over the values declared via `add_theme_support`.

Settings can also be controlled by context, providing a more fine-grained control over what exists via `add_theme_support`. As an example, let's say that a theme author wants to enable custom colors for the paragraph block exclusively. This is how it'd be done:

```json
{
"global": {
"settings": {
"settings": {
"global": {
"color": {
"custom": false
}
}
},
"core/paragraph": {
"settings": {
},
"core/paragraph": {
"color": {
"custom": true
}
}
}
}
```

Note, however, that not all settings are relevant for all contexts and the blocks they represent. The settings section provides an opt-in/opt-out mechanism for themes, but it's the block's responsibility to add support for the features that are relevant to it. For example, if a block doesn't implement the `dropCap` feature, a theme can't enable it for such a block through `experimental-theme.json`.
Expand All @@ -146,8 +119,8 @@ For example, for this input:

```json
{
"global": {
"settings": {
"settings": {
"global": {
"color": {
"palette": [
{
Expand Down Expand Up @@ -204,14 +177,14 @@ The goal is that presets can be defined using this format, although, right now,

#### Free-form CSS Custom Properties

In addition to create CSS Custom Properties for the presets, the theme.json also allows for themes to create their own, so they don't have to be enqueued separately. Any values declared within the `settings.custom` section will be transformed to CSS Custom Properties following this naming schema: `--wp--custom--<variable-name>`.
In addition to create CSS Custom Properties for the presets, the theme.json also allows for themes to create their own, so they don't have to be enqueued separately. Any values declared within the `settings.<some/context>.custom` section will be transformed to CSS Custom Properties following this naming schema: `--wp--custom--<variable-name>`.

For example, for this input:

```json
{
"global": {
"settings": {
"settings": {
"global": {
"custom": {
"base-font": 16,
"line-height": {
Expand Down Expand Up @@ -244,8 +217,8 @@ Each block declares which style properties it exposes. This has been coined as "

```json
{
"some/context": {
"styles": {
"styles": {
"some/context": {
"border": {
"radius": "value"
},
Expand Down Expand Up @@ -281,18 +254,16 @@ For example, an input like this:

```json
{
"core/heading/h1": {
"styles": {
"styles": {
"core/heading/h1": {
"color": {
"text": "var(--wp--preset--color--primary)"
},
"typography": {
"fontSize": "calc(1px * var(--wp--preset--font-size--huge))"
}
}
},
"core/heading/h4": {
"styles": {
},
"core/heading/h4": {
"color": {
"text": "var(--wp--preset--color--secondary)"
},
Expand Down
57 changes: 45 additions & 12 deletions lib/class-wp-theme-json-resolver.php
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,32 @@ private static function get_from_file( $file_path ) {
* containing the a translatable path from theme.json and an array
* of properties that are translatable.
*
* For example, given this input:
*
* {
* "settings": {
* "*": {
* "typography": {
* "fontSizes": [ "name" ],
* "fontStyles": [ "name" ]
* }
* }
* }
* }
*
* will return this output:
*
* [
* 0 => [
* 'path' => [ 'settings', '*', 'typography', 'fontSizes' ],
* 'translatable_keys' => [ 'name' ]
* ],
* 1 => [
* 'path' => [ 'settings', '*', 'typography', 'fontStyles' ],
* 'translatable_keys' => [ 'name']
* ]
* ]
*
* @param array $file_structure_partial A part of a theme.json i18n tree.
* @param array $current_path An array with a path on the theme.json i18n tree.
*
Expand Down Expand Up @@ -110,7 +136,6 @@ private static function get_presets_to_translate() {
if ( null === $theme_json_i18n ) {
$file_structure = self::get_from_file( __DIR__ . '/experimental-i18n-theme.json' );
$theme_json_i18n = self::theme_json_i18_file_structure_to_preset_paths( $file_structure );

}
return $theme_json_i18n;
}
Expand All @@ -123,29 +148,37 @@ private static function get_presets_to_translate() {
* Default 'default'.
*/
private static function translate_presets( &$theme_json_structure, $domain = 'default' ) {
if ( ! isset( $theme_json_structure['settings'] ) ) {
return;
}

$preset_to_translate = self::get_presets_to_translate();
foreach ( $theme_json_structure as &$context_value ) {
if ( empty( $context_value ) ) {
foreach ( $theme_json_structure['settings'] as &$settings ) {
if ( empty( $settings ) ) {
continue;
}

foreach ( $preset_to_translate as $preset ) {
$path = $preset['path'];
$path = array_slice( $preset['path'], 2 );
$translatable_keys = $preset['translatable_keys'];
$array_to_translate = gutenberg_experimental_get( $context_value, $path, null );
$array_to_translate = gutenberg_experimental_get( $settings, $path, null );
if ( null === $array_to_translate ) {
continue;
}

foreach ( $array_to_translate as &$item_to_translate ) {
foreach ( $translatable_keys as $translatable_key ) {
if ( empty( $item_to_translate[ $translatable_key ] ) ) {
continue;
}

// phpcs:ignore WordPress.WP.I18n.LowLevelTranslationFunction,WordPress.WP.I18n.NonSingularStringLiteralText,WordPress.WP.I18n.NonSingularStringLiteralDomain
$item_to_translate[ $translatable_key ] = translate( $item_to_translate[ $translatable_key ], $domain );
// phpcs:enable
}
}
gutenberg_experimental_set( $context_value, $path, $array_to_translate );

gutenberg_experimental_set( $settings, $path, $array_to_translate );
}
}
}
Expand Down Expand Up @@ -178,8 +211,8 @@ private static function get_core_origin() {
'vivid-cyan-blue' => __( 'Vivid cyan blue', 'gutenberg' ),
'vivid-purple' => __( 'Vivid purple', 'gutenberg' ),
);
if ( ! empty( $config['global']['settings']['color']['palette'] ) ) {
foreach ( $config['global']['settings']['color']['palette'] as &$color ) {
if ( ! empty( $config['settings']['global']['color']['palette'] ) ) {
foreach ( $config['settings']['global']['color']['palette'] as &$color ) {
$color['name'] = $default_colors_i18n[ $color['slug'] ];
}
}
Expand All @@ -198,8 +231,8 @@ private static function get_core_origin() {
'electric-grass' => __( 'Electric grass', 'gutenberg' ),
'midnight' => __( 'Midnight', 'gutenberg' ),
);
if ( ! empty( $config['global']['settings']['color']['gradients'] ) ) {
foreach ( $config['global']['settings']['color']['gradients'] as &$gradient ) {
if ( ! empty( $config['settings']['global']['color']['gradients'] ) ) {
foreach ( $config['settings']['global']['color']['gradients'] as &$gradient ) {
$gradient['name'] = $default_gradients_i18n[ $gradient['slug'] ];
}
}
Expand All @@ -211,8 +244,8 @@ private static function get_core_origin() {
'large' => __( 'Large', 'gutenberg' ),
'huge' => __( 'Huge', 'gutenberg' ),
);
if ( ! empty( $config['global']['settings']['typography']['fontSizes'] ) ) {
foreach ( $config['global']['settings']['typography']['fontSizes'] as &$font_size ) {
if ( ! empty( $config['settings']['global']['typography']['fontSizes'] ) ) {
foreach ( $config['settings']['global']['typography']['fontSizes'] as &$font_size ) {
$font_size['name'] = $default_font_sizes_i18n[ $font_size['slug'] ];
}
}
Expand Down
Loading