PluginProbe
Gutenberg / 9.7.2
Gutenberg v9.7.2
24.0.0 23.9.1 23.9.0 23.8.0 23.7.2 23.7.1 23.7.0 23.6.1 23.6.2 23.6.0 23.5.3 23.5.2 23.5.1 23.5.0 23.4.0 23.3.2 23.3.1 23.3.0 23.2.0 23.2.1 23.2.2 23.1.1 23.1.0 23.0.1 12.6.0 All 403 releases
← All changes | lib/global-styles.php +229 -87 7.4.09.7.2 View file →
@@ -1,131 +1,273 @@
1 1 <?php
2 2 /**
3 - * Global styles functions, filters and actions, etc.
3 + * Bootstraps Global Styles.
4 4 *
5 5 * @package gutenberg
6 6 */
7 7
8 8 /**
9 - * Function that given a branch of the global styles object recursively generates
10 - * an array defining all the css vars that the global styles object represents.
9 + * Whether the current theme has a theme.json file.
11 10 *
12 - * @param array $global_styles_branch Array representing a brach of the global styles object.
13 - * @param string $prefix Prefix to append to each variable.
14 - * @param bool $is_start Indicates if we are on the first call to gutenberg_get_css_vars (outside the recursion).
15 - * @return array An array whose keys are css variable names and whose values are the css variables value.
11 + * @return boolean
16 12 */
17 -function gutenberg_get_css_vars( $global_styles_branch, $prefix = '', $is_start = true ) {
18 - $result = array();
19 - foreach ( $global_styles_branch as $key => $value ) {
20 - $processed_key = str_replace( '/', '-', $key );
21 - $separator = $is_start ? '' : '--';
22 - $new_key = ( $prefix ? $prefix . $separator : '' ) . $processed_key;
13 +function gutenberg_experimental_global_styles_has_theme_json_support() {
14 + return is_readable( locate_template( 'experimental-theme.json' ) );
15 +}
23 16
24 - if ( is_array( $value ) ) {
25 - $result = array_merge(
26 - $result,
27 - gutenberg_get_css_vars( $value, $new_key, false )
28 - );
29 - } else {
30 - $result[ $new_key ] = $value;
17 +/**
18 + * Returns the theme presets registered via add_theme_support, if any.
19 + *
20 + * @param array $settings Existing editor settings.
21 + *
22 + * @return array Config that adheres to the theme.json schema.
23 + */
24 +function gutenberg_experimental_global_styles_get_theme_support_settings( $settings ) {
25 + $theme_settings = array();
26 + $theme_settings['global'] = array();
27 + $theme_settings['global']['settings'] = array();
28 +
29 + // Deprecated theme supports.
30 + if ( isset( $settings['disableCustomColors'] ) ) {
31 + if ( ! isset( $theme_settings['global']['settings']['color'] ) ) {
32 + $theme_settings['global']['settings']['color'] = array();
31 33 }
34 + $theme_settings['global']['settings']['color']['custom'] = ! $settings['disableCustomColors'];
32 35 }
33 - return $result;
34 -}
35 36
36 -/**
37 - * Function responsible for enqueuing the style that define the global styles css variables.
38 - */
39 -function gutenberg_enqueue_global_styles_assets() {
40 - if ( ! locate_template( 'experimental-theme.json' ) ) {
41 - return;
37 + if ( isset( $settings['disableCustomGradients'] ) ) {
38 + if ( ! isset( $theme_settings['global']['settings']['color'] ) ) {
39 + $theme_settings['global']['settings']['color'] = array();
40 + }
41 + $theme_settings['global']['settings']['color']['customGradient'] = ! $settings['disableCustomGradients'];
42 42 }
43 - $default_global_styles_path = dirname( dirname( __FILE__ ) ) . '/experimental-default-global-styles.json';
44 - $default_global_styles = null;
45 43
46 - if ( file_exists( $default_global_styles_path ) ) {
47 - $default_global_styles = json_decode(
48 - file_get_contents( $default_global_styles_path ),
49 - true
50 - );
44 + if ( isset( $settings['disableCustomFontSizes'] ) ) {
45 + if ( ! isset( $theme_settings['global']['settings']['typography'] ) ) {
46 + $theme_settings['global']['settings']['typography'] = array();
47 + }
48 + $theme_settings['global']['settings']['typography']['customFontSize'] = ! $settings['disableCustomFontSizes'];
51 49 }
52 50
53 - $theme_json_path = locate_template( 'experimental-theme.json' );
54 - $theme_json_global_styles = null;
55 - if ( $theme_json_path ) {
56 - $theme_json_global_styles = json_decode(
57 - file_get_contents( $theme_json_path ),
58 - true
59 - );
51 + if ( isset( $settings['enableCustomLineHeight'] ) ) {
52 + if ( ! isset( $theme_settings['global']['settings']['typography'] ) ) {
53 + $theme_settings['global']['settings']['typography'] = array();
54 + }
55 + $theme_settings['global']['settings']['typography']['customLineHeight'] = $settings['enableCustomLineHeight'];
60 56 }
61 57
62 - // To-do: Load user customizations from a CPT.
63 - $css_vars = array();
64 - foreach (
65 - array(
66 - $default_global_styles,
67 - $theme_json_global_styles,
68 - ) as $global_styles_definition
69 - ) {
70 - if ( ! $global_styles_definition ) {
71 - continue;
58 + if ( isset( $settings['enableCustomUnits'] ) ) {
59 + if ( ! isset( $theme_settings['global']['settings']['spacing'] ) ) {
60 + $theme_settings['global']['settings']['spacing'] = array();
72 61 }
73 - if ( isset( $global_styles_definition['global'] ) ) {
74 - $css_vars = array_merge(
75 - $css_vars,
76 - gutenberg_get_css_vars( $global_styles_definition['global'], '--wp-' )
77 - );
62 + $theme_settings['global']['settings']['spacing']['units'] = ( true === $settings['enableCustomUnits'] ) ?
63 + array( 'px', 'em', 'rem', 'vh', 'vw' ) :
64 + $settings['enableCustomUnits'];
65 + }
66 +
67 + if ( isset( $settings['colors'] ) ) {
68 + if ( ! isset( $theme_settings['global']['settings']['color'] ) ) {
69 + $theme_settings['global']['settings']['color'] = array();
78 70 }
79 - if ( isset( $global_styles_definition['blocks'] ) ) {
80 - $css_vars = array_merge(
81 - $css_vars,
82 - gutenberg_get_css_vars( $global_styles_definition['blocks'], '--wp-block-' )
83 - );
71 + $theme_settings['global']['settings']['color']['palette'] = $settings['colors'];
72 + }
73 +
74 + if ( isset( $settings['gradients'] ) ) {
75 + if ( ! isset( $theme_settings['global']['settings']['color'] ) ) {
76 + $theme_settings['global']['settings']['color'] = array();
84 77 }
78 + $theme_settings['global']['settings']['color']['gradients'] = $settings['gradients'];
85 79 }
86 80
87 - if ( empty( $css_vars ) ) {
81 + if ( isset( $settings['fontSizes'] ) ) {
82 + $font_sizes = $settings['fontSizes'];
83 + // Back-compatibility for presets without units.
84 + foreach ( $font_sizes as &$font_size ) {
85 + if ( is_numeric( $font_size['size'] ) ) {
86 + $font_size['size'] = $font_size['size'] . 'px';
87 + }
88 + }
89 + if ( ! isset( $theme_settings['global']['settings']['typography'] ) ) {
90 + $theme_settings['global']['settings']['typography'] = array();
91 + }
92 + $theme_settings['global']['settings']['typography']['fontSizes'] = $font_sizes;
93 + }
94 +
95 + // Things that didn't land in core yet, so didn't have a setting assigned.
96 + if ( current( (array) get_theme_support( 'custom-spacing' ) ) ) {
97 + if ( ! isset( $theme_settings['global']['settings']['spacing'] ) ) {
98 + $theme_settings['global']['settings']['spacing'] = array();
99 + }
100 + $theme_settings['global']['settings']['spacing']['customPadding'] = true;
101 + }
102 +
103 + if ( current( (array) get_theme_support( 'experimental-link-color' ) ) ) {
104 + if ( ! isset( $theme_settings['global']['settings']['color'] ) ) {
105 + $theme_settings['global']['settings']['color'] = array();
106 + }
107 + $theme_settings['global']['settings']['color']['link'] = true;
108 + }
109 +
110 + return $theme_settings;
111 +}
112 +
113 +/**
114 + * Takes a tree adhering to the theme.json schema and generates
115 + * the corresponding stylesheet.
116 + *
117 + * @param WP_Theme_JSON $tree Input tree.
118 + * @param string $type Type of stylesheet we want accepts 'all', 'block_styles', and 'css_variables'.
119 + *
120 + * @return string Stylesheet.
121 + */
122 +function gutenberg_experimental_global_styles_get_stylesheet( $tree, $type = 'all' ) {
123 + // Check if we can use cached.
124 + $can_use_cached = (
125 + ( 'all' === $type ) &&
126 + ( ! defined( 'WP_DEBUG' ) || ! WP_DEBUG ) &&
127 + ( ! defined( 'SCRIPT_DEBUG' ) || ! SCRIPT_DEBUG ) &&
128 + ( ! defined( 'REST_REQUEST' ) || ! REST_REQUEST ) &&
129 + ! is_admin()
130 + );
131 +
132 + if ( $can_use_cached ) {
133 + // Check if we have the styles already cached.
134 + $cached = get_transient( 'global_styles' );
135 + if ( $cached ) {
136 + return $cached;
137 + }
138 + }
139 +
140 + $stylesheet = $tree->get_stylesheet( $type );
141 +
142 + if ( ( 'all' === $type || 'block_styles' === $type ) && gutenberg_experimental_global_styles_has_theme_json_support() ) {
143 + // To support all themes, we added in the block-library stylesheet
144 + // a style rule such as .has-link-color a { color: var(--wp--style--color--link, #00e); }
145 + // so that existing link colors themes used didn't break.
146 + // We add this here to make it work for themes that opt-in to theme.json
147 + // In the future, we may do this differently.
148 + $stylesheet .= 'a{color:var(--wp--style--color--link, #00e);}';
149 + }
150 +
151 + if ( $can_use_cached ) {
152 + // Cache for a minute.
153 + // This cache doesn't need to be any longer, we only want to avoid spikes on high-traffic sites.
154 + set_transient( 'global_styles', $stylesheet, MINUTE_IN_SECONDS );
155 + }
156 +
157 + return $stylesheet;
158 +}
159 +
160 +/**
161 + * Fetches the preferences for each origin (core, theme, user)
162 + * and enqueues the resulting stylesheet.
163 + */
164 +function gutenberg_experimental_global_styles_enqueue_assets() {
165 + if ( ! gutenberg_experimental_global_styles_has_theme_json_support() ) {
88 166 return;
89 167 }
90 168
91 - $inline_style = ":root {\n";
92 - foreach ( $css_vars as $var => $value ) {
93 - $inline_style .= "\t" . $var . ': ' . $value . ";\n";
169 + $settings = gutenberg_get_common_block_editor_settings();
170 + $theme_support_data = gutenberg_experimental_global_styles_get_theme_support_settings( $settings );
171 +
172 + $resolver = new WP_Theme_JSON_Resolver();
173 + $all = $resolver->get_origin( $theme_support_data );
174 +
175 + $stylesheet = gutenberg_experimental_global_styles_get_stylesheet( $all );
176 + if ( empty( $stylesheet ) ) {
177 + return;
94 178 }
95 - $inline_style .= '}';
96 179
97 180 wp_register_style( 'global-styles', false, array(), true, true );
98 - wp_add_inline_style( 'global-styles', $inline_style );
181 + wp_add_inline_style( 'global-styles', $stylesheet );
99 182 wp_enqueue_style( 'global-styles' );
100 183 }
101 -add_action( 'enqueue_block_assets', 'gutenberg_enqueue_global_styles_assets' );
102 184
103 185 /**
104 - * Adds class wp-gs to the frontend body class if the theme defines a experimental-theme.json.
186 + * Adds the necessary data for the Global Styles client UI to the block settings.
105 187 *
106 - * @param array $classes Existing body classes.
107 - * @return array The filtered array of body classes.
188 + * @param array $settings Existing block editor settings.
189 + * @return array New block editor settings
108 190 */
109 -function gutenberg_add_wp_gs_class_front_end( $classes ) {
110 - if ( locate_template( 'experimental-theme.json' ) ) {
111 - return array_merge( $classes, array( 'wp-gs' ) );
191 +function gutenberg_experimental_global_styles_settings( $settings ) {
192 + $theme_support_data = gutenberg_experimental_global_styles_get_theme_support_settings( $settings );
193 + unset( $settings['colors'] );
194 + unset( $settings['disableCustomColors'] );
195 + unset( $settings['disableCustomFontSizes'] );
196 + unset( $settings['disableCustomGradients'] );
197 + unset( $settings['enableCustomLineHeight'] );
198 + unset( $settings['enableCustomUnits'] );
199 + unset( $settings['fontSizes'] );
200 + unset( $settings['gradients'] );
201 +
202 + $resolver = new WP_Theme_JSON_Resolver();
203 + $origin = 'theme';
204 + if (
205 + gutenberg_experimental_global_styles_has_theme_json_support() &&
206 + gutenberg_is_fse_theme()
207 + ) {
208 + // Only lookup for the user data if we need it.
209 + $origin = 'user';
112 210 }
113 - return $classes;
211 + $tree = $resolver->get_origin( $theme_support_data, $origin );
212 +
213 + // STEP 1: ADD FEATURES
214 + //
215 + // These need to be always added to the editor settings,
216 + // even for themes that don't support theme.json.
217 + // An example of this is that the presets are configured
218 + // from the theme support data.
219 + $settings['__experimentalFeatures'] = $tree->get_settings();
220 +
221 + // STEP 2 - IF EDIT-SITE, ADD DATA REQUIRED FOR GLOBAL STYLES SIDEBAR
222 + //
223 + // In the site editor, the user can change styles, so the client
224 + // needs the ability to create them. Hence, we pass it some data
225 + // for this: base styles (core+theme) and the ID of the user CPT.
226 + $screen = get_current_screen();
227 + if (
228 + ! empty( $screen ) &&
229 + function_exists( 'gutenberg_is_edit_site_page' ) &&
230 + gutenberg_is_edit_site_page( $screen->id ) &&
231 + gutenberg_experimental_global_styles_has_theme_json_support() &&
232 + gutenberg_is_fse_theme()
233 + ) {
234 + $user_cpt_id = WP_Theme_JSON_Resolver::get_user_custom_post_type_id();
235 + $base_styles = $resolver->get_origin( $theme_support_data, 'theme' )->get_raw_data();
236 +
237 + $settings['__experimentalGlobalStylesUserEntityId'] = $user_cpt_id;
238 + $settings['__experimentalGlobalStylesBaseStyles'] = $base_styles;
239 + } elseif ( gutenberg_experimental_global_styles_has_theme_json_support() ) {
240 + // STEP 3 - ADD STYLES IF THEME HAS SUPPORT
241 + //
242 + // If we are in a block editor context, but not in edit-site,
243 + // we add the styles via the settings, so the editor knows that
244 + // some of these should be added the wrapper class,
245 + // as if they were added via add_editor_styles.
246 + $settings['styles'][] = array(
247 + 'css' => gutenberg_experimental_global_styles_get_stylesheet( $tree, 'css_variables' ),
248 + '__experimentalNoWrapper' => true,
249 + );
250 + $settings['styles'][] = array(
251 + 'css' => gutenberg_experimental_global_styles_get_stylesheet( $tree, 'block_styles' ),
252 + );
253 + }
254 +
255 + return $settings;
114 256 }
115 -add_filter( 'body_class', 'gutenberg_add_wp_gs_class_front_end' );
116 257
117 -
118 258 /**
119 - * Adds class wp-gs to the block-editor body class if the theme defines a experimental-theme.json.
259 + * Register CPT to store/access user data.
120 260 *
121 - * @param string $classes Existing body classes separated by space.
122 - * @return string The filtered string of body classes.
261 + * @return array|undefined
123 262 */
124 -function gutenberg_add_wp_gs_class_editor( $classes ) {
125 - global $current_screen;
126 - if ( $current_screen->is_block_editor() && locate_template( 'experimental-theme.json' ) ) {
127 - return $classes . ' wp-gs';
263 +function gutenberg_experimental_global_styles_register_user_cpt() {
264 + if ( ! gutenberg_experimental_global_styles_has_theme_json_support() ) {
265 + return;
128 266 }
129 - return $classes;
267 +
268 + WP_Theme_JSON_Resolver::register_user_custom_post_type();
130 269 }
131 -add_filter( 'admin_body_class', 'gutenberg_add_wp_gs_class_editor' );
270 +
271 +add_action( 'init', 'gutenberg_experimental_global_styles_register_user_cpt' );
272 +add_filter( 'block_editor_settings', 'gutenberg_experimental_global_styles_settings', PHP_INT_MAX );
273 +add_action( 'wp_enqueue_scripts', 'gutenberg_experimental_global_styles_enqueue_assets' );