PluginProbe
Gutenberg / 11.9.1
Gutenberg v11.9.1
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 7.4.0 All 402 releases
gutenberg / lib / global-styles.php

global-styles.php in Gutenberg 11.9.1, at lib/global-styles.php

318 lines 10.9 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Bootstraps Global Styles.
4 *
5 * @package gutenberg
6 */
7
8 /**
9 * Fetches the preferences for each origin (core, theme, user)
10 * and enqueues the resulting stylesheet.
11 */
12 function gutenberg_experimental_global_styles_enqueue_assets() {
13 $stylesheet = gutenberg_get_global_stylesheet();
14 if ( empty( $stylesheet ) ) {
15 return;
16 }
17
18 if ( isset( wp_styles()->registered['global-styles'] ) ) {
19 wp_styles()->registered['global-styles']->extra['after'][0] = $stylesheet;
20 } else {
21 wp_register_style( 'global-styles', false, array(), true, true );
22 wp_add_inline_style( 'global-styles', $stylesheet );
23 wp_enqueue_style( 'global-styles' );
24 }
25 }
26
27 /**
28 * Adds the necessary settings for the Global Styles client UI.
29 *
30 * @param array $settings Existing block editor settings.
31 *
32 * @return array New block editor settings.
33 */
34 function gutenberg_experimental_global_styles_settings( $settings ) {
35 // Set what is the context for this data request.
36 $context = 'other';
37 if (
38 is_callable( 'get_current_screen' ) &&
39 function_exists( 'gutenberg_is_edit_site_page' ) &&
40 gutenberg_is_edit_site_page( get_current_screen()->id )
41 ) {
42 $context = 'site-editor';
43 }
44
45 if (
46 defined( 'REST_REQUEST' ) &&
47 REST_REQUEST &&
48 isset( $_GET['context'] ) &&
49 'mobile' === $_GET['context']
50 ) {
51 $context = 'mobile';
52 }
53
54 if ( 'mobile' === $context && WP_Theme_JSON_Resolver_Gutenberg::theme_has_support() ) {
55 $settings['__experimentalStyles'] = gutenberg_get_global_styles();
56 }
57
58 if ( 'other' === $context ) {
59 // Make sure the styles array exists.
60 // In some contexts, like the navigation editor, it doesn't.
61 if ( ! isset( $settings['styles'] ) ) {
62 $settings['styles'] = array();
63 }
64
65 // Reset existing global styles.
66 $styles_without_existing_global_styles = array();
67 foreach ( $settings['styles'] as $style ) {
68 if ( ! isset( $style['__unstableType'] ) || 'globalStyles' !== $style['__unstableType'] ) {
69 $styles_without_existing_global_styles[] = $style;
70 }
71 }
72
73 $new_global_styles = array();
74 $new_presets = array(
75 array(
76 'css' => 'variables',
77 '__unstableType' => 'presets',
78 '__experimentalNoWrapper' => true,
79 ),
80 array(
81 'css' => 'presets',
82 '__unstableType' => 'presets',
83 ),
84 );
85 foreach ( $new_presets as $new_style ) {
86 $style_css = gutenberg_get_global_stylesheet( array( $new_style['css'] ) );
87 if ( '' !== $style_css ) {
88 $new_style['css'] = $style_css;
89 $new_global_styles[] = $new_style;
90 }
91 }
92
93 $new_block_classes = array(
94 'css' => 'styles',
95 '__unstableType' => 'theme',
96 );
97 if ( WP_Theme_JSON_Resolver_Gutenberg::theme_has_support() ) {
98 $style_css = gutenberg_get_global_stylesheet( array( $new_block_classes['css'] ) );
99 if ( '' !== $style_css ) {
100 $new_block_classes['css'] = $style_css;
101 $new_global_styles[] = $new_block_classes;
102 }
103 }
104
105 $settings['styles'] = array_merge( $styles_without_existing_global_styles, $new_global_styles );
106 }
107
108 // Copied from get_block_editor_settings() at wordpress-develop/block-editor.php.
109 $settings['__experimentalFeatures'] = gutenberg_get_global_settings();
110
111 if ( isset( $settings['__experimentalFeatures']['color']['palette'] ) ) {
112 $colors_by_origin = $settings['__experimentalFeatures']['color']['palette'];
113 $settings['colors'] = isset( $colors_by_origin['user'] ) ?
114 $colors_by_origin['user'] : (
115 isset( $colors_by_origin['theme'] ) ?
116 $colors_by_origin['theme'] :
117 $colors_by_origin['core']
118 );
119 }
120
121 if ( isset( $settings['__experimentalFeatures']['color']['gradients'] ) ) {
122 $gradients_by_origin = $settings['__experimentalFeatures']['color']['gradients'];
123 $settings['gradients'] = isset( $gradients_by_origin['user'] ) ?
124 $gradients_by_origin['user'] : (
125 isset( $gradients_by_origin['theme'] ) ?
126 $gradients_by_origin['theme'] :
127 $gradients_by_origin['core']
128 );
129 }
130
131 if ( isset( $settings['__experimentalFeatures']['typography']['fontSizes'] ) ) {
132 $font_sizes_by_origin = $settings['__experimentalFeatures']['typography']['fontSizes'];
133 $settings['fontSizes'] = isset( $font_sizes_by_origin['user'] ) ?
134 $font_sizes_by_origin['user'] : (
135 isset( $font_sizes_by_origin['theme'] ) ?
136 $font_sizes_by_origin['theme'] :
137 $font_sizes_by_origin['core']
138 );
139 }
140
141 if ( isset( $settings['__experimentalFeatures']['color']['custom'] ) ) {
142 $settings['disableCustomColors'] = ! $settings['__experimentalFeatures']['color']['custom'];
143 unset( $settings['__experimentalFeatures']['color']['custom'] );
144 }
145 if ( isset( $settings['__experimentalFeatures']['color']['customGradient'] ) ) {
146 $settings['disableCustomGradients'] = ! $settings['__experimentalFeatures']['color']['customGradient'];
147 unset( $settings['__experimentalFeatures']['color']['customGradient'] );
148 }
149 if ( isset( $settings['__experimentalFeatures']['typography']['customFontSize'] ) ) {
150 $settings['disableCustomFontSizes'] = ! $settings['__experimentalFeatures']['typography']['customFontSize'];
151 unset( $settings['__experimentalFeatures']['typography']['customFontSize'] );
152 }
153 if ( isset( $settings['__experimentalFeatures']['typography']['lineHeight'] ) ) {
154 $settings['enableCustomLineHeight'] = $settings['__experimentalFeatures']['typography']['lineHeight'];
155 unset( $settings['__experimentalFeatures']['typography']['lineHeight'] );
156 }
157 if ( isset( $settings['__experimentalFeatures']['spacing']['units'] ) ) {
158 $settings['enableCustomUnits'] = $settings['__experimentalFeatures']['spacing']['units'];
159 }
160 if ( isset( $settings['__experimentalFeatures']['spacing']['padding'] ) ) {
161 $settings['enableCustomSpacing'] = $settings['__experimentalFeatures']['spacing']['padding'];
162 unset( $settings['__experimentalFeatures']['spacing']['padding'] );
163 }
164
165 return $settings;
166 }
167
168 /**
169 * Whether or not the Site Editor is available.
170 *
171 * @return boolean
172 */
173 function gutenberg_experimental_is_site_editor_available() {
174 return gutenberg_is_fse_theme();
175 }
176
177 /**
178 * Register CPT to store/access user data.
179 *
180 * @return void
181 */
182 function gutenberg_experimental_global_styles_register_user_cpt() {
183 if ( gutenberg_experimental_is_site_editor_available() ) {
184 WP_Theme_JSON_Resolver_Gutenberg::register_user_custom_post_type();
185 }
186 }
187
188 /**
189 * Sanitizes global styles user content removing unsafe rules.
190 *
191 * @param string $content Post content to filter.
192 * @return string Filtered post content with unsafe rules removed.
193 */
194 function gutenberg_global_styles_filter_post( $content ) {
195 $decoded_data = json_decode( wp_unslash( $content ), true );
196 $json_decoding_error = json_last_error();
197 if (
198 JSON_ERROR_NONE === $json_decoding_error &&
199 is_array( $decoded_data ) &&
200 isset( $decoded_data['isGlobalStylesUserThemeJSON'] ) &&
201 $decoded_data['isGlobalStylesUserThemeJSON']
202 ) {
203 unset( $decoded_data['isGlobalStylesUserThemeJSON'] );
204
205 $data_to_encode = WP_Theme_JSON_Gutenberg::remove_insecure_properties( $decoded_data );
206
207 $data_to_encode['isGlobalStylesUserThemeJSON'] = true;
208 return wp_slash( wp_json_encode( $data_to_encode ) );
209 }
210 return $content;
211 }
212
213 /**
214 * Adds the filters to filter global styles user theme.json.
215 */
216 function gutenberg_global_styles_kses_init_filters() {
217 add_filter( 'content_save_pre', 'gutenberg_global_styles_filter_post' );
218 add_filter( 'safe_style_css', 'gutenberg_global_styles_include_support_for_duotone', 10, 2 );
219 }
220
221 /**
222 * Removes the filters to filter global styles user theme.json.
223 */
224 function gutenberg_global_styles_kses_remove_filters() {
225 remove_filter( 'content_save_pre', 'gutenberg_global_styles_filter_post' );
226 }
227
228 /**
229 * Register global styles kses filters if the user does not have unfiltered_html capability.
230 *
231 * @uses render_block_core_navigation()
232 * @throws WP_Error An WP_Error exception parsing the block definition.
233 */
234 function gutenberg_global_styles_kses_init() {
235 gutenberg_global_styles_kses_remove_filters();
236 if ( ! current_user_can( 'unfiltered_html' ) ) {
237 gutenberg_global_styles_kses_init_filters();
238 }
239 }
240
241 /**
242 * This filter is the last being executed on force_filtered_html_on_import.
243 * If the input of the filter is true it means we are in an import situation and should
244 * enable kses, independently of the user capabilities.
245 * So in that case we call gutenberg_global_styles_kses_init_filters;
246 *
247 * @param string $arg Input argument of the filter.
248 * @return string Exactly what was passed as argument.
249 */
250 function gutenberg_global_styles_force_filtered_html_on_import_filter( $arg ) {
251 // force_filtered_html_on_import is true we need to init the global styles kses filters.
252 if ( $arg ) {
253 gutenberg_global_styles_kses_init_filters();
254 }
255 return $arg;
256 }
257
258 /**
259 * This filter is the last being executed on force_filtered_html_on_import.
260 * If the input of the filter is true it means we are in an import situation and should
261 * enable kses, independently of the user capabilities.
262 * So in that case we call gutenberg_global_styles_kses_init_filters;
263 *
264 * @param bool $allow_css Whether the CSS in the test string is considered safe.
265 * @param bool $css_test_string The CSS string to test..
266 * @return bool If $allow_css is true it returns true.
267 * If $allow_css is false and the CSS rule is referencing a WordPress css variable it returns true.
268 * Otherwise the function return false.
269 */
270 function gutenberg_global_styles_include_support_for_wp_variables( $allow_css, $css_test_string ) {
271 if ( $allow_css ) {
272 return $allow_css;
273 }
274 $allowed_preset_attributes = array(
275 'background',
276 'background-color',
277 'border-color',
278 'color',
279 'font-family',
280 'font-size',
281 );
282 $parts = explode( ':', $css_test_string, 2 );
283
284 if ( ! in_array( trim( $parts[0] ), $allowed_preset_attributes, true ) ) {
285 return $allow_css;
286 }
287 return ! ! preg_match( '/^var\(--wp-[a-zA-Z0-9\-]+\)$/', trim( $parts[1] ) );
288 }
289
290 /**
291 * This is for using kses to test user data.
292 *
293 * @param array $atts Allowed CSS property names, according to kses.
294 *
295 * @return array The new allowed CSS property names.
296 */
297 function gutenberg_global_styles_include_support_for_duotone( $atts ) {
298 $atts[] = 'filter';
299 return $atts;
300 }
301
302 // The else clause can be removed when plugin support requires WordPress 5.8.0+.
303 if ( function_exists( 'get_block_editor_settings' ) ) {
304 add_filter( 'block_editor_settings_all', 'gutenberg_experimental_global_styles_settings', PHP_INT_MAX );
305 } else {
306 add_filter( 'block_editor_settings', 'gutenberg_experimental_global_styles_settings', PHP_INT_MAX );
307 }
308
309 add_action( 'init', 'gutenberg_experimental_global_styles_register_user_cpt' );
310 add_action( 'wp_enqueue_scripts', 'gutenberg_experimental_global_styles_enqueue_assets' );
311
312 // kses actions&filters.
313 add_action( 'init', 'gutenberg_global_styles_kses_init' );
314 add_action( 'set_current_user', 'gutenberg_global_styles_kses_init' );
315 add_filter( 'force_filtered_html_on_import', 'gutenberg_global_styles_force_filtered_html_on_import_filter', 999 );
316 add_filter( 'safecss_filter_attr_allow_css', 'gutenberg_global_styles_include_support_for_wp_variables', 10, 2 );
317 // This filter needs to be executed last.
318