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