PluginProbe
Gutenberg / 23.5.3
Gutenberg v23.5.3
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 / experimental / kses.php

kses.php in Gutenberg 23.5.3, at lib/experimental/kses.php

163 lines 6.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Temporary compatibility shims for kses rules present in Gutenberg.
4 *
5 * The functions in this file should not be backported to core.
6 *
7 * @package gutenberg
8 */
9
10 /**
11 * Sanitizes global styles user content removing unsafe rules.
12 *
13 * This function is identical to the core version, but called the
14 * Gutenberg version of the theme JSON class (`WP_Theme_JSON_Gutenberg`).
15 *
16 * This function should not be backported to core.
17 *
18 * @since 5.9.0
19 *
20 * @param string $data Post content to filter.
21 * @return string Filtered post content with unsafe rules removed.
22 */
23 function gutenberg_filter_global_styles_post( $data ) {
24 $decoded_data = json_decode( wp_unslash( $data ), true );
25 $json_decoding_error = json_last_error();
26 if (
27 JSON_ERROR_NONE === $json_decoding_error &&
28 is_array( $decoded_data ) &&
29 isset( $decoded_data['isGlobalStylesUserThemeJSON'] ) &&
30 $decoded_data['isGlobalStylesUserThemeJSON']
31 ) {
32 unset( $decoded_data['isGlobalStylesUserThemeJSON'] );
33
34 $data_to_encode = WP_Theme_JSON_Gutenberg::remove_insecure_properties( $decoded_data, 'custom' );
35
36 $data_to_encode['isGlobalStylesUserThemeJSON'] = true;
37 /**
38 * JSON encode the data stored in post content.
39 * Escape characters that are likely to be mangled by HTML filters: "<>&".
40 *
41 * This matches the escaping in {@see WP_REST_Global_Styles_Controller_Gutenberg::prepare_item_for_database()}.
42 */
43 return wp_slash( wp_json_encode( $data_to_encode, JSON_UNESCAPED_SLASHES | JSON_HEX_TAG | JSON_HEX_AMP ) );
44 }
45 return $data;
46 }
47
48 /**
49 * Override core's kses_init_filters hooks for global styles,
50 * and use Gutenberg's version instead. This ensures that
51 * Gutenberg's `remove_insecure_properties` function can be called.
52 *
53 * The hooks are only set if they are already added, which ensures
54 * that global styles is only filtered for users without the `unfiltered_html`
55 * capability.
56 *
57 * This function should not be backported to core.
58 */
59 function gutenberg_override_core_kses_init_filters() {
60 if ( has_filter( 'content_save_pre', 'wp_filter_global_styles_post' ) ) {
61 remove_filter( 'content_save_pre', 'wp_filter_global_styles_post', 9 );
62 add_filter( 'content_save_pre', 'gutenberg_filter_global_styles_post', 9 );
63 }
64
65 if ( has_filter( 'content_filtered_save_pre', 'wp_filter_global_styles_post' ) ) {
66 remove_filter( 'content_filtered_save_pre', 'wp_filter_global_styles_post', 9 );
67 add_filter( 'content_filtered_save_pre', 'gutenberg_filter_global_styles_post', 9 );
68 }
69 }
70 // The 'kses_init_filters' is usually initialized with default priority. Use higher priority to override.
71 add_action( 'init', 'gutenberg_override_core_kses_init_filters', 20 );
72 add_action( 'set_current_user', 'gutenberg_override_core_kses_init_filters' );
73
74 if ( ! function_exists( 'allow_filter_in_styles' ) ) {
75 /**
76 * See https://github.com/WordPress/wordpress-develop/pull/4108
77 *
78 * Mark CSS safe if it contains a "filter: url('#wp-duotone-...')" rule.
79 *
80 * This function should not be backported to core.
81 *
82 * @param bool $allow_css Whether the CSS is allowed.
83 * @param string $css_test_string The CSS to test.
84 * @return bool Whether the CSS is allowed.
85 */
86 function allow_filter_in_styles( $allow_css, $css_test_string ) {
87 if ( preg_match(
88 "/^filter:\s*url\((['\"]?)#wp-duotone-[-a-zA-Z0-9]+\\1\)(\s+!important)?$/",
89 $css_test_string
90 ) ) {
91 return true;
92 }
93 return $allow_css;
94 }
95 }
96 add_filter( 'safecss_filter_attr_allow_css', 'allow_filter_in_styles', 10, 2 );
97
98 /**
99 * Allow combined gradient and url() background-image values in inline styles.
100 *
101 * WordPress's safecss_filter_attr() handles gradient and url() values
102 * separately for background-image, but fails when both appear in a single
103 * comma-separated declaration. The url() portion is stripped from the test
104 * string before the filter runs, but the gradient regex in core expects the
105 * gradient to be the only value and doesn't match when a trailing comma and
106 * whitespace remain. This leaves parentheses in the test string, which
107 * triggers the unsafe-character check.
108 *
109 * This filter catches that case: the test string still contains a valid
110 * gradient function with only commas and whitespace remaining after the
111 * url() was removed.
112 *
113 * @param bool $allow_css Whether the CSS is allowed.
114 * @param string $css_test_string The CSS declaration to test.
115 * @return bool Whether the CSS is allowed.
116 */
117 function gutenberg_allow_background_image_combined( $allow_css, $css_test_string ) {
118 if ( $allow_css ) {
119 return $allow_css;
120 }
121 /*
122 * The test string at this point has url() values already removed by
123 * safecss_filter_attr. What remains is a gradient with comma/whitespace
124 * residue where the url() was stripped. Two possible forms:
125 *
126 * Gradient first: "background-image:<gradient>(...), "
127 * URL first: "background-image:, <gradient>(...)"
128 *
129 * A trailing or leading comma (with optional whitespace) must be present
130 * to confirm a url() was actually removed. Without that residue, the
131 * gradient alone would already pass core's own check.
132 */
133 $gradient_pattern = '(?:linear|radial|conic|repeating-linear|repeating-radial|repeating-conic)-gradient\((?:[^()]|\([^()]*\))*\)';
134 $var_pattern = 'var\(--[a-zA-Z0-9_-]+(?:--[a-zA-Z0-9_-]+)*\)';
135 $value_pattern = "(?:$gradient_pattern|$var_pattern)";
136
137 // Gradient/var first, then comma+whitespace residue from stripped url().
138 $pattern_gradient_first = '/^background-image\s*:\s*' . $value_pattern . '\s*,[\s,]*$/';
139 // Stripped url() first (comma+whitespace residue), then gradient/var.
140 $pattern_url_first = '/^background-image\s*:[\s,]*,\s*' . $value_pattern . '\s*$/';
141
142 if ( preg_match( $pattern_gradient_first, $css_test_string ) || preg_match( $pattern_url_first, $css_test_string ) ) {
143 return true;
144 }
145
146 return $allow_css;
147 }
148 add_filter( 'safecss_filter_attr_allow_css', 'gutenberg_allow_background_image_combined', 10, 2 );
149
150 /**
151 * Update allowed inline style attributes list.
152 *
153 * @param string[] $attrs Array of allowed CSS attributes.
154 * @return string[] CSS attributes.
155 */
156 function gutenberg_safe_grid_attrs( $attrs ) {
157 $attrs[] = 'grid-column';
158 $attrs[] = 'grid-row';
159 $attrs[] = 'container-type';
160 return $attrs;
161 }
162 add_filter( 'safe_style_css', 'gutenberg_safe_grid_attrs' );
163