author | ymh <ymh.work@gmail.com> |
Fri, 05 Sep 2025 18:52:52 +0200 | |
changeset 22 | 8c2e4d02f4ef |
parent 21 | 48c4eec2b7e6 |
permissions | -rw-r--r-- |
19 | 1 |
<?php |
2 |
/** |
|
3 |
* WP_Theme_JSON_Schema class |
|
4 |
* |
|
5 |
* @package WordPress |
|
6 |
* @subpackage Theme |
|
7 |
* @since 5.9.0 |
|
8 |
*/ |
|
9 |
||
10 |
/** |
|
11 |
* Class that migrates a given theme.json structure to the latest schema. |
|
12 |
* |
|
13 |
* This class is for internal core usage and is not supposed to be used by extenders (plugins and/or themes). |
|
14 |
* This is a low-level API that may need to do breaking changes. Please, |
|
15 |
* use get_global_settings, get_global_styles, and get_global_stylesheet instead. |
|
16 |
* |
|
17 |
* @since 5.9.0 |
|
18 |
* @access private |
|
19 |
*/ |
|
21
48c4eec2b7e6
Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
19
diff
changeset
|
20 |
#[AllowDynamicProperties] |
19 | 21 |
class WP_Theme_JSON_Schema { |
22 |
||
23 |
/** |
|
24 |
* Maps old properties to their new location within the schema's settings. |
|
25 |
* This will be applied at both the defaults and individual block levels. |
|
26 |
*/ |
|
27 |
const V1_TO_V2_RENAMED_PATHS = array( |
|
28 |
'border.customRadius' => 'border.radius', |
|
29 |
'spacing.customMargin' => 'spacing.margin', |
|
30 |
'spacing.customPadding' => 'spacing.padding', |
|
31 |
'typography.customLineHeight' => 'typography.lineHeight', |
|
32 |
); |
|
33 |
||
34 |
/** |
|
35 |
* Function that migrates a given theme.json structure to the last version. |
|
36 |
* |
|
37 |
* @since 5.9.0 |
|
21
48c4eec2b7e6
Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
19
diff
changeset
|
38 |
* @since 6.6.0 Migrate up to v3 and add $origin parameter. |
19 | 39 |
* |
40 |
* @param array $theme_json The structure to migrate. |
|
21
48c4eec2b7e6
Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
19
diff
changeset
|
41 |
* @param string $origin Optional. What source of data this object represents. |
48c4eec2b7e6
Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
19
diff
changeset
|
42 |
* One of 'blocks', 'default', 'theme', or 'custom'. Default 'theme'. |
19 | 43 |
* @return array The structure in the last version. |
44 |
*/ |
|
21
48c4eec2b7e6
Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
19
diff
changeset
|
45 |
public static function migrate( $theme_json, $origin = 'theme' ) { |
19 | 46 |
if ( ! isset( $theme_json['version'] ) ) { |
47 |
$theme_json = array( |
|
48 |
'version' => WP_Theme_JSON::LATEST_SCHEMA, |
|
49 |
); |
|
50 |
} |
|
51 |
||
21
48c4eec2b7e6
Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
19
diff
changeset
|
52 |
// Migrate each version in order starting with the current version. |
48c4eec2b7e6
Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
19
diff
changeset
|
53 |
switch ( $theme_json['version'] ) { |
48c4eec2b7e6
Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
19
diff
changeset
|
54 |
case 1: |
48c4eec2b7e6
Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
19
diff
changeset
|
55 |
$theme_json = self::migrate_v1_to_v2( $theme_json ); |
48c4eec2b7e6
Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
19
diff
changeset
|
56 |
// Deliberate fall through. Once migrated to v2, also migrate to v3. |
48c4eec2b7e6
Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
19
diff
changeset
|
57 |
case 2: |
48c4eec2b7e6
Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
19
diff
changeset
|
58 |
$theme_json = self::migrate_v2_to_v3( $theme_json, $origin ); |
19 | 59 |
} |
60 |
||
61 |
return $theme_json; |
|
62 |
} |
|
63 |
||
64 |
/** |
|
65 |
* Removes the custom prefixes for a few properties |
|
66 |
* that were part of v1: |
|
67 |
* |
|
68 |
* 'border.customRadius' => 'border.radius', |
|
69 |
* 'spacing.customMargin' => 'spacing.margin', |
|
70 |
* 'spacing.customPadding' => 'spacing.padding', |
|
71 |
* 'typography.customLineHeight' => 'typography.lineHeight', |
|
72 |
* |
|
73 |
* @since 5.9.0 |
|
74 |
* |
|
75 |
* @param array $old Data to migrate. |
|
76 |
* |
|
77 |
* @return array Data without the custom prefixes. |
|
78 |
*/ |
|
79 |
private static function migrate_v1_to_v2( $old ) { |
|
80 |
// Copy everything. |
|
81 |
$new = $old; |
|
82 |
||
83 |
// Overwrite the things that changed. |
|
84 |
if ( isset( $old['settings'] ) ) { |
|
85 |
$new['settings'] = self::rename_paths( $old['settings'], self::V1_TO_V2_RENAMED_PATHS ); |
|
86 |
} |
|
87 |
||
88 |
// Set the new version. |
|
89 |
$new['version'] = 2; |
|
90 |
||
91 |
return $new; |
|
92 |
} |
|
93 |
||
94 |
/** |
|
21
48c4eec2b7e6
Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
19
diff
changeset
|
95 |
* Migrates from v2 to v3. |
48c4eec2b7e6
Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
19
diff
changeset
|
96 |
* |
48c4eec2b7e6
Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
19
diff
changeset
|
97 |
* - Sets settings.typography.defaultFontSizes to false if settings.typography.fontSizes are defined. |
48c4eec2b7e6
Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
19
diff
changeset
|
98 |
* - Sets settings.spacing.defaultSpacingSizes to false if settings.spacing.spacingSizes are defined. |
48c4eec2b7e6
Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
19
diff
changeset
|
99 |
* - Prevents settings.spacing.spacingSizes from merging with settings.spacing.spacingScale by |
48c4eec2b7e6
Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
19
diff
changeset
|
100 |
* unsetting spacingScale when spacingSizes are defined. |
48c4eec2b7e6
Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
19
diff
changeset
|
101 |
* |
48c4eec2b7e6
Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
19
diff
changeset
|
102 |
* @since 6.6.0 |
48c4eec2b7e6
Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
19
diff
changeset
|
103 |
* |
48c4eec2b7e6
Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
19
diff
changeset
|
104 |
* @param array $old Data to migrate. |
48c4eec2b7e6
Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
19
diff
changeset
|
105 |
* @param string $origin What source of data this object represents. |
48c4eec2b7e6
Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
19
diff
changeset
|
106 |
* One of 'blocks', 'default', 'theme', or 'custom'. |
48c4eec2b7e6
Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
19
diff
changeset
|
107 |
* @return array Data with defaultFontSizes set to false. |
48c4eec2b7e6
Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
19
diff
changeset
|
108 |
*/ |
48c4eec2b7e6
Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
19
diff
changeset
|
109 |
private static function migrate_v2_to_v3( $old, $origin ) { |
48c4eec2b7e6
Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
19
diff
changeset
|
110 |
// Copy everything. |
48c4eec2b7e6
Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
19
diff
changeset
|
111 |
$new = $old; |
48c4eec2b7e6
Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
19
diff
changeset
|
112 |
|
48c4eec2b7e6
Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
19
diff
changeset
|
113 |
// Set the new version. |
48c4eec2b7e6
Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
19
diff
changeset
|
114 |
$new['version'] = 3; |
48c4eec2b7e6
Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
19
diff
changeset
|
115 |
|
48c4eec2b7e6
Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
19
diff
changeset
|
116 |
/* |
48c4eec2b7e6
Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
19
diff
changeset
|
117 |
* Remaining changes do not need to be applied to the custom origin, |
48c4eec2b7e6
Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
19
diff
changeset
|
118 |
* as they should take on the value of the theme origin. |
48c4eec2b7e6
Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
19
diff
changeset
|
119 |
*/ |
48c4eec2b7e6
Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
19
diff
changeset
|
120 |
if ( 'custom' === $origin ) { |
48c4eec2b7e6
Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
19
diff
changeset
|
121 |
return $new; |
48c4eec2b7e6
Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
19
diff
changeset
|
122 |
} |
48c4eec2b7e6
Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
19
diff
changeset
|
123 |
|
48c4eec2b7e6
Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
19
diff
changeset
|
124 |
/* |
48c4eec2b7e6
Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
19
diff
changeset
|
125 |
* Even though defaultFontSizes and defaultSpacingSizes are new |
48c4eec2b7e6
Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
19
diff
changeset
|
126 |
* settings, we need to migrate them as they each control |
48c4eec2b7e6
Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
19
diff
changeset
|
127 |
* PRESETS_METADATA prevent_override values which were previously |
48c4eec2b7e6
Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
19
diff
changeset
|
128 |
* hardcoded to false. This only needs to happen when the theme provides |
48c4eec2b7e6
Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
19
diff
changeset
|
129 |
* fontSizes or spacingSizes as they could match the default ones and |
48c4eec2b7e6
Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
19
diff
changeset
|
130 |
* affect the generated CSS. |
48c4eec2b7e6
Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
19
diff
changeset
|
131 |
*/ |
48c4eec2b7e6
Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
19
diff
changeset
|
132 |
if ( isset( $old['settings']['typography']['fontSizes'] ) ) { |
48c4eec2b7e6
Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
19
diff
changeset
|
133 |
$new['settings']['typography']['defaultFontSizes'] = false; |
48c4eec2b7e6
Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
19
diff
changeset
|
134 |
} |
48c4eec2b7e6
Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
19
diff
changeset
|
135 |
|
48c4eec2b7e6
Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
19
diff
changeset
|
136 |
/* |
48c4eec2b7e6
Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
19
diff
changeset
|
137 |
* Similarly to defaultFontSizes, we need to migrate defaultSpacingSizes |
48c4eec2b7e6
Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
19
diff
changeset
|
138 |
* as it controls the PRESETS_METADATA prevent_override which was |
48c4eec2b7e6
Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
19
diff
changeset
|
139 |
* previously hardcoded to false. This only needs to happen when the |
48c4eec2b7e6
Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
19
diff
changeset
|
140 |
* theme provided spacing sizes via spacingSizes or spacingScale. |
48c4eec2b7e6
Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
19
diff
changeset
|
141 |
*/ |
48c4eec2b7e6
Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
19
diff
changeset
|
142 |
if ( |
48c4eec2b7e6
Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
19
diff
changeset
|
143 |
isset( $old['settings']['spacing']['spacingSizes'] ) || |
48c4eec2b7e6
Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
19
diff
changeset
|
144 |
isset( $old['settings']['spacing']['spacingScale'] ) |
48c4eec2b7e6
Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
19
diff
changeset
|
145 |
) { |
48c4eec2b7e6
Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
19
diff
changeset
|
146 |
$new['settings']['spacing']['defaultSpacingSizes'] = false; |
48c4eec2b7e6
Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
19
diff
changeset
|
147 |
} |
48c4eec2b7e6
Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
19
diff
changeset
|
148 |
|
48c4eec2b7e6
Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
19
diff
changeset
|
149 |
/* |
48c4eec2b7e6
Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
19
diff
changeset
|
150 |
* In v3 spacingSizes is merged with the generated spacingScale sizes |
48c4eec2b7e6
Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
19
diff
changeset
|
151 |
* instead of completely replacing them. The v3 behavior is what was |
48c4eec2b7e6
Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
19
diff
changeset
|
152 |
* documented for the v2 schema, but the code never actually did work |
48c4eec2b7e6
Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
19
diff
changeset
|
153 |
* that way. Instead of surprising users with a behavior change two |
48c4eec2b7e6
Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
19
diff
changeset
|
154 |
* years after the fact at the same time as a v3 update is introduced, |
48c4eec2b7e6
Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
19
diff
changeset
|
155 |
* we'll continue using the "bugged" behavior for v2 themes. And treat |
48c4eec2b7e6
Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
19
diff
changeset
|
156 |
* the "bug fix" as a breaking change for v3. |
48c4eec2b7e6
Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
19
diff
changeset
|
157 |
*/ |
48c4eec2b7e6
Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
19
diff
changeset
|
158 |
if ( isset( $old['settings']['spacing']['spacingSizes'] ) ) { |
48c4eec2b7e6
Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
19
diff
changeset
|
159 |
unset( $new['settings']['spacing']['spacingScale'] ); |
48c4eec2b7e6
Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
19
diff
changeset
|
160 |
} |
48c4eec2b7e6
Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
19
diff
changeset
|
161 |
|
48c4eec2b7e6
Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
19
diff
changeset
|
162 |
return $new; |
48c4eec2b7e6
Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
19
diff
changeset
|
163 |
} |
48c4eec2b7e6
Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
19
diff
changeset
|
164 |
|
48c4eec2b7e6
Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
19
diff
changeset
|
165 |
/** |
19 | 166 |
* Processes the settings subtree. |
167 |
* |
|
168 |
* @since 5.9.0 |
|
169 |
* |
|
170 |
* @param array $settings Array to process. |
|
171 |
* @param array $paths_to_rename Paths to rename. |
|
172 |
* |
|
173 |
* @return array The settings in the new format. |
|
174 |
*/ |
|
175 |
private static function rename_paths( $settings, $paths_to_rename ) { |
|
176 |
$new_settings = $settings; |
|
177 |
||
178 |
// Process any renamed/moved paths within default settings. |
|
179 |
self::rename_settings( $new_settings, $paths_to_rename ); |
|
180 |
||
181 |
// Process individual block settings. |
|
182 |
if ( isset( $new_settings['blocks'] ) && is_array( $new_settings['blocks'] ) ) { |
|
183 |
foreach ( $new_settings['blocks'] as &$block_settings ) { |
|
184 |
self::rename_settings( $block_settings, $paths_to_rename ); |
|
185 |
} |
|
186 |
} |
|
187 |
||
188 |
return $new_settings; |
|
189 |
} |
|
190 |
||
191 |
/** |
|
192 |
* Processes a settings array, renaming or moving properties. |
|
193 |
* |
|
194 |
* @since 5.9.0 |
|
195 |
* |
|
196 |
* @param array $settings Reference to settings either defaults or an individual block's. |
|
197 |
* @param array $paths_to_rename Paths to rename. |
|
198 |
*/ |
|
199 |
private static function rename_settings( &$settings, $paths_to_rename ) { |
|
200 |
foreach ( $paths_to_rename as $original => $renamed ) { |
|
201 |
$original_path = explode( '.', $original ); |
|
202 |
$renamed_path = explode( '.', $renamed ); |
|
203 |
$current_value = _wp_array_get( $settings, $original_path, null ); |
|
204 |
||
205 |
if ( null !== $current_value ) { |
|
206 |
_wp_array_set( $settings, $renamed_path, $current_value ); |
|
207 |
self::unset_setting_by_path( $settings, $original_path ); |
|
208 |
} |
|
209 |
} |
|
210 |
} |
|
211 |
||
212 |
/** |
|
213 |
* Removes a property from within the provided settings by its path. |
|
214 |
* |
|
215 |
* @since 5.9.0 |
|
216 |
* |
|
217 |
* @param array $settings Reference to the current settings array. |
|
218 |
* @param array $path Path to the property to be removed. |
|
219 |
*/ |
|
220 |
private static function unset_setting_by_path( &$settings, $path ) { |
|
21
48c4eec2b7e6
Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
19
diff
changeset
|
221 |
$tmp_settings = &$settings; |
19 | 222 |
$last_key = array_pop( $path ); |
223 |
foreach ( $path as $key ) { |
|
224 |
$tmp_settings = &$tmp_settings[ $key ]; |
|
225 |
} |
|
226 |
||
227 |
unset( $tmp_settings[ $last_key ] ); |
|
228 |
} |
|
229 |
} |