PluginProbe
Elementor Website Builder – more than just a page builder / 4.1.0-beta1
Elementor Website Builder – more than just a page builder v4.1.0-beta1
4.3.3 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 All 456 releases
← All changes | modules/global-classes/global-classes-repository.php +97 -197 4.2.3 → 4.1.0-beta1 View file →
@@ -4,9 +4,8 @@
4 4 use Elementor\Core\Kits\Documents\Kit;
5 5 use Elementor\Modules\DesignSystemSync\Classes\Global_Classes_Sync_Map;
6 6 use Elementor\Modules\GlobalClasses\Concerns\Has_Kit_Dependency;
7 7 use Elementor\Modules\GlobalClasses\Concerns\Has_Preview_Context;
8 -use Elementor\Modules\GlobalClasses\Utils\Global_Class_Data_Normalizer;
9 8
10 9 if ( ! defined( 'ABSPATH' ) ) {
11 10 exit; // Exit if accessed directly.
12 11 }
@@ -28,8 +27,12 @@
28 27 'event' => [
29 28 'frontend' => self::CONTEXT_FRONTEND,
30 29 'preview' => self::CONTEXT_PREVIEW,
31 30 ],
31 + 'meta_key' => [
32 + 'frontend' => self::META_KEY_FRONTEND,
33 + 'preview' => self::META_KEY_PREVIEW,
34 + ],
32 35 ];
33 36
34 37 private ?Global_Classes $cache = null;
35 38
@@ -66,15 +69,13 @@
66 69 return $this->labels()->get_ordered_labels();
67 70 }
68 71
69 72 public function get_order(): array {
70 - return Global_Classes_Order::make( $this->get_kit() )->set_preview( $this->is_preview() )->get_order();
73 + return Global_Classes_Order::make( $this->get_kit() )->get_order();
71 74 }
72 75
73 76 public function update_order_and_labels( array $order, array $new_labels ): void {
74 - Global_Classes_Order::make( $this->get_kit() )
75 - ->set_preview( $this->is_preview() )
76 - ->set_order( $order );
77 + Global_Classes_Order::make( $this->get_kit() )->set_order( $order );
77 78
78 79 $labels = $this->labels();
79 80 $existing_labels = $labels->get_labels();
80 81
@@ -83,16 +84,8 @@
83 84 }
84 85
85 86 $labels->set_labels( $existing_labels );
86 87
87 - if ( ! $this->is_preview() ) {
88 - Global_Classes_Order::make( $this->get_kit() )
89 - ->set_preview( true )
90 - ->set_order( $order );
91 -
92 - $this->clear_preview_labels_for_ids( array_keys( $new_labels ) );
93 - }
94 -
95 88 $this->cache = null;
96 89 }
97 90
98 91 private function labels(): Global_Classes_Labels {
@@ -99,9 +92,9 @@
99 92 return Global_Classes_Labels::make( $this->get_kit() )->set_preview( $this->is_preview() );
100 93 }
101 94
102 95 public function get( string $class_id ): ?array {
103 - $post = Global_Class_Post::find_by_class_id( $class_id, $this->is_preview(), $this->get_kit() );
96 + $post = Global_Class_Post::find_by_class_id( $class_id, $this->is_preview() );
104 97
105 98 return $post ? $post->to_array() : null;
106 99 }
107 100
@@ -109,17 +102,13 @@
109 102 if ( empty( $class_ids ) ) {
110 103 return [];
111 104 }
112 105
113 - $post_ids = Global_Classes_Post_IDs::make( $this->get_kit() )->get_post_ids( $class_ids );
114 106 $items = [];
115 107
116 - foreach ( $post_ids as $class_id => $post_id ) {
117 - $post = Global_Class_Post::from_post_id( $post_id, $this->is_preview() );
118 -
119 - if ( $post ) {
120 - $items[ $class_id ] = $post->to_array();
121 - }
108 + foreach ( $this->iterate_class_posts_for_ids( $class_ids ) as $class_post ) {
109 + $class_data = $class_post->to_array();
110 + $items[ $class_data['id'] ] = $class_data;
122 111 }
123 112
124 113 return $items;
125 114 }
@@ -141,28 +130,24 @@
141 130 $final_label_map[ $id ] = $before[ $id ];
142 131 }
143 132 }
144 133
145 - $affected_post_ids = $this->get_posts_affected_by_deletion( $to_delete );
146 -
147 134 $this->persist_class_batch_mutations( $to_delete, $to_create, $to_update, $touched_items, $is_preview );
148 135
149 - $classes_order = Global_Classes_Order::make( $this->get_kit() )->set_preview( $this->is_preview() );
136 + $classes_order = Global_Classes_Order::make( $this->get_kit() );
150 137 $classes_order->set_order( $order );
151 138 $labels->set_labels( $final_label_map );
152 139
153 140 if ( ! $is_preview ) {
154 141 Global_Classes_Sync_Map::make( $this->get_kit() )->apply_changes( $touched_items, $to_delete );
155 - Global_Classes_Order::make( $this->get_kit() )
156 - ->set_preview( true )
157 - ->set_order( $order );
158 142
159 - $this->bulk_clear_preview_meta( array_values( $to_update ) );
160 - $this->clear_preview_labels_for_ids( array_merge(
161 - array_values( $to_create ),
162 - array_values( $to_update ),
163 - array_values( $to_delete )
164 - ) );
143 + $this->each_class_id_batch( array_values( $to_update ), function ( string $class_id ) {
144 + $post = Global_Class_Post::find_by_class_id( $class_id, false );
145 + if ( $post ) {
146 + delete_post_meta( $post->get_post_id(), Global_Class_Post::META_KEY_DATA_PREVIEW );
147 + clean_post_cache( $post->get_post_id() );
148 + }
149 + } );
165 150 }
166 151
167 152 $this->cache = null;
168 153 $this->flush_runtime_cache();
@@ -171,18 +156,9 @@
171 156 'added' => $to_create,
172 157 'deleted' => $to_delete,
173 158 'modified' => $to_update,
174 159 'order' => $order_changed,
175 - 'affected_post_ids' => $affected_post_ids,
176 160 ] );
177 -
178 - if ( ! empty( $to_delete ) && ! $is_preview ) {
179 - do_action(
180 - 'elementor/global_classes/cleanup',
181 - $to_delete,
182 - $affected_post_ids
183 - );
184 - }
185 161 }
186 162
187 163 public function each_item( callable $cb, bool $skip_migration = false, int $batch_size = self::READ_BATCH_SIZE ): void {
188 164 $order = Global_Classes_Order::make( $this->get_kit() )->get_order();
@@ -198,69 +174,31 @@
198 174 }
199 175 }
200 176
201 177 public function put( array $items, array $order ) {
202 - $current_ids = Global_Classes_Order::make( $this->get_kit() )
203 - ->set_preview( $this->is_preview() )
204 - ->get_order();
178 + $current_ids = Global_Classes_Order::make( $this->get_kit() )->get_order();
205 179
206 180 $new_ids = array_keys( $items );
181 +
207 182 $current_order_string = implode( ';', $current_ids );
208 - $deleted_class_ids = array_values( array_diff( $current_ids, $new_ids ) );
209 183
210 184 $changes = [
211 185 'added' => array_values( array_diff( $new_ids, $current_ids ) ),
212 - 'deleted' => $deleted_class_ids,
186 + 'deleted' => array_values( array_diff( $current_ids, $new_ids ) ),
213 187 'modified' => array_values( array_intersect( $new_ids, $current_ids ) ),
214 188 'order' => implode( ';', $order ) !== $current_order_string,
215 189 ];
216 190
217 - /**
218 - * We collect all affected ids before the put_to_posts execution
219 - * as the update mechanism would handle the Global_Classes_Relations as it iterates over the update batches
220 - * So once we get to the cleanup phase - we would no longer have the relevant relations
221 - *
222 - * On top of that - by collecting all affected posts in advance, means we would iterate over each document's elements only once
223 - * (as the alternative would be to trigger the cleanup per removed class, but that means we may end up iterating over the same document N times, if all N styles are used in it)
224 - */
225 - $affected_post_ids = $this->get_posts_affected_by_deletion( $deleted_class_ids );
226 -
227 191 $this->put_to_posts( $items, $order, $current_ids );
228 192
229 193 $this->cache = null;
230 194
231 - $changes['affected_post_ids'] = $affected_post_ids;
232 -
233 195 do_action( 'elementor/global_classes/update', $this->get_context_key( 'event' ), $changes );
234 -
235 - if ( ! empty( $deleted_class_ids ) && ! $this->is_preview() ) {
236 - do_action(
237 - 'elementor/global_classes/cleanup',
238 - $deleted_class_ids,
239 - $affected_post_ids
240 - );
241 - }
242 196 }
243 197
244 - private function get_posts_affected_by_deletion( array $deleted_class_ids ): array {
245 - if ( empty( $deleted_class_ids ) ) {
246 - return [];
247 - }
248 -
249 - $relations = new Global_Classes_Relations();
250 - $post_ids = [];
251 -
252 - foreach ( $deleted_class_ids as $class_id ) {
253 - $post_ids[] = $relations->get_posts_by_style( $class_id );
254 - }
255 -
256 - return array_values( array_unique( array_merge( ...$post_ids ) ) );
257 - }
258 -
259 198 private function all_from_posts(): Global_Classes {
260 - $order = Global_Classes_Order::make( $this->get_kit() )
261 - ->set_preview( $this->is_preview() )
262 - ->get_order();
199 + $classes_order = Global_Classes_Order::make( $this->get_kit() );
200 + $order = $classes_order->get_order();
263 201
264 202 if ( empty( $order ) ) {
265 203 return Global_Classes::make( [], [] );
266 204 }
@@ -286,9 +224,9 @@
286 224 $to_update = array_intersect( $new_ids, $current_ids );
287 225
288 226 $this->persist_class_batch_mutations( $to_delete, $to_create, $to_update, $items, $is_preview );
289 227
290 - $classes_order = Global_Classes_Order::make( $this->get_kit() )->set_preview( $this->is_preview() );
228 + $classes_order = Global_Classes_Order::make( $this->get_kit() );
291 229 $classes_order->set_order( $order );
292 230
293 231 $label_map = [];
294 232 foreach ( $order as $id ) {
@@ -305,14 +243,15 @@
305 243 array_flip( $touched_ids )
306 244 );
307 245 Global_Classes_Sync_Map::make( $this->get_kit() )->apply_changes( $touched_items, array_values( $to_delete ) );
308 246
309 - $this->bulk_clear_preview_meta( array_values( $to_update ) );
310 - $this->clear_preview_labels_for_ids( array_merge(
311 - array_values( $to_create ),
312 - array_values( $to_update ),
313 - array_values( $to_delete )
314 - ) );
247 + $this->each_class_id_batch( array_values( $to_update ), function ( string $class_id ) {
248 + $post = Global_Class_Post::find_by_class_id( $class_id, false );
249 + if ( $post ) {
250 + delete_post_meta( $post->get_post_id(), Global_Class_Post::META_KEY_DATA_PREVIEW );
251 + clean_post_cache( $post->get_post_id() );
252 + }
253 + } );
315 254 }
316 255 }
317 256
318 257 private function iterate_class_posts_for_ids( array $class_ids ): \Generator {
@@ -329,13 +268,28 @@
329 268 ],
330 269 ],
331 270 ] );
332 271
272 + $seen_class_ids = [];
273 +
333 274 foreach ( $posts as $post ) {
275 + $class_id = get_post_meta( $post->ID, Global_Class_Post::META_KEY_ID, true );
276 +
277 + if ( $class_id && isset( $seen_class_ids[ $class_id ] ) ) {
278 + // if for some reason there's already a post meta to that class - delete any other ones
279 + // otherwise we may end up updating a stale post meta
280 + wp_delete_post( $post->ID, true );
281 + continue;
282 + }
283 +
284 + if ( $class_id ) {
285 + $seen_class_ids[ $class_id ] = true;
286 + }
287 +
334 288 yield Global_Class_Post::from_post( $post, $this->is_preview() );
335 289 clean_post_cache( $post->ID );
336 290 }
337 - unset( $posts );
291 + unset( $posts, $seen_class_ids );
338 292 $this->flush_runtime_cache();
339 293 }
340 294 }
341 295
@@ -346,28 +300,13 @@
346 300 array $items_by_id,
347 301 bool $is_preview
348 302 ): void {
349 303 $relations = new Global_Classes_Relations();
350 - $post_ids_map = Global_Classes_Post_IDs::make( $this->get_kit() );
351 304
352 - $ids_to_resolve = array_values( array_merge(
353 - array_values( $to_delete ),
354 - array_values( $to_update ),
355 - array_values( $to_create )
356 - ) );
357 - $post_ids = $post_ids_map->get_post_ids( $ids_to_resolve );
305 + $this->each_class_id_batch( array_values( $to_delete ), function ( string $class_id ) use ( $is_preview, $relations ) {
306 + $post = Global_Class_Post::find_by_class_id( $class_id, false );
358 307
359 - $this->each_class_id_batch(
360 - array_values( $to_delete ),
361 - function ( string $class_id ) use ( $is_preview, $relations, $post_ids ) {
362 - $post = isset( $post_ids[ $class_id ] )
363 - ? Global_Class_Post::from_post_id( $post_ids[ $class_id ], false )
364 - : null;
365 -
366 - if ( ! $post ) {
367 - return;
368 - }
369 -
308 + if ( $post ) {
370 309 if ( $is_preview ) {
371 310 $post->set_preview( true );
372 311 $post->update_data( [] );
373 312 clean_post_cache( $post->get_post_id() );
@@ -375,65 +314,57 @@
375 314 $relations->clear_class_relations( $class_id );
376 315 $post->delete();
377 316 }
378 317 }
379 - );
318 + } );
380 319
381 - $this->each_class_id_batch( $to_create, function ( string $class_id ) use ( $items_by_id, $is_preview, $post_ids, $post_ids_map ) {
320 + $this->each_class_id_batch( $to_create, function ( string $class_id ) use ( $items_by_id, $is_preview ) {
382 321 if ( ! isset( $items_by_id[ $class_id ] ) ) {
383 322 return;
384 323 }
385 324
386 325 $item = $items_by_id[ $class_id ];
387 - $data = Global_Class_Data_Normalizer::normalize_style_fields( $item );
388 - $kit = $this->get_kit();
389 - $existing_post_id = $post_ids[ $class_id ] ?? null;
390 - $existing_post = $existing_post_id ? Global_Class_Post::from_post_id( $existing_post_id, $is_preview ) : null;
326 + $data = $this->build_class_data_for_storage( $item );
391 327
392 - if ( $existing_post ) {
393 - $existing_post->update_data( $data );
328 + if ( $is_preview ) {
329 + $post = Global_Class_Post::find_by_class_id( $class_id, true );
394 330
395 - if ( ! $is_preview ) {
396 - $existing_post->update_label( $item['label'] );
331 + if ( $post ) {
332 + $post->set_preview( true );
333 + $post->update_data( $data );
334 + $post->update_label( $item['label'] );
335 + clean_post_cache( $post->get_post_id() );
336 + } else {
337 + $created = Global_Class_Post::create( $class_id, $item['label'], $data );
338 + if ( $created ) {
339 + clean_post_cache( $created->get_post_id() );
340 + }
397 341 }
342 + } else {
343 + $created = Global_Class_Post::create( $class_id, $item['label'], $data );
344 + if ( $created ) {
345 + clean_post_cache( $created->get_post_id() );
346 + }
347 + }
348 + } );
398 349
399 - clean_post_cache( $existing_post->get_post_id() );
400 -
350 + $this->each_class_id_batch( $to_update, function ( string $class_id ) use ( $items_by_id, $is_preview ) {
351 + if ( ! isset( $items_by_id[ $class_id ] ) ) {
401 352 return;
402 353 }
403 354
404 - $created = Global_Class_Post::create( $class_id, $item['label'], $data, $kit );
355 + $item = $items_by_id[ $class_id ];
356 + $post = Global_Class_Post::find_by_class_id( $class_id, $is_preview );
405 357
406 - if ( $created ) {
407 - $post_ids_map->set( $class_id, $created->get_post_id() );
408 - clean_post_cache( $created->get_post_id() );
358 + if ( ! $post ) {
359 + return;
409 360 }
361 +
362 + $data = $this->build_class_data_for_storage( $item );
363 + $post->update_data( $data );
364 + $post->update_label( $item['label'] );
365 + clean_post_cache( $post->get_post_id() );
410 366 } );
411 -
412 - $this->each_class_id_batch(
413 - $to_update,
414 - function ( string $class_id ) use ( $items_by_id, $is_preview, $post_ids ) {
415 - if ( ! isset( $items_by_id[ $class_id ] ) || ! isset( $post_ids[ $class_id ] ) ) {
416 - return;
417 - }
418 -
419 - $item = $items_by_id[ $class_id ];
420 - $post = Global_Class_Post::from_post_id( $post_ids[ $class_id ], $is_preview );
421 -
422 - if ( ! $post ) {
423 - return;
424 - }
425 -
426 - $data = Global_Class_Data_Normalizer::normalize_style_fields( $item );
427 - $post->update_data( $data );
428 -
429 - if ( ! $is_preview ) {
430 - $post->update_label( $item['label'] );
431 - }
432 -
433 - clean_post_cache( $post->get_post_id() );
434 - }
435 - );
436 367 }
437 368
438 369 public function delete_all(): void {
439 370 $order = $this->get_order();
@@ -438,9 +369,9 @@
438 369 public function delete_all(): void {
439 370 $order = $this->get_order();
440 371
441 372 $this->each_class_id_batch( $order, function ( string $class_id ) {
442 - $post = Global_Class_Post::find_by_class_id( $class_id, false, $this->get_kit() );
373 + $post = Global_Class_Post::find_by_class_id( $class_id );
443 374
444 375 if ( $post ) {
445 376 $post->delete();
446 377 }
@@ -449,52 +380,8 @@
449 380 Global_Classes_Order::make( $this->get_kit() )->set_order( [] );
450 381 $this->labels()->set_labels( [] );
451 382 }
452 383
453 - private function clear_preview_labels_for_ids( array $class_ids ): void {
454 - if ( empty( $class_ids ) ) {
455 - return;
456 - }
457 -
458 - $preview_labels = Global_Classes_Labels::make( $this->get_kit() )->set_preview( true );
459 - $labels_map = $preview_labels->get_labels();
460 -
461 - if ( empty( $labels_map ) ) {
462 - return;
463 - }
464 -
465 - $ids_to_remove = array_intersect( array_unique( $class_ids ), array_keys( $labels_map ) );
466 -
467 - if ( empty( $ids_to_remove ) ) {
468 - return;
469 - }
470 -
471 - foreach ( $ids_to_remove as $id ) {
472 - unset( $labels_map[ $id ] );
473 - }
474 -
475 - $preview_labels->set_labels( $labels_map );
476 - }
477 -
478 - private function bulk_clear_preview_meta( array $class_ids ): void {
479 - if ( empty( $class_ids ) ) {
480 - return;
481 - }
482 -
483 - $post_ids_map = Global_Classes_Post_IDs::make( $this->get_kit() );
484 -
485 - foreach ( array_chunk( $class_ids, self::PERSIST_BATCH_SIZE ) as $chunk ) {
486 - $post_ids = $post_ids_map->get_post_ids( $chunk );
487 -
488 - foreach ( $post_ids as $post_id ) {
489 - delete_post_meta( $post_id, Global_Class_Post::META_KEY_DATA_PREVIEW );
490 - clean_post_cache( $post_id );
491 - }
492 -
493 - $this->flush_runtime_cache();
494 - }
495 - }
496 -
497 384 private function each_class_id_batch( $class_ids, callable $callback, int $batch_size = self::PERSIST_BATCH_SIZE ): void {
498 385 $class_ids = is_array( $class_ids ) ? $class_ids : iterator_to_array( $class_ids, false );
499 386 foreach ( array_chunk( array_values( $class_ids ), $batch_size ) as $batch ) {
500 387 foreach ( $batch as $class_id ) {
@@ -507,6 +394,19 @@
507 394 private function flush_runtime_cache(): void {
508 395 if ( function_exists( 'wp_cache_flush_runtime' ) ) {
509 396 wp_cache_flush_runtime();
510 397 }
398 + }
399 +
400 + private function build_class_data_for_storage( array $item ): array {
401 + $data = [
402 + 'type' => $item['type'] ?? 'class',
403 + 'variants' => $item['variants'] ?? [],
404 + ];
405 +
406 + if ( array_key_exists( 'sync_to_v3', $item ) ) {
407 + $data['sync_to_v3'] = (bool) $item['sync_to_v3'];
408 + }
409 +
410 + return $data;
511 411 }
512 412 }