PluginProbe ʕ •ᴥ•ʔ
WPML Multilingual & Multicurrency for WooCommerce / 5.5.7
WPML Multilingual & Multicurrency for WooCommerce v5.5.7
5.5.7 5.3.8 5.3.9 5.4.3 5.4.4 5.4.5 5.5.1 5.5.1.1 5.5.2.2 5.5.2.3 5.5.3 5.5.3.1 5.5.4 5.5.5 5.5.6 trunk 0.9 1.0 1.1 1.2 1.3 1.4 1.5 2.0 2.2 2.3 2.3.1 2.3.2 3.0 3.0.1 3.1 3.2 3.2.1 3.2.2 3.3 3.3.1 3.3.2 3.3.3 3.3.4 3.4 3.4.1 3.4.2 3.4.3 3.5 3.5.1 3.5.2 3.5.3 3.5.4 3.5.5 3.6 3.6.1 3.6.10 3.6.11 3.6.2 3.6.3 3.6.4 3.6.5 3.6.5.1 3.6.6 3.6.7 3.6.8 3.6.9 3.7 3.7.1 3.7.10 3.7.11 3.7.12 3.7.13 3.7.14 3.7.15 3.7.16 3.7.2 3.7.3 3.7.4 3.7.5 3.7.6 3.7.7 3.7.8 3.7.9 3.8.0 3.8.1 3.8.2 3.8.3 3.8.4 3.8.5 3.8.6 3.9.0 3.9.1 3.9.1.1 3.9.2 3.9.3 3.9.4 3.9.5 4.0.0 4.0.1 4.0.2 4.0.3 4.0.4 4.1.0 4.1.1 4.1.2 4.1.3 4.1.4 4.10.0 4.10.1 4.10.2 4.10.3 4.10.4 4.11.2 4.11.3.2 4.11.5 4.11.6 4.12.1 4.12.4 4.12.5 4.12.6 4.2.0 4.2.0.1 4.2.1 4.2.1.1 4.2.10 4.2.2 4.2.3 4.2.4 4.2.5 4.2.6 4.2.7 4.2.7.1 4.2.8 4.2.8.1 4.2.9 4.3.0 4.3.1 4.3.2 4.3.2.1 4.3.3 4.3.4 4.3.5 4.3.6 4.3.7 4.4.0 4.4.1 4.4.2 4.4.2.1 4.5.0 4.6.0 4.6.1 4.6.2 4.6.2.1 4.6.3 4.6.5 4.6.6 4.6.7 4.7.0 4.7.1 4.7.2 4.7.3 4.7.4 4.7.5 4.7.6 4.7.7 4.7.8 4.7.9 4.8.0 4.9.0 4.9.1 5.0.1 5.0.2 5.1.1 5.1.2 5.1.3 5.2.0 5.2.1 5.3.2 5.3.3.1 5.3.4 5.3.5 5.3.6 5.3.7
woocommerce-multilingual / inc / translation-editor / class-wcml-synchronize-variations-data.php
woocommerce-multilingual / inc / translation-editor Last commit date
class-wcml-downloadable-products.php 4 weeks ago class-wcml-editor-save-filters.php 4 weeks ago class-wcml-editor-ui-product-job.php 4 weeks ago class-wcml-editor-ui-wysiwyg-field.php 5 years ago class-wcml-page-builders.php 4 weeks ago class-wcml-synchronize-product-data.php 4 weeks ago class-wcml-synchronize-variations-data.php 4 weeks ago class-wcml-translation-editor.php 4 weeks ago class-wcml-wc-admin-duplicate-product.php 4 weeks ago
class-wcml-synchronize-variations-data.php
603 lines
1 <?php
2
3 use WCML\Terms\SuspendWpmlFiltersFactory;
4 use WCML\Utilities\DB;
5 use WCML\Utilities\SyncHash;
6 use WPML\FP\Fns;
7 use WPML\FP\Obj;
8
9 class WCML_Synchronize_Variations_Data {
10
11 private $woocommerce_wpml;
12 private $sitepress;
13 private $wpdb;
14
15 public function __construct( woocommerce_wpml $woocommerce_wpml, $sitepress, wpdb $wpdb ) {
16 $this->woocommerce_wpml = $woocommerce_wpml;
17 $this->sitepress = $sitepress;
18 $this->wpdb = $wpdb;
19 }
20
21 public function add_hooks() {
22
23 add_action( 'wp_ajax_woocommerce_remove_variations', [ $this, 'remove_translations_for_variations' ], 9 );
24
25 add_action( 'wp_ajax_wpml_tt_save_term_translation', [ $this, 'update_taxonomy_in_variations' ], 7 );
26
27 add_action( 'wp_ajax_woocommerce_remove_variation', [ $this, 'remove_variation_ajax' ], 9 );
28
29 }
30
31 public function sync_product_variations_on_bulk_edit( $bulk_action, $data, $product_id ) {
32 $this->sync_product_variations_action( $product_id );
33 }
34
35 public function sync_product_variations_action( $productId ) {
36 $isOriginal = $this->woocommerce_wpml->products->is_original_product( $productId );
37
38 if ( ! $isOriginal ) {
39 return;
40 }
41
42 $trid = $this->sitepress->get_element_trid( $productId, 'post_product' );
43 if ( empty( $trid ) ) {
44 $trid = $this->wpdb->get_var(
45 $this->wpdb->prepare(
46 "SELECT trid FROM {$this->wpdb->prefix}icl_translations
47 WHERE element_id = %d AND element_type = 'post_product'",
48 $productId
49 )
50 );
51 }
52 if ( empty( $trid ) ) {
53 return;
54 }
55
56 $translationsIds = [];
57 $translationsLanguages = [];
58 $translations = $this->sitepress->get_element_translations( $trid, 'post_product' );
59 foreach ( $translations as $translation ) {
60 if ( ! $translation->original ) {
61 $translationsIds[] = $translation->element_id;
62 $translationsLanguages[ $translation->element_id ] = $translation->language_code;
63 }
64 }
65
66 if ( empty( $translationsIds ) ) {
67 return;
68 }
69
70 $product = get_post( $productId );
71 do_action( \WCML\Synchronization\Hooks::HOOK_SYNCHRONIZE_PRODUCT_COMPONENT, $product, $translationsIds, $translationsLanguages, \WCML\Synchronization\Store::COMPONENT_VARIATIONS );
72 do_action( \WCML\Synchronization\Hooks::HOOK_SYNCHRONIZE_PRODUCT_COMPONENT, $product, $translationsIds, $translationsLanguages, \WCML\Synchronization\Store::COMPONENT_ATTRIBUTES );
73 }
74
75 public function sync_product_variations_custom_data( $product_id ) {
76
77 $is_variable_product = $this->woocommerce_wpml->products->is_variable_product( $product_id );
78 if ( $is_variable_product ) {
79 $get_all_post_variations = $this->wpdb->get_results(
80 $this->wpdb->prepare(
81 "SELECT * FROM {$this->wpdb->posts}
82 WHERE post_status IN ('publish','private')
83 AND post_type = 'product_variation'
84 AND post_parent = %d
85 ORDER BY ID",
86 $product_id
87 )
88 );
89
90 foreach ( $get_all_post_variations as $post_data ) {
91
92 if ( (int) $this->woocommerce_wpml->settings['enable_multi_currency'] === WCML_MULTI_CURRENCIES_INDEPENDENT ) {
93 $this->woocommerce_wpml->multi_currency->custom_prices->sync_product_variations_custom_prices( $post_data->ID );
94 }
95
96 $this->woocommerce_wpml->downloadable->save_files_option( $post_data->ID );
97
98 }
99 }
100 }
101
102 public function sync_product_variations( $product_id, $tr_product_id, $lang, $args = [] ) {
103 global $wpml_post_translations;
104
105 $default_args = [
106 'editor_translations' => [],
107 'is_troubleshooting' => false,
108 'is_duplicate' => false,
109 ];
110 $args = wp_parse_args( $args, $default_args );
111
112 $is_variable_product = $this->woocommerce_wpml->products->is_variable_product( $product_id );
113
114 if ( ! $is_variable_product ) {
115 return;
116 }
117
118 $all_variations = $this->get_product_variations( $product_id );
119 if ( empty( $all_variations ) ) {
120 return;
121 }
122
123 remove_action( 'save_post', [ $wpml_post_translations, 'save_post_actions' ], 100 );
124
125 $translation_variations = [
126 'insert' => [],
127 'update' => [],
128 ];
129 $delayedFields = [];
130 $current_variations = $this->get_product_variations( $tr_product_id );
131 $wcml_data_store = wcml_product_data_store_cpt();
132
133 foreach ( $all_variations as $post_data ) {
134 $original_variation_id = $post_data->ID;
135 $isNewTranslatedVariation = false;
136 $this->woocommerce_wpml->downloadable->save_files_option( $original_variation_id );
137
138 $variation_id = $this->get_variation_id_by_lang( $lang, $original_variation_id );
139
140 if ( ! empty( $variation_id ) ) {
141 $this->wpdb->update(
142 $this->wpdb->posts,
143 [
144 'post_status' => $post_data->post_status,
145 'post_modified' => $post_data->post_modified,
146 'post_modified_gmt' => $post_data->post_modified_gmt,
147 'post_parent' => $tr_product_id,
148 'menu_order' => $post_data->menu_order,
149 ],
150 [ 'ID' => $variation_id ]
151 );
152 $translation_variations['update'][] = (int) $variation_id;
153 } else {
154 $replaced_guid = str_replace( $product_id, $tr_product_id, $post_data->guid );
155 $replaced_slug = str_replace( $product_id, $tr_product_id, $post_data->post_name );
156 $variation_id = wp_insert_post(
157 [
158 'post_author' => $post_data->post_author,
159 'post_date_gmt' => $post_data->post_date_gmt,
160 'post_content' => $post_data->post_content,
161 'post_title' => $post_data->post_title,
162 'post_excerpt' => $post_data->post_excerpt,
163 'post_status' => $post_data->post_status,
164 'comment_status' => $post_data->comment_status,
165 'ping_status' => $post_data->ping_status,
166 'post_password' => $post_data->post_password,
167 'post_name' => $replaced_slug,
168 'to_ping' => $post_data->to_ping,
169 'pinged' => $post_data->pinged,
170 'post_modified' => $post_data->post_modified,
171 'post_modified_gmt' => $post_data->post_modified_gmt,
172 'post_content_filtered' => $post_data->post_content_filtered,
173 'post_parent' => $tr_product_id,
174 'guid' => $replaced_guid,
175 'menu_order' => $post_data->menu_order,
176 'post_type' => $post_data->post_type,
177 'post_mime_type' => $post_data->post_mime_type,
178 'comment_count' => $post_data->comment_count,
179 ]
180 );
181 $trid = $this->sitepress->get_element_trid( $original_variation_id, 'post_product_variation' );
182 $this->sitepress->set_element_language_details( $variation_id, 'post_product_variation', $trid, $lang );
183 $isNewTranslatedVariation = true;
184 $translation_variations['insert'][] = (int) $variation_id;
185 $delayedFields[] = [
186 'post_id' => $variation_id,
187 'meta_key' => '_wcml_duplicate_of_variation',
188 'meta_value' => $original_variation_id,
189 ];
190 }
191
192 $variationDelayedFields = $this->duplicate_variation_data( $original_variation_id, $variation_id, $args['editor_translations'], $lang, $args['is_troubleshooting'], $isNewTranslatedVariation );
193 $delayedFields = array_merge( $delayedFields, $variationDelayedFields );
194
195 $this->sync_variations_taxonomies( $original_variation_id, $variation_id, $lang, $isNewTranslatedVariation );
196
197 if ( $args['is_duplicate'] ) {
198 $delayedFields[] = [
199 'post_id' => $variation_id,
200 'meta_key' => '_variation_description',
201 'meta_value' => get_post_meta( $original_variation_id, '_variation_description', true ),
202 ];
203 }
204
205 if ( isset( $args['editor_translations'][ md5( '_variation_description' . $original_variation_id ) ] ) ) {
206 $delayedFields[] = [
207 'post_id' => $variation_id,
208 'meta_key' => '_variation_description',
209 'meta_value' => $args['editor_translations'][ md5( '_variation_description' . $original_variation_id ) ],
210 ];
211 }
212
213 $this->woocommerce_wpml->media->sync_variation_thumbnail_id( $original_variation_id, $variation_id, $lang );
214
215 $this->woocommerce_wpml->downloadable->sync_files_to_translations( $original_variation_id, $variation_id, $args['editor_translations'] );
216
217 $this->delete_removed_variation_attributes( $product_id, $variation_id );
218
219 $this->woocommerce_wpml->sync_product_data->sync_product_stock( wc_get_product( $original_variation_id ), wc_get_product( $variation_id ) );
220
221 $wcml_data_store->update_lookup_table_data( $variation_id );
222
223 }
224
225 $this->processDelayedFields( $delayedFields, $translation_variations['update'] );
226
227 foreach ( $current_variations as $current_post_variation ) {
228 if ( ! in_array( (int) $current_post_variation->ID, $translation_variations['update'] ) ) {
229 wp_delete_post( $current_post_variation->ID, true );
230 }
231 }
232
233 delete_transient( 'wc_product_children_' . $tr_product_id );
234 delete_transient( '_transient_wc_product_children_ids_' . $tr_product_id );
235
236 $this->sync_prices_variation_ids( $product_id, $tr_product_id, $lang );
237
238 add_action( 'save_post', [ $wpml_post_translations, 'save_post_actions' ], 100, 2 );
239
240 foreach ( $current_variations as $current_post_variation ) {
241 if ( in_array( (int) $current_post_variation->ID, $translation_variations['update'], true ) ) {
242 wp_cache_delete( $current_post_variation->ID, 'post_meta' );
243 }
244 }
245 }
246
247 public function get_variation_id_by_lang( $lang, $original_variation_id ) {
248 return $this->sitepress->get_object_id( $original_variation_id, 'product_variation', false, $lang );
249 }
250
251 public function sync_variations_taxonomies( $original_variation_id, $tr_variation_id, $lang, $isNewTranslatedVariation = false ) {
252 global $wpml_term_translations;
253 $returnTrue = Fns::always( true );
254 add_filter( 'wpml_disable_term_adjust_id', $returnTrue );
255 $filtersSuspend = SuspendWpmlFiltersFactory::create();
256
257 $taxonomies = get_object_taxonomies( 'product_variation' );
258 $taxonomiesToSync = array_values( array_diff( $taxonomies, [ 'translation_priority' ] ) );
259 $taxonomiesToSync = apply_filters( 'wcml_product_variations_taxonomies_to_sync', $taxonomiesToSync, $original_variation_id, $tr_variation_id, $lang );
260 $found = false;
261 $all_terms = WPML_Non_Persistent_Cache::get( $original_variation_id, __CLASS__, $found );
262 if ( ! $found ) {
263 $all_terms = wp_get_object_terms( $original_variation_id, $taxonomiesToSync );
264 if ( is_wp_error( $all_terms ) ) {
265 $all_terms = [];
266 }
267 WPML_Non_Persistent_Cache::set( $original_variation_id, $all_terms, __CLASS__ );
268 }
269
270 foreach ( $taxonomiesToSync as $taxonomy ) {
271 $terms = array_filter(
272 $all_terms,
273 function ( $term ) use ( $taxonomy ) {
274 return $term->taxonomy === $taxonomy;
275 }
276 );
277
278 if ( empty( $terms ) ) {
279 if (
280 ! $isNewTranslatedVariation &&
281 ! $this->woocommerce_wpml->terms->is_translatable_wc_taxonomy( $taxonomy )
282 ) {
283 wp_set_object_terms( $tr_variation_id, [], $taxonomy );
284 }
285 continue;
286 }
287
288 $tt_ids = [];
289 $tt_ids_trans = [];
290 $term_ids = [];
291 $term_ids_trans = [];
292
293 foreach ( $terms as $term ) {
294 if ( $this->sitepress->is_translated_taxonomy( $taxonomy ) ) {
295 $tt_ids[] = $term->term_taxonomy_id;
296 } else {
297 $term_ids[] = $term->term_id;
298 }
299 }
300
301 foreach ( $tt_ids as $tt_id ) {
302 $tt_id_trans = $wpml_term_translations->element_id_in( $tt_id, $lang );
303 if ( $tt_id_trans ) {
304 $tt_ids_trans[] = $tt_id_trans;
305 }
306 }
307
308 $tt_ids_trans = array_values( array_unique( array_map( 'intval', $tt_ids_trans ) ) );
309 if ( ! empty( $tt_ids_trans ) ) {
310 $term_ids_trans = $this->wpdb->get_col(
311 $this->wpdb->prepare(
312 "SELECT term_id FROM {$this->wpdb->term_taxonomy} WHERE term_taxonomy_id IN (" . DB::prepareIn( $tt_ids_trans, '%d' ) . ") LIMIT %d",
313 count( $tt_ids_trans )
314 )
315 );
316 }
317
318 $terms_to_sync = array_merge( $term_ids, $term_ids_trans );
319 $terms_to_sync = array_unique( array_map( 'intval', $terms_to_sync ) );
320
321 if ( empty( $terms_to_sync ) ) {
322 continue;
323 }
324 wp_set_object_terms( $tr_variation_id, $terms_to_sync, $taxonomy, true );
325 }
326
327 remove_filter( 'wpml_disable_term_adjust_id', $returnTrue );
328 $filtersSuspend->resume();
329 }
330
331 public function duplicate_variation_data( $original_variation_id, $variation_id, $data, $lang, $trbl, $deprecatedBool = false ) {
332 global $iclTranslationManagement;
333 $settings = $iclTranslationManagement->settings['custom_fields_translation'];
334 $all_meta = get_post_custom( $original_variation_id );
335 $post_fields = null;
336 $excludedKeys = WPML_Post_Custom_Field_Setting_Keys::get_excluded_keys();
337 $delayedFields = [];
338
339 unset( $all_meta[ SyncHash::META_KEY ] );
340
341 foreach ( $all_meta as $meta_key => $meta ) {
342 if ( in_array( $meta_key, $excludedKeys, true ) ) {
343 continue;
344 }
345
346 $meta_value = reset( $meta );
347 if ( ! $meta_value ) {
348 $meta_value = '';
349 }
350
351 if ( substr( $meta_key, 0, 10 ) === 'attribute_' ) {
352 if ( '' !== $meta_value ) {
353 $trn_post_meta = $this->woocommerce_wpml->attributes->get_translated_variation_attribute_post_meta( $meta_value, $meta_key, $original_variation_id, $variation_id, $lang );
354 $meta_value = $trn_post_meta['meta_value'];
355 $meta_key = $trn_post_meta['meta_key'];
356 } else {
357 $meta_value = '';
358 }
359 $delayedFields[] = [
360 'post_id' => $variation_id,
361 'meta_key' => $meta_key,
362 'meta_value' => maybe_unserialize( $meta_value ),
363 ];
364 continue;
365 }
366
367 if ( ! isset( $settings[ $meta_key ] ) || WPML_IGNORE_CUSTOM_FIELD === (int) $settings[ $meta_key ] ) {
368 continue;
369 }
370
371 if (
372 in_array( $meta_key, [ '_sale_price', '_regular_price', '_price' ], true ) &&
373 ( $trbl || WCML_MULTI_CURRENCIES_INDEPENDENT === (int) $this->woocommerce_wpml->settings['enable_multi_currency'] )
374 ) {
375 $delayedFields[] = [
376 'post_id' => $variation_id,
377 'meta_key' => $meta_key,
378 'meta_value' => $meta_value,
379 ];
380 continue;
381 }
382
383 if ( (int) Obj::prop( $meta_key, $settings ) === WPML_COPY_CUSTOM_FIELD ) {
384 $delayedFields[] = [
385 'post_id' => $variation_id,
386 'meta_key' => $meta_key,
387 'meta_value' => $meta_value,
388 ];
389 continue;
390 }
391
392 if ( (int) Obj::prop( $meta_key, $settings ) === WPML_TRANSLATE_CUSTOM_FIELD ) {
393 $post_fields = $this->woocommerce_wpml->sync_product_data->sync_custom_field_value( $meta_key, $data, $variation_id, $post_fields, $original_variation_id, true );
394 continue;
395 }
396 }
397
398 WCML_Synchronize_Product_Data::syncDeletedCustomFields( $original_variation_id, $variation_id );
399
400 return $delayedFields;
401 }
402
403 public function delete_removed_variation_attributes( $orig_product_id, $variation_id ) {
404
405 $original_product_attr = get_post_meta( $orig_product_id, '_product_attributes', true );
406
407 $get_all_variation_attributes = $this->wpdb->get_results(
408 $this->wpdb->prepare(
409 "SELECT * FROM {$this->wpdb->postmeta} WHERE post_id = %d AND meta_key LIKE 'attribute_%%' ",
410 $variation_id
411 )
412 );
413
414 foreach ( $get_all_variation_attributes as $variation_attribute ) {
415 $attribute_name = substr( $variation_attribute->meta_key, 10 );
416 if ( ! isset( $original_product_attr[ $attribute_name ] ) ) {
417 delete_post_meta( $variation_id, $variation_attribute->meta_key );
418 }
419 }
420
421 }
422
423 public function get_product_variations( $product_id ) {
424
425 $cache_key = $product_id;
426 $cache_group = 'product_variations';
427 $temp_product_variations = wp_cache_get( $cache_key, $cache_group );
428 if ( $temp_product_variations ) {
429 return $temp_product_variations;
430 }
431
432 $variations = $this->wpdb->get_results(
433 $this->wpdb->prepare(
434 "SELECT * FROM {$this->wpdb->posts}
435 WHERE post_status IN ('publish','private')
436 AND post_type = 'product_variation'
437 AND post_parent = %d ORDER BY ID",
438 $product_id
439 )
440 );
441
442 wp_cache_set( $cache_key, $variations, $cache_group );
443
444 return $variations;
445 }
446
447 public function remove_translations_for_variations() {
448 check_ajax_referer( 'delete-variations', 'security' );
449
450 if ( ! current_user_can( 'edit_products' ) ) {
451 die( -1 );
452 }
453 $variation_ids = (array) $_POST['variation_ids'];
454
455 foreach ( $variation_ids as $variation_id ) {
456 $trid = $this->sitepress->get_element_trid( $variation_id, 'post_product_variation' );
457 $translations = $this->sitepress->get_element_translations( $trid, 'post_product_variation' );
458
459 foreach ( $translations as $translation ) {
460 if ( ! $translation->original ) {
461 wp_delete_post( $translation->element_id );
462 }
463 }
464 }
465 }
466
467 public function update_taxonomy_in_variations() {
468 _doing_it_wrong(
469 'WCML_Synchronize_Variations_Data::update_taxonomy_in_variations',
470 __( 'This method is no longer executed by WPML.' ),
471 '5.3.5'
472 );
473 }
474
475 public function remove_variation_ajax() {
476 check_ajax_referer( 'delete-variation', 'security' );
477
478 if ( ! current_user_can( 'edit_products' ) ) {
479 die( -1 );
480 }
481
482 if ( isset( $_POST['variation_id'] ) ) {
483 $trid = $this->sitepress->get_element_trid( (int) filter_input( INPUT_POST, 'variation_id', FILTER_SANITIZE_NUMBER_INT ), 'post_product_variation' );
484 if ( $trid ) {
485 $translations = $this->sitepress->get_element_translations( $trid, 'post_product_variation' );
486 if ( $translations ) {
487 foreach ( $translations as $translation ) {
488 if ( ! $translation->original ) {
489 wp_delete_post( $translation->element_id, true );
490 }
491 }
492 }
493 }
494 }
495 }
496
497 public function sync_prices_variation_ids( $product_id, $tr_product_id, $language ) {
498
499 $prices_variation_ids_fields = [
500 '_min_price_variation_id',
501 '_min_regular_price_variation_id',
502 '_min_sale_price_variation_id',
503 '_max_price_variation_id',
504 '_max_regular_price_variation_id',
505 '_max_sale_price_variation_id',
506 ];
507
508 foreach ( $prices_variation_ids_fields as $price_field ) {
509
510 $original_price_variation_id = get_post_meta( $product_id, $price_field, true );
511
512 if ( $original_price_variation_id ) {
513 $translated_price_variation_id = apply_filters( 'wpml_object_id', $original_price_variation_id, 'product_variation', false, $language );
514 if ( ! is_null( $translated_price_variation_id ) ) {
515 update_post_meta( $tr_product_id, $price_field, $translated_price_variation_id );
516 }
517 }
518 }
519 }
520
521 private function processDelayedFields( $delayedFields, $existingVariationTranslations ) {
522 if ( empty( $delayedFields ) ) {
523 return;
524 }
525
526 $allMetaData = empty( $existingVariationTranslations) ? [] : $this->wpdb->get_results(
527 "SELECT meta_id, post_id, meta_key FROM {$this->wpdb->postmeta} where post_id IN (" . DB::prepareIn( $existingVariationTranslations, '%d' ) . ")",
528 ARRAY_A
529 );
530 $metaDataByVariationIds = [];
531 foreach ( $allMetaData as $metaData ) {
532 $metaDataByVariationIds[ $metaData['post_id'] ][ $metaData['meta_id'] ] = $metaData['meta_key'];
533 }
534
535 $delayedFieldsActions = [];
536 foreach ( $delayedFields as $delayedFieldData ) {
537 $fieldPostId = $delayedFieldData['post_id'];
538 $fieldMetaKey = $delayedFieldData['meta_key'];
539 $fieldMetaValue = $delayedFieldData['meta_value'];
540 $delayedFieldsActions[ $fieldMetaKey ]['meta_value'] = $fieldMetaValue;
541 $metaDataByVariationId = Obj::propOr( [], $fieldPostId, $metaDataByVariationIds );
542 if ( in_array( $fieldMetaKey, $metaDataByVariationId, true ) ) {
543 $fieldMetaIds = array_keys( $metaDataByVariationId, $fieldMetaKey );
544 if ( count( $fieldMetaIds ) > 1 ) {
545 $delayedFieldsActions[ $fieldMetaKey ]['delete'][ $fieldPostId ] = $fieldMetaIds;
546 $delayedFieldsActions[ $fieldMetaKey ]['insert'][ $fieldPostId ] = $fieldMetaValue;
547 } else {
548 $delayedFieldsActions[ $fieldMetaKey ]['update'][ $fieldMetaValue ][ $fieldPostId ] = $fieldPostId;
549 }
550 } else {
551 $delayedFieldsActions[ $fieldMetaKey ]['insert'][ $fieldPostId ] = $fieldMetaValue;
552 }
553 }
554
555 foreach ( $delayedFieldsActions as $delayedFieldMetaKey => $delayedFieldMetaData ) {
556 $dataToDelete = Obj::propOr( [], 'delete', $delayedFieldMetaData );
557 if ( ! empty( $dataToDelete ) ) {
558 $metaIdsToDelete = [];
559 foreach ( $dataToDelete as $itemMetaIdsToDelete ) {
560 $metaIdsToDelete = array_merge( $metaIdsToDelete, $itemMetaIdsToDelete );
561 }
562 $this->wpdb->query(
563 "DELETE FROM {$this->wpdb->postmeta}
564 WHERE meta_id IN (" . DB::prepareIn( $metaIdsToDelete, '%d' ) . ")"
565 );
566 }
567
568 $dataToInsert = Obj::propOr( [], 'insert', $delayedFieldMetaData );
569 if ( ! empty( $dataToInsert )) {
570 $insertValues = [];
571 foreach ( $dataToInsert as $idToInsert => $valueToInsert ) {
572 $insertValues[] = $this->wpdb->prepare( "(%d,%s,%s)", $idToInsert, $delayedFieldMetaKey, $valueToInsert );
573 }
574 $this->wpdb->query(
575 "INSERT INTO {$this->wpdb->postmeta}
576 (`post_id`,`meta_key`,`meta_value`)
577 VALUES " . implode( ',', $insertValues )
578 );
579 }
580
581 $dataToUpdate = Obj::propOr( [], 'update', $delayedFieldMetaData );
582 if ( ! empty( $dataToUpdate ) ) {
583 foreach ( $dataToUpdate as $updateMetaValue => $idsToUpdate ) {
584 $idsToUpdate = array_values( array_unique( array_map( 'intval', $idsToUpdate ) ) );
585 if ( ! empty( $idsToUpdate ) ) {
586 $this->wpdb->query(
587 $this->wpdb->prepare(
588 "UPDATE {$this->wpdb->postmeta}
589 SET meta_value = %s
590 WHERE meta_key = %s
591 AND post_id IN (" . DB::prepareIn( $idsToUpdate, '%d' ) . ")",
592 $updateMetaValue,
593 $delayedFieldMetaKey
594 )
595 );
596 }
597 }
598 }
599 }
600 }
601
602 }
603