PluginProbe
Elementor Website Builder – more than just a page builder / 3.28.0-dev2
Elementor Website Builder – more than just a page builder v3.28.0-dev2
4.3.1 4.3.0 4.3.0-beta3 4.3.0-beta2 4.3.0-beta1 4.2.4 4.2.3 4.2.2 4.2.1 4.2.0 4.1.5 4.2.0-beta2 4.2.0-dev2 4.2.0-beta1 4.1.4 4.1.3 4.1.2 4.1.1 4.1.0 4.1.0-beta3 4.1.0-dev3 4.0.9 4.1.0-beta2 4.1.0-dev2 4.0.8 All 454 releases
← All changes | modules/atomic-widgets/parsers/style-parser.php +68 -170 4.3.0 → 3.28.0-dev2 View file →
@@ -5,21 +5,23 @@
5 5 if ( ! defined( 'ABSPATH' ) ) {
6 6 exit; // Exit if accessed directly.
7 7 }
8 8
9 -use Elementor\Modules\AtomicWidgets\OptIn\Opt_In;
10 -use Elementor\Plugin;
11 -use Elementor\Utils;
12 -use Elementor\Core\Utils\Api\Parse_Result;
13 -use Elementor\Modules\AtomicWidgets\Styles\Style_States;
14 -
15 9 class Style_Parser {
16 10 const VALID_TYPES = [
17 11 'class',
18 12 ];
19 13
14 + const VALID_STATES = [
15 + 'hover',
16 + 'active',
17 + 'focus',
18 + null,
19 + ];
20 20
21 21 private array $schema;
22 + private array $errors_bag = [];
23 + private $should_validate_id = true;
22 24
23 25 public function __construct( array $schema ) {
24 26 $this->schema = $schema;
25 27 }
@@ -27,40 +29,48 @@
27 29 public static function make( array $schema ): self {
28 30 return new static( $schema );
29 31 }
30 32
33 + public function without_id() {
34 + $this->should_validate_id = false;
35 +
36 + return $this;
37 + }
38 +
31 39 /**
32 40 * @param array $style
33 41 * the style object to validate
42 + *
43 + * @return array{
44 + * 0: bool,
45 + * 1: array<string, mixed>,
46 + * 2: array<string>
47 + * }
34 48 */
35 - private function validate( array $style ): Parse_Result {
49 + public function validate( array $style ): array {
36 50 $validated_style = $style;
37 - $result = Parse_Result::make();
38 51
39 - if ( ! isset( $style['id'] ) || ! is_string( $style['id'] ) ) {
40 - $result->errors()->add( 'id', 'missing_or_invalid' );
52 + if ( $this->should_validate_id && ( ! isset( $style['id'] ) || ! is_string( $style['id'] ) ) ) {
53 + $this->errors_bag[] = 'id';
41 54 }
42 55
43 56 if ( ! isset( $style['type'] ) || ! in_array( $style['type'], self::VALID_TYPES, true ) ) {
44 - $result->errors()->add( 'type', 'missing_or_invalid' );
57 + $this->errors_bag[] = 'type';
45 58 }
46 59
47 60 if ( ! isset( $style['label'] ) || ! is_string( $style['label'] ) ) {
48 - $result->errors()->add( 'label', 'missing_or_invalid' );
49 - } elseif ( Plugin::$instance->experiments->is_feature_active( Opt_In::EXPERIMENT_NAME ) ) {
50 - $label_validation = $this->validate_style_label( $style['label'] );
51 -
52 - if ( ! $label_validation['is_valid'] ) {
53 - $result->errors()->add( 'label', $label_validation['error_message'] );
54 - }
61 + $this->errors_bag[] = 'label';
55 62 }
56 63
57 64 if ( ! isset( $style['variants'] ) || ! is_array( $style['variants'] ) ) {
58 - $result->errors()->add( 'variants', 'missing_or_invalid' );
59 -
65 + $this->errors_bag[] = 'variants';
60 66 unset( $validated_style['variants'] );
61 67
62 - return $result->wrap( $validated_style );
68 + return [
69 + false,
70 + $validated_style,
71 + $this->errors_bag,
72 + ];
63 73 }
64 74
65 75 $props_parser = Props_Parser::make( $this->schema );
66 76
@@ -65,199 +75,87 @@
65 75 $props_parser = Props_Parser::make( $this->schema );
66 76
67 77 foreach ( $style['variants'] as $variant_index => $variant ) {
68 78 if ( ! isset( $variant['meta'] ) ) {
69 - $result->errors()->add( 'meta', 'missing' );
70 -
79 + $this->errors_bag[] = 'meta';
71 80 continue;
72 81 }
73 82
74 - $meta_result = $this->validate_meta( $variant['meta'] );
75 - $custom_css_result = $this->validate_custom_css( $variant );
83 + $is_variant_meta_valid = $this->validate_meta( $variant['meta'] );
76 84
77 - $result->errors()->merge( $meta_result->errors(), 'meta' );
78 - $result->errors()->merge( $custom_css_result->errors(), 'custom_css' );
85 + if ( $is_variant_meta_valid ) {
86 + [, $validated_props, $variant_errors] = $props_parser->validate( $variant['props'] );
87 + $this->errors_bag = array_merge( $this->errors_bag, $variant_errors );
79 88
80 - if ( $meta_result->is_valid() ) {
81 - $variant_result = $props_parser->validate( $variant['props'] );
82 -
83 - $result->errors()->merge( $variant_result->errors(), "variants[$variant_index]" );
84 -
85 - $validated_style['variants'][ $variant_index ]['props'] = $variant_result->unwrap();
89 + $validated_style['variants'][ $variant_index ]['props'] = $validated_props;
86 90 } else {
87 91 unset( $validated_style['variants'][ $variant_index ] );
88 92 }
89 93 }
90 94
91 - return $result->wrap( $validated_style );
92 - }
95 + $is_valid = empty( $this->errors_bag );
93 96
94 - private function validate_style_label( string $label ): array {
95 - $label = strtolower( $label );
96 -
97 - $reserved_class_names = [ 'container' ];
98 -
99 - if ( strlen( $label ) > 50 ) {
100 - return [
101 - 'is_valid' => false,
102 - 'error_message' => 'class_name_too_long',
103 - ];
104 - }
105 -
106 - if ( strlen( $label ) < 2 ) {
107 - return [
108 - 'is_valid' => false,
109 - 'error_message' => 'class_name_too_short',
110 - ];
111 - }
112 -
113 - if ( in_array( $label, $reserved_class_names, true ) ) {
114 - return [
115 - 'is_valid' => false,
116 - 'error_message' => 'reserved_class_name',
117 - ];
118 - }
119 -
120 - $regexes = [
121 - [
122 - 'pattern' => '/^(|[^0-9].*)$/',
123 - 'message' => 'class_name_starts_with_digit',
124 - ],
125 - [
126 - 'pattern' => '/^\S*$/',
127 - 'message' => 'class_name_contains_spaces',
128 - ],
129 - [
130 - 'pattern' => '/^(|[a-zA-Z0-9_-]+)$/',
131 - 'message' => 'class_name_invalid_chars',
132 - ],
133 - [
134 - 'pattern' => '/^(?!--).*/',
135 - 'message' => 'class_name_double_hyphen',
136 - ],
137 - [
138 - 'pattern' => '/^(?!-[0-9])/',
139 - 'message' => 'class_name_starts_with_hyphen_digit',
140 - ],
141 - ];
142 -
143 - foreach ( $regexes as $rule ) {
144 - if ( ! preg_match( $rule['pattern'], $label ) ) {
145 - return [
146 - 'is_valid' => false,
147 - 'error_message' => $rule['message'],
148 - ];
149 - }
150 - }
151 97 return [
152 - 'is_valid' => true,
153 - 'error_message' => null,
98 + $is_valid,
99 + $validated_style,
100 + $this->errors_bag,
154 101 ];
155 102 }
156 103
157 - private function validate_meta( $meta ): Parse_Result {
158 - $result = Parse_Result::make();
159 -
104 + public function validate_meta( $meta ): bool {
160 105 if ( ! is_array( $meta ) ) {
161 - $result->errors()->add( 'meta', 'invalid_type' );
162 -
163 - return $result;
106 + $this->errors_bag[] = 'meta';
107 + return false;
164 108 }
165 109
166 - if ( ! array_key_exists( 'state', $meta ) || ! Style_States::is_valid_state( $meta['state'] ) ) {
167 - $result->errors()->add( 'state', 'missing_or_invalid_value' );
168 -
169 - return $result;
110 + if ( ! array_key_exists( 'state', $meta ) || ! in_array( $meta['state'], self::VALID_STATES, true ) ) {
111 + $this->errors_bag[] = 'meta';
112 + return false;
170 113 }
171 114
172 115 // TODO: Validate breakpoint based on the existing breakpoints in the system [EDS-528]
173 116 if ( ! isset( $meta['breakpoint'] ) || ! is_string( $meta['breakpoint'] ) ) {
174 - $result->errors()->add( 'breakpoint', 'missing_or_invalid_value' );
175 -
176 - return $result;
117 + $this->errors_bag[] = 'meta';
118 + return false;
177 119 }
178 120
179 - return $result;
121 + return true;
180 122 }
181 123
182 - private function validate_custom_css( array $variant ): Parse_Result {
183 - $result = Parse_Result::make();
184 -
185 - if ( ! empty( $variant['custom_css']['raw'] ) && (
186 - ! is_string( $variant['custom_css']['raw'] ) ||
187 - null === Utils::decode_string( $variant['custom_css']['raw'], null )
188 - )
189 - ) {
190 - $result->errors()->add( 'custom_css', 'invalid_type' );
191 - }
192 -
193 - return $result;
194 - }
195 -
196 - private function sanitize_meta( $meta ) {
197 - if ( ! is_array( $meta ) ) {
198 - return [];
199 - }
200 -
201 - if ( isset( $meta['breakpoint'] ) ) {
202 - $meta['breakpoint'] = sanitize_key( $meta['breakpoint'] );
203 - }
204 -
205 - return $meta;
206 - }
207 -
208 - private function sanitize_custom_css( array $variant ) {
209 - if ( empty( $variant['custom_css']['raw'] ) ) {
210 - return null;
211 - }
212 -
213 - $custom_css = Utils::decode_string( $variant['custom_css']['raw'] );
214 - $custom_css = sanitize_textarea_field( $custom_css );
215 - $custom_css = [ 'raw' => Utils::encode_string( $custom_css ) ];
216 -
217 - return empty( $custom_css['raw'] ) ? null : $custom_css;
218 - }
219 -
220 124 /**
221 125 * @param array $style
222 126 * the style object to sanitize
127 + *
128 + * @return array<string, mixed>
223 129 */
224 - private function sanitize( array $style ): Parse_Result {
130 + public function sanitize( array $style ): array {
225 131 $props_parser = Props_Parser::make( $this->schema );
226 132
227 - if ( isset( $style['label'] ) ) {
228 - $style['label'] = sanitize_text_field( $style['label'] );
229 - }
230 -
231 - if ( isset( $style['id'] ) ) {
232 - $style['id'] = sanitize_key( $style['id'] );
233 - }
234 -
235 - if ( isset( $style['sync_to_v3'] ) ) {
236 - $style['sync_to_v3'] = (bool) $style['sync_to_v3'];
237 - }
238 -
239 133 if ( ! empty( $style['variants'] ) ) {
240 134 foreach ( $style['variants'] as $variant_index => $variant ) {
241 - $style['variants'][ $variant_index ]['props'] = $props_parser->sanitize( $variant['props'] )->unwrap();
242 - $style['variants'][ $variant_index ]['meta'] = $this->sanitize_meta( $variant['meta'] );
243 - $style['variants'][ $variant_index ]['custom_css'] = $this->sanitize_custom_css( $variant );
135 + $style['variants'][ $variant_index ]['props'] = $props_parser->sanitize( $variant['props'] );
244 136 }
245 137 }
246 138
247 - return Parse_Result::make()->wrap( $style );
139 + return $style;
248 140 }
249 141
250 142 /**
251 143 * @param array $style
252 144 * the style object to parse
145 + *
146 + * @return array{
147 + * 0: bool,
148 + * 1: array<string, mixed>,
149 + * 2: array<string>
150 + * }
253 151 */
254 - public function parse( array $style ): Parse_Result {
255 - $validate_result = $this->validate( $style );
152 + public function parse( array $style ): array {
153 + [ $is_valid, $validated, $errors_bag ] = $this->validate( $style );
256 154
257 - $sanitize_result = $this->sanitize( $validate_result->unwrap() );
258 -
259 - $sanitize_result->errors()->merge( $validate_result->errors() );
260 -
261 - return $sanitize_result;
155 + return [
156 + $is_valid,
157 + $this->sanitize( $validated ),
158 + $errors_bag,
159 + ];
262 160 }
263 161 }