/inc/translation-editor/class-wcml-synchronize-product-data.php

  1. <?php 
  2.  
  3. class WCML_Synchronize_Product_Data{ 
  4.  
  5. private $woocommerce_wpml; 
  6. /** 
  7. * @var SitePress 
  8. */ 
  9. private $sitepress; 
  10. private $wpdb; 
  11.  
  12. public function __construct( &$woocommerce_wpml, &$sitepress, &$wpdb ) { 
  13. $this->woocommerce_wpml = $woocommerce_wpml; 
  14. $this->sitepress = $sitepress; 
  15. $this->wpdb = $wpdb; 
  16.  
  17. if( is_admin() ) { 
  18. // filters to sync variable products 
  19. add_action( 'save_post', array( $this, 'synchronize_products' ), 110, 2 ); // After WPML 
  20.  
  21. add_action( 'icl_pro_translation_completed', array( $this, 'icl_pro_translation_completed' ) ); 
  22.  
  23. add_filter( 'icl_make_duplicate', array( $this, 'icl_make_duplicate'), 110, 4 ); 
  24.  
  25. //quick & bulk edit 
  26. add_action( 'woocommerce_product_quick_edit_save', array( $this, 'woocommerce_product_quick_edit_save' ) ); 
  27. add_action( 'woocommerce_product_bulk_edit_save', array( $this, 'woocommerce_product_quick_edit_save' ) ); 
  28.  
  29. add_action( 'wpml_translation_update', array( $this, 'icl_connect_translations_action' ) ); 
  30.  
  31. add_action( 'deleted_term_relationships', array( $this, 'delete_term_relationships_update_term_count' ), 10, 2 ); 
  32.  
  33. add_action( 'woocommerce_reduce_order_stock', array( $this, 'sync_product_stocks_reduce' ) ); 
  34. add_action( 'woocommerce_restore_order_stock', array( $this, 'sync_product_stocks_restore' ) ); 
  35. add_action( 'woocommerce_product_set_stock_status', array($this, 'sync_stock_status_for_translations' ), 10, 2); 
  36. add_action( 'woocommerce_variation_set_stock_status', array($this, 'sync_stock_status_for_translations' ), 10, 2); 
  37.  
  38. add_filter( 'future_product', array( $this, 'set_schedule_for_translations'), 10, 2 ); 
  39.  
  40. /** 
  41. * This function takes care of synchronizing products 
  42. */ 
  43. public function synchronize_products( $post_id, $post ) { 
  44. global $pagenow, $wp; 
  45.  
  46. $original_language = $this->woocommerce_wpml->products->get_original_product_language( $post_id ); 
  47. $current_language = $this->sitepress->get_current_language(); 
  48. $original_product_id = $this->woocommerce_wpml->products->get_original_product_id( $post_id ); 
  49.  
  50. $wpml_media_options = maybe_unserialize( get_option( '_wpml_media' ) ); 
  51.  
  52. if( $wpml_media_options[ 'new_content_settings' ][ 'duplicate_media' ] ) { 
  53. //sync product gallery 
  54. $this->woocommerce_wpml->media->sync_product_gallery( $original_product_id ); 
  55. // check its a product 
  56. $post_type = get_post_type( $post_id ); 
  57. //set trid for variations 
  58. if ( $post_type == 'product_variation' ) { 
  59. $var_lang = $this->sitepress->get_language_for_element( wp_get_post_parent_id( $post_id ), 'post_product' ); 
  60. if( $this->woocommerce_wpml->products->is_original_product( wp_get_post_parent_id( $post_id ) ) ) { 
  61. $this->sitepress->set_element_language_details( $post_id, 'post_product_variation', false, $var_lang ); 
  62.  
  63. // exceptions 
  64. $ajax_call = ( !empty( $_POST[ 'icl_ajx_action' ] ) && $_POST[ 'icl_ajx_action' ] == 'make_duplicates' ); 
  65. $api_call = !empty( $wp->query_vars['wc-api-version'] ); 
  66. if ( 
  67. $post_type != 'product' || 
  68. ( empty( $original_product_id ) || isset( $_POST[ 'autosave' ] ) ) || 
  69. ( $pagenow != 'post.php' && $pagenow != 'post-new.php' && $pagenow != 'admin.php' && !$ajax_call && !$api_call ) || 
  70. ( isset( $_GET[ 'action' ] ) && $_GET[ 'action' ] == 'trash' ) 
  71. ) { 
  72. return; 
  73. // Remove filter to avoid double sync 
  74. remove_action( 'save_post', array( $this, 'synchronize_products' ), 110, 2 ); 
  75.  
  76. do_action( 'wcml_before_sync_product', $original_product_id, $post_id ); 
  77.  
  78. //trnsl_interface option 
  79. if ( !$this->woocommerce_wpml->settings['trnsl_interface'] && $original_language != $current_language ) { 
  80. if( !isset( $_POST[ 'wp-preview' ] ) || empty( $_POST[ 'wp-preview' ] ) ) { 
  81. //make sure we sync post in current language 
  82. $post_id = apply_filters( 'translate_object_id', $post_id, 'product', false, $current_language ); 
  83. $this->sync_product_data( $original_product_id, $post_id, $current_language ); 
  84. return; 
  85.  
  86. //update products order 
  87. $this->woocommerce_wpml->products->update_order_for_product_translations( $original_product_id ); 
  88.  
  89. // pick posts to sync 
  90. $trid = $this->sitepress->get_element_trid( $original_product_id, 'post_product' ); 
  91. $translations = $this->sitepress->get_element_translations( $trid, 'post_product', false, true ); 
  92.  
  93. foreach( $translations as $translation ) { 
  94. if ( !$translation->original ) { 
  95. $this->sync_product_data( $original_product_id, $translation->element_id, $translation->language_code ); 
  96.  
  97. //save custom options for variations 
  98. $this->woocommerce_wpml->sync_variations_data->sync_product_variations_custom_data( $original_product_id ); 
  99.  
  100. if( $this->woocommerce_wpml->settings[ 'enable_multi_currency' ] == WCML_MULTI_CURRENCIES_INDEPENDENT ) { 
  101. //save custom prices 
  102. $this->woocommerce_wpml->multi_currency->custom_prices->save_custom_prices( $original_product_id ); 
  103.  
  104. //save files option 
  105. $this->woocommerce_wpml->downloadable->save_files_option( $original_product_id ); 
  106.  
  107.  
  108. public function sync_product_data( $original_product_id, $tr_product_id, $lang ) { 
  109.  
  110. do_action( 'wcml_before_sync_product_data', $original_product_id, $tr_product_id, $lang ); 
  111.  
  112. $this->duplicate_product_post_meta( $original_product_id, $tr_product_id ); 
  113.  
  114. $this->sync_date_and_parent( $original_product_id, $tr_product_id, $lang ); 
  115.  
  116. $this->woocommerce_wpml->attributes->sync_product_attr( $original_product_id, $tr_product_id ); 
  117.  
  118. $this->woocommerce_wpml->attributes->sync_default_product_attr( $original_product_id, $tr_product_id, $lang ); 
  119.  
  120. $wpml_media_options = maybe_unserialize( get_option( '_wpml_media' ) ); 
  121. //sync media 
  122. if( $wpml_media_options[ 'new_content_settings' ][ 'duplicate_featured' ] ) { 
  123. //sync feature image 
  124. $this->woocommerce_wpml->media->sync_thumbnail_id( $original_product_id, $tr_product_id, $lang ); 
  125.  
  126. //sync taxonomies 
  127. $this->sync_product_taxonomies( $original_product_id, $tr_product_id, $lang ); 
  128.  
  129. //duplicate variations 
  130. $this->woocommerce_wpml->sync_variations_data->sync_product_variations( $original_product_id, $tr_product_id, $lang ); 
  131.  
  132. $this->sync_linked_products( $original_product_id, $tr_product_id, $lang ); 
  133.  
  134. // Clear any unwanted data 
  135. wc_delete_product_transients( $tr_product_id ); 
  136.  
  137. public function sync_product_taxonomies( $original_product_id, $tr_product_id, $lang ) { 
  138. $taxonomies = get_object_taxonomies( 'product' ); 
  139. remove_filter( 'terms_clauses', array( $this->sitepress, 'terms_clauses' ), 10, 4 ); 
  140. foreach( $taxonomies as $taxonomy ) { 
  141.  
  142. $terms = wp_get_object_terms( $original_product_id, $taxonomy ); 
  143. $tt_ids = array(); 
  144. $tt_names = array(); 
  145. if ($terms) { 
  146. foreach ($terms as $term) { 
  147. if( $term->taxonomy == 'product_type' ) { 
  148. $tt_names[] = $term->name; 
  149. continue; 
  150. $tt_ids[] = $term->term_id; 
  151.  
  152. if( $taxonomy == 'product_type' ) { 
  153. wp_set_post_terms( $tr_product_id, $tt_names, $taxonomy ); 
  154. }else{ 
  155. $this->wcml_update_term_count_by_ids( $tt_ids, $lang, $taxonomy, $tr_product_id ); 
  156. add_filter( 'terms_clauses', array( $this->sitepress, 'terms_clauses' ), 10, 4 ); 
  157.  
  158. public function delete_term_relationships_update_term_count( $object_id, $tt_ids ) { 
  159.  
  160. if( get_post_type( $object_id ) == 'product' ) { 
  161.  
  162. $language_details = $this->sitepress->get_element_language_details( $object_id, 'post_product' ); 
  163. $translations = $this->sitepress->get_element_translations( $language_details->trid, 'post_product', false, true ); 
  164.  
  165. foreach( $translations as $translation ) { 
  166. if ( !$translation->original ) { 
  167. $this->wcml_update_term_count_by_ids( $tt_ids, $translation->language_code ); 
  168.  
  169. public function wcml_update_term_count_by_ids( $tt_ids, $language, $taxonomy = '', $tr_product_id = false ) { 
  170. $terms_array = array(); 
  171. $terms_to_insert = array(); 
  172.  
  173. foreach( $tt_ids as $tt_id ) { 
  174.  
  175. $tr_id = apply_filters( 'translate_object_id', $tt_id, $taxonomy, false, $language ); 
  176.  
  177. if( !is_null( $tr_id ) ) { 
  178. // not using get_term - unfiltered get_term 
  179. $translated_term = $this->wpdb->get_row( $this->wpdb->prepare( " 
  180. SELECT * FROM {$this->wpdb->terms} t JOIN {$this->wpdb->term_taxonomy} x ON x.term_id = t.term_id WHERE t.term_id = %d", $tr_id ) ); 
  181. if( is_taxonomy_hierarchical( $taxonomy ) ) { 
  182. $terms_to_insert[] = (int)$translated_term->term_id; 
  183. }else{ 
  184. $terms_to_insert[] = $translated_term->slug; 
  185.  
  186. $terms_array[] = $translated_term->term_taxonomy_id; 
  187.  
  188.  
  189. if( $tr_product_id ) { 
  190. wp_set_post_terms( $tr_product_id, $terms_to_insert, $taxonomy ); 
  191.  
  192. if( in_array( $taxonomy, array( 'product_cat', 'product_tag' ) ) ) { 
  193. $this->sitepress->switch_lang( $language ); 
  194. wp_update_term_count( $terms_array, $taxonomy ); 
  195. $this->sitepress->switch_lang( ); 
  196.  
  197. public function sync_linked_products( $product_id, $translated_product_id, $lang ) { 
  198. //sync up-sells 
  199. $original_up_sells = maybe_unserialize( get_post_meta( $product_id, '_upsell_ids', true ) ); 
  200. $trnsl_up_sells = array(); 
  201. if( $original_up_sells ) { 
  202. foreach( $original_up_sells as $original_up_sell_product ) { 
  203. $trnsl_up_sells[] = apply_filters( 'translate_object_id', $original_up_sell_product, get_post_type( $original_up_sell_product ), false, $lang ); 
  204. update_post_meta( $translated_product_id, '_upsell_ids', $trnsl_up_sells ); 
  205. //sync cross-sells 
  206. $original_cross_sells = maybe_unserialize( get_post_meta( $product_id, '_crosssell_ids', true ) ); 
  207. $trnsl_cross_sells = array(); 
  208. if( $original_cross_sells ) 
  209. foreach( $original_cross_sells as $original_cross_sell_product ) { 
  210. $trnsl_cross_sells[] = apply_filters( 'translate_object_id', $original_cross_sell_product, get_post_type( $original_cross_sell_product ), false, $lang ); 
  211. update_post_meta( $translated_product_id, '_crosssell_ids', $trnsl_cross_sells ); 
  212. // refresh parent-children transients (e.g. this child goes to private or draft) 
  213. $translated_product_parent_id = wp_get_post_parent_id( $translated_product_id ); 
  214. if ( $translated_product_parent_id ) { 
  215. delete_transient( 'wc_product_children_' . $translated_product_parent_id ); 
  216. delete_transient( '_transient_wc_product_children_ids_' . $translated_product_parent_id ); 
  217.  
  218.  
  219.  
  220. public function sync_product_stocks_reduce( $order ) { 
  221. return $this->sync_product_stocks( $order, 'reduce' ); 
  222.  
  223. public function sync_product_stocks_restore( $order ) { 
  224. return $this->sync_product_stocks( $order, 'restore' ); 
  225.  
  226. /** 
  227. * @param $order WC_Order 
  228. * @param $action 
  229. */ 
  230. public function sync_product_stocks( $order, $action ) { 
  231.  
  232. foreach( $order->get_items() as $item ) { 
  233.  
  234. if( $item instanceof WC_Order_Item_Product ) { 
  235. $variation_id = $item->get_variation_id(); 
  236. $product_id = $item->get_product_id(); 
  237. $qty = $item->get_quantity(); 
  238. }else{ 
  239. $variation_id = isset( $item[ 'variation_id' ] ) ? $item[ 'variation_id' ] : 0; 
  240. $product_id = $item[ 'product_id' ]; 
  241. $qty = $item[ 'qty' ]; 
  242.  
  243. if( $variation_id > 0 ) { 
  244. $trid = $this->sitepress->get_element_trid( $variation_id, 'post_product_variation' ); 
  245. $translations = $this->sitepress->get_element_translations( $trid, 'post_product_variation' ); 
  246. $ld = $this->sitepress->get_element_language_details( $variation_id, 'post_product_variation' ); 
  247. } else { 
  248. $trid = $this->sitepress->get_element_trid( $product_id, 'post_product' ); 
  249. $translations = $this->sitepress->get_element_translations( $trid, 'post_product' ); 
  250. $ld = $this->sitepress->get_element_language_details( $product_id, 'post_product' ); 
  251.  
  252. // Process for non-current languages 
  253. foreach( $translations as $translation ) { 
  254. if ( $ld->language_code != $translation->language_code ) { 
  255. //check if product exist 
  256. if( get_post_type( $translation->element_id ) == 'product_variation' && !get_post( wp_get_post_parent_id( $translation->element_id ) ) ) { 
  257. continue; 
  258. $_product = wc_get_product( $translation->element_id ); 
  259.  
  260. if( $_product && $_product->exists() && $_product->managing_stock() ) { 
  261. $total_sales = get_post_meta( $translation->element_id, 'total_sales', true); 
  262.  
  263. if( $action == 'reduce') { 
  264. $stock = WooCommerce_Functions_Wrapper::reduce_stock( $translation->element_id, $qty ); 
  265. $total_sales += $qty; 
  266. }else{ 
  267. $stock = WooCommerce_Functions_Wrapper::increase_stock( $translation->element_id, $qty ); 
  268. $total_sales -= $qty; 
  269. update_post_meta( $translation->element_id, 'total_sales', $total_sales ); 
  270.  
  271. public function sync_stock_status_for_translations( $id, $status ) { 
  272.  
  273. if( $this->woocommerce_wpml->products->is_original_product( $id ) ) { 
  274. $type = get_post_type( $id ); 
  275. $trid = $this->sitepress->get_element_trid( $id, 'post_'.$type ); 
  276. $translations = $this->sitepress->get_element_translations( $trid, 'post_'.$type, true); 
  277.  
  278. foreach ( $translations as $translation ) { 
  279. if ( !$translation->original ) { 
  280. update_post_meta( $translation->element_id, '_stock_status', $status ); 
  281.  
  282.  
  283. //sync product parent & post_status 
  284. public function sync_date_and_parent( $duplicated_post_id, $post_id, $lang ) { 
  285. $tr_parent_id = apply_filters( 'translate_object_id', wp_get_post_parent_id( $duplicated_post_id ), 'product', false, $lang ); 
  286. $orig_product = get_post( $duplicated_post_id ); 
  287. $args = array(); 
  288. $args[ 'post_parent' ] = is_null( $tr_parent_id )? 0 : $tr_parent_id; 
  289. //sync product date 
  290.  
  291. if( !empty( $this->woocommerce_wpml->settings[ 'products_sync_date' ] ) ) { 
  292. $args[ 'post_date' ] = $orig_product->post_date; 
  293. $this->wpdb->update( 
  294. $this->wpdb->posts,  
  295. $args,  
  296. array( 'id' => $post_id ) 
  297. ); 
  298.  
  299. public function set_schedule_for_translations( $deprecated, $post ) { 
  300.  
  301. if( $this->woocommerce_wpml->products->is_original_product( $post->ID ) ) { 
  302. $trid = $this->sitepress->get_element_trid( $post->ID, 'post_product'); 
  303. $translations = $this->sitepress->get_element_translations( $trid, 'post_product', true); 
  304. foreach( $translations as $translation ) { 
  305. if( !$translation->original ) { 
  306. wp_clear_scheduled_hook( 'publish_future_post', array( $translation->element_id ) ); 
  307. wp_schedule_single_event( strtotime( get_gmt_from_date( $post->post_date) . ' GMT' ), 'publish_future_post', array( $translation->element_id ) ); 
  308.  
  309. public function icl_pro_translation_completed( $tr_product_id ) { 
  310.  
  311. if( get_post_type( $tr_product_id ) == 'product' ) { 
  312.  
  313. $trid = $this->sitepress->get_element_trid( $tr_product_id, 'post_product' ); 
  314. $translations = $this->sitepress->get_element_translations( $trid, 'post_product' ); 
  315.  
  316. foreach( $translations as $translation ) { 
  317. if( $translation->original ) { 
  318. $original_product_id = $translation->element_id; 
  319.  
  320. if( !isset( $original_product_id ) ) { 
  321. return; 
  322.  
  323. $lang = $this->sitepress->get_language_for_element( $tr_product_id, 'post_product' ); 
  324. $this->sync_product_data( $original_product_id, $tr_product_id, $lang ); 
  325.  
  326.  
  327.  
  328. public function icl_make_duplicate( $master_post_id, $lang, $postarr, $id ) { 
  329. if( get_post_type( $master_post_id ) == 'product' ) { 
  330.  
  331. $master_post_id = $this->woocommerce_wpml->products->get_original_product_id( $master_post_id ); 
  332.  
  333. $this->sync_product_data( $master_post_id, $id, $lang ); 
  334.  
  335. public function woocommerce_product_quick_edit_save( $product ) { 
  336.  
  337. $product_id = WooCommerce_Functions_Wrapper::get_product_id( $product ); 
  338. $is_original = $this->woocommerce_wpml->products->is_original_product( $product_id ); 
  339. $trid = $this->sitepress->get_element_trid( $product_id, 'post_product' ); 
  340.  
  341. if( $trid ) { 
  342. $translations = $this->sitepress->get_element_translations( $trid, 'post_product' ); 
  343. if( $translations ) { 
  344. foreach( $translations as $translation ) { 
  345. if( $is_original ) { 
  346. if( !$translation->original ) { 
  347. $this->sync_product_data( $product_id, $translation->element_id, $translation->language_code ); 
  348. $this->sync_date_and_parent( $product_id, $translation->element_id, $translation->language_code ); 
  349. }elseif( $translation->original ) { 
  350. $this->sync_product_data( $translation->element_id, $product_id, $this->sitepress->get_language_for_element( $product_id, 'post_product' ) ); 
  351. $this->sync_date_and_parent( $translation->element_id, $product_id, $this->sitepress->get_language_for_element( $product_id, 'post_product' ) ); 
  352.  
  353. //duplicate product post meta 
  354. public function duplicate_product_post_meta( $original_product_id, $trnsl_product_id, $data = false ) { 
  355. global $iclTranslationManagement; 
  356.  
  357. if( $this->check_if_product_fields_sync_needed( $original_product_id, $trnsl_product_id, 'postmeta_fields' ) ) { 
  358. $settings = $iclTranslationManagement->settings[ 'custom_fields_translation' ]; 
  359. $all_meta = get_post_custom( $original_product_id ); 
  360. $post_fields = null; 
  361.  
  362. unset( $all_meta[ '_thumbnail_id' ] ); 
  363.  
  364. foreach ( $all_meta as $key => $meta ) { 
  365. if ( !isset( $settings[ $key ] ) || $settings[ $key ] == WPML_IGNORE_CUSTOM_FIELD ) { 
  366. continue; 
  367. foreach ( $meta as $meta_value ) { 
  368. if( $key == '_downloadable_files' ) { 
  369. $this->woocommerce_wpml->downloadable->sync_files_to_translations( $original_product_id, $trnsl_product_id, $data ); 
  370. }elseif ( $data ) { 
  371. if ( isset( $settings[ $key ] ) && $settings[ $key ] == WPML_TRANSLATE_CUSTOM_FIELD ) { 
  372.  
  373. $post_fields = $this->sync_custom_field_value( $key, $data, $trnsl_product_id, $post_fields ); 
  374.  
  375. do_action( 'wcml_after_duplicate_product_post_meta', $original_product_id, $trnsl_product_id, $data ); 
  376.  
  377. public function sync_custom_field_value( $custom_field, $translation_data, $trnsl_product_id, $post_fields, $original_product_id = false, $is_variation = false ) { 
  378.  
  379. if( is_null( $post_fields ) ) { 
  380. $post_fields = array(); 
  381. if( isset( $_POST['data'] ) ) { 
  382. $post_args = wp_parse_args( $_POST['data'] ); 
  383. $post_fields = $post_args[ 'fields' ]; 
  384.  
  385. $custom_filed_key = $is_variation && $original_product_id ? $custom_field.$original_product_id : $custom_field; 
  386.  
  387. if( isset( $translation_data[ md5( $custom_filed_key ) ] ) ) { 
  388. $meta_value = $translation_data[ md5( $custom_filed_key ) ]; 
  389. $meta_value = apply_filters( 'wcml_meta_value_before_add', $meta_value, $custom_filed_key ); 
  390. update_post_meta( $trnsl_product_id, $custom_field, $meta_value ); 
  391. unset( $post_fields[ $custom_filed_key ] ); 
  392. }else{ 
  393. foreach( $post_fields as $post_field_key => $post_field ) { 
  394. $meta_value = $translation_data[ md5( $post_field_key ) ]; 
  395. $field_key = explode( ':', $post_field_key ); 
  396. if( $field_key[0] == $custom_filed_key ) { 
  397. if( substr( $field_key[1], 0, 3 ) == 'new' ) { 
  398. add_post_meta( $trnsl_product_id, $custom_field, $meta_value ); 
  399. }else{ 
  400. update_meta( $field_key[1], $custom_field, $meta_value ); 
  401. unset( $post_fields[ $post_field_key ] ); 
  402.  
  403. return $post_fields; 
  404.  
  405.  
  406. public function icl_connect_translations_action() { 
  407. if( isset( $_POST[ 'icl_ajx_action' ] ) && $_POST[ 'icl_ajx_action' ] == 'connect_translations' ) { 
  408. $new_trid = $_POST['new_trid']; 
  409. $post_type = $_POST['post_type']; 
  410. $post_id = $_POST['post_id']; 
  411. $set_as_source = $_POST['set_as_source']; 
  412.  
  413. if ($post_type == 'product') { 
  414.  
  415. $translations = $this->sitepress->get_element_translations($new_trid, 'post_' . $post_type); 
  416.  
  417. if ($translations) { 
  418. foreach ($translations as $translation) { 
  419. //current as original need sync translation 
  420. if ($translation->original) { 
  421. if ($set_as_source) { 
  422. $orig_id = $post_id; 
  423. $trnsl_id = $translation->element_id; 
  424. $lang = $translation->language_code; 
  425. } else { 
  426. $orig_id = $translation->element_id; 
  427. $trnsl_id = $post_id; 
  428. $lang = $this->sitepress->get_current_language(); 
  429. $this->sync_product_data($orig_id, $trnsl_id, $lang); 
  430. $this->sync_date_and_parent($orig_id, $trnsl_id, $lang); 
  431. $this->sitepress->copy_custom_fields($orig_id, $trnsl_id); 
  432. $this->woocommerce_wpml->translation_editor->create_product_translation_package($orig_id, $new_trid, $lang, ICL_TM_COMPLETE); 
  433. } else { 
  434. if ( $set_as_source ) { 
  435. $this->sync_product_data($post_id, $translation->element_id, $translation->language_code); 
  436. $this->sync_date_and_parent($post_id, $translation->element_id, $translation->language_code); 
  437. $this->sitepress->copy_custom_fields($post_id, $translation->element_id); 
  438. $this->woocommerce_wpml->translation_editor->create_product_translation_package($post_id, $new_trid, $translation->language_code, ICL_TM_COMPLETE); 
  439.  
  440. public function check_if_product_fields_sync_needed( $original_id, $trnsl_post_id, $fields_group ) { 
  441.  
  442. $cache_group = 'is_product_fields_sync_needed'; 
  443. $cache_key = $trnsl_post_id.$fields_group; 
  444. $temp_is_sync_needed = wp_cache_get( $cache_key, $cache_group ); 
  445.  
  446. if( $temp_is_sync_needed !== false ) return (bool) $temp_is_sync_needed; 
  447.  
  448. $is_sync_needed = true; 
  449. $hash = ''; 
  450.  
  451. switch( $fields_group ) { 
  452. case 'postmeta_fields': 
  453. $custom_fields = get_post_custom( $original_id ); 
  454. unset( $custom_fields[ 'wcml_sync_hash' ] ); 
  455. $hash = md5( serialize( $custom_fields ) ); 
  456. break; 
  457. case 'taxonomies': 
  458. $all_taxs = get_object_taxonomies( get_post_type( $original_id ) ); 
  459. $taxs = array(); 
  460.  
  461. if ( !empty( $all_taxs ) ) { 
  462. foreach ($all_taxs as $tt) { 
  463. $terms = get_the_terms( $original_id, $tt ); 
  464. if( !empty( $terms ) ) { 
  465. foreach ( $terms as $term ) { 
  466. $taxs[] = $term->term_id; 
  467.  
  468. $hash = md5( join( ', ', $taxs ) ); 
  469. break; 
  470. case 'default_attributes': 
  471. $hash = md5( get_post_meta( $original_id, '_default_attributes', true ) ); 
  472. break; 
  473.  
  474. $wcml_sync_hash = get_post_meta( $trnsl_post_id, 'wcml_sync_hash', true ); 
  475. $post_md5 = $wcml_sync_hash === '' ? array() : maybe_unserialize( $wcml_sync_hash ); 
  476.  
  477. if( isset( $post_md5[ $fields_group ] ) && $post_md5[ $fields_group ] == $hash ) { 
  478. $is_sync_needed = false; 
  479. }else{ 
  480. $post_md5[ $fields_group ] = $hash; 
  481. update_post_meta( $trnsl_post_id, 'wcml_sync_hash', $post_md5 ); 
  482.  
  483. wp_cache_set( $cache_key, intval( $is_sync_needed ), $cache_group ); 
  484.  
  485. return $is_sync_needed; 
  486.  
.