WooCommerce Multilingual – run WooCommerce with WPML - Version 2.0

Version Description

  • Fix variation sync to more than one language
  • Fix custom field sync for new variations
  • Fix rounding of amounts in PayPal
  • Adjust product stock sync to WC 2.x
  • Add automatic id translation of logout page
  • Adjust permalink warnings to WC 2.x
  • Clean up code
Download this release

Release Info

Developer dgwatkins
Plugin Icon 128x128 WooCommerce Multilingual – run WooCommerce with WPML
Version 2.0
Comparing to
See all releases

Code changes from version 1.5 to 2.0

Files changed (4) hide show
  1. readme.txt +24 -4
  2. woocommerce_wpml.class.php +367 -363
  3. wpml-config.xml +0 -1
  4. wpml-woocommerce.php +2 -2
readme.txt CHANGED
@@ -5,7 +5,7 @@ Tags: CMS, woocommerce, commerce, ecommerce, e-commerce, products, WPML, multili
5
  License: GPLv2
6
  Requires at least: 3.0
7
  Tested up to: 3.5
8
- Stable tag: 1.5
9
 
10
  Allows running fully multilingual e-commerce sites using WooCommerce and WPML.
11
 
@@ -13,7 +13,7 @@ Allows running fully multilingual e-commerce sites using WooCommerce and WPML.
13
 
14
  This 'glue' plugin makes it possible to run fully multilingual e-commerce sites using [WooCommerce](http://wordpress.org/extend/plugins/woocommerce/) and [WPML](http://wpml.org). It makes products and store pages translatable, lets visitors switch languages and order products in their language.
15
 
16
- >> WooCommerce Multilingual is currently compatible with WooCommerce 1.x only. We are working on a new version for WooCommerce 2.x. We will write about updates in [WPML blog](http://wpml.org/blog/).
17
 
18
  = Features =
19
 
@@ -36,9 +36,9 @@ When you need help, go to [WPML technical support forum](http://wpml.org/forums/
36
 
37
  = Downloads =
38
 
39
- This version of WooCommerce Multilingual works with WooCommerce 1.x. The latest version is [WooCommerce 1.6.6](http://downloads.wordpress.org/plugin/woocommerce.1.6.6.zip). You can see other versions in the [WooCommerce Developers](http://wordpress.org/extend/plugins/woocommerce/developers/) page.
40
 
41
- You will also need [WPML](http://wpml.org), together with the String Translation module, which is part of the [Multilingual CMS](http://wpml.org/purchase/) package.
42
 
43
  == Installation ==
44
 
@@ -68,6 +68,23 @@ In order for the checkout and store pages to appear translated, you need to crea
68
 
69
  == Changelog ==
70
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
71
  = 1.5 =
72
  * Fixed manually setting prices in translated products.
73
  * Take advantage of WPML's new slug translation feature.
@@ -133,6 +150,9 @@ In order for the checkout and store pages to appear translated, you need to crea
133
 
134
  == Upgrade Notice ==
135
 
 
 
 
136
  = 1.5 =
137
  Variation translation works a lot better now. This version runs best with WooCommerce 1.6.6.
138
 
5
  License: GPLv2
6
  Requires at least: 3.0
7
  Tested up to: 3.5
8
+ Stable tag: 2.0
9
 
10
  Allows running fully multilingual e-commerce sites using WooCommerce and WPML.
11
 
13
 
14
  This 'glue' plugin makes it possible to run fully multilingual e-commerce sites using [WooCommerce](http://wordpress.org/extend/plugins/woocommerce/) and [WPML](http://wpml.org). It makes products and store pages translatable, lets visitors switch languages and order products in their language.
15
 
16
+ >> This version of WooCommerce Multilingual has been updated to work with WooCommerce 2.x. We are keeping backward compatibility with WooCommerce 1.x.
17
 
18
  = Features =
19
 
36
 
37
  = Downloads =
38
 
39
+ This version of WooCommerce Multilingual works with WooCommerce 2.x. It has been tested with [WooCommerce 2.0.3](http://downloads.wordpress.org/plugin/woocommerce.2.0.3.zip). You can see other versions in the [WooCommerce Developers](http://wordpress.org/extend/plugins/woocommerce/developers/) page.
40
 
41
+ You will also need [WPML](http://wpml.org), together with the String Translation and the Translation Management modules, which are part of the [Multilingual CMS](http://wpml.org/purchase/) package.
42
 
43
  == Installation ==
44
 
68
 
69
  == Changelog ==
70
 
71
+ = 2.1 =
72
+ * Add admin notices for required plugins
73
+ * Add support for 'Review Order' and 'Lost Password' pages
74
+ * Fix rounding issues in currency conversion
75
+ * Variations: pick translated terms using 'trid' gives better results
76
+ * Variations: sync to all languages when there are more than 2 languages
77
+ * Improvement: load JS/CSS only when needed
78
+
79
+ = 2.0 =
80
+ * Fix variation sync to more than one language
81
+ * Fix custom field sync for new variations
82
+ * Fix rounding of amounts in PayPal
83
+ * Adjust product stock sync to WC 2.x
84
+ * Add automatic id translation of logout page
85
+ * Adjust permalink warnings to WC 2.x
86
+ * Clean up code
87
+
88
  = 1.5 =
89
  * Fixed manually setting prices in translated products.
90
  * Take advantage of WPML's new slug translation feature.
150
 
151
  == Upgrade Notice ==
152
 
153
+ = 2.0 =
154
+ More variation fixes and compatibility with WooCommerce 2.x
155
+
156
  = 1.5 =
157
  Variation translation works a lot better now. This version runs best with WooCommerce 1.6.6.
158
 
woocommerce_wpml.class.php CHANGED
@@ -1,8 +1,9 @@
1
  <?php
2
  class woocommerce_wpml {
3
-
4
  var $currencies;
5
-
 
6
  function __construct(){
7
  add_action('plugins_loaded', array($this, 'init'), 2);
8
  $this->currencies = array(
@@ -17,22 +18,41 @@ class woocommerce_wpml {
17
  'GBP' => '&pound;'
18
  );
19
  }
20
-
21
  function init(){
22
  global $sitepress;
23
 
24
- if(!defined('ICL_SITEPRESS_VERSION') || ICL_PLUGIN_INACTIVE){
25
- if(!function_exists('is_multisite') || !is_multisite()) {
26
- add_action('admin_notices', array($this, 'no_wpml_warning'));
27
- }
28
- return false;
29
- } else if(version_compare(ICL_SITEPRESS_VERSION, '2.0.5', '<')){
30
- add_action('admin_notices', array($this, 'old_wpml_warning'));
31
- return false;
32
- } else if(!class_exists('woocommerce')){
33
- add_action('admin_notices', array($this, 'no_woocommerce'));
34
- return false;
35
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
36
 
37
  if(get_option('icl_is_wcml_installed') !== 'yes'){
38
  $this->wcml_install();
@@ -40,17 +60,7 @@ class woocommerce_wpml {
40
 
41
  add_action('admin_notices', array($this, 'check_for_incompatible_permalinks'));
42
 
43
- add_filter('woocommerce_get_checkout_url', array($this, 'get_checkout_page_id'));
44
- add_filter('woocommerce_get_checkout_page_id', array($this, 'checkout_page_id'));
45
- add_filter('woocommerce_get_cart_page_id', array($this, 'get_cart_page_id'));
46
- add_filter('woocommerce_get_myaccount_page_id', array($this, 'get_myaccount_page_id'));
47
- add_filter('woocommerce_get_edit_address_page_id', array($this, 'get_edit_address_page_id'));
48
- add_filter('woocommerce_get_view_order_page_id', array($this, 'get_view_order_page_id'));
49
- add_filter('woocommerce_get_change_password_page_id', array($this, 'get_change_password_page_id'));
50
- add_filter('woocommerce_get_thanks_page_id', array($this, 'get_thanks_page_id'));
51
- add_filter('woocommerce_get_shop_page_id', array($this, 'shop_page_id'));
52
- add_filter('woocommerce_get_terms_page_id', array($this, 'terms_page_id'));
53
- add_filter('woocommerce_get_pay_page_id', array($this, 'pay_page_id'));
54
  add_filter('woocommerce_get_checkout_payment_url', array($this, 'do_redirect'));
55
  add_filter('woocommerce_get_cancel_order_url', array($this, 'do_redirect'));
56
  add_filter('woocommerce_get_return_url', array($this, 'do_redirect'));
@@ -67,24 +77,26 @@ class woocommerce_wpml {
67
  add_filter('woocommerce_gateway_description', array($this, 'gateway_description'), 10, 2);
68
  add_filter('woocommerce_json_search_found_products', array($this, 'search_products'));
69
  add_filter('woocommerce_currency', array($this, 'set_ml_currency'));
70
- //add_filter('woocommerce_paypal_amount', array($this, 'paypal_amount'));
71
- add_action('admin_print_scripts', array($this,'js_scripts_setup'), 11);
72
  add_action('init', array($this, 'translate_email_notifications'));
73
 
 
74
  add_filter('gettext_with_context', array($this, 'default_slug_translation'), 0, 4);
75
- add_filter('option_woocommerce_permalinks', array($this, 'custom_slug_translation'));
76
 
77
- // Translate shop page settings
78
  add_filter('option_woocommerce_shop_page_id', array($this, 'translate_pages_in_settings'));
79
  add_filter('option_woocommerce_terms_page_id', array($this, 'translate_pages_in_settings'));
80
  add_filter('option_woocommerce_cart_page_id', array($this, 'translate_pages_in_settings'));
81
  add_filter('option_woocommerce_checkout_page_id', array($this, 'translate_pages_in_settings'));
 
82
  add_filter('option_woocommerce_pay_page_id', array($this, 'translate_pages_in_settings'));
83
  add_filter('option_woocommerce_thanks_page_id', array($this, 'translate_pages_in_settings'));
 
84
  add_filter('option_woocommerce_myaccount_page_id', array($this, 'translate_pages_in_settings'));
85
  add_filter('option_woocommerce_edit_address_page_id', array($this, 'translate_pages_in_settings'));
86
  add_filter('option_woocommerce_view_order_page_id', array($this, 'translate_pages_in_settings'));
87
  add_filter('option_woocommerce_change_password_page_id', array($this, 'translate_pages_in_settings'));
 
88
 
89
  if(get_option('icl_enable_multi_currency') == 'yes'){
90
  if(get_option('currency_converting_option') == '1'){
@@ -113,7 +125,6 @@ class woocommerce_wpml {
113
  add_action('save_post', array($this, 'sync_variations'), 11, 2); // After WPML
114
  add_filter('icl_make_duplicate', array($this, 'sync_variations_for_duplicates'), 11, 4);
115
 
116
-
117
  add_action('admin_menu', array($this, 'menu'));
118
  add_action('init', array($this, 'load_css_and_js'));
119
 
@@ -291,28 +302,12 @@ class woocommerce_wpml {
291
  return $terms;
292
  }
293
 
294
- // Catch custom slugs for translation
295
- function custom_slug_translation($permalinks) {
296
- if (!empty($permalinks['product_base'])) {
297
- $permalinks['product_base'] = _x($permalinks['product_base'], 'URL slug', 'woocommerce');
298
- }
299
- return $permalinks;
300
- }
301
-
302
  function register_shipping_methods($available_methods){
303
-
304
  foreach($available_methods as $method){
305
- if(function_exists('icl_register_string')){
306
- icl_register_string('woocommerce', $method->label .'_shipping_method_title', $method->label);
307
- }
308
-
309
- if(function_exists('icl_t')){
310
- $method->label = icl_t('woocommerce', $method->label .'_shipping_method_title', $method->label);
311
- }
312
  }
313
-
314
- return $available_methods;
315
 
 
316
  }
317
 
318
  function tax_rates($rates){
@@ -383,35 +378,37 @@ class woocommerce_wpml {
383
  return $languages;
384
  }
385
 
386
- /**
387
- * Adds admin notice.
388
- */
389
- function no_wpml_warning(){
390
- ?>
391
- <div class="message error"><p><?php printf(__('WooCommerce Multilingual is enabled but not effective. It requires <a href="%s">WPML</a> in order to work.', 'plugin woocommerce'),
392
- 'http://wpml.org/'); ?></p></div>
393
- <?php
394
- }
395
-
396
- /**
397
- * Adds admin notice.
398
- */
399
- function old_wpml_warning(){
400
- ?>
401
- <div class="message error"><p><?php printf(__('WooCommerce Multilingual is enabled but not effective. It is not compatible with <a href="%s">WPML</a> versions prior 2.0.5.', 'plugin woocommerce'),
402
- 'http://wpml.org/'); ?></p></div>
403
- <?php
404
- }
 
 
405
 
406
- /**
407
- * Adds admin notice.
408
- */
409
- function no_woocommerce(){
410
- ?>
411
- <div class="message error"><p><?php printf(__('WooCommerce Multilingual is enabled but not effective. It requires <a href="%s">WooCommerce</a> in order to work.', 'plugin woocommerce'),
412
- 'http://www.woothemes.com/woocommerce/'); ?></p></div>
413
- <?php
414
- }
415
 
416
  /**
417
  * Install the plugin.
@@ -444,9 +441,45 @@ class woocommerce_wpml {
444
  function check_for_incompatible_permalinks() {
445
  global $sitepress, $sitepress_settings;
446
 
447
- // Check if the shop prefix is disabled, if so we are ok
448
- if (get_option('woocommerce_prepend_shop_page_to_products', 'yes') != "yes") {
449
- return;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
450
  }
451
 
452
  // Check if slug translation is enabled
@@ -457,29 +490,6 @@ class woocommerce_wpml {
457
  $compatible = false;
458
  }
459
 
460
- // Check if translated shop pages have the same slug
461
- $allsame = true;
462
- $shop_page_id = get_option('woocommerce_shop_page_id', false);
463
- if (!empty($shop_page_id)) {
464
- $slug = @get_page($shop_page_id)->post_name;
465
- $languages = icl_get_languages('skip_missing=0');
466
- if (sizeof($languages) < 2) {
467
- return;
468
- }
469
- foreach ($languages as $language) {
470
- if ($language['language_code'] != $sitepress->get_default_language()) {
471
- $translated_shop_page_id = icl_object_id($shop_page_id, 'page', false, $language['language_code']);
472
- if (!empty($translated_shop_page_id)) {
473
- $translated_slug = get_page($translated_shop_page_id)->post_name;
474
- if (!empty($translated_slug) && $translated_slug != $slug) {
475
- $allsame = false;
476
- break;
477
- }
478
- }
479
- }
480
- }
481
- }
482
-
483
  // display messages
484
  if (!$allsame) {
485
  ?>
@@ -489,8 +499,7 @@ class woocommerce_wpml {
489
  }
490
  if (!$compatible) {
491
  ?>
492
- <div class="message error"><p><?php printf(__('If you want to translate product slugs, you need to disable the shop prefix for products in <a href="%s">WooCommerce Settings</a>', 'plugin woocommerce'),
493
- 'admin.php?page=woocommerce_settings&tab=pages'); ?></p></div>
494
  <?php
495
  }
496
  }
@@ -508,30 +517,25 @@ class woocommerce_wpml {
508
  }
509
 
510
  /**
511
- * Filters upsell/crosell products in the correct language.
512
- */
513
  function search_products($found_products){
514
  global $wpdb, $sitepress;
515
 
516
  $current_page_language = $sitepress->get_current_language();
517
 
518
- foreach($found_products as $product_id => $output_v){
519
- $post_data = $wpdb->get_row("SELECT * FROM ". $wpdb->prefix ."icl_translations WHERE element_id = '$product_id'");
520
  $product_language = $post_data->language_code;
521
 
522
  if($product_language !== $current_page_language){
523
  unset($found_products[$product_id]);
524
- }
525
- }
526
 
527
  return $found_products;
528
  }
529
-
530
- // Return the correct amount in a second language.
531
- function paypal_amount($amount){
532
- return $amount;
533
- }
534
-
535
  // Set multilingual currency.
536
  function set_ml_currency($currency){
537
  global $wpdb, $sitepress;
@@ -565,92 +569,9 @@ class woocommerce_wpml {
565
  /**
566
  * Filters WooCommerce checkout link.
567
  */
568
- function get_checkout_page_id(){
569
  return get_permalink(icl_object_id(get_option('woocommerce_checkout_page_id'), 'page', true));
570
  }
571
-
572
- /**
573
- * Filters WooCommerce checkout page id.
574
- */
575
- function checkout_page_id(){
576
- return icl_object_id(get_option('woocommerce_checkout_page_id'), 'page', true);
577
- }
578
-
579
- /**
580
- * Filters WooCommerce cart link.
581
- */
582
- function get_cart_page_id() {
583
- return icl_object_id(get_option('woocommerce_cart_page_id'), 'page', true);
584
- }
585
-
586
- /**
587
- * Filters WooCommerce my account link.
588
- */
589
- function get_myaccount_page_id(){
590
- return icl_object_id(get_option('woocommerce_myaccount_page_id'), 'page', true);
591
- }
592
-
593
- /**
594
- * Filters WooCommerce my account edit address link.
595
- */
596
- function get_edit_address_page_id(){
597
- return icl_object_id(get_option('woocommerce_edit_address_page_id'), 'page', true);
598
- }
599
-
600
- /**
601
- * Filters WooCommerce view order link.
602
- */
603
- function get_view_order_page_id(){
604
- // avoid redirect to the my account page
605
- if(get_option('woocommerce_view_order_page_id') !== get_option('woocommerce_checkout_page_id')){
606
- $return = icl_object_id(get_option('woocommerce_view_order_page_id'), 'page', true);
607
- } else {
608
- $return = false;
609
- }
610
-
611
- return $return;
612
- }
613
-
614
- /**
615
- * Filters WooCommerce my account change password link.
616
- */
617
- function get_change_password_page_id(){
618
- return icl_object_id(get_option('woocommerce_change_password_page_id'), 'page', true);
619
- }
620
-
621
- /**
622
- * Filters WooCommerce thanks link.
623
- */
624
- function get_thanks_page_id(){
625
- return icl_object_id(get_option('woocommerce_thanks_page_id'), 'page', true);
626
- }
627
-
628
- /**
629
- * Filters WooCommerce shop link.
630
- */
631
- function shop_page_id(){
632
- return icl_object_id(get_option('woocommerce_shop_page_id'), 'page', false);
633
- }
634
-
635
- /**
636
- * Filters WooCommerce terms link.
637
- */
638
- function terms_page_id(){
639
- return icl_object_id(get_option('woocommerce_terms_page_id'), 'page', false);
640
- }
641
-
642
- /**
643
- * Filters WooCommerce pay page id
644
- */
645
- function pay_page_id(){
646
- $is_cart_page = icl_object_id(get_option('woocommerce_cart_page_id'), 'page', true);
647
-
648
- if(is_page($is_cart_page)){
649
- //return
650
- } else {
651
- return icl_object_id(get_option('woocommerce_pay_page_id'), 'page', true);
652
- }
653
- }
654
 
655
  /**
656
  * After email translation switch language to default.
@@ -788,7 +709,7 @@ class woocommerce_wpml {
788
  global $post;
789
 
790
  $post_type = get_post_type($post->ID);
791
- $checkout_page_id = $this->checkout_page_id();
792
 
793
  if($post_type == 'product' || is_page($checkout_page_id)){
794
  $output = '';
@@ -807,6 +728,7 @@ class woocommerce_wpml {
807
  }
808
 
809
  function attribute_terms($terms){
 
810
  // remove autop
811
  $terms = str_replace('<p>', '', $terms);
812
  $terms = str_replace('</p>', '', $terms);
@@ -816,7 +738,12 @@ class woocommerce_wpml {
816
  $out = array();
817
  foreach ($terms as $term) {
818
  $term = trim($term);
819
- $out[] = icl_t('woocommerce', $term .'_attribute_name', $term);
 
 
 
 
 
820
  }
821
 
822
  return wpautop(wptexturize(implode(", ", $out)));
@@ -908,15 +835,16 @@ class woocommerce_wpml {
908
  function woocommerce_price($price){
909
  global $sitepress, $wpdb;
910
 
911
- $sql = "SELECT value FROM ". $wpdb->prefix ."icl_currencies WHERE language_code = '". $sitepress->get_current_language() ."'";
912
- $currency = $wpdb->get_results($sql, OBJECT);
913
-
914
- if($currency){
915
- $exchange_rate = $currency[0]->value;
916
- $price = $price * $exchange_rate;
917
-
918
- $price = apply_filters('woocommerce_multilingual_price', $price);
919
- }
 
920
 
921
  return $price;
922
  }
@@ -931,10 +859,7 @@ class woocommerce_wpml {
931
  function email_header() {
932
  global $sitepress, $order_id;
933
 
934
- $lang = null;
935
- if (!current_user_can( 'manage_woocommerce' )) {
936
- $lang = get_post_meta($order_id, 'wpml_language', TRUE);
937
- }
938
 
939
  if(empty($lang)){
940
  if(isset($_SESSION['wpml_globalcart_language'])){
@@ -959,16 +884,51 @@ class woocommerce_wpml {
959
  $sitepress->switch_lang();
960
  }
961
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
962
  /*
963
  Only when translated products are ordered, force adjusting stock information for all translations
964
  When a product in the default language is ordered stocks are adjusted automatically
965
  */
966
- function sync_product_stocks($order){
967
  global $sitepress;
968
  $order_id = $order->id;
969
 
970
  foreach ( $order->get_items() as $item ) {
971
-
972
  if (isset($item['variation_id']) && $item['variation_id']>0){
973
  $ld = $sitepress->get_element_language_details($item['variation_id'], 'post_product_variation');
974
  $product_id = icl_object_id( $item['variation_id'], 'product_variation', true, $sitepress->get_default_language());
@@ -1000,6 +960,41 @@ class woocommerce_wpml {
1000
 
1001
  }
1002
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1003
  /**
1004
  * Adds language to order post type.
1005
  *
@@ -1033,7 +1028,7 @@ class woocommerce_wpml {
1033
  if($currency){
1034
  $exchange_rate = $currency[0]->value;
1035
  $min_price = $min_price / $exchange_rate;
1036
- $min_price = round($min_price);
1037
  }
1038
  }
1039
 
@@ -1058,51 +1053,71 @@ class woocommerce_wpml {
1058
  if($currency){
1059
  $exchange_rate = $currency[0]->value;
1060
  $max_price = $max_price / $exchange_rate;
1061
- $max_price = round($max_price);
1062
  }
1063
  }
1064
 
1065
  return $max_price;
1066
  }
1067
-
 
 
 
1068
  function sync_variations_for_duplicates($master_post_id, $lang, $postarr, $id) {
1069
  $this->sync_variations($id, $postarr);
1070
  }
1071
 
1072
- function sync_variations($post_id, $post){
1073
- global $wpdb, $pagenow, $sitepress;
 
 
 
1074
 
 
1075
  $post_type = get_post_type($post_id);
1076
- $ajax_call = (!empty($_POST['icl_ajx_action']) && $_POST['icl_ajx_action'] == 'make_duplicates');
1077
- $duplicated_post_id = icl_object_id($post_id, 'product', false, $sitepress->get_default_language());
 
1078
 
1079
  // exceptions
 
 
1080
  if (empty($duplicated_post_id) || isset($_POST['autosave'])) {
1081
  return;
1082
  }
1083
-
 
 
 
1084
  // get language code
1085
  $language_details = $sitepress->get_element_language_details($post_id, 'post_product');
1086
  if (empty($language_details)) {
1087
  return;
1088
  }
1089
- $lang = $language_details->language_code;
1090
-
1091
- if ($lang == $sitepress->get_default_language()) {
1092
- return;
1093
- }
1094
 
1095
- // Filter upsell products, crosell products and default attributes for translations
1096
- if(($pagenow == 'post.php' || $pagenow == 'post-new.php' || $ajax_call ) && $post_type == 'product'){
 
 
 
 
 
 
 
 
 
 
 
1097
 
 
1098
  $original_product_upsell_ids = get_post_meta($duplicated_post_id, '_upsell_ids', TRUE);
1099
  if(!empty($original_product_upsell_ids)){
1100
  $unserialized_upsell_ids = maybe_unserialize($original_product_upsell_ids);
1101
-
1102
  foreach($unserialized_upsell_ids as $k => $product_id){
1103
  // get the correct language
1104
  $upsell_product_translation_id = icl_object_id($product_id, 'product', false, $lang);
1105
-
1106
  if($upsell_product_translation_id){
1107
  $unserialized_upsell_ids[$k] = $upsell_product_translation_id;
1108
  // if it isn't translated - unset it
@@ -1110,20 +1125,20 @@ class woocommerce_wpml {
1110
  unset($unserialized_upsell_ids[$k]);
1111
  }
1112
  }
1113
-
1114
  $data = array('meta_value' => maybe_serialize($unserialized_upsell_ids));
1115
  $where = array('post_id' => $post_id, 'meta_key' => '_upsell_ids');
1116
  $wpdb->update($wpdb->postmeta, $data, $where);
1117
  }
1118
-
1119
  $original_product_crosssell_ids = get_post_meta($duplicated_post_id, '_crosssell_ids', TRUE);
1120
  if(!empty($original_product_crosssell_ids)){
1121
  $unserialized_crosssell_ids = maybe_unserialize($original_product_crosssell_ids);
1122
-
1123
  foreach($unserialized_crosssell_ids as $k => $product_id){
1124
  // get the correct language
1125
  $crosssell_product_translation_id = icl_object_id($product_id, 'product', false, $lang);
1126
-
1127
  if($crosssell_product_translation_id){
1128
  $unserialized_crosssell_ids[$k] = $crosssell_product_translation_id;
1129
  // if it isn't translated - unset it
@@ -1131,12 +1146,12 @@ class woocommerce_wpml {
1131
  unset($unserialized_crosssell_ids[$k]);
1132
  }
1133
  }
1134
-
1135
  $data = array('meta_value' => maybe_serialize($unserialized_crosssell_ids));
1136
  $where = array('post_id' => $post_id, 'meta_key' => '_crosssell_ids');
1137
  $wpdb->update($wpdb->postmeta, $data, $where);
1138
  }
1139
-
1140
  $original_default_attributes = get_post_meta($duplicated_post_id, '_default_attributes', TRUE);
1141
  if(!empty($original_default_attributes)){
1142
  $unserialized_default_attributes = maybe_unserialize($original_default_attributes);
@@ -1153,114 +1168,110 @@ class woocommerce_wpml {
1153
  unset($unserialized_default_attributes[$attribute]);
1154
  }
1155
  }
1156
-
1157
  $data = array('meta_value' => maybe_serialize($unserialized_default_attributes));
1158
  $where = array('post_id' => $post_id, 'meta_key' => '_default_attributes');
1159
  $wpdb->update($wpdb->postmeta, $data, $where);
1160
  }
1161
 
1162
- }
1163
-
1164
- if( ($pagenow == 'post.php' || $ajax_call ) && $post_type == 'product' && !empty($duplicated_post_id)){
1165
-
1166
- $get_variation_term_id = $wpdb->get_var("SELECT term_id FROM $wpdb->terms WHERE name = 'variable'");
1167
- $get_variation_term_taxonomy_id = $wpdb->get_var("SELECT tt.term_taxonomy_id FROM $wpdb->term_relationships tr
1168
  LEFT JOIN $wpdb->term_taxonomy tt ON tt.term_taxonomy_id = tr.term_taxonomy_id
1169
  WHERE object_id = '$duplicated_post_id' AND taxonomy = 'product_type'");
1170
 
1171
- $is_post_has_variations = $wpdb->get_results("SELECT * FROM $wpdb->term_relationships WHERE object_id = '$duplicated_post_id' AND term_taxonomy_id = '$get_variation_term_taxonomy_id'");
1172
- if(!empty($is_post_has_variations)) $is_post_has_variations = TRUE;
1173
 
1174
- // synchronize term data, postmeta and post variations
1175
- if($is_post_has_variations){
1176
- // synchronize post variations
1177
- $get_all_post_variations = $wpdb->get_results("SELECT * FROM $wpdb->posts
1178
- WHERE post_status = 'publish' AND post_type = 'product_variation' AND post_parent = '$duplicated_post_id'");
1179
 
1180
- $duplicated_post_variation_ids = array();
1181
- foreach($get_all_post_variations as $k => $post_data){
1182
- $duplicated_post_variation_ids[] = $post_data->ID;
1183
- }
1184
 
1185
- foreach($get_all_post_variations as $k => $post_data){
1186
- // Find if this has already been duplicated
1187
- $variation_id = $wpdb->get_var("SELECT post_id FROM $wpdb->postmeta WHERE meta_key = '_wcml_duplicate_of_variation' AND meta_value = '$post_data->ID'");
1188
-
1189
- if (!empty($variation_id)) {
1190
- // Update variation
1191
- wp_update_post(array(
1192
- 'ID' => $variation_id,
1193
- 'post_author' => $post_data->post_author,
1194
- 'post_date_gmt' => $post_data->post_date_gmt,
1195
- 'post_content' => $post_data->post_content,
1196
- 'post_title' => $post_data->post_title,
1197
- 'post_excerpt' => $post_data->post_excerpt,
1198
- 'post_status' => $post_data->post_status,
1199
- 'comment_status' => $post_data->comment_status,
1200
- 'ping_status' => $post_data->ping_status,
1201
- 'post_password' => $post_data->post_password,
1202
- 'post_name' => $post_data->post_name,
1203
- 'to_ping' => $post_data->to_ping,
1204
- 'pinged' => $post_data->pinged,
1205
- 'post_modified' => $post_data->post_modified,
1206
- 'post_modified_gmt' => $post_data->post_modified_gmt,
1207
- 'post_content_filtered' => $post_data->post_content_filtered,
1208
- 'post_parent' => $post_id, // current post ID
1209
- 'menu_order' => $post_data->menu_order,
1210
- 'post_type' => $post_data->post_type,
1211
- 'post_mime_type' => $post_data->post_mime_type,
1212
- 'comment_count' => $post_data->comment_count
1213
- ));
1214
- } else {
1215
- // Add new variation
1216
- $guid = $post_data->guid;
1217
- $replaced_guid = str_replace($duplicated_post_id, $post_id, $guid);
1218
- $slug = $post_data->post_name;
1219
- $replaced_slug = str_replace($duplicated_post_id, $post_id, $slug);
1220
- $variation_id = wp_insert_post(array(
1221
- 'post_author' => $post_data->post_author,
1222
- 'post_date_gmt' => $post_data->post_date_gmt,
1223
- 'post_content' => $post_data->post_content,
1224
- 'post_title' => $post_data->post_title,
1225
- 'post_excerpt' => $post_data->post_excerpt,
1226
- 'post_status' => $post_data->post_status,
1227
- 'comment_status' => $post_data->comment_status,
1228
- 'ping_status' => $post_data->ping_status,
1229
- 'post_password' => $post_data->post_password,
1230
- 'post_name' => $replaced_slug,
1231
- 'to_ping' => $post_data->to_ping,
1232
- 'pinged' => $post_data->pinged,
1233
- 'post_modified' => $post_data->post_modified,
1234
- 'post_modified_gmt' => $post_data->post_modified_gmt,
1235
- 'post_content_filtered' => $post_data->post_content_filtered,
1236
- 'post_parent' => $post_id, // current post ID
1237
- 'guid' => $replaced_guid,
1238
- 'menu_order' => $post_data->menu_order,
1239
- 'post_type' => $post_data->post_type,
1240
- 'post_mime_type' => $post_data->post_mime_type,
1241
- 'comment_count' => $post_data->comment_count
1242
- ));
1243
- update_post_meta($variation_id, '_wcml_duplicate_of_variation', $post_data->ID);
1244
- update_post_meta($variation_id, '_icl_duplicate_of', $post_data->ID);
1245
- $trid = $sitepress->get_element_trid($post_data->ID, 'post_product_variation');
1246
- $sitepress->set_element_language_details($variation_id, 'post_product_variation', $trid, $lang, $sitepress->get_default_language());
1247
- }
1248
- }
 
1249
 
1250
- $get_current_post_variations = $wpdb->get_results("SELECT * FROM $wpdb->posts
1251
- WHERE post_status = 'publish' AND post_type = 'product_variation' AND post_parent = '$post_id'");
 
 
 
 
 
 
 
 
1252
 
1253
- // Delete variations that no longer exist
1254
- foreach ($get_current_post_variations as $post_data) {
1255
- $variation_id = get_post_meta($post_data->ID, '_wcml_duplicate_of_variation', true);
1256
- if (!in_array($variation_id, $duplicated_post_variation_ids)) {
1257
- wp_delete_post($variation_id, true);
1258
- }
1259
- }
1260
-
1261
  // custom fields to copy
1262
- global $iclTranslationManagement;
1263
- $cf = $iclTranslationManagement->settings['custom_fields_translation'];
1264
 
1265
  // synchronize post variations post meta
1266
  $current_post_variation_ids = array();
@@ -1282,45 +1293,43 @@ class woocommerce_wpml {
1282
  $tax = substr($meta_key, 10);
1283
  if (taxonomy_exists($tax)) {
1284
  $taxs[] = $tax;
1285
- $attid = get_term_by('slug', $meta_value, $tax)->term_id;
1286
- $attid = icl_object_id($attid, $tax, false, $lang);
1287
- if (!$attid) {
1288
- // if term not translated, skip
1289
- continue;
 
 
1290
  }
1291
- $meta_value = get_term_by('id', $attid, $tax)->slug;
1292
- } else {
1293
- icl_register_string('woocommerce', $meta_value .'_attribute_name', $meta_value);
1294
  }
1295
  }
1296
  // update current post variations meta
1297
- if (!empty($attid) || in_array($meta_key, $cf) && $cf[$meta_key] == 1) {
1298
  update_post_meta($current_post_variation_ids[$dp_key], $meta_key, $meta_value);
1299
  }
1300
  }
1301
  }
1302
 
1303
  // Sync terms
1304
- $nontranslated = array();
1305
  $taxs = array_unique($taxs);
1306
  foreach ($taxs as $tax) {
1307
  $terms = wp_get_object_terms($duplicated_post_id, $tax);
1308
  $update = array();
1309
  foreach ($terms as $term) {
1310
- $term_id = intval(icl_object_id($term->term_id, $tax, false, $lang));
1311
- if ($term_id > 0) {
1312
- $update[] = $term_id;
1313
- } else {
1314
- // dont sync non-translated terms
1315
- $nontranslated[] = $term;
1316
  }
1317
  }
1318
  wp_set_object_terms($post_id, $update, $tax);
1319
  }
1320
 
1321
- }
1322
- }
1323
- }
 
 
1324
 
1325
  /**
1326
  * Creates WCML page.
@@ -1343,15 +1352,10 @@ class woocommerce_wpml {
1343
  * Adds additional CSS and JS.
1344
  */
1345
  function load_css_and_js() {
1346
- wp_enqueue_style('wpml-wcml', WCML_PLUGIN_URL . '/assets/css/management.css', array(), WCML_VERSION);
1347
-
1348
- wp_enqueue_script(
1349
- 'jquery-validate',
1350
- plugin_dir_url(__FILE__) . '/assets/js/jquery.validate.min.js',
1351
- array('jquery'),
1352
- '1.8.1',
1353
- true
1354
- );
1355
  }
1356
 
1357
  /**
1
  <?php
2
  class woocommerce_wpml {
3
+
4
  var $currencies;
5
+ var $missing;
6
+
7
  function __construct(){
8
  add_action('plugins_loaded', array($this, 'init'), 2);
9
  $this->currencies = array(
18
  'GBP' => '&pound;'
19
  );
20
  }
21
+
22
  function init(){
23
  global $sitepress;
24
 
25
+ $allok = true;
26
+ $this->missing = array();
27
+ if(!defined('ICL_SITEPRESS_VERSION') || ICL_PLUGIN_INACTIVE){
28
+ if(!function_exists('is_multisite') || !is_multisite()) {
29
+ $this->missing['WPML'] = 'http://wpml.org';
30
+ $allok = false;
31
+ }
32
+ } else if(version_compare(ICL_SITEPRESS_VERSION, '2.0.5', '<')){
33
+ add_action('admin_notices', array($this, 'old_wpml_warning'));
34
+ $allok = false;
35
+ }
36
+
37
+ if(!class_exists('woocommerce')){
38
+ $this->missing['WooCommerce'] = 'http://www.woothemes.com/woocommerce/';
39
+ $allok = false;
40
+ }
41
+
42
+ if(!defined('WPML_TM_VERSION')){
43
+ $this->missing['WPML Translation Management'] = 'http://wpml.org';
44
+ $allok = false;
45
+ }
46
+
47
+ if(!defined('WPML_ST_VERSION')){
48
+ $this->missing['WPML String Translation'] = 'http://wpml.org';
49
+ $allok = false;
50
+ }
51
+
52
+ if (!$allok) {
53
+ add_action('admin_notices', array($this, 'missing_plugins_warning'));
54
+ return false;
55
+ }
56
 
57
  if(get_option('icl_is_wcml_installed') !== 'yes'){
58
  $this->wcml_install();
60
 
61
  add_action('admin_notices', array($this, 'check_for_incompatible_permalinks'));
62
 
63
+ add_filter('woocommerce_get_checkout_url', array($this, 'get_checkout_page_url'));
 
 
 
 
 
 
 
 
 
 
64
  add_filter('woocommerce_get_checkout_payment_url', array($this, 'do_redirect'));
65
  add_filter('woocommerce_get_cancel_order_url', array($this, 'do_redirect'));
66
  add_filter('woocommerce_get_return_url', array($this, 'do_redirect'));
77
  add_filter('woocommerce_gateway_description', array($this, 'gateway_description'), 10, 2);
78
  add_filter('woocommerce_json_search_found_products', array($this, 'search_products'));
79
  add_filter('woocommerce_currency', array($this, 'set_ml_currency'));
80
+ add_action('admin_print_scripts', array($this,'js_scripts_setup'), 11);
 
81
  add_action('init', array($this, 'translate_email_notifications'));
82
 
83
+ // Slug translation
84
  add_filter('gettext_with_context', array($this, 'default_slug_translation'), 0, 4);
 
85
 
86
+ // Translate shop page ids
87
  add_filter('option_woocommerce_shop_page_id', array($this, 'translate_pages_in_settings'));
88
  add_filter('option_woocommerce_terms_page_id', array($this, 'translate_pages_in_settings'));
89
  add_filter('option_woocommerce_cart_page_id', array($this, 'translate_pages_in_settings'));
90
  add_filter('option_woocommerce_checkout_page_id', array($this, 'translate_pages_in_settings'));
91
+ add_filter('option_woocommerce_review_order_page_id', array($this, 'translate_pages_in_settings'));
92
  add_filter('option_woocommerce_pay_page_id', array($this, 'translate_pages_in_settings'));
93
  add_filter('option_woocommerce_thanks_page_id', array($this, 'translate_pages_in_settings'));
94
+ add_filter('option_woocommerce_lost_password_page_id', array($this, 'translate_pages_in_settings'));
95
  add_filter('option_woocommerce_myaccount_page_id', array($this, 'translate_pages_in_settings'));
96
  add_filter('option_woocommerce_edit_address_page_id', array($this, 'translate_pages_in_settings'));
97
  add_filter('option_woocommerce_view_order_page_id', array($this, 'translate_pages_in_settings'));
98
  add_filter('option_woocommerce_change_password_page_id', array($this, 'translate_pages_in_settings'));
99
+ add_filter('option_woocommerce_logout_page_id', array($this, 'translate_pages_in_settings'));
100
 
101
  if(get_option('icl_enable_multi_currency') == 'yes'){
102
  if(get_option('currency_converting_option') == '1'){
125
  add_action('save_post', array($this, 'sync_variations'), 11, 2); // After WPML
126
  add_filter('icl_make_duplicate', array($this, 'sync_variations_for_duplicates'), 11, 4);
127
 
 
128
  add_action('admin_menu', array($this, 'menu'));
129
  add_action('init', array($this, 'load_css_and_js'));
130
 
302
  return $terms;
303
  }
304
 
 
 
 
 
 
 
 
 
305
  function register_shipping_methods($available_methods){
 
306
  foreach($available_methods as $method){
307
+ $method->label = icl_translate('woocommerce', $method->label .'_shipping_method_title', $method->label);
 
 
 
 
 
 
308
  }
 
 
309
 
310
+ return $available_methods;
311
  }
312
 
313
  function tax_rates($rates){
378
  return $languages;
379
  }
380
 
381
+ /**
382
+ * Adds admin notice.
383
+ */
384
+ function missing_plugins_warning(){
385
+ $missing = '';
386
+ $counter = 0;
387
+ foreach ($this->missing as $title => $url) {
388
+ $counter ++;
389
+ if ($counter == sizeof($this->missing)) {
390
+ $sep = '';
391
+ } elseif ($counter == sizeof($this->missing) - 1) {
392
+ $sep = ' ' . __('and', 'plugin woocommerce') . ' ';
393
+ } else {
394
+ $sep = ', ';
395
+ }
396
+ $missing .= '<a href="' . $url . '">' . $title . '</a>' . $sep;
397
+ }
398
+ ?>
399
+ <div class="message error"><p><?php printf(__('WooCommerce Multilingual is enabled but not effective. It requires %s in order to work.', 'plugin woocommerce'), $missing); ?></p></div>
400
+ <?php
401
+ }
402
 
403
+ /**
404
+ * Adds admin notice.
405
+ */
406
+ function old_wpml_warning(){
407
+ ?>
408
+ <div class="message error"><p><?php printf(__('WooCommerce Multilingual is enabled but not effective. It is not compatible with <a href="%s">WPML</a> versions prior 2.0.5.', 'plugin woocommerce'),
409
+ 'http://wpml.org/'); ?></p></div>
410
+ <?php
411
+ }
412
 
413
  /**
414
  * Install the plugin.
441
  function check_for_incompatible_permalinks() {
442
  global $sitepress, $sitepress_settings;
443
 
444
+ if ( version_compare( WOOCOMMERCE_VERSION, "2.0.0" ) >= 0 ) {
445
+ // WooCommerce 2.x specific checks
446
+ $permalinks = get_option('woocommerce_permalinks', array('product_base' => ''));
447
+ if (empty($permalinks['product_base'])) {
448
+ return;
449
+ }
450
+ $message = sprintf(__('If you want to translate product slugs, you need to keep the default permalink structure for products in <a href="%s">Permalink Settings</a>', 'plugin woocommerce'), 'options-permalink.php');
451
+ } else {
452
+ // WooCommerce 1.x specific checks
453
+ if (get_option('woocommerce_prepend_shop_page_to_products', 'yes') != "yes") {
454
+ return;
455
+ }
456
+ $message = sprintf(__('If you want to translate product slugs, you need to disable the shop prefix for products in <a href="%s">WooCommerce Settings</a>', 'plugin woocommerce'), 'admin.php?page=woocommerce_settings&tab=pages');
457
+ }
458
+
459
+ // Check if translated shop pages have the same slug (only 1.x)
460
+ $allsame = true;
461
+ if ( version_compare( WOOCOMMERCE_VERSION, "2.0.0" ) >= 0 ) {
462
+ } else {
463
+ $shop_page_id = get_option('woocommerce_shop_page_id', false);
464
+ if (!empty($shop_page_id)) {
465
+ $slug = @get_page($shop_page_id)->post_name;
466
+ $languages = icl_get_languages('skip_missing=0');
467
+ if (sizeof($languages) < 2) {
468
+ return;
469
+ }
470
+ foreach ($languages as $language) {
471
+ if ($language['language_code'] != $sitepress->get_default_language()) {
472
+ $translated_shop_page_id = icl_object_id($shop_page_id, 'page', false, $language['language_code']);
473
+ if (!empty($translated_shop_page_id)) {
474
+ $translated_slug = get_page($translated_shop_page_id)->post_name;
475
+ if (!empty($translated_slug) && $translated_slug != $slug) {
476
+ $allsame = false;
477
+ break;
478
+ }
479
+ }
480
+ }
481
+ }
482
+ }
483
  }
484
 
485
  // Check if slug translation is enabled
490
  $compatible = false;
491
  }
492
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
493
  // display messages
494
  if (!$allsame) {
495
  ?>
499
  }
500
  if (!$compatible) {
501
  ?>
502
+ <div class="message error"><p><?php echo $message; ?></p></div>
 
503
  <?php
504
  }
505
  }
517
  }
518
 
519
  /**
520
+ * Filters upsell/crosell products in the correct language.
521
+ */
522
  function search_products($found_products){
523
  global $wpdb, $sitepress;
524
 
525
  $current_page_language = $sitepress->get_current_language();
526
 
527
+ foreach($found_products as $product_id => $output_v){
528
+ $post_data = $wpdb->get_row("SELECT * FROM ". $wpdb->prefix ."icl_translations WHERE element_id = '$product_id'");
529
  $product_language = $post_data->language_code;
530
 
531
  if($product_language !== $current_page_language){
532
  unset($found_products[$product_id]);
533
+ }
534
+ }
535
 
536
  return $found_products;
537
  }
538
+
 
 
 
 
 
539
  // Set multilingual currency.
540
  function set_ml_currency($currency){
541
  global $wpdb, $sitepress;
569
  /**
570
  * Filters WooCommerce checkout link.
571
  */
572
+ function get_checkout_page_url(){
573
  return get_permalink(icl_object_id(get_option('woocommerce_checkout_page_id'), 'page', true));
574
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
575
 
576
  /**
577
  * After email translation switch language to default.
709
  global $post;
710
 
711
  $post_type = get_post_type($post->ID);
712
+ $checkout_page_id = get_option('woocommerce_checkout_page_id');
713
 
714
  if($post_type == 'product' || is_page($checkout_page_id)){
715
  $output = '';
728
  }
729
 
730
  function attribute_terms($terms){
731
+ global $sitepress;
732
  // remove autop
733
  $terms = str_replace('<p>', '', $terms);
734
  $terms = str_replace('</p>', '', $terms);
738
  $out = array();
739
  foreach ($terms as $term) {
740
  $term = trim($term);
741
+ if ($sitepress->get_default_language() == $sitepress->get_current_language()) {
742
+ $term = icl_translate('woocommerce', $term .'_attribute_name', $term);
743
+ } else {
744
+ $term = icl_t('woocommerce', $term .'_attribute_name', $term);
745
+ }
746
+ $out[] = $term;
747
  }
748
 
749
  return wpautop(wptexturize(implode(", ", $out)));
835
  function woocommerce_price($price){
836
  global $sitepress, $wpdb;
837
 
838
+ if (get_option('icl_enable_multi_currency') != 'yes') {
839
+ $sql = "SELECT value FROM ". $wpdb->prefix ."icl_currencies WHERE language_code = '". $sitepress->get_current_language() ."'";
840
+ $currency = $wpdb->get_results($sql, OBJECT);
841
+
842
+ if($currency){
843
+ $exchange_rate = $currency[0]->value;
844
+ $price = round($price * $exchange_rate, (int) get_option( 'woocommerce_price_num_decimals' ));
845
+ $price = apply_filters('woocommerce_multilingual_price', $price);
846
+ }
847
+ }
848
 
849
  return $price;
850
  }
859
  function email_header() {
860
  global $sitepress, $order_id;
861
 
862
+ $lang = get_post_meta($order_id, 'wpml_language', TRUE);
 
 
 
863
 
864
  if(empty($lang)){
865
  if(isset($_SESSION['wpml_globalcart_language'])){
884
  $sitepress->switch_lang();
885
  }
886
 
887
+ /*
888
+ * WC compat layer: get product id
889
+ */
890
+
891
+ function get_product_id_from_order_item($item) {
892
+ if ( version_compare( WOOCOMMERCE_VERSION, "2.0.0" ) >= 0 ) {
893
+ // WC 2.0
894
+ return isset($item['product_id']) ? $item['product_id'] : false;
895
+ } else {
896
+ return isset($item['product_id']) ? $item['product_id'] : false;
897
+ }
898
+ }
899
+
900
+
901
+ /*
902
+ * WC compat layer: get product
903
+ */
904
+
905
+ function wcml_get_product($product_id) {
906
+ if ( version_compare( WOOCOMMERCE_VERSION, "2.0.0" ) >= 0 ) {
907
+ // WC 2.0
908
+ return get_product( $product_id);
909
+ } else {
910
+ return new WC_Product($product_id);
911
+ }
912
+ }
913
+
914
+ function sync_product_stocks($order) {
915
+ if ( version_compare( WOOCOMMERCE_VERSION, "2.0.0" ) >= 0 ) {
916
+ // WC 2.0
917
+ return $this->sync_product_stocks20($order);
918
+ } else {
919
+ return $this->sync_product_stocks16($order);
920
+ }
921
+ }
922
+
923
  /*
924
  Only when translated products are ordered, force adjusting stock information for all translations
925
  When a product in the default language is ordered stocks are adjusted automatically
926
  */
927
+ function sync_product_stocks16($order){
928
  global $sitepress;
929
  $order_id = $order->id;
930
 
931
  foreach ( $order->get_items() as $item ) {
 
932
  if (isset($item['variation_id']) && $item['variation_id']>0){
933
  $ld = $sitepress->get_element_language_details($item['variation_id'], 'post_product_variation');
934
  $product_id = icl_object_id( $item['variation_id'], 'product_variation', true, $sitepress->get_default_language());
960
 
961
  }
962
 
963
+ function sync_product_stocks20($order){
964
+ global $sitepress;
965
+ $order_id = $order->id;
966
+
967
+ foreach ( $order->get_items() as $item ) {
968
+ if (isset($item['variation_id']) && $item['variation_id']>0){
969
+ $ld = $sitepress->get_element_language_details($item['variation_id'], 'post_product_variation');
970
+ $product_id = icl_object_id( $item['variation_id'], 'product_variation', true, $sitepress->get_default_language());
971
+ $_product = get_product($product_id);
972
+ }else{
973
+ $ld = $sitepress->get_element_language_details($item['product_id'], 'post_product');
974
+ $product_id = icl_object_id( $item['product_id'], 'product', true, $sitepress->get_default_language());
975
+ $_product = get_product($product_id);
976
+ }
977
+
978
+ // Process for non-default languages
979
+ if ($ld->language_code != $sitepress->get_default_language()) {
980
+
981
+ // Out of stock attribute
982
+ if ($_product->managing_stock() && !$_product->backorders_allowed() && $_product->get_total_stock()<=0){
983
+ $outofstock = 'outofstock';
984
+ }else{
985
+ $outofstock = false;
986
+ }
987
+
988
+ if ( $_product && $_product->exists() && $_product->managing_stock() ) {
989
+ $stock = $_product->reduce_stock($item['qty']);
990
+ $total_sales = get_post_meta($_product->id, 'total_sales', true);
991
+ $total_sales += $item['qty'];
992
+ update_post_meta($product_id, 'total_sales', $total_sales);
993
+ }
994
+ }
995
+ }
996
+
997
+ }
998
  /**
999
  * Adds language to order post type.
1000
  *
1028
  if($currency){
1029
  $exchange_rate = $currency[0]->value;
1030
  $min_price = $min_price / $exchange_rate;
1031
+ $min_price = round($min_price,(int) get_option( 'woocommerce_price_num_decimals' ));
1032
  }
1033
  }
1034
 
1053
  if($currency){
1054
  $exchange_rate = $currency[0]->value;
1055
  $max_price = $max_price / $exchange_rate;
1056
+ $max_price = round($max_price,(int) get_option( 'woocommerce_price_num_decimals' ));
1057
  }
1058
  }
1059
 
1060
  return $max_price;
1061
  }
1062
+
1063
+ /**
1064
+ * This function synchronizes variations when we first create a duplicate
1065
+ */
1066
  function sync_variations_for_duplicates($master_post_id, $lang, $postarr, $id) {
1067
  $this->sync_variations($id, $postarr);
1068
  }
1069
 
1070
+ /**
1071
+ * This function takes care of synchronizing variations from original to translations
1072
+ */
1073
+ function sync_variations($post_id, $post){
1074
+ global $wpdb, $pagenow, $sitepress, $sitepress_settings;
1075
 
1076
+ // check its a product
1077
  $post_type = get_post_type($post_id);
1078
+ if ($post_type != 'product') {
1079
+ return;
1080
+ }
1081
 
1082
  // exceptions
1083
+ $ajax_call = (!empty($_POST['icl_ajx_action']) && $_POST['icl_ajx_action'] == 'make_duplicates');
1084
+ $duplicated_post_id = icl_object_id($post_id, 'product', false, $sitepress->get_default_language());
1085
  if (empty($duplicated_post_id) || isset($_POST['autosave'])) {
1086
  return;
1087
  }
1088
+ if($pagenow != 'post.php' && $pagenow != 'post-new.php' && !$ajax_call){
1089
+ return;
1090
+ }
1091
+
1092
  // get language code
1093
  $language_details = $sitepress->get_element_language_details($post_id, 'post_product');
1094
  if (empty($language_details)) {
1095
  return;
1096
  }
 
 
 
 
 
1097
 
1098
+ // pick posts to sync
1099
+ $posts = array();
1100
+ $translations = $sitepress->get_element_translations($language_details->trid, 'post_product');
1101
+ foreach ($translations as $translation) {
1102
+ if ($translation->original) {
1103
+ $duplicated_post_id = $translation->element_id;
1104
+ } else {
1105
+ $posts[$translation->element_id] = $translation;
1106
+ }
1107
+ }
1108
+
1109
+ foreach ($posts as $post_id => $translation) {
1110
+ $lang = $translation->language_code;
1111
 
1112
+ // Filter upsell products, crosell products and default attributes for translations
1113
  $original_product_upsell_ids = get_post_meta($duplicated_post_id, '_upsell_ids', TRUE);
1114
  if(!empty($original_product_upsell_ids)){
1115
  $unserialized_upsell_ids = maybe_unserialize($original_product_upsell_ids);
1116
+
1117
  foreach($unserialized_upsell_ids as $k => $product_id){
1118
  // get the correct language
1119
  $upsell_product_translation_id = icl_object_id($product_id, 'product', false, $lang);
1120
+
1121
  if($upsell_product_translation_id){
1122
  $unserialized_upsell_ids[$k] = $upsell_product_translation_id;
1123
  // if it isn't translated - unset it
1125
  unset($unserialized_upsell_ids[$k]);
1126
  }
1127
  }
1128
+
1129
  $data = array('meta_value' => maybe_serialize($unserialized_upsell_ids));
1130
  $where = array('post_id' => $post_id, 'meta_key' => '_upsell_ids');
1131
  $wpdb->update($wpdb->postmeta, $data, $where);
1132
  }
1133
+
1134
  $original_product_crosssell_ids = get_post_meta($duplicated_post_id, '_crosssell_ids', TRUE);
1135
  if(!empty($original_product_crosssell_ids)){
1136
  $unserialized_crosssell_ids = maybe_unserialize($original_product_crosssell_ids);
1137
+
1138
  foreach($unserialized_crosssell_ids as $k => $product_id){
1139
  // get the correct language
1140
  $crosssell_product_translation_id = icl_object_id($product_id, 'product', false, $lang);
1141
+
1142
  if($crosssell_product_translation_id){
1143
  $unserialized_crosssell_ids[$k] = $crosssell_product_translation_id;
1144
  // if it isn't translated - unset it
1146
  unset($unserialized_crosssell_ids[$k]);
1147
  }
1148
  }
1149
+
1150
  $data = array('meta_value' => maybe_serialize($unserialized_crosssell_ids));
1151
  $where = array('post_id' => $post_id, 'meta_key' => '_crosssell_ids');
1152
  $wpdb->update($wpdb->postmeta, $data, $where);
1153
  }
1154
+
1155
  $original_default_attributes = get_post_meta($duplicated_post_id, '_default_attributes', TRUE);
1156
  if(!empty($original_default_attributes)){
1157
  $unserialized_default_attributes = maybe_unserialize($original_default_attributes);
1168
  unset($unserialized_default_attributes[$attribute]);
1169
  }
1170
  }
1171
+
1172
  $data = array('meta_value' => maybe_serialize($unserialized_default_attributes));
1173
  $where = array('post_id' => $post_id, 'meta_key' => '_default_attributes');
1174
  $wpdb->update($wpdb->postmeta, $data, $where);
1175
  }
1176
 
1177
+ $get_variation_term_id = $wpdb->get_var("SELECT term_id FROM $wpdb->terms WHERE name = 'variable'");
1178
+ $get_variation_term_taxonomy_id = $wpdb->get_var("SELECT tt.term_taxonomy_id FROM $wpdb->term_relationships tr
 
 
 
 
1179
  LEFT JOIN $wpdb->term_taxonomy tt ON tt.term_taxonomy_id = tr.term_taxonomy_id
1180
  WHERE object_id = '$duplicated_post_id' AND taxonomy = 'product_type'");
1181
 
1182
+ $is_post_has_variations = $wpdb->get_results("SELECT * FROM $wpdb->term_relationships WHERE object_id = '$duplicated_post_id' AND term_taxonomy_id = '$get_variation_term_taxonomy_id'");
1183
+ if(!empty($is_post_has_variations)) $is_post_has_variations = TRUE;
1184
 
1185
+ // synchronize term data, postmeta and post variations
1186
+ if($is_post_has_variations){
1187
+ // synchronize post variations
1188
+ $get_all_post_variations = $wpdb->get_results("SELECT * FROM $wpdb->posts
1189
+ WHERE post_status = 'publish' AND post_type = 'product_variation' AND post_parent = '$duplicated_post_id'");
1190
 
1191
+ $duplicated_post_variation_ids = array();
1192
+ foreach($get_all_post_variations as $k => $post_data){
1193
+ $duplicated_post_variation_ids[] = $post_data->ID;
1194
+ }
1195
 
1196
+ foreach($get_all_post_variations as $k => $post_data){
1197
+ // Find if this has already been duplicated
1198
+ $variation_id = $wpdb->get_var("SELECT post_id FROM $wpdb->postmeta
1199
+ JOIN {$wpdb->prefix}icl_translations ON element_id = post_id AND element_type = 'post_product_variation' AND language_code = '$lang'
1200
+ WHERE meta_key = '_wcml_duplicate_of_variation' AND meta_value = '$post_data->ID'");
1201
+ if (!empty($variation_id)) {
1202
+ // Update variation
1203
+ wp_update_post(array(
1204
+ 'ID' => $variation_id,
1205
+ 'post_author' => $post_data->post_author,
1206
+ 'post_date_gmt' => $post_data->post_date_gmt,
1207
+ 'post_content' => $post_data->post_content,
1208
+ 'post_title' => $post_data->post_title,
1209
+ 'post_excerpt' => $post_data->post_excerpt,
1210
+ 'post_status' => $post_data->post_status,
1211
+ 'comment_status' => $post_data->comment_status,
1212
+ 'ping_status' => $post_data->ping_status,
1213
+ 'post_password' => $post_data->post_password,
1214
+ 'post_name' => $post_data->post_name,
1215
+ 'to_ping' => $post_data->to_ping,
1216
+ 'pinged' => $post_data->pinged,
1217
+ 'post_modified' => $post_data->post_modified,
1218
+ 'post_modified_gmt' => $post_data->post_modified_gmt,
1219
+ 'post_content_filtered' => $post_data->post_content_filtered,
1220
+ 'post_parent' => $post_id, // current post ID
1221
+ 'menu_order' => $post_data->menu_order,
1222
+ 'post_type' => $post_data->post_type,
1223
+ 'post_mime_type' => $post_data->post_mime_type,
1224
+ 'comment_count' => $post_data->comment_count
1225
+ ));
1226
+ } else {
1227
+ // Add new variation
1228
+ $guid = $post_data->guid;
1229
+ $replaced_guid = str_replace($duplicated_post_id, $post_id, $guid);
1230
+ $slug = $post_data->post_name;
1231
+ $replaced_slug = str_replace($duplicated_post_id, $post_id, $slug);
1232
+ $variation_id = wp_insert_post(array(
1233
+ 'post_author' => $post_data->post_author,
1234
+ 'post_date_gmt' => $post_data->post_date_gmt,
1235
+ 'post_content' => $post_data->post_content,
1236
+ 'post_title' => $post_data->post_title,
1237
+ 'post_excerpt' => $post_data->post_excerpt,
1238
+ 'post_status' => $post_data->post_status,
1239
+ 'comment_status' => $post_data->comment_status,
1240
+ 'ping_status' => $post_data->ping_status,
1241
+ 'post_password' => $post_data->post_password,
1242
+ 'post_name' => $replaced_slug,
1243
+ 'to_ping' => $post_data->to_ping,
1244
+ 'pinged' => $post_data->pinged,
1245
+ 'post_modified' => $post_data->post_modified,
1246
+ 'post_modified_gmt' => $post_data->post_modified_gmt,
1247
+ 'post_content_filtered' => $post_data->post_content_filtered,
1248
+ 'post_parent' => $post_id, // current post ID
1249
+ 'guid' => $replaced_guid,
1250
+ 'menu_order' => $post_data->menu_order,
1251
+ 'post_type' => $post_data->post_type,
1252
+ 'post_mime_type' => $post_data->post_mime_type,
1253
+ 'comment_count' => $post_data->comment_count
1254
+ ));
1255
+ update_post_meta($variation_id, '_wcml_duplicate_of_variation', $post_data->ID);
1256
+ update_post_meta($variation_id, '_icl_duplicate_of', $post_data->ID);
1257
+ $trid = $sitepress->get_element_trid($post_data->ID, 'post_product_variation');
1258
+ $sitepress->set_element_language_details($variation_id, 'post_product_variation', $trid, $lang, $sitepress->get_default_language());
1259
+ }
1260
+ }
1261
 
1262
+ $get_current_post_variations = $wpdb->get_results("SELECT * FROM $wpdb->posts
1263
+ WHERE post_status = 'publish' AND post_type = 'product_variation' AND post_parent = '$post_id'");
1264
+
1265
+ // Delete variations that no longer exist
1266
+ foreach ($get_current_post_variations as $post_data) {
1267
+ $variation_id = get_post_meta($post_data->ID, '_wcml_duplicate_of_variation', true);
1268
+ if (!in_array($variation_id, $duplicated_post_variation_ids)) {
1269
+ wp_delete_post($variation_id, true);
1270
+ }
1271
+ }
1272
 
 
 
 
 
 
 
 
 
1273
  // custom fields to copy
1274
+ $cf = (array)$sitepress_settings['translation-management']['custom_fields_translation'];
 
1275
 
1276
  // synchronize post variations post meta
1277
  $current_post_variation_ids = array();
1293
  $tax = substr($meta_key, 10);
1294
  if (taxonomy_exists($tax)) {
1295
  $taxs[] = $tax;
1296
+ $attid = get_term_by('slug', $meta_value, $tax)->term_taxonomy_id;
1297
+ $trid = $sitepress->get_element_trid($attid, 'tax_' . $tax);
1298
+ if ($trid) {
1299
+ $translations = $sitepress->get_element_translations($trid,'tax_' . $tax);
1300
+ if (isset($translations[$lang])) {
1301
+ $meta_value = get_term_by('id', $translations[$lang]->term_id, $tax)->slug;
1302
+ }
1303
  }
 
 
 
1304
  }
1305
  }
1306
  // update current post variations meta
1307
+ if ((substr($meta_key, 0, 10) == 'attribute_' || isset($cf[$meta_key]) && $cf[$meta_key] == 1)) {
1308
  update_post_meta($current_post_variation_ids[$dp_key], $meta_key, $meta_value);
1309
  }
1310
  }
1311
  }
1312
 
1313
  // Sync terms
 
1314
  $taxs = array_unique($taxs);
1315
  foreach ($taxs as $tax) {
1316
  $terms = wp_get_object_terms($duplicated_post_id, $tax);
1317
  $update = array();
1318
  foreach ($terms as $term) {
1319
+ $trid = $sitepress->get_element_trid($term->term_taxonomy_id, 'tax_' . $tax);
1320
+ $translations = $sitepress->get_element_translations($trid,'tax_' . $tax);
1321
+ if (isset($translations[$lang])) {
1322
+ $update[] = intval($translations[$lang]->term_id);
 
 
1323
  }
1324
  }
1325
  wp_set_object_terms($post_id, $update, $tax);
1326
  }
1327
 
1328
+ }
1329
+
1330
+ }
1331
+
1332
+ }
1333
 
1334
  /**
1335
  * Creates WCML page.
1352
  * Adds additional CSS and JS.
1353
  */
1354
  function load_css_and_js() {
1355
+ if(isset($_GET['page']) && $_GET['page'] == 'wpml-wcml') {
1356
+ wp_enqueue_style('wpml-wcml', WCML_PLUGIN_URL . '/assets/css/management.css', array(), WCML_VERSION);
1357
+ wp_enqueue_script('jquery-validate', plugin_dir_url(__FILE__) . '/assets/js/jquery.validate.min.js', array('jquery'), '1.8.1', true);
1358
+ }
 
 
 
 
 
1359
  }
1360
 
1361
  /**
wpml-config.xml CHANGED
@@ -32,7 +32,6 @@
32
  <custom-field action="copy">_height</custom-field>
33
  <custom-field action="copy">_length</custom-field>
34
  <custom-field action="copy">_woocommerce_exclude_image</custom-field>
35
- <custom-field action="copy">_wp_attached_file</custom-field>
36
  <custom-field action="copy">total_sales</custom-field>
37
  </custom-fields>
38
  <custom-types>
32
  <custom-field action="copy">_height</custom-field>
33
  <custom-field action="copy">_length</custom-field>
34
  <custom-field action="copy">_woocommerce_exclude_image</custom-field>
 
35
  <custom-field action="copy">total_sales</custom-field>
36
  </custom-fields>
37
  <custom-types>
wpml-woocommerce.php CHANGED
@@ -5,11 +5,11 @@
5
  Description: Allows running fully multilingual e-Commerce sites with WooCommerce and WPML. <a href="http://wpml.org/documentation/related-projects/woocommerce-multilingual/">Documentation</a>.
6
  Author: ICanLocalize
7
  Author URI: http://wpml.org/
8
- Version: 1.5
9
  */
10
 
11
  if(defined('WCML_VERSION')) return;
12
- define('WCML_VERSION', '1.5');
13
  define('WCML_PLUGIN_PATH', dirname(__FILE__));
14
  define('WCML_PLUGIN_FOLDER', basename(WCML_PLUGIN_PATH));
15
  define('WCML_PLUGIN_URL', plugins_url() . '/' . WCML_PLUGIN_FOLDER);
5
  Description: Allows running fully multilingual e-Commerce sites with WooCommerce and WPML. <a href="http://wpml.org/documentation/related-projects/woocommerce-multilingual/">Documentation</a>.
6
  Author: ICanLocalize
7
  Author URI: http://wpml.org/
8
+ Version: 2.0
9
  */
10
 
11
  if(defined('WCML_VERSION')) return;
12
+ define('WCML_VERSION', '2.0');
13
  define('WCML_PLUGIN_PATH', dirname(__FILE__));
14
  define('WCML_PLUGIN_FOLDER', basename(WCML_PLUGIN_PATH));
15
  define('WCML_PLUGIN_URL', plugins_url() . '/' . WCML_PLUGIN_FOLDER);