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 +98 -203 4.3.3 → 4.1.0-beta1 View file →
@@ -2,11 +2,10 @@
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\Core\Kits\Concerns\Has_Kit_Dependency;
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
@@ -91,9 +92,9 @@
91 92 return Global_Classes_Labels::make( $this->get_kit() )->set_preview( $this->is_preview() );
92 93 }
93 94
94 95 public function get( string $class_id ): ?array {
95 - $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() );
96 97
97 98 return $post ? $post->to_array() : null;
98 99 }
99 100
@@ -101,17 +102,13 @@
101 102 if ( empty( $class_ids ) ) {
102 103 return [];
103 104 }
104 105
105 - $post_ids = Global_Classes_Post_IDs::make( $this->get_kit() )->get_post_ids( $class_ids );
106 106 $items = [];
107 107
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 - }
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;
114 111 }
115 112
116 113 return $items;
117 114 }
@@ -133,26 +130,24 @@
133 130 $final_label_map[ $id ] = $before[ $id ];
134 131 }
135 132 }
136 133
137 - $affected_post_ids = $this->get_posts_affected_by_deletion( $to_delete );
138 -
139 134 $this->persist_class_batch_mutations( $to_delete, $to_create, $to_update, $touched_items, $is_preview );
140 135
141 - $classes_order = Global_Classes_Order::make( $this->get_kit() )->set_preview( $this->is_preview() );
136 + $classes_order = Global_Classes_Order::make( $this->get_kit() );
142 137 $classes_order->set_order( $order );
143 138 $labels->set_labels( $final_label_map );
144 139
145 140 if ( ! $is_preview ) {
146 141 Global_Classes_Sync_Map::make( $this->get_kit() )->apply_changes( $touched_items, $to_delete );
147 - $this->propagate_order_to_preview( $order, $to_delete );
148 142
149 - $this->bulk_clear_preview_meta( array_values( $to_update ) );
150 - $this->clear_preview_labels_for_ids( array_merge(
151 - array_values( $to_create ),
152 - array_values( $to_update ),
153 - array_values( $to_delete )
154 - ) );
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 + } );
155 150 }
156 151
157 152 $this->cache = null;
158 153 $this->flush_runtime_cache();
@@ -161,35 +156,11 @@
161 156 'added' => $to_create,
162 157 'deleted' => $to_delete,
163 158 'modified' => $to_update,
164 159 'order' => $order_changed,
165 - 'affected_post_ids' => $affected_post_ids,
166 160 ] );
167 -
168 - if ( ! empty( $to_delete ) && ! $is_preview ) {
169 - do_action(
170 - 'elementor/global_classes/cleanup',
171 - $to_delete,
172 - $affected_post_ids
173 - );
174 - }
175 161 }
176 162
177 - private function propagate_order_to_preview( array $published_order, array $deleted_ids ): void {
178 - $preview_order = Global_Classes_Order::make( $this->get_kit() )->set_preview( true );
179 - $existing_order = $preview_order->get_order();
180 - $unpublished_ids = array_flip( array_diff( $existing_order, $published_order, $deleted_ids ) );
181 - $merged_order = $published_order;
182 -
183 - foreach ( $existing_order as $position => $id ) {
184 - if ( isset( $unpublished_ids[ $id ] ) ) {
185 - array_splice( $merged_order, min( $position, count( $merged_order ) ), 0, [ $id ] );
186 - }
187 - }
188 -
189 - $preview_order->set_order( $merged_order );
190 - }
191 -
192 163 public function each_item( callable $cb, bool $skip_migration = false, int $batch_size = self::READ_BATCH_SIZE ): void {
193 164 $order = Global_Classes_Order::make( $this->get_kit() )->get_order();
194 165
195 166 if ( empty( $order ) ) {
@@ -203,69 +174,31 @@
203 174 }
204 175 }
205 176
206 177 public function put( array $items, array $order ) {
207 - $current_ids = Global_Classes_Order::make( $this->get_kit() )
208 - ->set_preview( $this->is_preview() )
209 - ->get_order();
178 + $current_ids = Global_Classes_Order::make( $this->get_kit() )->get_order();
210 179
211 180 $new_ids = array_keys( $items );
181 +
212 182 $current_order_string = implode( ';', $current_ids );
213 - $deleted_class_ids = array_values( array_diff( $current_ids, $new_ids ) );
214 183
215 184 $changes = [
216 185 'added' => array_values( array_diff( $new_ids, $current_ids ) ),
217 - 'deleted' => $deleted_class_ids,
186 + 'deleted' => array_values( array_diff( $current_ids, $new_ids ) ),
218 187 'modified' => array_values( array_intersect( $new_ids, $current_ids ) ),
219 188 'order' => implode( ';', $order ) !== $current_order_string,
220 189 ];
221 190
222 - /**
223 - * We collect all affected ids before the put_to_posts execution
224 - * as the update mechanism would handle the Global_Classes_Relations as it iterates over the update batches
225 - * So once we get to the cleanup phase - we would no longer have the relevant relations
226 - *
227 - * On top of that - by collecting all affected posts in advance, means we would iterate over each document's elements only once
228 - * (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)
229 - */
230 - $affected_post_ids = $this->get_posts_affected_by_deletion( $deleted_class_ids );
231 -
232 191 $this->put_to_posts( $items, $order, $current_ids );
233 192
234 193 $this->cache = null;
235 194
236 - $changes['affected_post_ids'] = $affected_post_ids;
237 -
238 195 do_action( 'elementor/global_classes/update', $this->get_context_key( 'event' ), $changes );
239 -
240 - if ( ! empty( $deleted_class_ids ) && ! $this->is_preview() ) {
241 - do_action(
242 - 'elementor/global_classes/cleanup',
243 - $deleted_class_ids,
244 - $affected_post_ids
245 - );
246 - }
247 196 }
248 197
249 - private function get_posts_affected_by_deletion( array $deleted_class_ids ): array {
250 - if ( empty( $deleted_class_ids ) ) {
251 - return [];
252 - }
253 -
254 - $relations = new Global_Classes_Relations();
255 - $post_ids = [];
256 -
257 - foreach ( $deleted_class_ids as $class_id ) {
258 - $post_ids[] = $relations->get_posts_by_style( $class_id );
259 - }
260 -
261 - return array_values( array_unique( array_merge( ...$post_ids ) ) );
262 - }
263 -
264 198 private function all_from_posts(): Global_Classes {
265 - $order = Global_Classes_Order::make( $this->get_kit() )
266 - ->set_preview( $this->is_preview() )
267 - ->get_order();
199 + $classes_order = Global_Classes_Order::make( $this->get_kit() );
200 + $order = $classes_order->get_order();
268 201
269 202 if ( empty( $order ) ) {
270 203 return Global_Classes::make( [], [] );
271 204 }
@@ -291,9 +224,9 @@
291 224 $to_update = array_intersect( $new_ids, $current_ids );
292 225
293 226 $this->persist_class_batch_mutations( $to_delete, $to_create, $to_update, $items, $is_preview );
294 227
295 - $classes_order = Global_Classes_Order::make( $this->get_kit() )->set_preview( $this->is_preview() );
228 + $classes_order = Global_Classes_Order::make( $this->get_kit() );
296 229 $classes_order->set_order( $order );
297 230
298 231 $label_map = [];
299 232 foreach ( $order as $id ) {
@@ -310,14 +243,15 @@
310 243 array_flip( $touched_ids )
311 244 );
312 245 Global_Classes_Sync_Map::make( $this->get_kit() )->apply_changes( $touched_items, array_values( $to_delete ) );
313 246
314 - $this->bulk_clear_preview_meta( array_values( $to_update ) );
315 - $this->clear_preview_labels_for_ids( array_merge(
316 - array_values( $to_create ),
317 - array_values( $to_update ),
318 - array_values( $to_delete )
319 - ) );
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 + } );
320 254 }
321 255 }
322 256
323 257 private function iterate_class_posts_for_ids( array $class_ids ): \Generator {
@@ -334,13 +268,28 @@
334 268 ],
335 269 ],
336 270 ] );
337 271
272 + $seen_class_ids = [];
273 +
338 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 +
339 288 yield Global_Class_Post::from_post( $post, $this->is_preview() );
340 289 clean_post_cache( $post->ID );
341 290 }
342 - unset( $posts );
291 + unset( $posts, $seen_class_ids );
343 292 $this->flush_runtime_cache();
344 293 }
345 294 }
346 295
@@ -351,28 +300,13 @@
351 300 array $items_by_id,
352 301 bool $is_preview
353 302 ): void {
354 303 $relations = new Global_Classes_Relations();
355 - $post_ids_map = Global_Classes_Post_IDs::make( $this->get_kit() );
356 304
357 - $ids_to_resolve = array_values( array_merge(
358 - array_values( $to_delete ),
359 - array_values( $to_update ),
360 - array_values( $to_create )
361 - ) );
362 - $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 );
363 307
364 - $this->each_class_id_batch(
365 - array_values( $to_delete ),
366 - function ( string $class_id ) use ( $is_preview, $relations, $post_ids ) {
367 - $post = isset( $post_ids[ $class_id ] )
368 - ? Global_Class_Post::from_post_id( $post_ids[ $class_id ], false )
369 - : null;
370 -
371 - if ( ! $post ) {
372 - return;
373 - }
374 -
308 + if ( $post ) {
375 309 if ( $is_preview ) {
376 310 $post->set_preview( true );
377 311 $post->update_data( [] );
378 312 clean_post_cache( $post->get_post_id() );
@@ -380,65 +314,57 @@
380 314 $relations->clear_class_relations( $class_id );
381 315 $post->delete();
382 316 }
383 317 }
384 - );
318 + } );
385 319
386 - $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 ) {
387 321 if ( ! isset( $items_by_id[ $class_id ] ) ) {
388 322 return;
389 323 }
390 324
391 325 $item = $items_by_id[ $class_id ];
392 - $data = Global_Class_Data_Normalizer::normalize_style_fields( $item );
393 - $kit = $this->get_kit();
394 - $existing_post_id = $post_ids[ $class_id ] ?? null;
395 - $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 );
396 327
397 - if ( $existing_post ) {
398 - $existing_post->update_data( $data );
328 + if ( $is_preview ) {
329 + $post = Global_Class_Post::find_by_class_id( $class_id, true );
399 330
400 - if ( ! $is_preview ) {
401 - $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 + }
402 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 + } );
403 349
404 - clean_post_cache( $existing_post->get_post_id() );
405 -
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 ] ) ) {
406 352 return;
407 353 }
408 354
409 - $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 );
410 357
411 - if ( $created ) {
412 - $post_ids_map->set( $class_id, $created->get_post_id() );
413 - clean_post_cache( $created->get_post_id() );
358 + if ( ! $post ) {
359 + return;
414 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() );
415 366 } );
416 -
417 - $this->each_class_id_batch(
418 - $to_update,
419 - function ( string $class_id ) use ( $items_by_id, $is_preview, $post_ids ) {
420 - if ( ! isset( $items_by_id[ $class_id ] ) || ! isset( $post_ids[ $class_id ] ) ) {
421 - return;
422 - }
423 -
424 - $item = $items_by_id[ $class_id ];
425 - $post = Global_Class_Post::from_post_id( $post_ids[ $class_id ], $is_preview );
426 -
427 - if ( ! $post ) {
428 - return;
429 - }
430 -
431 - $data = Global_Class_Data_Normalizer::normalize_style_fields( $item );
432 - $post->update_data( $data );
433 -
434 - if ( ! $is_preview ) {
435 - $post->update_label( $item['label'] );
436 - }
437 -
438 - clean_post_cache( $post->get_post_id() );
439 - }
440 - );
441 367 }
442 368
443 369 public function delete_all(): void {
444 370 $order = $this->get_order();
@@ -443,9 +369,9 @@
443 369 public function delete_all(): void {
444 370 $order = $this->get_order();
445 371
446 372 $this->each_class_id_batch( $order, function ( string $class_id ) {
447 - $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 );
448 374
449 375 if ( $post ) {
450 376 $post->delete();
451 377 }
@@ -454,52 +380,8 @@
454 380 Global_Classes_Order::make( $this->get_kit() )->set_order( [] );
455 381 $this->labels()->set_labels( [] );
456 382 }
457 383
458 - private function clear_preview_labels_for_ids( array $class_ids ): void {
459 - if ( empty( $class_ids ) ) {
460 - return;
461 - }
462 -
463 - $preview_labels = Global_Classes_Labels::make( $this->get_kit() )->set_preview( true );
464 - $labels_map = $preview_labels->get_labels();
465 -
466 - if ( empty( $labels_map ) ) {
467 - return;
468 - }
469 -
470 - $ids_to_remove = array_intersect( array_unique( $class_ids ), array_keys( $labels_map ) );
471 -
472 - if ( empty( $ids_to_remove ) ) {
473 - return;
474 - }
475 -
476 - foreach ( $ids_to_remove as $id ) {
477 - unset( $labels_map[ $id ] );
478 - }
479 -
480 - $preview_labels->set_labels( $labels_map );
481 - }
482 -
483 - private function bulk_clear_preview_meta( array $class_ids ): void {
484 - if ( empty( $class_ids ) ) {
485 - return;
486 - }
487 -
488 - $post_ids_map = Global_Classes_Post_IDs::make( $this->get_kit() );
489 -
490 - foreach ( array_chunk( $class_ids, self::PERSIST_BATCH_SIZE ) as $chunk ) {
491 - $post_ids = $post_ids_map->get_post_ids( $chunk );
492 -
493 - foreach ( $post_ids as $post_id ) {
494 - delete_post_meta( $post_id, Global_Class_Post::META_KEY_DATA_PREVIEW );
495 - clean_post_cache( $post_id );
496 - }
497 -
498 - $this->flush_runtime_cache();
499 - }
500 - }
501 -
502 384 private function each_class_id_batch( $class_ids, callable $callback, int $batch_size = self::PERSIST_BATCH_SIZE ): void {
503 385 $class_ids = is_array( $class_ids ) ? $class_ids : iterator_to_array( $class_ids, false );
504 386 foreach ( array_chunk( array_values( $class_ids ), $batch_size ) as $batch ) {
505 387 foreach ( $batch as $class_id ) {
@@ -512,6 +394,19 @@
512 394 private function flush_runtime_cache(): void {
513 395 if ( function_exists( 'wp_cache_flush_runtime' ) ) {
514 396 wp_cache_flush_runtime();
515 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;
516 411 }
517 412 }