Global Settings & Styles (theme.json
)
Theme.json has been introduced in WordPress 5.8 as the way to control the overall appearance and settings of blocks. These settings and style presets get applied both in the editor and on the frontend of the site.
When to use theme.json
By default any new WordPress Theme at 10up includes a theme.json
file with some minimal configuration. It is recommended to keep this file and use it to control which settings should be exposed on each block in the editor. Theme.json is the easiest mechanism of controlling what options should be exposed.
How to use theme.json
The theme.json
file gets added to the root directory of a Theme. There are two main areas that you can control with the theme.json
file: settings and styles. Both of these can have properties defined on the global level, meaning applying to the entire site with all its blocks, or on the block level where you can target individual block types.
{
"settings": {
// Global settings get defined here...
"blocks": {
// Block specific settings get defined here...
}
},
"styles" : {
// Global styles get defined here...
"blocks": {
// Block specific styles get defined here...
}
}
}
Add the $schema
key to your theme.json
files:
{
"$schema": "https://schemas.wp.org/trunk/theme.json"
}
This will give you autocomplete and inline documentation while working on theme.json
files.
You can interchange trunk
with a specific WordPress version like so: https://schemas.wp.org/wp/5.9/theme.json
As mentioned earlier the theme.json
file has two main purposes. It allows you to control which settings get displayed, and also define certain default values for styles. This styling mechanism is build on CSS custom properties.
So when you define a custom color palette like so:
{
"$schema": "https://schemas.wp.org/trunk/theme.json",
"version": 2,
"settings": {
"color": {
"palette": [
{
"name": "Black",
"slug": "black",
"color": "#000000"
},
{
"name": "White",
"slug": "white",
"color": "#ffffff"
}
]
},
"blocks": {
"core/paragraph": {
"color": {
"palette": [
{
"name": "Red",
"slug": "red",
"color": "#ff0000"
}
]
}
}
}
}
}
WordPress automatically generates and includes the following custom properties get added to the page:
body {
--wp--preset--color--black: #000000;
--wp--preset--color--white: #ffffff;
}
.wp-block-paragraph {
--wp--preset--color--red: #ff0000;
}
By default WordPress caches the Stylesheet that gets generated out of theme.json
. For development purposes you can bypass that caching by enabling debug mode via the WP_DEBUG
global in your wp-config.php
. (SCRIPT_DEBUG
also achieves the same thing)
Understanding the cascade
These settings and styles exist at three levels, each overwriting the specificity of the previous layer. At the root there is the default core theme.json
file which houses all the default values for everything. All the properties in this core theme.json
file can be overwritten via the theme.json
file of a theme. Finally there also is the third layer which is the user generated theme.json
that comes out of the global styles panel in the site editor. This only impacts "Block Based Themes" which allow users to define colors, fonts, etc. manually using the Site Editor.
Using the values from theme.json
custom blocks
You can access the settings & values defined in theme.json
via the useSetting
hook. This hook accepts a string
as its parameter which is used as the path for a setting. This means that it checks through the different specificity levels whether a value has been defined for this key.
It first checks whether the user has defined something, then whether the block has defined something in its settings, following the global settings in theme.json
. If none of these places have any value it will use the default value specified in core.
import { useSetting } from '@wordpress/block-editor';
export function BlockEdit() {
const isEnabled = useSetting( 'typography.dropCap' );
// ...
}
Example:
Lets say we have this theme.json
file:
{
"settings": {
"typography": {
"dropCap": false
}
},
"blocks": [
"core/paragraph": {
"settings": {
"typography": {
"dropCap": true
}
}
}
]
}
Using useSetting('typography.dropCap')
would only return true
if it is being called from within the core/paragraph
block.
Filtering theme.json
data
Starting in WordPress 6.1 it is possible to filter the values of theme.json
on the server. There are 4 different hooks for the 4 different layers or theme.json
. Default, Blocks, Theme, and User.
wp_theme_json_data_default
: hooks into the default data provided by WordPresswp_theme_json_data_blocks
: hooks into the data provided by the blockswp_theme_json_data_theme
: hooks into the data provided by the themewp_theme_json_data_user
: hooks into the data provided by the user
Each of these filters receives an instance of the WP_Theme_JSON_Data
class with the data for the respective layer. To provide new data, the filter callback needs to use the update_with( $new_data )
method, where $new_data
is a valid theme.json
-like structure.
As with any theme.json
, the new data needs to declare which version
of the theme.json
is using, so it can correctly be migrated.
function filter_theme_json_theme( $theme_json ){
$new_data = array(
'version' => 2,
'settings' => array(
'color' => array(
'text' => false,
'palette' => array(
array(
'slug' => 'foreground',
'color' => 'black',
'name' => __( 'Foreground', 'theme-domain' ),
),
array(
'slug' => 'background',
'color' => 'white',
'name' => __( 'Background', 'theme-domain' ),
),
),
),
),
);
return $theme_json->update_with( $new_data );
}
add_filter( 'wp_theme_json_data_theme', 'filter_theme_json_theme' );
Filtering theme.json
client side
Having the filters available on the backend is great. But sometimes we need to be able to change settings based on contextual clues. That isn't possible on the server because we cannot access the actual state of the block consuming the theme.json
settings on the server.
In order to allow for these types of contextual settings a new client side hook called blockEditor.useSetting.before
was introduced in WordPress 6.2.
import { select } from '@wordpress/data';
import { addFilter } from '@wordpress/hooks';
import { store as blockEditorStore } from '@wordpress/block-editor';
/**
* Disable text color controls on Heading blocks
* when placed inside of Media & Text blocks.
*/
addFilter(
'blockEditor.useSetting.before',
'namespace/useSetting.before',
( settingValue, settingName, clientId, blockName ) => {
if ( blockName === 'core/heading' ) {
const { getBlockParents, getBlockName } = select( blockEditorStore );
const blockParents = getBlockParents( clientId, true );
const isNestedInMediaTextBlock = blockParents.some( ( ancestorId ) => getBlockName( ancestorId ) === 'core/media-text' );
if ( isNestedInMediaTextBlock && settingName === 'color.text' ) {
return false;
}
}
return settingValue;
}
);
Links
- Block Editor Handbook - Global Settings & Styles (theme.json)
- Block Editor Handbook - Theme JSON API Reference
- Filters for theme.json data - WordPress 6.1 Dev Note
- How to modify theme.json data using server-side filters - WordPress Developer Blog
- Customize settings for any block in WordPress 6.2 - WordPress 6.2 Dev Note