diff --git a/docs/how-to-guides/themes/theme-json.md b/docs/how-to-guides/themes/theme-json.md index e96c4a5c4ac94d..6f71290eaf63a3 100644 --- a/docs/how-to-guides/themes/theme-json.md +++ b/docs/how-to-guides/themes/theme-json.md @@ -587,6 +587,46 @@ Note that the name of the variable is created by adding `--` in between each nes #### Settings examples +- Enable a specifc colour for a nested block, from the color palette: + +```json +{ + "version": 2, + "settings": { + "color": { + "palette": [ + { + "slug": "red", + "name": "Red", + "color": "#ce0808" + }, + { + "slug": "light", + "name": "Light", + "color": "#f5f7f9" + } + ] + }, + "blocks": { + "core/quote": { + "core/heading": { + "color": { + "text": true, + "palette": [ + { + "slug": "red", + "name": "Red", + "color": "#ce0808" + } + ] + } + } + } + } + } +} +``` + - Enable custom colors only for the paragraph block: ```json diff --git a/docs/reference-guides/theme-json-reference/theme-json-living.md b/docs/reference-guides/theme-json-reference/theme-json-living.md index 0096a41be04baf..061c1db655729c 100644 --- a/docs/reference-guides/theme-json-reference/theme-json-living.md +++ b/docs/reference-guides/theme-json-reference/theme-json-living.md @@ -139,10 +139,10 @@ Border styles. | radius | undefined | | | style | string | | | width | string | | -| top | undefined | | -| right | undefined | | -| bottom | undefined | | -| left | undefined | | +| top | object | color, style, width | +| right | object | color, style, width | +| bottom | object | color, style, width | +| left | object | color, style, width | --- diff --git a/schemas/json/theme.json b/schemas/json/theme.json index 58cfe1ea001f08..01cb1503fc3b97 100644 --- a/schemas/json/theme.json +++ b/schemas/json/theme.json @@ -8,6 +8,7 @@ "reference": "https://developer.wordpress.org/block-editor/how-to-guides/themes/theme-json/" }, "settingsPropertiesAppearanceTools": { + "type": "object", "properties": { "appearanceTools": { "description": "Setting that enables the following UI tools:\n\n- border: color, radius, style, width\n- color: link\n- spacing: blockGap, margin, padding\n- typography: lineHeight", @@ -26,6 +27,7 @@ } }, "settingsPropertiesBorder": { + "type": "object", "properties": { "border": { "description": "Settings related to borders.", @@ -57,6 +59,7 @@ } }, "settingsPropertiesColor": { + "type": "object", "properties": { "color": { "description": "Settings related to colors.", @@ -186,6 +189,7 @@ } }, "settingsPropertiesLayout": { + "type": "object", "properties": { "layout": { "description": "Settings related to layout.", @@ -205,6 +209,7 @@ } }, "settingsPropertiesSpacing": { + "type": "object", "properties": { "spacing": { "description": "Settings related to spacing.", @@ -305,6 +310,7 @@ } }, "settingsPropertiesTypography": { + "type": "object", "properties": { "typography": { "description": "Settings related to typography.", @@ -374,18 +380,25 @@ }, "fluid": { "description": "Specifics the minimum and maximum font size value of a fluid font size. Set to `false` to bypass fluid calculations and use the static `size` value.", - "type": [ "object", "boolean" ], - "properties": { - "min": { - "description": "A min font size for fluid font size calculations in px, rem or em.", - "type": "string" + "oneOf": [ + { + "type": "object", + "properties": { + "min": { + "description": "A min font size for fluid font size calculations in px, rem or em.", + "type": "string" + }, + "max": { + "description": "A max font size for fluid font size calculations in px, rem or em.", + "type": "string" + } + }, + "additionalProperties": false }, - "max": { - "description": "A max font size for fluid font size calculations in px, rem or em.", - "type": "string" + { + "type": "boolean" } - }, - "additionalProperties": false + ] } }, "additionalProperties": false @@ -427,7 +440,6 @@ }, "fontWeight": { "description": "List of available font weights, separated by a space.", - "type": "string", "default": "400", "oneOf": [ { @@ -515,6 +527,7 @@ } }, "settingsPropertiesCustom": { + "type": "object", "properties": { "custom": { "description": "Generate custom CSS custom properties of the form `--wp--custom--{key}--{nested-key}: {value};`. `camelCased` keys are transformed to `kebab-case` as to follow the CSS property naming schema. Keys at different depth levels are separated by `--`, so keys should not include `--` in the name.", @@ -553,10 +566,11 @@ } ] }, - "settingsBlocksPropertiesComplete": { + "settingsBlocksProperties": { "type": "object", "properties": { "core/archives": { + "type": "object", "description": "Archive block. Display a monthly archive of your posts. This block has no block-level settings", "additionalProperties": false }, @@ -567,14 +581,16 @@ "$ref": "#/definitions/settingsPropertiesComplete" }, "core/block": { - "$ref": "#/definitions/settingsPropertiesComplete" + "$ref": "#/definitions/settingsNestedPropertiesComplete" }, "core/button": { + "type": "object", "allOf": [ { "$ref": "#/definitions/settingsPropertiesAppearanceTools" }, { + "type": "object", "properties": { "border": { "description": "Settings related to borders.\nGutenberg plugin required.", @@ -589,17 +605,25 @@ } } }, - { "$ref": "#/definitions/settingsPropertiesColor" }, - { "$ref": "#/definitions/settingsPropertiesLayout" }, - { "$ref": "#/definitions/settingsPropertiesSpacing" }, + { + "$ref": "#/definitions/settingsPropertiesColor" + }, + { + "$ref": "#/definitions/settingsPropertiesLayout" + }, + { + "$ref": "#/definitions/settingsPropertiesSpacing" + }, { "$ref": "#/definitions/settingsPropertiesTypography" }, - { "$ref": "#/definitions/settingsPropertiesCustom" } + { + "$ref": "#/definitions/settingsPropertiesCustom" + } ] }, "core/buttons": { - "$ref": "#/definitions/settingsPropertiesComplete" + "$ref": "#/definitions/settingsNestedPropertiesComplete" }, "core/calendar": { "$ref": "#/definitions/settingsPropertiesComplete" @@ -611,10 +635,10 @@ "$ref": "#/definitions/settingsPropertiesComplete" }, "core/column": { - "$ref": "#/definitions/settingsPropertiesComplete" + "$ref": "#/definitions/settingsNestedPropertiesComplete" }, "core/columns": { - "$ref": "#/definitions/settingsPropertiesComplete" + "$ref": "#/definitions/settingsNestedPropertiesComplete" }, "core/comment-author-name": { "$ref": "#/definitions/settingsPropertiesComplete" @@ -632,13 +656,13 @@ "$ref": "#/definitions/settingsPropertiesComplete" }, "core/comment-template": { - "$ref": "#/definitions/settingsPropertiesComplete" + "$ref": "#/definitions/settingsNestedPropertiesComplete" }, "core/comments": { - "$ref": "#/definitions/settingsPropertiesComplete" + "$ref": "#/definitions/settingsNestedPropertiesComplete" }, "core/cover": { - "$ref": "#/definitions/settingsPropertiesComplete" + "$ref": "#/definitions/settingsNestedPropertiesComplete" }, "core/embed": { "$ref": "#/definitions/settingsPropertiesComplete" @@ -650,16 +674,16 @@ "$ref": "#/definitions/settingsPropertiesComplete" }, "core/gallery": { - "$ref": "#/definitions/settingsPropertiesComplete" + "$ref": "#/definitions/settingsNestedPropertiesComplete" }, "core/group": { - "$ref": "#/definitions/settingsPropertiesComplete" + "$ref": "#/definitions/settingsNestedPropertiesComplete" }, "core/heading": { "$ref": "#/definitions/settingsPropertiesComplete" }, "core/home-link": { - "$ref": "#/definitions/settingsPropertiesComplete" + "$ref": "#/definitions/settingsNestedPropertiesComplete" }, "core/html": { "$ref": "#/definitions/settingsPropertiesComplete" @@ -674,13 +698,13 @@ "$ref": "#/definitions/settingsPropertiesComplete" }, "core/list": { - "$ref": "#/definitions/settingsPropertiesComplete" + "$ref": "#/definitions/settingsNestedPropertiesComplete" }, "core/loginout": { "$ref": "#/definitions/settingsPropertiesComplete" }, "core/media-text": { - "$ref": "#/definitions/settingsPropertiesComplete" + "$ref": "#/definitions/settingsNestedPropertiesComplete" }, "core/missing": { "$ref": "#/definitions/settingsPropertiesComplete" @@ -689,10 +713,10 @@ "$ref": "#/definitions/settingsPropertiesComplete" }, "core/navigation": { - "$ref": "#/definitions/settingsPropertiesComplete" + "$ref": "#/definitions/settingsNestedPropertiesComplete" }, "core/navigation-link": { - "$ref": "#/definitions/settingsPropertiesComplete" + "$ref": "#/definitions/settingsNestedPropertiesComplete" }, "core/nextpage": { "$ref": "#/definitions/settingsPropertiesComplete" @@ -707,19 +731,19 @@ "$ref": "#/definitions/settingsPropertiesComplete" }, "core/post-comments": { - "$ref": "#/definitions/settingsPropertiesComplete" + "$ref": "#/definitions/settingsNestedPropertiesComplete" }, "core/post-comments-count": { - "$ref": "#/definitions/settingsPropertiesComplete" + "$ref": "#/definitions/settingsNestedPropertiesComplete" }, "core/post-comments-form": { - "$ref": "#/definitions/settingsPropertiesComplete" + "$ref": "#/definitions/settingsNestedPropertiesComplete" }, "core/post-comments-link": { - "$ref": "#/definitions/settingsPropertiesComplete" + "$ref": "#/definitions/settingsNestedPropertiesComplete" }, "core/post-content": { - "$ref": "#/definitions/settingsPropertiesComplete" + "$ref": "#/definitions/settingsNestedPropertiesComplete" }, "core/post-date": { "$ref": "#/definitions/settingsPropertiesComplete" @@ -734,7 +758,7 @@ "$ref": "#/definitions/settingsPropertiesComplete" }, "core/post-template": { - "$ref": "#/definitions/settingsPropertiesComplete" + "$ref": "#/definitions/settingsNestedPropertiesComplete" }, "core/post-terms": { "$ref": "#/definitions/settingsPropertiesComplete" @@ -749,25 +773,25 @@ "$ref": "#/definitions/settingsPropertiesComplete" }, "core/query": { - "$ref": "#/definitions/settingsPropertiesComplete" + "$ref": "#/definitions/settingsNestedPropertiesComplete" }, "core/query-pagination": { - "$ref": "#/definitions/settingsPropertiesComplete" + "$ref": "#/definitions/settingsNestedPropertiesComplete" }, "core/query-pagination-next": { - "$ref": "#/definitions/settingsPropertiesComplete" + "$ref": "#/definitions/settingsNestedPropertiesComplete" }, "core/query-pagination-numbers": { - "$ref": "#/definitions/settingsPropertiesComplete" + "$ref": "#/definitions/settingsNestedPropertiesComplete" }, "core/query-pagination-previous": { - "$ref": "#/definitions/settingsPropertiesComplete" + "$ref": "#/definitions/settingsNestedPropertiesComplete" }, "core/query-title": { - "$ref": "#/definitions/settingsPropertiesComplete" + "$ref": "#/definitions/settingsNestedPropertiesComplete" }, "core/quote": { - "$ref": "#/definitions/settingsPropertiesComplete" + "$ref": "#/definitions/settingsNestedPropertiesComplete" }, "core/rss": { "$ref": "#/definitions/settingsPropertiesComplete" @@ -794,7 +818,7 @@ "$ref": "#/definitions/settingsPropertiesComplete" }, "core/social-links": { - "$ref": "#/definitions/settingsPropertiesComplete" + "$ref": "#/definitions/settingsNestedPropertiesComplete" }, "core/spacer": { "$ref": "#/definitions/settingsPropertiesComplete" @@ -809,7 +833,7 @@ "$ref": "#/definitions/settingsPropertiesComplete" }, "core/template-part": { - "$ref": "#/definitions/settingsPropertiesComplete" + "$ref": "#/definitions/settingsNestedPropertiesComplete" }, "core/term-description": { "$ref": "#/definitions/settingsPropertiesComplete" @@ -835,10 +859,222 @@ }, "patternProperties": { "^[a-z][a-z0-9-]*/[a-z][a-z0-9-]*$": { - "$ref": "#/definitions/settingsPropertiesComplete" + "$ref": "#/definitions/settingsNestedPropertiesComplete" } - }, - "additionalProperties": false + } + }, + "settingsBlocksPropertiesComplete": { + "type": "object", + "allOf": [ + { + "$ref": "#/definitions/settingsBlocksProperties" + }, + { + "properties": { + "core/archives": {}, + "core/audio": {}, + "core/avatar": {}, + "core/block": {}, + "core/button": {}, + "core/buttons": {}, + "core/calendar": {}, + "core/categories": {}, + "core/code": {}, + "core/column": {}, + "core/columns": {}, + "core/comment-author-name": {}, + "core/comment-content": {}, + "core/comment-date": {}, + "core/comment-edit-link": {}, + "core/comment-reply-link": {}, + "core/comment-template": {}, + "core/comments": {}, + "core/cover": {}, + "core/embed": {}, + "core/file": {}, + "core/freeform": {}, + "core/gallery": {}, + "core/group": {}, + "core/heading": {}, + "core/home-link": {}, + "core/html": {}, + "core/image": {}, + "core/latest-comments": {}, + "core/latest-posts": {}, + "core/list": {}, + "core/loginout": {}, + "core/media-text": {}, + "core/missing": {}, + "core/more": {}, + "core/navigation": {}, + "core/navigation-link": {}, + "core/nextpage": {}, + "core/page-list": {}, + "core/paragraph": {}, + "core/post-author": {}, + "core/post-comments": {}, + "core/post-comments-count": {}, + "core/post-comments-form": {}, + "core/post-comments-link": {}, + "core/post-content": {}, + "core/post-date": {}, + "core/post-excerpt": {}, + "core/post-featured-image": {}, + "core/post-navigation-link": {}, + "core/post-template": {}, + "core/post-terms": {}, + "core/post-title": {}, + "core/preformatted": {}, + "core/pullquote": {}, + "core/query": {}, + "core/query-pagination": {}, + "core/query-pagination-next": {}, + "core/query-pagination-numbers": {}, + "core/query-pagination-previous": {}, + "core/query-title": {}, + "core/quote": {}, + "core/rss": {}, + "core/search": {}, + "core/separator": {}, + "core/shortcode": {}, + "core/site-logo": {}, + "core/site-tagline": {}, + "core/site-title": {}, + "core/social-link": {}, + "core/social-links": {}, + "core/spacer": {}, + "core/table": {}, + "core/table-of-contents": {}, + "core/tag-cloud": {}, + "core/template-part": {}, + "core/term-description": {}, + "core/text-columns": {}, + "core/verse": {}, + "core/video": {}, + "core/widget-area": {}, + "core/legacy-widget": {}, + "core/widget-group": {} + }, + "patternProperties": { + "^[a-z][a-z0-9-]*/[a-z][a-z0-9-]*$": { + "$ref": "#/definitions/settingsPropertiesComplete" + } + }, + "additionalProperties": false + } + ] + }, + "settingsNestedPropertiesComplete": { + "type": "object", + "allOf": [ + { + "$ref": "#/definitions/settingsProperties" + }, + { + "$ref": "#/definitions/settingsBlocksProperties" + }, + { + "properties": { + "appearanceTools": {}, + "border": {}, + "color": {}, + "layout": {}, + "spacing": {}, + "typography": {}, + "custom": {}, + + "core/archives": {}, + "core/audio": {}, + "core/avatar": {}, + "core/block": {}, + "core/button": {}, + "core/buttons": {}, + "core/calendar": {}, + "core/categories": {}, + "core/code": {}, + "core/column": {}, + "core/columns": {}, + "core/comment-author-name": {}, + "core/comment-content": {}, + "core/comment-date": {}, + "core/comment-edit-link": {}, + "core/comment-reply-link": {}, + "core/comment-template": {}, + "core/comments": {}, + "core/cover": {}, + "core/embed": {}, + "core/file": {}, + "core/freeform": {}, + "core/gallery": {}, + "core/group": {}, + "core/heading": {}, + "core/home-link": {}, + "core/html": {}, + "core/image": {}, + "core/latest-comments": {}, + "core/latest-posts": {}, + "core/list": {}, + "core/loginout": {}, + "core/media-text": {}, + "core/missing": {}, + "core/more": {}, + "core/navigation": {}, + "core/navigation-link": {}, + "core/nextpage": {}, + "core/page-list": {}, + "core/paragraph": {}, + "core/post-author": {}, + "core/post-comments": {}, + "core/post-comments-count": {}, + "core/post-comments-form": {}, + "core/post-comments-link": {}, + "core/post-content": {}, + "core/post-date": {}, + "core/post-excerpt": {}, + "core/post-featured-image": {}, + "core/post-navigation-link": {}, + "core/post-template": {}, + "core/post-terms": {}, + "core/post-title": {}, + "core/preformatted": {}, + "core/pullquote": {}, + "core/query": {}, + "core/query-pagination": {}, + "core/query-pagination-next": {}, + "core/query-pagination-numbers": {}, + "core/query-pagination-previous": {}, + "core/query-title": {}, + "core/quote": {}, + "core/rss": {}, + "core/search": {}, + "core/separator": {}, + "core/shortcode": {}, + "core/site-logo": {}, + "core/site-tagline": {}, + "core/site-title": {}, + "core/social-link": {}, + "core/social-links": {}, + "core/spacer": {}, + "core/table": {}, + "core/table-of-contents": {}, + "core/tag-cloud": {}, + "core/template-part": {}, + "core/term-description": {}, + "core/text-columns": {}, + "core/verse": {}, + "core/video": {}, + "core/widget-area": {}, + "core/legacy-widget": {}, + "core/widget-group": {} + }, + "patternProperties": { + "^[a-z][a-z0-9-]*/[a-z][a-z0-9-]*$": { + "$ref": "#/definitions/settingsPropertiesComplete" + } + }, + "additionalProperties": false + } + ] }, "settingsCustomAdditionalProperties": { "type": "object", @@ -857,6 +1093,7 @@ } }, "stylesProperties": { + "type": "object", "properties": { "border": { "description": "Border styles.", @@ -904,60 +1141,76 @@ "type": "string" }, "top": { - "color": { - "description": "Sets the `border-top-color` CSS property.", - "type": "string" - }, - "style": { - "description": "Sets the `border-top-style` CSS property.", - "type": "string" + "type": "object", + "properties": { + "color": { + "description": "Sets the `border-top-color` CSS property.", + "type": "string" + }, + "style": { + "description": "Sets the `border-top-style` CSS property.", + "type": "string" + }, + "width": { + "description": "Sets the `border-top-width` CSS property.", + "type": "string" + } }, - "width": { - "description": "Sets the `border-top-width` CSS property.", - "type": "string" - } + "additionalProperties": false }, "right": { - "color": { - "description": "Sets the `border-right-color` CSS property.", - "type": "string" - }, - "style": { - "description": "Sets the `border-right-style` CSS property.", - "type": "string" + "type": "object", + "properties": { + "color": { + "description": "Sets the `border-right-color` CSS property.", + "type": "string" + }, + "style": { + "description": "Sets the `border-right-style` CSS property.", + "type": "string" + }, + "width": { + "description": "Sets the `border-right-width` CSS property.", + "type": "string" + } }, - "width": { - "description": "Sets the `border-right-width` CSS property.", - "type": "string" - } + "additionalProperties": false }, "bottom": { - "color": { - "description": "Sets the `border-bottom-color` CSS property.", - "type": "string" - }, - "style": { - "description": "Sets the `border-bottom-style` CSS property.", - "type": "string" + "type": "object", + "properties": { + "color": { + "description": "Sets the `border-bottom-color` CSS property.", + "type": "string" + }, + "style": { + "description": "Sets the `border-bottom-style` CSS property.", + "type": "string" + }, + "width": { + "description": "Sets the `border-bottom-width` CSS property.", + "type": "string" + } }, - "width": { - "description": "Sets the `border-bottom-width` CSS property.", - "type": "string" - } + "additionalProperties": false }, "left": { - "color": { - "description": "Sets the `border-left-color` CSS property.", - "type": "string" - }, - "style": { - "description": "Sets the `border-left-style` CSS property.", - "type": "string" + "type": "object", + "properties": { + "color": { + "description": "Sets the `border-left-color` CSS property.", + "type": "string" + }, + "style": { + "description": "Sets the `border-left-style` CSS property.", + "type": "string" + }, + "width": { + "description": "Sets the `border-left-width` CSS property.", + "type": "string" + } }, - "width": { - "description": "Sets the `border-left-width` CSS property.", - "type": "string" - } + "additionalProperties": false } }, "additionalProperties": false diff --git a/test/integration/theme-schema.test.js b/test/integration/theme-schema.test.js new file mode 100644 index 00000000000000..e721e5eca05e46 --- /dev/null +++ b/test/integration/theme-schema.test.js @@ -0,0 +1,23 @@ +/** + * External dependencies + */ +import Ajv from 'ajv-draft-04'; + +/** + * Internal dependencies + */ +import themeSchema from '../../schemas/json/theme.json'; + +describe( 'theme.json schema', () => { + const ajv = new Ajv( { + // Used for matching unknown blocks without repeating core blocks names + // with patternProperties in settings.blocks and settings.styles + allowMatchingProperties: true, + } ); + + it( 'compiles in strict mode', async () => { + const result = ajv.compile( themeSchema ); + + expect( result.errors ).toBe( null ); + } ); +} );