PluginProbe
Elementor Website Builder – more than just a page builder / 3.25.2
Elementor Website Builder – more than just a page builder v3.25.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 4.0.8 All 454 releases
← All changes | modules/atomic-widgets/props-resolver/props-resolver.php +83 -65 4.3.1 → 3.25.2 View file →
@@ -1,12 +1,9 @@
1 1 <?php
2 2
3 3 namespace Elementor\Modules\AtomicWidgets\PropsResolver;
4 4
5 -use Elementor\Modules\AtomicWidgets\PropTypes\Base\Array_Prop_Type;
6 -use Elementor\Modules\AtomicWidgets\PropTypes\Base\Object_Prop_Type;
7 -use Elementor\Modules\AtomicWidgets\PropTypes\Contracts\Prop_Type;
8 -use Elementor\Modules\AtomicWidgets\PropTypes\Union_Prop_Type;
5 +use Elementor\Modules\AtomicWidgets\PropTypes\Prop_Type;
9 6 use Exception;
10 7
11 8 if ( ! defined( 'ABSPATH' ) ) {
12 9 exit; // Exit if accessed directly.
@@ -11,102 +8,120 @@
11 8 if ( ! defined( 'ABSPATH' ) ) {
12 9 exit; // Exit if accessed directly.
13 10 }
14 11
15 -abstract class Props_Resolver {
16 - protected static array $instances = [];
12 +class Props_Resolver {
13 + /**
14 + * Each transformer can return a value that is also a transformable value,
15 + * which means that it can be transformed again by another transformer.
16 + * This constant defines the maximum depth of transformations to avoid infinite loops.
17 + */
18 + const TRANSFORM_DEPTH_LIMIT = 3;
17 19
18 - protected Transformers_Registry $transformers_registry;
20 + const CONTEXT_SETTINGS = 'settings';
21 + const CONTEXT_STYLES = 'styles';
19 22
20 - protected function __construct( Transformers_Registry $transformers_registry ) {
21 - $this->transformers_registry = $transformers_registry;
23 + /**
24 + * @var array<string, Props_Resolver>
25 + */
26 + private static array $instances = [];
27 +
28 + private Transformers_Registry $transformers;
29 +
30 + private function __construct( Transformers_Registry $transformers ) {
31 + $this->transformers = $transformers;
22 32 }
23 33
24 - protected static function instance( string $context ) {
25 - if ( ! isset( static::$instances[ $context ] ) ) {
26 - $instance = new static( new Transformers_Registry() );
34 + public static function for_styles() {
35 + return self::instance( self::CONTEXT_STYLES );
36 + }
27 37
28 - static::$instances[ $context ] = $instance;
38 + public static function for_settings() {
39 + return self::instance( self::CONTEXT_SETTINGS );
40 + }
29 41
30 - do_action(
31 - "elementor/atomic-widgets/$context/transformers/register",
32 - $instance->get_transformers_registry(),
33 - $instance
34 - );
42 + private static function instance( string $context, bool $fresh = false ): self {
43 + if ( ! isset( self::$instances[ $context ] ) || $fresh ) {
44 + $registry = new Transformers_Registry();
45 +
46 + do_action( "elementor/atomic-widgets/{$context}/transformers/register", $registry );
47 +
48 + self::$instances[ $context ] = new self( $registry );
35 49 }
36 50
37 - return static::$instances[ $context ];
51 + return self::$instances[ $context ];
38 52 }
39 53
40 - public static function reset(): void {
41 - static::$instances = [];
42 - }
54 + public function resolve( array $schema, array $props ): array {
55 + $resolved_props = [];
43 56
44 - public function get_transformers_registry(): Transformers_Registry {
45 - return $this->transformers_registry;
46 - }
57 + foreach ( $schema as $key => $prop_type ) {
58 + if ( ! ( $prop_type instanceof Prop_Type ) ) {
59 + continue;
60 + }
47 61
48 - protected function transform( $value, $key, Prop_Type $prop_type ) {
49 - if ( $prop_type instanceof Union_Prop_Type ) {
50 - $prop_type = $prop_type->get_prop_type( $value['$$type'] );
62 + if ( ! array_key_exists( $key, $props ) ) {
63 + $resolved_props[ $key ] = $prop_type->get_default();
64 + continue;
65 + }
51 66
52 - if ( ! $prop_type ) {
53 - return null;
67 + $resolved_props[ $key ] = $props[ $key ];
68 +
69 + // Merge the top-level defaults for transformable props.
70 + if (
71 + $this->is_nested_transformable( $resolved_props[ $key ] ) &&
72 + $this->is_nested_transformable( $prop_type->get_default() )
73 + ) {
74 + $resolved_props[ $key ]['value'] = array_merge(
75 + $prop_type->get_default()['value'],
76 + $resolved_props[ $key ]['value']
77 + );
54 78 }
55 79 }
56 80
57 - if ( $value['$$type'] !== $prop_type::get_key() ) {
81 + return array_map(
82 + fn( $value ) => $this->transform( $value ),
83 + $resolved_props
84 + );
85 + }
86 +
87 + private function transform( $value, int $depth = 0 ) {
88 + if ( ! $value || ! $this->is_transformable( $value ) ) {
89 + return $value;
90 + }
91 +
92 + if ( $depth >= self::TRANSFORM_DEPTH_LIMIT ) {
58 93 return null;
59 94 }
60 95
61 - if ( $prop_type instanceof Object_Prop_Type ) {
62 - if ( ! is_array( $value['value'] ) ) {
63 - return null;
64 - }
96 + if ( isset( $value['disabled'] ) && true === $value['disabled'] ) {
97 + return null;
98 + }
65 99
66 - $value['value'] = $this->resolve(
67 - $prop_type->get_shape(),
100 + // Transform nested transformable values recursively.
101 + if ( is_array( $value['value'] ) ) {
102 + $value['value'] = array_map(
103 + fn( $item ) => $this->transform( $item ),
68 104 $value['value']
69 105 );
70 106 }
71 107
72 - if ( $prop_type instanceof Array_Prop_Type ) {
73 - if ( ! is_array( $value['value'] ) ) {
74 - return null;
75 - }
108 + $transformer = $this->transformers->get( $value['$$type'] );
76 109
77 - $resolved_items = [];
78 -
79 - foreach ( $value['value'] as $item ) {
80 - $resolved = $this->resolve_item( $item, null, $prop_type->get_item_type() );
81 -
82 - if ( null !== $resolved ) {
83 - $resolved_items[] = $resolved;
84 - }
85 - }
86 -
87 - $value['value'] = $resolved_items;
88 - }
89 -
90 - $transformer = $this->transformers_registry->get( $value['$$type'] );
91 -
92 110 if ( ! ( $transformer instanceof Transformer_Base ) ) {
93 111 return null;
94 112 }
95 113
96 114 try {
97 - $context = Props_Resolver_Context::make()
98 - ->set_key( $key )
99 - ->set_disabled( (bool) ( $value['disabled'] ?? false ) )
100 - ->set_prop_type( $prop_type );
115 + $transformed_value = $transformer->transform( $value['value'] );
101 116
102 - return $transformer->transform( $value['value'], $context );
117 + return $this->transform( $transformed_value, $depth + 1 );
103 118 } catch ( Exception $e ) {
104 119 return null;
105 120 }
106 121 }
107 122
108 - protected function is_transformable( $value ): bool {
123 + private function is_transformable( $value ): bool {
109 124 return (
110 125 ! empty( $value['$$type'] ) &&
111 126 array_key_exists( 'value', $value )
112 127 );
@@ -111,8 +126,11 @@
111 126 array_key_exists( 'value', $value )
112 127 );
113 128 }
114 129
115 - abstract public function resolve( array $schema, array $props ): array;
116 -
117 - abstract protected function resolve_item( $value, $key, Prop_Type $prop_type );
130 + private function is_nested_transformable( $value ): bool {
131 + return (
132 + $this->is_transformable( $value ) &&
133 + is_array( $value['value'] )
134 + );
135 + }
118 136 }