PluginProbe
Elementor Website Builder – more than just a page builder / 3.27.4
Elementor Website Builder – more than just a page builder v3.27.4
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 4.1.0-beta1 4.1.0-dev1 All 452 releases
← All changes | modules/atomic-widgets/parsers/style-parser.php +65 -179 4.2.43.27.4 View file →
@@ -5,21 +5,19 @@
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 - const VALID_TYPES = [
17 - 'class',
10 + const VALID_STATES = [
11 + 'hover',
12 + 'active',
13 + 'focus',
14 + null,
18 15 ];
19 16
20 -
21 17 private array $schema;
18 + private array $errors_bag = [];
19 + private $should_validate_id = true;
22 20
23 21 public function __construct( array $schema ) {
24 22 $this->schema = $schema;
25 23 }
@@ -27,40 +25,40 @@
27 25 public static function make( array $schema ): self {
28 26 return new static( $schema );
29 27 }
30 28
29 + public function without_id() {
30 + $this->should_validate_id = false;
31 +
32 + return $this;
33 + }
34 +
31 35 /**
32 36 * @param array $style
33 37 * the style object to validate
38 + *
39 + * @return array{
40 + * 0: bool,
41 + * 1: array<string, mixed>,
42 + * 2: array<string>
43 + * }
34 44 */
35 - private function validate( array $style ): Parse_Result {
45 + public function validate( array $style ): array {
36 46 $validated_style = $style;
37 - $result = Parse_Result::make();
38 47
39 - if ( ! isset( $style['id'] ) || ! is_string( $style['id'] ) ) {
40 - $result->errors()->add( 'id', 'missing_or_invalid' );
48 + if ( $this->should_validate_id && ( ! isset( $style['id'] ) || ! is_string( $style['id'] ) ) ) {
49 + $this->errors_bag[] = 'id';
41 50 }
42 51
43 - if ( ! isset( $style['type'] ) || ! in_array( $style['type'], self::VALID_TYPES, true ) ) {
44 - $result->errors()->add( 'type', 'missing_or_invalid' );
45 - }
46 -
47 - 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 - }
55 - }
56 -
57 52 if ( ! isset( $style['variants'] ) || ! is_array( $style['variants'] ) ) {
58 - $result->errors()->add( 'variants', 'missing_or_invalid' );
59 -
53 + $this->errors_bag[] = 'variants';
60 54 unset( $validated_style['variants'] );
61 55
62 - return $result->wrap( $validated_style );
56 + return [
57 + false,
58 + $validated_style,
59 + $this->errors_bag,
60 + ];
63 61 }
64 62
65 63 $props_parser = Props_Parser::make( $this->schema );
66 64
@@ -65,199 +63,87 @@
65 63 $props_parser = Props_Parser::make( $this->schema );
66 64
67 65 foreach ( $style['variants'] as $variant_index => $variant ) {
68 66 if ( ! isset( $variant['meta'] ) ) {
69 - $result->errors()->add( 'meta', 'missing' );
70 -
67 + $this->errors_bag[] = 'meta';
71 68 continue;
72 69 }
73 70
74 - $meta_result = $this->validate_meta( $variant['meta'] );
75 - $custom_css_result = $this->validate_custom_css( $variant );
71 + $is_variant_meta_valid = $this->validate_meta( $variant['meta'] );
76 72
77 - $result->errors()->merge( $meta_result->errors(), 'meta' );
78 - $result->errors()->merge( $custom_css_result->errors(), 'custom_css' );
73 + if ( $is_variant_meta_valid ) {
74 + [, $validated_props, $variant_errors] = $props_parser->validate( $variant['props'] );
75 + $this->errors_bag = array_merge( $this->errors_bag, $variant_errors );
79 76
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();
77 + $validated_style['variants'][ $variant_index ]['props'] = $validated_props;
86 78 } else {
87 79 unset( $validated_style['variants'][ $variant_index ] );
88 80 }
89 81 }
90 82
91 - return $result->wrap( $validated_style );
92 - }
83 + $is_valid = empty( $this->errors_bag );
93 84
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 85 return [
152 - 'is_valid' => true,
153 - 'error_message' => null,
86 + $is_valid,
87 + $validated_style,
88 + $this->errors_bag,
154 89 ];
155 90 }
156 91
157 - private function validate_meta( $meta ): Parse_Result {
158 - $result = Parse_Result::make();
159 -
92 + public function validate_meta( $meta ): bool {
160 93 if ( ! is_array( $meta ) ) {
161 - $result->errors()->add( 'meta', 'invalid_type' );
162 -
163 - return $result;
94 + $this->errors_bag[] = 'meta';
95 + return false;
164 96 }
165 97
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;
98 + if ( ! array_key_exists( 'state', $meta ) || ! in_array( $meta['state'], self::VALID_STATES, true ) ) {
99 + $this->errors_bag[] = 'meta';
100 + return false;
170 101 }
171 102
172 103 // TODO: Validate breakpoint based on the existing breakpoints in the system [EDS-528]
173 104 if ( ! isset( $meta['breakpoint'] ) || ! is_string( $meta['breakpoint'] ) ) {
174 - $result->errors()->add( 'breakpoint', 'missing_or_invalid_value' );
175 -
176 - return $result;
105 + $this->errors_bag[] = 'meta';
106 + return false;
177 107 }
178 108
179 - return $result;
109 + return true;
180 110 }
181 111
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 112 /**
221 113 * @param array $style
222 114 * the style object to sanitize
115 + *
116 + * @return array<string, mixed>
223 117 */
224 - private function sanitize( array $style ): Parse_Result {
118 + public function sanitize( array $style ): array {
225 119 $props_parser = Props_Parser::make( $this->schema );
226 120
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 121 if ( ! empty( $style['variants'] ) ) {
240 122 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 );
123 + $style['variants'][ $variant_index ]['props'] = $props_parser->sanitize( $variant['props'] );
244 124 }
245 125 }
246 126
247 - return Parse_Result::make()->wrap( $style );
127 + return $style;
248 128 }
249 129
250 130 /**
251 131 * @param array $style
252 132 * the style object to parse
133 + *
134 + * @return array{
135 + * 0: bool,
136 + * 1: array<string, mixed>,
137 + * 2: array<string>
138 + * }
253 139 */
254 - public function parse( array $style ): Parse_Result {
255 - $validate_result = $this->validate( $style );
140 + public function parse( array $style ): array {
141 + [ $is_valid, $validated, $errors_bag ] = $this->validate( $style );
256 142
257 - $sanitize_result = $this->sanitize( $validate_result->unwrap() );
258 -
259 - $sanitize_result->errors()->merge( $validate_result->errors() );
260 -
261 - return $sanitize_result;
143 + return [
144 + $is_valid,
145 + $this->sanitize( $validated ),
146 + $errors_bag,
147 + ];
262 148 }
263 149 }