PluginProbe
Elementor Website Builder – more than just a page builder / 4.3.0-beta3
Elementor Website Builder – more than just a page builder v4.3.0-beta3
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
elementor / modules / atomic-widgets / utils / atomic-prop-remap.php

atomic-prop-remap.php in Elementor Website Builder – more than just a page builder 4.3.0-beta3, at modules/atomic-widgets/utils/atomic-prop-remap.php

244 lines 6.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace Elementor\Modules\AtomicWidgets\Utils;
4
5 use Elementor\Modules\AtomicWidgets\PropTypes\Query_Prop_Type;
6
7 if ( ! defined( 'ABSPATH' ) ) {
8 exit; // Exit if accessed directly.
9 }
10
11 class Atomic_Prop_Remap {
12 public const KIND_POST = 'post';
13 public const KIND_TERM = 'term';
14 public const KIND_USER = 'user';
15
16 public const FILTER_KEY_TERMS = 'terms';
17 public const FILTER_KEY_AUTHORS = 'authors';
18 public const FILTER_KEY_MANUAL_SELECTION = 'manual_selection';
19 public const FILTER_KEY_CURRENT_POST = 'current_post';
20
21 private const MAP_BY_KIND = [
22 self::KIND_POST => 'post_ids',
23 self::KIND_TERM => 'term_ids',
24 self::KIND_USER => 'user_ids',
25 ];
26
27 /**
28 * @var list<array{element_id: string, path: string, missing_kind: string, source_id: int}>
29 */
30 private static array $warnings = [];
31
32 private static ?string $current_element_id = null;
33
34 private static string $current_path = '';
35
36 public static function apply( array $elements, array $replacements ): array {
37 self::ensure_handlers_registered();
38 self::$warnings = [];
39
40 if ( ! self::has_any_map( $replacements ) ) {
41 return $elements;
42 }
43
44 $remapped = array_map(
45 function ( $element ) use ( $replacements ) {
46 return self::remap_element( $element, $replacements );
47 },
48 $elements
49 );
50
51 if ( function_exists( 'apply_filters' ) ) {
52 self::$warnings = apply_filters( 'elementor/atomic-widgets/import_warnings', self::$warnings, $replacements );
53 }
54
55 return $remapped;
56 }
57
58 public static function consume_warnings(): array {
59 $warnings = self::$warnings;
60 self::$warnings = [];
61
62 return $warnings;
63 }
64
65 public static function register_builtin_handlers(): void {
66 Atomic_Prop_Remap_Handlers::register();
67 }
68
69 public static function set_tag_resolver( ?callable $resolver ): void {
70 Atomic_Prop_Remap_Handlers::set_tag_resolver( $resolver );
71 }
72
73 public static function remap_id( $id_node, string $kind, array $replacements ) {
74 $source_id = self::extract_numeric_id( $id_node );
75
76 if ( null === $source_id ) {
77 return $id_node;
78 }
79
80 $mapped_id = self::lookup_mapped_id( $source_id, $kind, $replacements );
81
82 if ( null === $mapped_id ) {
83 self::record_warning( $kind, $source_id );
84
85 return $id_node;
86 }
87
88 return self::write_numeric_id( $id_node, $mapped_id );
89 }
90
91 public static function extract_numeric_id( $node ): ?int {
92 if ( is_numeric( $node ) ) {
93 return (int) $node;
94 }
95
96 if ( is_array( $node ) && isset( $node['value'] ) && is_numeric( $node['value'] ) ) {
97 return (int) $node['value'];
98 }
99
100 return null;
101 }
102
103 public static function extract_string( $node ): string {
104 if ( is_string( $node ) ) {
105 return $node;
106 }
107
108 if ( is_array( $node ) && isset( $node['value'] ) && is_string( $node['value'] ) ) {
109 return $node['value'];
110 }
111
112 return '';
113 }
114
115 private static function ensure_handlers_registered(): void {
116 if ( ! Atomic_Prop_Remap_Registry::has( Query_Prop_Type::get_key() ) ) {
117 self::register_builtin_handlers();
118 }
119
120 if ( function_exists( 'do_action' ) ) {
121 do_action( 'elementor/atomic-widgets/import/id-remap-handlers/register' );
122 }
123 }
124
125 private static function remap_element( $element, array $replacements ) {
126 if ( ! is_array( $element ) ) {
127 return $element;
128 }
129
130 $previous_element_id = self::$current_element_id;
131 self::$current_element_id = isset( $element['id'] ) && is_string( $element['id'] )
132 ? $element['id']
133 : ( self::$current_element_id ?? '' );
134
135 if ( ! empty( $element['settings'] ) && is_array( $element['settings'] ) ) {
136 $element['settings'] = self::walk( $element['settings'], $replacements, [] );
137 }
138
139 if ( ! empty( $element['elements'] ) && is_array( $element['elements'] ) ) {
140 $element['elements'] = array_map(
141 function ( $child ) use ( $replacements ) {
142 return self::remap_element( $child, $replacements );
143 },
144 $element['elements']
145 );
146 }
147
148 self::$current_element_id = $previous_element_id;
149
150 return $element;
151 }
152
153 private static function walk( $value, array $replacements, array $context ) {
154 if ( ! is_array( $value ) ) {
155 return $value;
156 }
157
158 if ( self::is_atomic( $value ) ) {
159 return self::walk_atomic( $value, $replacements, $context );
160 }
161
162 $walked = [];
163
164 foreach ( $value as $key => $item ) {
165 $previous_path = self::$current_path;
166 self::$current_path = '' === self::$current_path ? (string) $key : self::$current_path . '.' . $key;
167 $walked[ $key ] = self::walk( $item, $replacements, $context );
168 self::$current_path = $previous_path;
169 }
170
171 return $walked;
172 }
173
174 private static function walk_atomic( array $atomic, array $replacements, array $context ) {
175 $handler = Atomic_Prop_Remap_Registry::get( $atomic['$$type'] );
176 $descend = function ( $child, array $child_context = [] ) use ( $replacements ) {
177 return self::walk( $child, $replacements, $child_context );
178 };
179
180 if ( $handler ) {
181 return $handler( $atomic, $replacements, $descend, $context );
182 }
183
184 if ( isset( $atomic['value'] ) ) {
185 $atomic['value'] = $descend( $atomic['value'], $context );
186 }
187
188 return $atomic;
189 }
190
191 private static function write_numeric_id( $node, int $mapped_id ) {
192 if ( is_array( $node ) && array_key_exists( 'value', $node ) ) {
193 $node['value'] = $mapped_id;
194
195 return $node;
196 }
197
198 return $mapped_id;
199 }
200
201 private static function lookup_mapped_id( int $source_id, string $kind, array $replacements ): ?int {
202 $map_key = self::MAP_BY_KIND[ $kind ] ?? null;
203
204 if ( null === $map_key ) {
205 return null;
206 }
207
208 $map = $replacements[ $map_key ] ?? [];
209
210 if ( isset( $map[ $source_id ] ) ) {
211 return (int) $map[ $source_id ];
212 }
213
214 if ( isset( $map[ (string) $source_id ] ) ) {
215 return (int) $map[ (string) $source_id ];
216 }
217
218 return null;
219 }
220
221 private static function record_warning( string $kind, int $source_id ): void {
222 self::$warnings[] = [
223 'element_id' => self::$current_element_id ?? '',
224 'path' => self::$current_path,
225 'missing_kind' => $kind,
226 'source_id' => $source_id,
227 ];
228 }
229
230 private static function is_atomic( array $value ): bool {
231 return isset( $value['$$type'] ) && is_string( $value['$$type'] );
232 }
233
234 private static function has_any_map( array $replacements ): bool {
235 foreach ( self::MAP_BY_KIND as $map_key ) {
236 if ( ! empty( $replacements[ $map_key ] ) ) {
237 return true;
238 }
239 }
240
241 return false;
242 }
243 }
244