PluginProbe
Elementor Website Builder – more than just a page builder / 3.35.0-dev4
Elementor Website Builder – more than just a page builder v3.35.0-dev4
4.3.2 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 All 455 releases
← All changes | modules/atomic-widgets/elements/base/has-atomic-base.php +164 -212 4.3.0-beta2 → 3.35.0-dev4 View file →
@@ -4,11 +4,8 @@
4 4
5 5 use Elementor\Element_Base;
6 6 use Elementor\Modules\AtomicWidgets\Controls\Base\Atomic_Control_Base;
7 7 use Elementor\Modules\AtomicWidgets\Controls\Section;
8 -use Elementor\Modules\AtomicWidgets\Elements\Atomic_Form\Atomic_Form;
9 -use Elementor\Modules\AtomicWidgets\Elements\Loader\Frontend_Assets_Loader;
10 -use Elementor\Modules\AtomicWidgets\Logger\Logger;
11 8 use Elementor\Modules\AtomicWidgets\PropsResolver\Render_Props_Resolver;
12 9 use Elementor\Modules\AtomicWidgets\PropTypes\Contracts\Prop_Type;
13 10 use Elementor\Modules\AtomicWidgets\Styles\Style_Schema;
14 11 use Elementor\Modules\AtomicWidgets\Parsers\Props_Parser;
@@ -16,12 +13,10 @@
16 13 use Elementor\Modules\AtomicWidgets\PropTypes\Attributes_Prop_Type;
17 14 use Elementor\Modules\AtomicWidgets\PropTypes\Key_Value_Prop_Type;
18 15 use Elementor\Modules\AtomicWidgets\PropTypes\Link_Prop_Type;
19 16 use Elementor\Modules\AtomicWidgets\PropTypes\Primitives\String_Prop_Type;
20 -use Elementor\Modules\AtomicWidgets\PropTypes\Prop_Duplication_Behavior;
21 17 use Elementor\Utils;
22 18 use Elementor\Modules\Components\PropTypes\Overridable_Prop_Type;
23 -use Elementor\Modules\AtomicWidgets\Styles\Atomic_Widget_Styles;
24 19
25 20 if ( ! defined( 'ABSPATH' ) ) {
26 21 exit; // Exit if accessed directly.
27 22 }
@@ -30,20 +25,9 @@
30 25 * @mixin Element_Base
31 26 */
32 27 trait Has_Atomic_Base {
33 28 use Has_Base_Styles;
34 - use Has_Base_Settings;
35 29
36 - public static function html_tag_follows_link(): bool {
37 - return true;
38 - }
39 -
40 - public static function get_computed_html_tag( array $settings ): string {
41 - return Html_Tag_Computer::compute( $settings, 'div', [
42 - Html_Tag_Computer::FOLLOW_LINK_OPTION => static::html_tag_follows_link(),
43 - ] );
44 - }
45 -
46 30 public function has_widget_inner_wrapper(): bool {
47 31 return false;
48 32 }
49 33
@@ -100,74 +84,23 @@
100 84
101 85 private function parse_atomic_styles( array $data ): array {
102 86 $styles = $data['styles'] ?? [];
103 87 $style_parser = Style_Parser::make( Style_Schema::get() );
104 - $validated_styles = [];
105 88
106 89 foreach ( $styles as $style_id => $style ) {
107 90 $result = $style_parser->parse( $style );
108 91
109 92 if ( ! $result->is_valid() ) {
110 - Logger::warning(
111 - $this->format_styles_validation_error_message(
112 - $style_id,
113 - $data,
114 - $style,
115 - $result->errors()->to_string()
116 - )
117 - );
118 - continue;
93 + $widget_id = $data['id'] ?? 'unknown';
94 + throw new \Exception( esc_html( "Styles validation failed for style `$style_id`. Widget ID: `$widget_id`. " . $result->errors()->to_string() ) );
119 95 }
120 96
121 - $validated_styles[ $style_id ] = $result->unwrap();
97 + $styles[ $style_id ] = $result->unwrap();
122 98 }
123 99
124 - return $validated_styles;
100 + return $styles;
125 101 }
126 102
127 - private function format_styles_validation_error_message(
128 - string $style_id,
129 - array $data,
130 - array $style,
131 - string $validation_errors
132 - ): string {
133 - $widget_id = $data['id'] ?? 'unknown';
134 - $structure_label = $this->get_editor_structure_label( $data );
135 - $style_label = isset( $style['label'] ) && is_string( $style['label'] ) ? $style['label'] : null;
136 -
137 - $message_parts = [
138 - "Styles validation failed for style `$style_id` (widget `$widget_id`)",
139 - ];
140 -
141 - if ( $structure_label ) {
142 - $message_parts[] = "Structure label: `$structure_label`";
143 - } else {
144 - $element_name = $this->get_title();
145 -
146 - if ( '' === $element_name ) {
147 - $element_name = $this->get_name();
148 - }
149 -
150 - $message_parts[] = "Element: `$element_name`";
151 - }
152 -
153 - if ( $style_label ) {
154 - $message_parts[] = "Style label: `$style_label`";
155 - }
156 -
157 - return implode( '. ', $message_parts ) . '. ' . $validation_errors;
158 - }
159 -
160 - private function get_editor_structure_label( array $data ): ?string {
161 - $title = $data['editor_settings']['title'] ?? $this->editor_settings['title'] ?? null;
162 -
163 - if ( ! is_string( $title ) || '' === $title ) {
164 - return null;
165 - }
166 -
167 - return $title;
168 - }
169 -
170 103 private function parse_atomic_settings( array $settings ): array {
171 104 $schema = static::get_props_schema();
172 105 $props_parser = Props_Parser::make( $schema );
173 106
@@ -199,8 +132,67 @@
199 132
200 133 return [];
201 134 }
202 135
136 + private function convert_prop_type_interactions_to_legacy( $interactions ) {
137 + $legacy_items = [];
138 +
139 + foreach ( $interactions['items'] as $item ) {
140 + if ( isset( $item['$$type'] ) && 'interaction-item' === $item['$$type'] ) {
141 + $legacy_item = $this->extract_legacy_interaction_from_prop_type( $item );
142 + if ( $legacy_item ) {
143 + $legacy_items[] = $legacy_item;
144 + }
145 + } else {
146 + $legacy_items[] = $item;
147 + }
148 + }
149 +
150 + return [
151 + 'version' => $interactions['version'] ?? 1,
152 + 'items' => $legacy_items,
153 + ];
154 + }
155 +
156 + private function extract_legacy_interaction_from_prop_type( $item ) {
157 + if ( ! isset( $item['value'] ) || ! is_array( $item['value'] ) ) {
158 + return null;
159 + }
160 +
161 + $item_value = $item['value'];
162 +
163 + $interaction_id = $this->extract_prop_value( $item_value, 'interaction_id' );
164 + $trigger = $this->extract_prop_value( $item_value, 'trigger' );
165 + $animation = $this->extract_prop_value( $item_value, 'animation' );
166 +
167 + if ( ! is_array( $animation ) ) {
168 + return null;
169 + }
170 +
171 + $effect = $this->extract_prop_value( $animation, 'effect' );
172 + $type = $this->extract_prop_value( $animation, 'type' );
173 + $direction = $this->extract_prop_value( $animation, 'direction' );
174 + $timing_config = $this->extract_prop_value( $animation, 'timing_config' );
175 +
176 + $duration = 300;
177 + $delay = 0;
178 +
179 + if ( is_array( $timing_config ) ) {
180 + $duration = $this->extract_prop_value( $timing_config, 'duration', 300 );
181 + $delay = $this->extract_prop_value( $timing_config, 'delay', 0 );
182 + }
183 +
184 + $animation_id = implode( '-', [ $trigger, $effect, $type, $direction, $duration, $delay ] );
185 +
186 + return [
187 + 'interaction_id' => $interaction_id,
188 + 'animation' => [
189 + 'animation_id' => $animation_id,
190 + 'animation_type' => 'full-preset',
191 + ],
192 + ];
193 + }
194 +
203 195 private function extract_prop_value( $data, $key, $default = '' ) {
204 196 if ( ! is_array( $data ) || ! isset( $data[ $key ] ) ) {
205 197 return $default;
206 198 }
@@ -247,45 +239,20 @@
247 239 final public function get_data_for_save() {
248 240 $data = parent::get_data_for_save();
249 241
250 242 $data['version'] = $this->version;
243 + $data['settings'] = $this->parse_atomic_settings( $data['settings'] );
244 + $data['styles'] = $this->parse_atomic_styles( $data );
245 + $data['editor_settings'] = $this->parse_editor_settings( $data['editor_settings'] );
251 246
252 - $this->set_data_field_for_save(
253 - $data,
254 - 'settings',
255 - $this->parse_atomic_settings( $data['settings'] ?? [] )
256 - );
257 -
258 - $this->set_data_field_for_save(
259 - $data,
260 - 'styles',
261 - $this->parse_atomic_styles( $data )
262 - );
263 -
264 - $this->set_data_field_for_save(
265 - $data,
266 - 'editor_settings',
267 - $this->parse_editor_settings( $data['editor_settings'] ?? [] )
268 - );
269 -
270 - $this->set_data_field_for_save(
271 - $data,
272 - 'interactions',
273 - $this->transform_interactions_for_save( $data['interactions'] ?? [] )
274 - );
275 -
247 + if ( isset( $data['interactions'] ) && ! empty( $data['interactions'] ) ) {
248 + $data['interactions'] = $this->transform_interactions_for_save( $data['interactions'] );
249 + } else {
250 + $data['interactions'] = [];
251 + }
276 252 return $data;
277 253 }
278 254
279 - private function set_data_field_for_save( array &$data, string $key, $value ): void {
280 - if ( ! empty( $value ) ) {
281 - $data[ $key ] = $value;
282 - return;
283 - }
284 -
285 - unset( $data[ $key ] );
286 - }
287 -
288 255 private function transform_interactions_for_save( $interactions ) {
289 256 $decoded = $this->decode_interactions_data( $interactions );
290 257
291 258 if ( empty( $decoded['items'] ) ) {
@@ -314,9 +281,9 @@
314 281
315 282 final public function get_raw_data( $with_html_content = false ) {
316 283 $raw_data = parent::get_raw_data( $with_html_content );
317 284
318 - $raw_data['styles'] = Atomic_Widget_Styles::get_license_based_filtered_styles( $this->styles ?? [] );
285 + $raw_data['styles'] = $this->styles;
319 286 $raw_data['interactions'] = $this->interactions ?? [];
320 287 $raw_data['editor_settings'] = $this->editor_settings;
321 288
322 289 return $raw_data;
@@ -331,31 +298,18 @@
331 298
332 299 public function get_atomic_settings(): array {
333 300 $schema = static::get_props_schema();
334 301 $props = $this->get_settings();
302 + $initial_attributes = $this->get_initial_attributes();
335 303
336 - $merged_attribute_values = array_merge(
337 - $this->get_initial_attributes()['value'] ?? [],
304 + $props['attributes'] = Attributes_Prop_Type::generate( array_merge(
305 + $initial_attributes['value'] ?? [],
338 306 $props['attributes']['value'] ?? []
339 - );
340 - $props['attributes'] = Attributes_Prop_Type::generate( $merged_attribute_values );
307 + ) );
341 308
342 - $parsed = Render_Props_Resolver::for_settings()->resolve( $schema, $props );
343 -
344 - return $this->transform_link_for_render( $parsed );
309 + return Render_Props_Resolver::for_settings()->resolve( $schema, $props );
345 310 }
346 311
347 - protected function transform_link_for_render( array $parsed ): array {
348 - $link_attributes = isset( $parsed['link'] ) ? $this->get_link_attributes_string( $parsed['link'] ) : '';
349 -
350 - $parsed['link'] = ! empty( $link_attributes ) ? [
351 - 'tag' => $parsed['link']['tag'],
352 - 'attributes' => $link_attributes,
353 - ] : null;
354 -
355 - return $parsed;
356 - }
357 -
358 312 protected function get_initial_attributes() {
359 313 return Attributes_Prop_Type::generate( [
360 314 Key_Value_Prop_Type::generate( [
361 315 'key' => String_Prop_Type::generate( 'data-e-type' ),
@@ -392,24 +346,15 @@
392 346 if ( isset( $data['title'] ) && is_string( $data['title'] ) ) {
393 347 $editor_data['title'] = sanitize_text_field( $data['title'] );
394 348 }
395 349
396 - if ( isset( $data['grid_outline'] ) && is_bool( $data['grid_outline'] ) ) {
397 - $editor_data['grid_outline'] = $data['grid_outline'];
398 - }
399 -
400 350 return $editor_data;
401 351 }
402 352
403 353 public static function get_props_schema(): array {
404 354 $schema = static::define_props_schema();
355 + $schema['_cssid'] = String_Prop_Type::make()->meta( Overridable_Prop_Type::ignore() );
405 356
406 - if ( ! isset( $schema['_cssid'] ) ) {
407 - $schema['_cssid'] = String_Prop_Type::make()
408 - ->meta( Overridable_Prop_Type::ignore() )
409 - ->meta( Prop_Duplication_Behavior::clear() );
410 - }
411 -
412 357 return apply_filters(
413 358 'elementor/atomic-widgets/props-schema',
414 359 $schema
415 360 );
@@ -414,117 +359,124 @@
414 359 $schema
415 360 );
416 361 }
417 362
418 - protected function set_render_context( array $context_pairs ): void {
419 - foreach ( $context_pairs as $context_pair ) {
420 - $context_key = $context_pair['context_key'] ?? static::class;
421 - $context = $context_pair['context'];
422 - Render_Context::push( $context_key, $context );
363 + public function get_interactions_ids() {
364 + $animation_ids = [];
365 +
366 + $list_of_interactions = ( is_array( $this->interactions ) && isset( $this->interactions['items'] ) )
367 + ? $this->interactions['items']
368 + : [];
369 +
370 + foreach ( $list_of_interactions as $interaction ) {
371 + if ( isset( $interaction['$$type'] ) && 'interaction-item' === $interaction['$$type'] ) {
372 + $animation_id = $this->extract_animation_id_from_prop_type( $interaction );
373 + if ( $animation_id ) {
374 + $animation_ids[] = $animation_id;
375 + }
376 + } elseif ( isset( $interaction['animation']['animation_id'] ) ) {
377 + $animation_ids[] = $interaction['animation']['animation_id'];
378 + }
423 379 }
380 +
381 + return $animation_ids;
424 382 }
425 383
426 - protected function clear_render_context( array $context_pairs ): void {
427 - foreach ( $context_pairs as $context_pair ) {
428 - $context_key = $context_pair['context_key'] ?? static::class;
429 - Render_Context::pop( $context_key );
384 + private function extract_animation_id_from_prop_type( $item ) {
385 + if ( ! isset( $item['value'] ) || ! is_array( $item['value'] ) ) {
386 + return null;
430 387 }
388 +
389 + $item_value = $item['value'];
390 +
391 + $trigger = $this->extract_prop_value( $item_value, 'trigger' );
392 + $animation = $this->extract_prop_value( $item_value, 'animation' );
393 +
394 + if ( ! is_array( $animation ) ) {
395 + return null;
396 + }
397 +
398 + $effect = $this->extract_prop_value( $animation, 'effect' );
399 + $type = $this->extract_prop_value( $animation, 'type' );
400 + $direction = $this->extract_prop_value( $animation, 'direction' );
401 + $timing_config = $this->extract_prop_value( $animation, 'timing_config' );
402 + $config = $this->extract_prop_value( $animation, 'config' );
403 +
404 + $duration = 300;
405 + $delay = 0;
406 + $replay = 0;
407 + $relative_to = 'viewport';
408 + $offset_top = 15;
409 + $offset_bottom = 85;
410 +
411 + if ( is_array( $timing_config ) ) {
412 + $duration = $this->extract_prop_value( $timing_config, 'duration', 300 );
413 + $delay = $this->extract_prop_value( $timing_config, 'delay', 0 );
414 + }
415 +
416 + if ( is_array( $config ) ) {
417 + $relative_to = $this->extract_prop_value( $config, 'relative_to', 'viewport' );
418 + $offset_top = $this->extract_prop_value( $config, 'offset_top', 15 );
419 + $offset_bottom = $this->extract_prop_value( $config, 'offset_bottom', 85 );
420 +
421 + $replay = $this->extract_prop_value( $config, 'replay', 0 );
422 + if ( empty( $replay ) && 0 !== $replay && '0' !== $replay ) {
423 + $replay = 0;
424 + }
425 + } else {
426 + $replay = 0;
427 + }
428 +
429 + return implode( '-', [ $trigger, $effect, $type, $direction, $duration, $delay, $replay, $relative_to, $offset_top, $offset_bottom ] );
431 430 }
432 431
433 432 public function print_content() {
434 433 $defined_context = $this->define_render_context();
435 434
436 - if ( empty( $defined_context ) ) {
435 + $context_key = $defined_context['context_key'] ?? static::class;
436 + $element_context = $defined_context['context'] ?? [];
437 +
438 + $has_context = ! empty( $element_context );
439 +
440 + if ( ! $has_context ) {
437 441 return parent::print_content();
438 442 }
439 443
440 - $this->set_render_context( $defined_context );
444 + Render_Context::push( $context_key, $element_context );
441 445
442 446 parent::print_content();
443 447
444 - $this->clear_render_context( $defined_context );
448 + Render_Context::pop( $context_key );
445 449 }
446 450
447 451 /**
448 452 * Define the context for element's Render_Context.
449 453 *
450 - * @return array Array of context pairs. Each pair is an associative array with:
451 - * - 'context_key' (optional): The context key. Defaults to static::class if not provided.
452 - * - 'context' (required): The context value (can be any type).
453 - *
454 - * @example
455 - * [
456 - * [
457 - * 'context_key' => 'custom-key',
458 - * 'context' => ['some' => 'data'],
459 - * ],
460 - * [
461 - * 'context' => ['instance_id' => $this->get_id()],
462 - * ],
463 - * ]
454 + * @return array{context_key: ?string, context: array}
464 455 */
465 456 protected function define_render_context(): array {
466 - return [];
457 + return [
458 + 'context_key' => null,
459 + 'context' => [],
460 + ];
467 461 }
468 462
469 - protected function get_link_attributes( $link_settings ) {
470 - if ( empty( $link_settings['href'] ) ) {
471 - return [];
472 - }
473 -
463 + protected function get_link_attributes( $link_settings, $add_key_to_result = false ) {
474 464 $tag = $link_settings['tag'] ?? Link_Prop_Type::DEFAULT_TAG;
475 - $url = $link_settings['href'];
465 + $href = $link_settings['href'];
476 466 $target = $link_settings['target'] ?? '_self';
477 - $is_action_link = 'button' === $tag;
478 - $url_attr_key = $is_action_link ? 'data-action-link' : 'href';
479 467
480 - return [
481 - $url_attr_key => $url,
468 + $is_button = 'button' === $tag;
469 + $href_attribute_key = $is_button ? 'data-action-link' : 'href';
470 +
471 + $result = [
472 + $href_attribute_key => $href,
482 473 'target' => $target,
483 474 ];
484 - }
485 475
486 - private function get_link_attributes_string( $link_settings ) {
487 - $link_attributes = $this->get_link_attributes( $link_settings );
488 -
489 - if ( empty( $link_attributes ) ) {
490 - return '';
476 + if ( $add_key_to_result ) {
477 + $result['key'] = $href_attribute_key;
491 478 }
492 479
493 - $parts = [];
494 -
495 - foreach ( $link_attributes as $key => $value ) {
496 - if ( 'tag' === $key ) {
497 - continue;
498 - }
499 -
500 - $parts[] = sprintf( '%s="%s"', $key, esc_attr( $value ) );
501 - }
502 -
503 - return implode( ' ', $parts );
504 - }
505 -
506 - public function has_action_link() {
507 - if ( ! $this->get_id() ) {
508 - return true;
509 - }
510 -
511 - $link_settings = $this->get_atomic_setting( 'link' ) ?? null;
512 - $attributes = $this->get_link_attributes( $link_settings );
513 -
514 - return isset( $attributes['data-action-link'] );
515 - }
516 -
517 - public function get_script_depends() {
518 - $depends = parent::get_script_depends();
519 -
520 - if ( $this->has_action_link() ) {
521 - $depends[] = Frontend_Assets_Loader::ACTION_LINK_HANDLERS_HANDLE;
522 - }
523 -
524 - if ( Atomic_Form::is_instance_form( $this ) ) {
525 - $depends[] = Frontend_Assets_Loader::FORM_HANDLERS_HANDLE;
526 - }
527 -
528 - return $depends;
480 + return $result;
529 481 }
530 482 }