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 |