WooCommerce Multilingual – run WooCommerce with WPML - Version 4.3.5

Version Description

  • Fix rest translation in products creation
  • Fixed incorrect translation matched for Table Rate Shipping title
  • Price is not saved correctly via "Quick Edit" if secondary currency is selected on front
  • Fixed a performance issue when a product has a lot of variations.
  • Fixed variation image synchronization
  • Lower priority of 'woocommerce_cart_item_name' hook for "WooCommerce Product Subtitle" and others to work
  • Fixed performance issues on product listing page with big amount of attributes
  • Fixed fatal error with WPML older than 3.9
  • Fix redirection to wcml dashboard in a specific case if you skip wizard
  • Fixed stock status when purchasing the last product in the second language which does not update status for original
  • WooCommerce Product Bundle synchronizations problems when re-creating bundle product translation
  • Fixed Woo Variations Table Compatibility issue with overwritten product title in specific scenario
  • Fix cosmetic issue with mutli-currency message in product post screen
  • Fixed infinite loop with large product numbers and languages
Download this release

Release Info

Developer sergey.r
Plugin Icon 128x128 WooCommerce Multilingual – run WooCommerce with WPML
Version 4.3.5
Comparing to
See all releases

Code changes from version 4.3.4 to 4.3.5

changelog/4.3.4.md CHANGED
@@ -2,6 +2,7 @@
2
  * [wcml-2494] Fixed error: Cannot redeclare woocommerce_wp_text_input
3
  * [wcml-2492] Fixed error when creating booking from admin without creating order
4
  * [wcml-2491] Fixed Woocommerce Dynamic Price issue with Advanced category price in second language
 
5
  * [wcml-2485] Fix situation with filtering WC attributes calling by sku
6
  * [wcml-2484] Fix a problem that you cannot delete booking from trash
7
  * [wcml-2482] Fix prevent letters in multicurrency popup for number of decimals
2
  * [wcml-2494] Fixed error: Cannot redeclare woocommerce_wp_text_input
3
  * [wcml-2492] Fixed error when creating booking from admin without creating order
4
  * [wcml-2491] Fixed Woocommerce Dynamic Price issue with Advanced category price in second language
5
+ * [wcml-2488] Fixed attachments duplication when synchronizing gallery
6
  * [wcml-2485] Fix situation with filtering WC attributes calling by sku
7
  * [wcml-2484] Fix a problem that you cannot delete booking from trash
8
  * [wcml-2482] Fix prevent letters in multicurrency popup for number of decimals
changelog/4.3.5.md ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Fixes
2
+ * [wcml-2522] Fix rest translation in products creation
3
+ * [wcml-2519] Fixed incorrect translation matched for Table Rate Shipping title
4
+ * [wcml-2518] Price is not saved correctly via "Quick Edit" if secondary currency is selected on front
5
+ * [wcml-2517] Fixed a performance issue when a product has a lot of variations.
6
+ * [wcml-2515] Fixed variation image synchronization
7
+ * [wcml-2514] Lower priority of 'woocommerce_cart_item_name' hook for "WooCommerce Product Subtitle" and others to work
8
+ * [wcml-2512] Fixed performance issues on product listing page with big amount of attributes
9
+ * [wcml-2511] Fixed fatal error with WPML older than 3.9
10
+ * [wcml-2510] Fix redirection to wcml dashboard in a specific case if you skip wizard
11
+ * [wcml-2509] Fixed stock status when purchasing the last product in the second language which does not update status for original
12
+ * [wcml-2508] WooCommerce Product Bundle synchronizations problems when re-creating bundle product translation
13
+ * [wcml-2507] Fixed Woo Variations Table Compatibility issue with overwritten product title in specific scenario
14
+ * [wcml-2505] Fix cosmetic issue with mutli-currency message in product post screen
15
+ * [wcml-2480] Fixed infinite loop with large product numbers and languages
classes/class-wcml-admin-cookie.php CHANGED
@@ -22,6 +22,7 @@ class WCML_Admin_Cookie{
22
  if( null === $expiration ){
23
  $expiration = time() + DAY_IN_SECONDS;
24
  }
 
25
  wc_setcookie( $this->name, $value, $expiration );
26
  }
27
 
@@ -36,4 +37,10 @@ class WCML_Admin_Cookie{
36
  return $value;
37
  }
38
 
39
- }
 
 
 
 
 
 
22
  if( null === $expiration ){
23
  $expiration = time() + DAY_IN_SECONDS;
24
  }
25
+ $this->handle_cache_plugins();
26
  wc_setcookie( $this->name, $value, $expiration );
27
  }
28
 
37
  return $value;
38
  }
39
 
40
+ /**
41
+ * @param $name
42
+ */
43
+ private function handle_cache_plugins() {
44
+ do_action( 'wpsc_add_cookie', $this->name );
45
+ }
46
+ }
classes/class-woocommerce-wpml.php CHANGED
@@ -91,7 +91,7 @@ class woocommerce_wpml {
91
 
92
  $WCML_REST_API = new WCML_REST_API();
93
 
94
- if ( class_exists( 'WooCommerce' ) && defined( 'WC_VERSION' ) && 'yes' == get_option( 'woocommerce_api_enabled' ) && ! is_null( $sitepress ) ) {
95
  if ( version_compare( WC_VERSION, '2.6', '>=' ) && $WCML_REST_API->is_rest_api_request() ) {
96
  $wcml_rest_api_query_filters_products = new WCML_REST_API_Query_Filters_Products( $wpml_query_filter );
97
  $wcml_rest_api_query_filters_orders = new WCML_REST_API_Query_Filters_Orders( $wpdb );
91
 
92
  $WCML_REST_API = new WCML_REST_API();
93
 
94
+ if ( class_exists( 'WooCommerce' ) && defined( 'WC_VERSION' ) && ! is_null( $sitepress ) ) {
95
  if ( version_compare( WC_VERSION, '2.6', '>=' ) && $WCML_REST_API->is_rest_api_request() ) {
96
  $wcml_rest_api_query_filters_products = new WCML_REST_API_Query_Filters_Products( $wpml_query_filter );
97
  $wcml_rest_api_query_filters_orders = new WCML_REST_API_Query_Filters_Orders( $wpdb );
classes/urls/class-wcml-xdomain-data.php CHANGED
@@ -58,7 +58,7 @@ class WCML_xDomain_Data {
58
  if ( has_filter( 'wpml_get_cross_domain_language_data' ) ) { // After WPML 3.2.7
59
  $xdomain_data = apply_filters( 'wpml_get_cross_domain_language_data', array() );
60
  } elseif ( isset( $_GET['xdomain_data'] ) ) {
61
- $xdomain_data = json_decode( base64_decode( $_GET['xdomain_data'] ), JSON_OBJECT_AS_ARRAY );
62
  }
63
 
64
  if ( isset( $xdomain_data['wcsid'] ) ) {
@@ -97,4 +97,4 @@ class WCML_xDomain_Data {
97
 
98
  }
99
 
100
- }
58
  if ( has_filter( 'wpml_get_cross_domain_language_data' ) ) { // After WPML 3.2.7
59
  $xdomain_data = apply_filters( 'wpml_get_cross_domain_language_data', array() );
60
  } elseif ( isset( $_GET['xdomain_data'] ) ) {
61
+ $xdomain_data = json_decode( base64_decode( $_GET['xdomain_data'] ), true );
62
  }
63
 
64
  if ( isset( $xdomain_data['wcsid'] ) ) {
97
 
98
  }
99
 
100
+ }
compatibility/class-wcml-bookings.php CHANGED
@@ -1235,7 +1235,8 @@ class WCML_Bookings {
1235
 
1236
  function set_booking_currency( $currency_code = false ) {
1237
 
1238
- if ( ! isset( $_COOKIE ['_wcml_booking_currency'] ) && ! headers_sent() ) {
 
1239
 
1240
 
1241
  $currency_code = get_woocommerce_currency();
@@ -1253,7 +1254,8 @@ class WCML_Bookings {
1253
  }
1254
 
1255
  if ( $currency_code ) {
1256
- setcookie( '_wcml_booking_currency', $currency_code, time() + 86400, COOKIEPATH, COOKIE_DOMAIN );
 
1257
  }
1258
 
1259
  }
@@ -2566,4 +2568,4 @@ class WCML_Bookings {
2566
 
2567
  }
2568
 
2569
- }
1235
 
1236
  function set_booking_currency( $currency_code = false ) {
1237
 
1238
+ $cookie_name = '_wcml_booking_currency';
1239
+ if ( ! isset( $_COOKIE [ $cookie_name ] ) && ! headers_sent() ) {
1240
 
1241
 
1242
  $currency_code = get_woocommerce_currency();
1254
  }
1255
 
1256
  if ( $currency_code ) {
1257
+ do_action( 'wpsc_add_cookie', $cookie_name );
1258
+ setcookie( $cookie_name, $currency_code, time() + 86400, COOKIEPATH, COOKIE_DOMAIN );
1259
  }
1260
 
1261
  }
2568
 
2569
  }
2570
 
2571
+ }
compatibility/class-wcml-product-bundles.php CHANGED
@@ -58,6 +58,8 @@ class WCML_Product_Bundles {
58
  add_action( 'wp_insert_post', array( $this, 'sync_product_bundle_meta_with_translations' ), 10 );
59
 
60
  add_filter( 'woocommerce_json_search_found_products', array( $this, 'woocommerce_json_search_filter_found_products' ) );
 
 
61
  }
62
 
63
  // product bundle using separate custom fields for prices
@@ -834,4 +836,12 @@ class WCML_Product_Bundles {
834
  return $found_products;
835
  }
836
 
 
 
 
 
 
 
 
 
837
  }
58
  add_action( 'wp_insert_post', array( $this, 'sync_product_bundle_meta_with_translations' ), 10 );
59
 
60
  add_filter( 'woocommerce_json_search_found_products', array( $this, 'woocommerce_json_search_filter_found_products' ) );
61
+
62
+ add_action( 'woocommerce_before_delete_bundled_item', array( $this, 'delete_bundled_item_relationship' ) );
63
  }
64
 
65
  // product bundle using separate custom fields for prices
836
  return $found_products;
837
  }
838
 
839
+ public function delete_bundled_item_relationship( $bundle_item ){
840
+
841
+ $this->wpdb->query( $this->wpdb->prepare(
842
+ "DELETE FROM {$this->wpdb->prefix}woocommerce_bundled_itemmeta WHERE `meta_value` = %d AND `meta_key` LIKE 'translation_item_id_of_%'", $bundle_item->get_id()
843
+ ) );
844
+
845
+ }
846
+
847
  }
compatibility/class-wcml-woo-var-table.php ADDED
@@ -0,0 +1,32 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ * Woo Variations table Compatibility class
4
+ */
5
+
6
+ class WCML_Woo_Var_Table {
7
+
8
+ /**
9
+ * @var string
10
+ */
11
+ private $current_language;
12
+
13
+ /**
14
+ * @param string $current_language
15
+ */
16
+ function __construct( $current_language ){
17
+ $this->current_language = $current_language;
18
+ }
19
+
20
+ function add_hooks() {
21
+
22
+ add_filter( 'vartable_add_to_cart_product_id', array( $this, 'filter_add_to_cart_product_id' ) );
23
+ }
24
+
25
+ function filter_add_to_cart_product_id( $product_id ) {
26
+
27
+ $product_id = apply_filters( 'translate_object_id', $product_id, get_post_type( $product_id ), true, $this->current_language );
28
+
29
+ return $product_id;
30
+ }
31
+
32
+ }
inc/admin-menus/class-wcml-admin-menus.php CHANGED
@@ -214,9 +214,10 @@ class WCML_Admin_Menus{
214
  self::is_post_action_needs_redirect()
215
  ) {
216
  $prid = (int) $_GET['post'];
217
- wp_redirect( admin_url( 'admin.php?page=wpml-wcml&tab=products&prid=' . $prid ) );
218
- exit;
219
-
 
220
  } elseif ( self::is_admin_duplicate_page_action( $pagenow ) && self::is_post_product_translation_screen() ) {
221
 
222
  wp_redirect( admin_url( 'admin.php?page=wpml-wcml&tab=products' ) );
214
  self::is_post_action_needs_redirect()
215
  ) {
216
  $prid = (int) $_GET['post'];
217
+ if( 'auto-draft' !== get_post_status( $prid ) ){
218
+ wp_redirect( admin_url( 'admin.php?page=wpml-wcml&tab=products&prid=' . $prid ) );
219
+ exit;
220
+ }
221
  } elseif ( self::is_admin_duplicate_page_action( $pagenow ) && self::is_post_product_translation_screen() ) {
222
 
223
  wp_redirect( admin_url( 'admin.php?page=wpml-wcml&tab=products' ) );
inc/class-wcml-attributes.php CHANGED
@@ -620,12 +620,20 @@ class WCML_Attributes{
620
  */
621
  public function filter_product_variation_post_meta_attribute_values_in_current_language( $value, $object_id, $meta_key, $single ) {
622
 
623
- if ( 'product_variation' === get_post_type( $object_id ) && '' === $meta_key ) {
 
 
 
 
 
 
 
 
624
 
625
  remove_filter( 'get_post_metadata', array(
626
  $this,
627
  'filter_product_variation_post_meta_attribute_values_in_current_language'
628
- ), 10, 4 );
629
 
630
  $all_meta = get_post_meta( $object_id );
631
 
@@ -643,6 +651,8 @@ class WCML_Attributes{
643
  }
644
  }
645
 
 
 
646
  return $all_meta;
647
  }
648
 
620
  */
621
  public function filter_product_variation_post_meta_attribute_values_in_current_language( $value, $object_id, $meta_key, $single ) {
622
 
623
+ if ( '' === $meta_key && 'product_variation' === get_post_type( $object_id ) ) {
624
+
625
+ $cache_group = 'wpml-all-meta-product-variation';
626
+ $cache_key = $this->sitepress->get_current_language() . $object_id;
627
+ $cached_value = wp_cache_get( $cache_key, $cache_group );
628
+
629
+ if ( $cached_value ) {
630
+ return $cached_value;
631
+ }
632
 
633
  remove_filter( 'get_post_metadata', array(
634
  $this,
635
  'filter_product_variation_post_meta_attribute_values_in_current_language'
636
+ ), 10 );
637
 
638
  $all_meta = get_post_meta( $object_id );
639
 
651
  }
652
  }
653
 
654
+ wp_cache_add( $cache_key, $all_meta, $cache_group );
655
+
656
  return $all_meta;
657
  }
658
 
inc/class-wcml-compatibility.php CHANGED
@@ -247,6 +247,12 @@ class WCML_Compatibility {
247
  $this->relevanssi->add_hooks();
248
  }
249
 
 
 
 
 
 
 
250
  }
251
 
252
  }
247
  $this->relevanssi->add_hooks();
248
  }
249
 
250
+ // Woo Variations Table
251
+ if ( defined( 'WOO_VARIATIONS_TABLE_VERSION') ) {
252
+ $this->wpb_woo_var_table = new WCML_Woo_Var_Table( $this->sitepress->get_current_language() );
253
+ $this->wpb_woo_var_table->add_hooks();
254
+ }
255
+
256
  }
257
 
258
  }
inc/class-wcml-media.php CHANGED
@@ -83,6 +83,22 @@ class WCML_Media{
83
  }
84
  }
85
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
86
  public function sync_product_gallery( $product_id ) {
87
 
88
  $product_gallery = get_post_meta( $product_id, '_product_image_gallery', true );
83
  }
84
  }
85
 
86
+ public function sync_variation_thumbnail_id( $variation_id, $translated_variation_id, $lang ){
87
+ $thumbnail_id = get_post_meta( $variation_id, '_thumbnail_id', true );
88
+ $translated_thumbnail = apply_filters( 'translate_object_id', $thumbnail_id, 'attachment', false, $lang );
89
+
90
+ if( is_null( $translated_thumbnail ) && $thumbnail_id ){
91
+ $factory = new WPML_Media_Attachments_Duplication_Factory();
92
+ $media_duplicate = $factory->create();
93
+ $translated_thumbnail = $media_duplicate->create_duplicate_attachment( $thumbnail_id, wp_get_post_parent_id( $thumbnail_id ), $lang );
94
+ }
95
+
96
+ update_post_meta( $translated_variation_id, '_thumbnail_id', $translated_thumbnail );
97
+ update_post_meta( $variation_id, '_wpml_media_duplicate', 1 );
98
+ update_post_meta( $variation_id, '_wpml_media_featured', 1 );
99
+ }
100
+
101
+
102
  public function sync_product_gallery( $product_id ) {
103
 
104
  $product_gallery = get_post_meta( $product_id, '_product_image_gallery', true );
inc/class-wcml-orders.php CHANGED
@@ -3,7 +3,7 @@ class WCML_Orders{
3
 
4
  private $woocommerce_wpml;
5
  private $sitepress;
6
-
7
  private $standard_order_notes = array(
8
  'Order status changed from %s to %s.',
9
  'Order item stock reduced successfully.',
@@ -31,12 +31,12 @@ class WCML_Orders{
31
 
32
  add_action( 'wp_ajax_wcml_order_delete_items', array( $this, 'order_delete_items' ) );
33
  }
34
-
35
  function init(){
36
-
37
  add_action('woocommerce_shipping_update_ajax', array($this, 'fix_shipping_update'));
38
  add_action('woocommerce_checkout_update_order_meta', array($this, 'set_order_language'));
39
-
40
  add_filter('icl_lang_sel_copy_parameters', array($this, 'append_query_parameters'));
41
 
42
  add_filter('the_comments', array($this, 'get_filtered_comments'));
@@ -111,7 +111,7 @@ class WCML_Orders{
111
 
112
  return $comments;
113
  }
114
-
115
  function woocommerce_order_get_items( $items, $order ){
116
 
117
  if( isset( $_GET[ 'post' ] ) && get_post_type( $_GET[ 'post' ] ) == 'shop_order' ) {
@@ -186,10 +186,11 @@ class WCML_Orders{
186
  }
187
  }elseif( $item instanceof WC_Order_Item_Shipping ){
188
  if( $item->get_method_id() ){
 
189
  $item->set_method_title(
190
  $this->woocommerce_wpml->shipping->translate_shipping_method_title(
191
  $item->get_method_title(),
192
- $item->get_method_id(),
193
  $language_to_filter
194
  )
195
  );
@@ -262,40 +263,40 @@ class WCML_Orders{
262
  $wpdb->update( $wpdb->prefix.'woocommerce_order_itemmeta', array( 'meta_value' => $value ), array( 'order_item_id' => $item_id, 'meta_key' => $key ) );
263
  }
264
  }
265
-
266
  // Fix for shipping update on the checkout page.
267
  function fix_shipping_update($amount){
268
  global $sitepress, $post;
269
-
270
  if($sitepress->get_current_language() !== $sitepress->get_default_language() && $post->ID == $this->checkout_page_id()){
271
-
272
  $_SESSION['icl_checkout_shipping_amount'] = $amount;
273
-
274
  $amount = $_SESSION['icl_checkout_shipping_amount'];
275
-
276
  }
277
-
278
  return $amount;
279
  }
280
 
281
 
282
  /**
283
  * Adds language to order post type.
284
- *
285
  * Language was stored in the session created on checkout page.
286
  * See params().
287
- *
288
  * @param type $order_id
289
- */
290
- function set_order_language($order_id) {
291
  if(!get_post_meta($order_id, 'wpml_language')){
292
  $language = isset($_SESSION['wpml_globalcart_language']) ? $_SESSION['wpml_globalcart_language'] : ICL_LANGUAGE_CODE;
293
  update_post_meta($order_id, 'wpml_language', $language);
294
  }
295
  }
296
-
297
  function append_query_parameters($parameters){
298
-
299
  if(is_order_received_page() || is_checkout()){
300
  if(!in_array('order', $parameters)) $parameters[] = 'order';
301
  if(!in_array('key', $parameters)) $parameters[] = 'key';
@@ -367,7 +368,9 @@ class WCML_Orders{
367
  die();
368
  }
369
 
370
- setcookie('_wcml_dashboard_order_language', filter_input( INPUT_POST, 'lang', FILTER_SANITIZE_FULL_SPECIAL_CHARS ), time() + 86400, COOKIEPATH, COOKIE_DOMAIN);
 
 
371
 
372
  }
373
 
3
 
4
  private $woocommerce_wpml;
5
  private $sitepress;
6
+
7
  private $standard_order_notes = array(
8
  'Order status changed from %s to %s.',
9
  'Order item stock reduced successfully.',
31
 
32
  add_action( 'wp_ajax_wcml_order_delete_items', array( $this, 'order_delete_items' ) );
33
  }
34
+
35
  function init(){
36
+
37
  add_action('woocommerce_shipping_update_ajax', array($this, 'fix_shipping_update'));
38
  add_action('woocommerce_checkout_update_order_meta', array($this, 'set_order_language'));
39
+
40
  add_filter('icl_lang_sel_copy_parameters', array($this, 'append_query_parameters'));
41
 
42
  add_filter('the_comments', array($this, 'get_filtered_comments'));
111
 
112
  return $comments;
113
  }
114
+
115
  function woocommerce_order_get_items( $items, $order ){
116
 
117
  if( isset( $_GET[ 'post' ] ) && get_post_type( $_GET[ 'post' ] ) == 'shop_order' ) {
186
  }
187
  }elseif( $item instanceof WC_Order_Item_Shipping ){
188
  if( $item->get_method_id() ){
189
+ $shipping_id = $item->get_method_id() . $item->get_instance_id();
190
  $item->set_method_title(
191
  $this->woocommerce_wpml->shipping->translate_shipping_method_title(
192
  $item->get_method_title(),
193
+ $shipping_id,
194
  $language_to_filter
195
  )
196
  );
263
  $wpdb->update( $wpdb->prefix.'woocommerce_order_itemmeta', array( 'meta_value' => $value ), array( 'order_item_id' => $item_id, 'meta_key' => $key ) );
264
  }
265
  }
266
+
267
  // Fix for shipping update on the checkout page.
268
  function fix_shipping_update($amount){
269
  global $sitepress, $post;
270
+
271
  if($sitepress->get_current_language() !== $sitepress->get_default_language() && $post->ID == $this->checkout_page_id()){
272
+
273
  $_SESSION['icl_checkout_shipping_amount'] = $amount;
274
+
275
  $amount = $_SESSION['icl_checkout_shipping_amount'];
276
+
277
  }
278
+
279
  return $amount;
280
  }
281
 
282
 
283
  /**
284
  * Adds language to order post type.
285
+ *
286
  * Language was stored in the session created on checkout page.
287
  * See params().
288
+ *
289
  * @param type $order_id
290
+ */
291
+ function set_order_language($order_id) {
292
  if(!get_post_meta($order_id, 'wpml_language')){
293
  $language = isset($_SESSION['wpml_globalcart_language']) ? $_SESSION['wpml_globalcart_language'] : ICL_LANGUAGE_CODE;
294
  update_post_meta($order_id, 'wpml_language', $language);
295
  }
296
  }
297
+
298
  function append_query_parameters($parameters){
299
+
300
  if(is_order_received_page() || is_checkout()){
301
  if(!in_array('order', $parameters)) $parameters[] = 'order';
302
  if(!in_array('key', $parameters)) $parameters[] = 'key';
368
  die();
369
  }
370
 
371
+ $cookie_name = '_wcml_dashboard_order_language';
372
+ do_action( 'wpsc_add_cookie', $cookie_name );
373
+ setcookie( $cookie_name, filter_input( INPUT_POST, 'lang', FILTER_SANITIZE_FULL_SPECIAL_CHARS ), time() + 86400, COOKIEPATH, COOKIE_DOMAIN );
374
 
375
  }
376
 
inc/class-wcml-upgrade.php CHANGED
@@ -25,7 +25,8 @@ class WCML_Upgrade{
25
  '4.2.10',
26
  '4.2.11',
27
  '4.3.0',
28
- '4.3.4'
 
29
  );
30
 
31
  function __construct(){
@@ -99,7 +100,7 @@ class WCML_Upgrade{
99
  if(empty($version_in_db) && get_option('icl_is_wcml_installed')){
100
  $version_in_db = '2.3.2';
101
  }
102
-
103
  $migration_ran = false;
104
 
105
  if ( $version_in_db && version_compare( $version_in_db, WCML_VERSION, '<' ) ) {
@@ -712,4 +713,18 @@ class WCML_Upgrade{
712
 
713
  }
714
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
715
  }
25
  '4.2.10',
26
  '4.2.11',
27
  '4.3.0',
28
+ '4.3.4',
29
+ '4.3.5'
30
  );
31
 
32
  function __construct(){
100
  if(empty($version_in_db) && get_option('icl_is_wcml_installed')){
101
  $version_in_db = '2.3.2';
102
  }
103
+
104
  $migration_ran = false;
105
 
106
  if ( $version_in_db && version_compare( $version_in_db, WCML_VERSION, '<' ) ) {
713
 
714
  }
715
 
716
+ private function upgrade_4_3_5() {
717
+
718
+ if ( class_exists( 'WC_Product_Bundle' ) && function_exists( 'WC_PB' ) ) {
719
+
720
+ global $wpdb;
721
+ //delete wrong bundle items
722
+ $wpdb->query( "DELETE FROM {$wpdb->prefix}woocommerce_bundled_itemmeta WHERE `meta_key` LIKE 'translation_item_id_of_%' AND `meta_value` IN ( SELECT bundled_item_id FROM {$wpdb->prefix}woocommerce_bundled_items WHERE `product_id` = 0 AND `bundle_id` = 0 ) " );
723
+ $wpdb->query( "DELETE FROM {$wpdb->prefix}woocommerce_bundled_items WHERE `product_id` = 0 AND `bundle_id` = 0 " );
724
+ $not_existing_items = $wpdb->get_col( "SELECT m.`meta_id` FROM {$wpdb->prefix}woocommerce_bundled_itemmeta AS m LEFT JOIN {$wpdb->prefix}woocommerce_bundled_items as i ON m.meta_value = i.bundled_item_id WHERE m.`meta_key` LIKE 'translation_item_id_of_%' AND i.`bundled_item_id` IS NULL" );
725
+ $wpdb->query( $wpdb->prepare( "DELETE FROM {$wpdb->prefix}woocommerce_bundled_itemmeta WHERE `meta_id` IN ( %s )", join( ',', $not_existing_items ) ) );
726
+ }
727
+
728
+ }
729
+
730
  }
inc/class-wcml-wc-shipping.php CHANGED
@@ -112,9 +112,9 @@ class WCML_WC_Shipping{
112
  }
113
 
114
  function translate_shipping_methods_in_package( $available_methods ){
115
-
116
  foreach($available_methods as $key => $method){
117
- $available_methods[$key]->label = $this->translate_shipping_method_title( $method->label, $key );
 
118
  }
119
 
120
  return $available_methods;
112
  }
113
 
114
  function translate_shipping_methods_in_package( $available_methods ){
 
115
  foreach($available_methods as $key => $method){
116
+ $shipping_id = $method->method_id . $method->instance_id;
117
+ $available_methods[$key]->label = $this->translate_shipping_method_title( $method->label, $shipping_id );
118
  }
119
 
120
  return $available_methods;
inc/class-wcml-wc-strings.php CHANGED
@@ -1,123 +1,134 @@
1
  <?php
2
 
3
- class WCML_WC_Strings{
4
 
5
- private $translations_from_mo_file = array();
6
- private $mo_files = array();
7
- private $current_language;
8
 
9
- /** @var woocommerce_wpml */
10
- private $woocommerce_wpml;
11
- /** @var Sitepress */
12
- private $sitepress;
13
 
14
- public $settings = array();
15
 
16
- /**
17
- * WCML_WC_Strings constructor.
18
- *
19
- * @param woocommerce_wpml $woocommerce_wpml
20
- * @param SitePress $sitepress
21
- */
22
- public function __construct( woocommerce_wpml $woocommerce_wpml, SitePress $sitepress ){
23
- $this->woocommerce_wpml = $woocommerce_wpml;
24
- $this->sitepress = $sitepress;
25
- }
26
 
27
- function add_hooks(){
28
 
29
- add_action( 'init', array( $this, 'add_on_init_hooks' ) );
30
- add_action( 'registered_taxonomy', array ( $this, 'translate_attributes_label_in_wp_taxonomies' ), 100, 3 );
31
- }
32
 
33
- function add_on_init_hooks(){
34
- global $pagenow;
35
 
36
- $this->current_language = $this->sitepress->get_current_language();
37
- if( $this->current_language == 'all' ){
38
- $this->current_language = $this->sitepress->get_default_language();
39
- }
40
 
41
- //translate attribute label
42
- add_filter('woocommerce_attribute_label',array($this,'translated_attribute_label'),10,3);
43
- add_filter('woocommerce_checkout_product_title',array($this,'translated_checkout_product_title'),10,2);
44
- add_filter( 'woocommerce_cart_item_name', array( $this, 'translated_cart_item_name' ), 10, 2 );
45
 
46
- if( is_admin() && $pagenow == 'options-permalink.php' ){
47
- add_filter( 'gettext_with_context', array( $this, 'category_base_in_strings_language' ), 99, 3 );
48
- add_action( 'admin_footer', array( $this, 'show_custom_url_base_translation_links' ) );
49
- add_action('admin_footer', array($this, 'show_custom_url_base_language_requirement'));
50
- }
51
- add_action( 'woocommerce_product_options_attributes', array ( $this, 'notice_after_woocommerce_product_options_attributes' ) );
52
 
53
- add_filter( 'woocommerce_attribute_taxonomies', array( $this, 'translate_attribute_taxonomies_labels' ) );
 
 
 
 
 
 
 
 
 
 
 
54
 
55
- add_filter('woocommerce_get_breadcrumb', array($this, 'filter_woocommerce_breadcrumbs' ), 10, 2 );
56
- }
 
 
57
 
58
- function translated_attribute_label($label, $name, $product_obj = false){
59
- global $product, $sitepress_settings;
60
 
61
- $product_id = false;
62
- $lang = $this->sitepress->get_current_language();
63
 
64
- if( isset( $_GET[ 'post' ] ) && get_post_type( $_GET[ 'post' ] ) == 'shop_order' ){
65
- $lang = $this->sitepress->get_user_admin_language( get_current_user_id(), true );
66
- }
67
 
68
- if( $product && is_object( $product ) ){
69
- $product_id = WooCommerce_Functions_Wrapper::get_product_id( $product );
70
- }elseif( is_numeric( $product_obj ) ){
71
- $product_id = $product_obj;
72
- }elseif( $product_obj ){
73
- $product_id = WooCommerce_Functions_Wrapper::get_product_id( $product_obj );
74
- }
75
 
76
- $name = $this->woocommerce_wpml->attributes->filter_attribute_name( $name, $product_id, true );
 
 
 
 
 
 
77
 
78
- if( $product_id ){
79
 
80
- $custom_attr_translation = $this->woocommerce_wpml->attributes->get_attr_label_translations( $product_id, $lang ) ;
81
 
82
- if( $custom_attr_translation ){
83
- if( isset( $custom_attr_translation[$name] ) ){
84
- return $custom_attr_translation[$name];
85
- }
86
- }
87
 
88
- }
 
 
 
 
89
 
90
- $trnsl_label = apply_filters( 'wpml_translate_single_string', $label, 'WordPress', 'taxonomy singular name: '.$label, $lang );
91
 
92
- if( $label != $trnsl_label ){
93
- return $trnsl_label;
94
- }
95
 
96
- if(is_admin() && !wpml_is_ajax()){
 
 
97
 
98
- $string_language = $this->get_string_language( 'taxonomy singular name: '.$label, 'WordPress' );
99
 
100
- if($this->sitepress->get_user_admin_language( get_current_user_id(), true ) != $string_language){
101
- $string_id = icl_get_string_id( 'taxonomy singular name: '.$label, 'WordPress' );
102
- $strings = icl_get_string_translations_by_id($string_id);
103
- if($strings){
104
- return $strings[$this->sitepress->get_user_admin_language( get_current_user_id(), true )]['value'];
105
- }
106
- }else{
107
- return $label;
108
- }
109
 
110
- }
 
 
 
 
 
 
 
 
111
 
112
- // backward compatibility for WCML < 3.6.1
113
- $trnsl_labels = get_option('wcml_custom_attr_translations');
114
 
115
- if( isset( $trnsl_labels[$lang][$name] ) && !empty( $trnsl_labels[$lang][$name] ) ){
116
- return $trnsl_labels[$lang][$name];
117
- }
118
 
119
- return $label;
120
- }
 
 
 
 
121
 
122
  /**
123
  * @param string $title
@@ -132,7 +143,7 @@ class WCML_WC_Strings{
132
  $product_id = $values['variation_id'] ? $values['variation_id'] : $values['product_id'];
133
 
134
  $translated_product_id = apply_filters( 'translate_object_id', $product_id, 'product', true );
135
- $translated_title = get_the_title( $translated_product_id );
136
 
137
  if ( strstr( $title, '</a>' ) ) {
138
  $title = sprintf( '<a href="%s">%s</a>', $values['data']->get_permalink(), $translated_title );
@@ -144,352 +155,358 @@ class WCML_WC_Strings{
144
  return $title;
145
  }
146
 
147
- function translated_checkout_product_title( $title, $product ){
148
 
149
- if( $product ){
150
- $tr_product_id = apply_filters( 'translate_object_id', WooCommerce_Functions_Wrapper::get_product_id( $product ), 'product', true, $this->current_language );
151
- $title = get_the_title($tr_product_id);
152
- }
153
 
154
- return $title;
155
- }
156
 
157
- // Catch the default slugs for translation
158
- function translate_default_slug($translation, $text, $context, $domain) {
159
 
160
- if ($context == 'slug' || $context == 'default-slug') {
161
- $wc_slug = $this->woocommerce_wpml->url_translation->get_woocommerce_product_base();
162
- if(is_admin()){
163
- $admin_language = $this->sitepress->get_admin_language();
164
- }
165
- $current_language = $this->sitepress->get_current_language();
166
-
167
- $strings_language = $this->get_domain_language('woocommerce');
168
 
169
- if ($text == $wc_slug && $domain == 'woocommerce' && $strings_language) {
170
- $this->sitepress->switch_lang($strings_language);
171
- $translation = _x($text, 'URL slug', $domain);
172
- $this->sitepress->switch_lang($current_language);
173
- if(is_admin()){
174
- $this->sitepress->set_admin_language($admin_language);
175
- }
176
- }else{
177
- $translation = $text;
178
- }
179
 
180
- if(!is_admin()){
181
- $this->sitepress->switch_lang($current_language);
182
- }
183
- }
 
 
 
 
 
 
184
 
185
- return $translation;
 
 
 
186
 
187
- }
188
 
 
189
 
190
 
191
- function show_custom_url_base_language_requirement(){
192
- $category_base = ($c = get_option('category_base') ) ? $c : 'category';
193
- ?>
194
  <script>
195
- if(jQuery('#woocommerce_permalink_structure').length){
196
  jQuery('#woocommerce_permalink_structure').parent().append(jQuery('#wpml_wcml_custom_base_req').html());
197
  }
198
- if(jQuery('input[name="woocommerce_product_category_slug"]').length && jQuery('input[name="woocommerce_product_category_slug"]').val() == '<?php echo $category_base ?>'){
199
  jQuery('input[name="woocommerce_product_category_slug"]').parent().append('<br><i class="icon-warning-sign"><?php
200
- _e('You are using the same value as for the regular category base. This is known to create conflicts resulting in urls not working properly.', 'woocommerce-multilingual') ?></i>');
201
  }
202
  </script>
203
- <?php
204
-
205
- }
206
-
207
- function show_custom_url_base_translation_links(){
208
-
209
- $permalink_options = get_option( 'woocommerce_permalinks' );
210
-
211
- $lang_selector = new WPML_Simple_Language_Selector( $this->sitepress );
212
-
213
- $bases = array( 'tag_base' => 'product_tag', 'category_base' => 'product_cat', 'attribute_base' => 'attribute', 'product_base' => 'product' );
214
-
215
- foreach( $bases as $key => $base ){
216
-
217
- switch($base){
218
- case 'product_tag':
219
- $input_name = 'woocommerce_product_tag_slug';
220
- $value = !empty( $permalink_options['tag_base'] ) ? $permalink_options['tag_base'] : $this->woocommerce_wpml->url_translation->default_product_tag_base;
221
- break;
222
- case 'product_cat':
223
- $input_name = 'woocommerce_product_category_slug';
224
- $value = !empty( $permalink_options['category_base'] ) ? $permalink_options['category_base'] : $this->woocommerce_wpml->url_translation->default_product_category_base;
225
- break;
226
- case 'attribute':
227
- $input_name = 'woocommerce_product_attribute_slug';
228
- $value = !empty( $permalink_options['attribute_base'] ) ? $permalink_options['attribute_base'] : '';
229
- break;
230
- case 'product':
231
- $input_name = 'product_permalink_structure';
232
- if( empty( $permalink_options['product_base'] ) ){
233
- $value = _x( 'product', 'default-slug', 'woocommerce' );
234
- }else{
235
- $value = trim( $permalink_options['product_base'], '/' );
236
- }
237
 
238
- break;
239
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
240
 
241
- $language = $this->get_string_language( trim( $value, '/' ), $this->woocommerce_wpml->url_translation->url_strings_context(), $this->woocommerce_wpml->url_translation->url_string_name( $base ) );
242
 
243
- if( is_null($language) ){
244
- $language = $this->sitepress->get_default_language();
245
- }
246
 
247
- echo $lang_selector->render( array( 'id' => $key.'_language_selector', 'name' => $key.'_language', 'selected' => $language, 'show_please_select' => false ) ); ?>
 
 
 
 
 
248
 
249
  <script>
250
  var input = jQuery('input[name="<?php echo $input_name ?>"]');
251
 
252
- if(input.length){
253
 
254
- if( '<?php echo $input_name ?>' == 'product_permalink_structure' && jQuery('input[name="product_permalink"]:checked').val() == '' ){
255
  input = jQuery('input[name="product_permalink"]:checked').closest('.form-table').find('code').eq(0);
256
  }
257
 
258
  input.parent().append('<div class="translation_controls"></div>');
259
 
260
- if( '<?php echo $input_name ?>' == 'woocommerce_product_attribute_slug' && input.val() == '' ){
261
 
262
  input.parent().find('.translation_controls').append('&nbsp;');
263
 
264
- }else{
265
  input.parent().find('.translation_controls').append('<a href="<?php
266
- echo admin_url( 'admin.php?page=wpml-wcml&tab=slugs' )
267
- ?>"><?php _e('translations', 'woocommerce-multilingual') ?></a>');
268
  }
269
 
270
- jQuery('#<?php echo $key ?>_language_selector').prependTo( input.parent().find('.translation_controls') );
271
  }
272
  </script>
273
- <?php }
274
 
275
- }
276
-
277
- function category_base_in_strings_language($text, $original_value, $context){
278
- if($context == 'slug' && ($original_value == 'product-category' || $original_value == 'product-tag')){
279
- $text = $original_value;
280
- }
281
- return $text;
282
- }
283
-
284
- function product_permalink_slug(){
285
- $permalinks = get_option( 'woocommerce_permalinks' );
286
- $slug = empty( $permalinks['product_base'] ) ? 'product' : trim($permalinks['product_base'],'/');
287
-
288
- return $slug;
289
- }
290
 
291
- function get_domain_language( $domain ){
 
 
 
292
 
293
- $lang_of_domain = new WPML_Language_Of_Domain( $this->sitepress );
294
- $domain_lang = $lang_of_domain->get_language( $domain );
295
 
296
- if ( $domain_lang ) {
297
- $source_lang = $domain_lang;
298
- }else{
299
- $source_lang = 'en';
300
- }
301
 
302
- return $source_lang;
303
- }
304
 
305
- function get_string_language( $value, $context, $name = false ){
306
- global $wpdb;
307
 
308
- if( $name !== false ){
 
309
 
310
- $string_language = apply_filters( 'wpml_get_string_language', null, $context, $name );
 
 
 
 
311
 
312
- }else{
 
313
 
314
- $string_id = icl_get_string_id( $value, $context, $name );
 
315
 
316
- if( !$string_id ){
317
- return 'en';
318
- }
319
 
320
- $string_object = new WPML_ST_String($string_id, $wpdb);
321
- $string_language = $string_object->get_language();
322
 
323
- }
324
 
325
- if( !$string_language ){
326
- return 'en';
327
- }
328
 
329
- return $string_language;
 
 
330
 
331
- }
 
332
 
333
- function set_string_language( $value, $context, $name , $language ){
334
- global $wpdb;
335
 
336
- $string_id = icl_get_string_id( $value, $context, $name );
 
 
337
 
338
- $string_object = new WPML_ST_String( $string_id, $wpdb );
339
- $string_language = $string_object->set_language( $language );
340
 
341
- return $string_language;
342
- }
343
 
 
 
344
 
345
- /*
346
- * Filter breadcrumbs
347
- *
348
- */
349
- function filter_woocommerce_breadcrumbs( $breadcrumbs, $object ){
350
 
351
- $current_language = $this->sitepress->get_current_language();
352
- $default_language = $this->sitepress->get_default_language();
353
 
354
- $woocommerce_shop_page = wc_get_page_id( 'shop' );
 
355
 
356
- if( isset( $woocommerce_shop_page ) ) {
357
 
358
- $is_shop_page_active = get_post_status( $woocommerce_shop_page );
 
 
 
 
359
 
360
- if ( ( $current_language != $default_language || $default_language != 'en' ) && $is_shop_page_active === 'publish' ) {
 
361
 
362
- $shop_page = get_post( $woocommerce_shop_page );
363
 
364
- // If permalinks contain the shop page in the URI prepend the breadcrumb with shop
365
- // Similar to WC_Breadcrumb::prepend_shop_page
366
- $trnsl_base = $this->woocommerce_wpml->url_translation->get_base_translation( 'product', $current_language );
367
- if ( $trnsl_base['translated_base'] === '' ) {
368
- $trnsl_base['translated_base'] = $trnsl_base['original_value'];
369
- }
370
 
371
- if ( is_woocommerce() && $shop_page->ID && strstr( $trnsl_base['translated_base'], urldecode( $shop_page->post_name ) ) && get_option( 'page_on_front' ) != $shop_page->ID ) {
372
- $breadcrumbs_buff = array();
373
- $i = 0;
374
- foreach ( $breadcrumbs as $key => $breadcrumb ) {
375
 
376
- //Prepend the shop page to shop breadcrumbs
377
- if ( $key === 0 && $breadcrumbs[1][1] != get_post_type_archive_link( 'product' ) ) {
378
- $breadcrumbs_buff[ $i ] = array(
379
- $shop_page->post_title,
380
- get_post_type_archive_link( 'product' )
381
- );
382
- $i ++;
383
- }
384
 
385
- if ( ! in_array( $breadcrumb, $breadcrumbs_buff ) ) {
386
- $breadcrumbs_buff[ $i ] = $breadcrumb;
387
- }
388
- $i ++;
389
- }
390
 
391
- $breadcrumbs = $breadcrumbs_buff;
 
 
 
 
 
392
 
393
- $breadcrumbs = array_values( $breadcrumbs );
394
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
395
 
396
- }
397
- }
398
 
399
- return $breadcrumbs;
400
- }
401
 
402
- /*
403
- * Add notice message to users
404
- */
405
- function notice_after_woocommerce_product_options_attributes(){
406
 
407
- if( isset( $_GET['post'] ) && $this->sitepress->get_default_language() != $this->sitepress->get_current_language() ){
408
- $original_product_id = apply_filters( 'translate_object_id', $_GET['post'], 'product', true, $this->sitepress->get_default_language() );
409
 
410
- printf( '<p>'.__('In order to edit custom attributes you need to use the <a href="%s">custom product translation editor</a>', 'woocommerce-multilingual').'</p>', admin_url('admin.php?page=wpml-wcml&tab=products&prid='.$original_product_id ) );
411
- }
412
- }
413
 
414
  function translate_attribute_taxonomies_labels( $attribute_taxonomies ) {
415
 
416
- if ( is_admin() && ! wpml_is_ajax() ) {
 
417
 
418
- foreach ( $attribute_taxonomies as $key => $attribute_taxonomy ) {
419
- $string_language = $this->get_string_language( $attribute_taxonomy->attribute_label, 'WordPress', 'taxonomy singular name: ' . $attribute_taxonomy->attribute_label );
 
420
 
421
- if ( $this->sitepress->get_current_language() == $string_language ) {
422
- continue;
423
- }
424
 
425
- $string_id = icl_get_string_id( $attribute_taxonomy->attribute_label, 'WordPress', 'taxonomy singular name: ' . $attribute_taxonomy->attribute_label );
426
- $strings = icl_get_string_translations_by_id( $string_id );
427
-
428
- if ( $strings && isset( $strings[ $this->sitepress->get_current_language() ] ) ) {
429
- $attribute_taxonomies[ $key ]->attribute_label = $strings[ $this->sitepress->get_current_language() ]['value'];
430
- }
431
  }
432
-
433
  }
434
 
435
  return $attribute_taxonomies;
436
  }
437
 
438
- function get_translation_from_woocommerce_mo_file( $string, $language, $return_original = true ){
439
 
440
- $original_string = $string;
441
 
442
- if ( ! isset( $this->translations_from_mo_file[ $original_string ][ $language ] ) ) {
443
 
444
- if ( ! isset( $this->translations_from_mo_file[ $original_string ] ) ) {
445
- $this->translations_from_mo_file[ $original_string ] = array();
446
- }
447
 
448
- if ( ! isset( $this->mo_files[ $language ] ) ) {
449
- $mo = new MO();
450
- $mo_file = WP_LANG_DIR . '/plugins/woocommerce-' . $this->sitepress->get_locale( $language ) . '.mo';
451
- if( !file_exists( $mo_file ) ){
452
- return $return_original ? $string : null;
453
- }
454
 
455
- $mo->import_from_file( $mo_file );
456
- $this->mo_files[ $language ] = &$mo->entries;
457
- }
458
 
459
- if( in_array( $string, array( 'product','product-category','product-tag' ) ) ){
460
- $string = 'slug'. chr(4) .$string;
461
- }
462
 
463
- if( isset( $this->mo_files[ $language ][$string] ) ){
464
- $this->translations_from_mo_file[ $original_string ][ $language ] = $this->mo_files[ $language ][$string]->translations[0];
465
- } else {
466
- $this->translations_from_mo_file[ $original_string ][ $language ] = $return_original ? $original_string : null;
467
- }
468
- }
469
 
470
- return $this->translations_from_mo_file[ $original_string ][ $language ];
471
 
472
- }
473
 
474
- function translate_attributes_label_in_wp_taxonomies( $taxonomy, $obj_type, $args ){
475
- global $wp_taxonomies;
476
- $obj_type = array_unique( (array) $obj_type );
477
 
478
- $current_language = $this->sitepress->get_current_language();
479
 
480
- if( $current_language != 'all' && in_array( 'product', $obj_type ) && substr( $taxonomy, 0, 3) == 'pa_' && isset( $wp_taxonomies[ $taxonomy ] )){
481
 
482
- if( is_array( $args['labels'] ) ){
483
- $name = $args['labels']['singular_name'];
484
- }else{
485
- $name = $args['labels']->name;
486
- }
487
 
488
- $wp_taxonomies[$taxonomy]->labels->name = apply_filters( 'wpml_translate_single_string', $name, 'WordPress', 'taxonomy singular name: '.$name, $current_language );
489
 
490
 
491
- }
492
 
493
- }
494
 
495
  }
1
  <?php
2
 
3
+ class WCML_WC_Strings {
4
 
5
+ private $translations_from_mo_file = array();
6
+ private $mo_files = array();
7
+ private $current_language;
8
 
9
+ /** @var woocommerce_wpml */
10
+ private $woocommerce_wpml;
11
+ /** @var Sitepress */
12
+ private $sitepress;
13
 
14
+ public $settings = array();
15
 
16
+ /**
17
+ * WCML_WC_Strings constructor.
18
+ *
19
+ * @param woocommerce_wpml $woocommerce_wpml
20
+ * @param SitePress $sitepress
21
+ */
22
+ public function __construct( woocommerce_wpml $woocommerce_wpml, SitePress $sitepress ) {
23
+ $this->woocommerce_wpml = $woocommerce_wpml;
24
+ $this->sitepress = $sitepress;
25
+ }
26
 
27
+ function add_hooks() {
28
 
29
+ add_action( 'init', array( $this, 'add_on_init_hooks' ) );
30
+ add_action( 'registered_taxonomy', array( $this, 'translate_attributes_label_in_wp_taxonomies' ), 100, 3 );
31
+ }
32
 
33
+ function add_on_init_hooks() {
34
+ global $pagenow;
35
 
36
+ $this->current_language = $this->sitepress->get_current_language();
37
+ if ( $this->current_language == 'all' ) {
38
+ $this->current_language = $this->sitepress->get_default_language();
39
+ }
40
 
41
+ //translate attribute label
42
+ add_filter( 'woocommerce_attribute_label', array( $this, 'translated_attribute_label' ), 10, 3 );
43
+ add_filter( 'woocommerce_checkout_product_title', array( $this, 'translated_checkout_product_title' ), 10, 2 );
44
+ add_filter( 'woocommerce_cart_item_name', array( $this, 'translated_cart_item_name' ), -1, 2 );
45
 
46
+ if ( is_admin() ) {
 
 
 
 
 
47
 
48
+ if ( 'edit.php' !== $pagenow && ! wpml_is_ajax() ) {
49
+ add_filter( 'woocommerce_attribute_taxonomies', array(
50
+ $this,
51
+ 'translate_attribute_taxonomies_labels'
52
+ ) );
53
+ }
54
+ if ( 'options-permalink.php' === $pagenow ) {
55
+ add_filter( 'gettext_with_context', array( $this, 'category_base_in_strings_language' ), 99, 3 );
56
+ add_action( 'admin_footer', array( $this, 'show_custom_url_base_translation_links' ) );
57
+ add_action( 'admin_footer', array( $this, 'show_custom_url_base_language_requirement' ) );
58
+ }
59
+ }
60
 
61
+ add_action( 'woocommerce_product_options_attributes', array(
62
+ $this,
63
+ 'notice_after_woocommerce_product_options_attributes'
64
+ ) );
65
 
66
+ add_filter( 'woocommerce_get_breadcrumb', array( $this, 'filter_woocommerce_breadcrumbs' ), 10, 2 );
67
+ }
68
 
69
+ function translated_attribute_label( $label, $name, $product_obj = false ) {
70
+ global $product, $sitepress_settings;
71
 
72
+ $product_id = false;
73
+ $lang = $this->sitepress->get_current_language();
 
74
 
75
+ if ( isset( $_GET['post'] ) && get_post_type( $_GET['post'] ) == 'shop_order' ) {
76
+ $lang = $this->sitepress->get_user_admin_language( get_current_user_id(), true );
77
+ }
 
 
 
 
78
 
79
+ if ( $product && is_object( $product ) ) {
80
+ $product_id = WooCommerce_Functions_Wrapper::get_product_id( $product );
81
+ } elseif ( is_numeric( $product_obj ) ) {
82
+ $product_id = $product_obj;
83
+ } elseif ( $product_obj ) {
84
+ $product_id = WooCommerce_Functions_Wrapper::get_product_id( $product_obj );
85
+ }
86
 
87
+ $name = $this->woocommerce_wpml->attributes->filter_attribute_name( $name, $product_id, true );
88
 
89
+ if ( $product_id ) {
90
 
91
+ $custom_attr_translation = $this->woocommerce_wpml->attributes->get_attr_label_translations( $product_id, $lang );
 
 
 
 
92
 
93
+ if ( $custom_attr_translation ) {
94
+ if ( isset( $custom_attr_translation[ $name ] ) ) {
95
+ return $custom_attr_translation[ $name ];
96
+ }
97
+ }
98
 
99
+ }
100
 
101
+ $trnsl_label = apply_filters( 'wpml_translate_single_string', $label, 'WordPress', 'taxonomy singular name: ' . $label, $lang );
 
 
102
 
103
+ if ( $label != $trnsl_label ) {
104
+ return $trnsl_label;
105
+ }
106
 
107
+ if ( is_admin() && ! wpml_is_ajax() ) {
108
 
109
+ $string_language = $this->get_string_language( 'taxonomy singular name: ' . $label, 'WordPress' );
 
 
 
 
 
 
 
 
110
 
111
+ if ( $this->sitepress->get_user_admin_language( get_current_user_id(), true ) != $string_language ) {
112
+ $string_id = icl_get_string_id( 'taxonomy singular name: ' . $label, 'WordPress' );
113
+ $strings = icl_get_string_translations_by_id( $string_id );
114
+ if ( $strings ) {
115
+ return $strings[ $this->sitepress->get_user_admin_language( get_current_user_id(), true ) ]['value'];
116
+ }
117
+ } else {
118
+ return $label;
119
+ }
120
 
121
+ }
 
122
 
123
+ // backward compatibility for WCML < 3.6.1
124
+ $trnsl_labels = get_option( 'wcml_custom_attr_translations' );
 
125
 
126
+ if ( isset( $trnsl_labels[ $lang ][ $name ] ) && ! empty( $trnsl_labels[ $lang ][ $name ] ) ) {
127
+ return $trnsl_labels[ $lang ][ $name ];
128
+ }
129
+
130
+ return $label;
131
+ }
132
 
133
  /**
134
  * @param string $title
143
  $product_id = $values['variation_id'] ? $values['variation_id'] : $values['product_id'];
144
 
145
  $translated_product_id = apply_filters( 'translate_object_id', $product_id, 'product', true );
146
+ $translated_title = get_the_title( $translated_product_id );
147
 
148
  if ( strstr( $title, '</a>' ) ) {
149
  $title = sprintf( '<a href="%s">%s</a>', $values['data']->get_permalink(), $translated_title );
155
  return $title;
156
  }
157
 
158
+ function translated_checkout_product_title( $title, $product ) {
159
 
160
+ if ( $product ) {
161
+ $tr_product_id = apply_filters( 'translate_object_id', WooCommerce_Functions_Wrapper::get_product_id( $product ), 'product', true, $this->current_language );
162
+ $title = get_the_title( $tr_product_id );
163
+ }
164
 
165
+ return $title;
166
+ }
167
 
168
+ // Catch the default slugs for translation
169
+ function translate_default_slug( $translation, $text, $context, $domain ) {
170
 
171
+ if ( $context == 'slug' || $context == 'default-slug' ) {
172
+ $wc_slug = $this->woocommerce_wpml->url_translation->get_woocommerce_product_base();
173
+ if ( is_admin() ) {
174
+ $admin_language = $this->sitepress->get_admin_language();
175
+ }
176
+ $current_language = $this->sitepress->get_current_language();
 
 
177
 
178
+ $strings_language = $this->get_domain_language( 'woocommerce' );
 
 
 
 
 
 
 
 
 
179
 
180
+ if ( $text == $wc_slug && $domain == 'woocommerce' && $strings_language ) {
181
+ $this->sitepress->switch_lang( $strings_language );
182
+ $translation = _x( $text, 'URL slug', $domain );
183
+ $this->sitepress->switch_lang( $current_language );
184
+ if ( is_admin() ) {
185
+ $this->sitepress->set_admin_language( $admin_language );
186
+ }
187
+ } else {
188
+ $translation = $text;
189
+ }
190
 
191
+ if ( ! is_admin() ) {
192
+ $this->sitepress->switch_lang( $current_language );
193
+ }
194
+ }
195
 
196
+ return $translation;
197
 
198
+ }
199
 
200
 
201
+ function show_custom_url_base_language_requirement() {
202
+ $category_base = ( $c = get_option( 'category_base' ) ) ? $c : 'category';
203
+ ?>
204
  <script>
205
+ if (jQuery('#woocommerce_permalink_structure').length) {
206
  jQuery('#woocommerce_permalink_structure').parent().append(jQuery('#wpml_wcml_custom_base_req').html());
207
  }
208
+ if (jQuery('input[name="woocommerce_product_category_slug"]').length && jQuery('input[name="woocommerce_product_category_slug"]').val() == '<?php echo $category_base ?>') {
209
  jQuery('input[name="woocommerce_product_category_slug"]').parent().append('<br><i class="icon-warning-sign"><?php
210
+ _e( 'You are using the same value as for the regular category base. This is known to create conflicts resulting in urls not working properly.', 'woocommerce-multilingual' ) ?></i>');
211
  }
212
  </script>
213
+ <?php
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
214
 
215
+ }
216
+
217
+ function show_custom_url_base_translation_links() {
218
+
219
+ $permalink_options = get_option( 'woocommerce_permalinks' );
220
+
221
+ $lang_selector = new WPML_Simple_Language_Selector( $this->sitepress );
222
+
223
+ $bases = array(
224
+ 'tag_base' => 'product_tag',
225
+ 'category_base' => 'product_cat',
226
+ 'attribute_base' => 'attribute',
227
+ 'product_base' => 'product'
228
+ );
229
+
230
+ foreach ( $bases as $key => $base ) {
231
+
232
+ switch ( $base ) {
233
+ case 'product_tag':
234
+ $input_name = 'woocommerce_product_tag_slug';
235
+ $value = ! empty( $permalink_options['tag_base'] ) ? $permalink_options['tag_base'] : $this->woocommerce_wpml->url_translation->default_product_tag_base;
236
+ break;
237
+ case 'product_cat':
238
+ $input_name = 'woocommerce_product_category_slug';
239
+ $value = ! empty( $permalink_options['category_base'] ) ? $permalink_options['category_base'] : $this->woocommerce_wpml->url_translation->default_product_category_base;
240
+ break;
241
+ case 'attribute':
242
+ $input_name = 'woocommerce_product_attribute_slug';
243
+ $value = ! empty( $permalink_options['attribute_base'] ) ? $permalink_options['attribute_base'] : '';
244
+ break;
245
+ case 'product':
246
+ $input_name = 'product_permalink_structure';
247
+ if ( empty( $permalink_options['product_base'] ) ) {
248
+ $value = _x( 'product', 'default-slug', 'woocommerce' );
249
+ } else {
250
+ $value = trim( $permalink_options['product_base'], '/' );
251
+ }
252
+
253
+ break;
254
+ }
255
 
256
+ $language = $this->get_string_language( trim( $value, '/' ), $this->woocommerce_wpml->url_translation->url_strings_context(), $this->woocommerce_wpml->url_translation->url_string_name( $base ) );
257
 
258
+ if ( is_null( $language ) ) {
259
+ $language = $this->sitepress->get_default_language();
260
+ }
261
 
262
+ echo $lang_selector->render( array(
263
+ 'id' => $key . '_language_selector',
264
+ 'name' => $key . '_language',
265
+ 'selected' => $language,
266
+ 'show_please_select' => false
267
+ ) ); ?>
268
 
269
  <script>
270
  var input = jQuery('input[name="<?php echo $input_name ?>"]');
271
 
272
+ if (input.length) {
273
 
274
+ if ('<?php echo $input_name ?>' == 'product_permalink_structure' && jQuery('input[name="product_permalink"]:checked').val() == '') {
275
  input = jQuery('input[name="product_permalink"]:checked').closest('.form-table').find('code').eq(0);
276
  }
277
 
278
  input.parent().append('<div class="translation_controls"></div>');
279
 
280
+ if ('<?php echo $input_name ?>' == 'woocommerce_product_attribute_slug' && input.val() == '') {
281
 
282
  input.parent().find('.translation_controls').append('&nbsp;');
283
 
284
+ } else {
285
  input.parent().find('.translation_controls').append('<a href="<?php
286
+ echo admin_url( 'admin.php?page=wpml-wcml&tab=slugs' )
287
+ ?>"><?php _e( 'translations', 'woocommerce-multilingual' ) ?></a>');
288
  }
289
 
290
+ jQuery('#<?php echo $key ?>_language_selector').prependTo(input.parent().find('.translation_controls'));
291
  }
292
  </script>
293
+ <?php }
294
 
295
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
296
 
297
+ function category_base_in_strings_language( $text, $original_value, $context ) {
298
+ if ( $context == 'slug' && ( $original_value == 'product-category' || $original_value == 'product-tag' ) ) {
299
+ $text = $original_value;
300
+ }
301
 
302
+ return $text;
303
+ }
304
 
305
+ function product_permalink_slug() {
306
+ $permalinks = get_option( 'woocommerce_permalinks' );
307
+ $slug = empty( $permalinks['product_base'] ) ? 'product' : trim( $permalinks['product_base'], '/' );
 
 
308
 
309
+ return $slug;
310
+ }
311
 
312
+ function get_domain_language( $domain ) {
 
313
 
314
+ $lang_of_domain = new WPML_Language_Of_Domain( $this->sitepress );
315
+ $domain_lang = $lang_of_domain->get_language( $domain );
316
 
317
+ if ( $domain_lang ) {
318
+ $source_lang = $domain_lang;
319
+ } else {
320
+ $source_lang = 'en';
321
+ }
322
 
323
+ return $source_lang;
324
+ }
325
 
326
+ function get_string_language( $value, $context, $name = false ) {
327
+ global $wpdb;
328
 
329
+ if ( $name !== false ) {
 
 
330
 
331
+ $string_language = apply_filters( 'wpml_get_string_language', null, $context, $name );
 
332
 
333
+ } else {
334
 
335
+ $string_id = icl_get_string_id( $value, $context, $name );
 
 
336
 
337
+ if ( ! $string_id ) {
338
+ return 'en';
339
+ }
340
 
341
+ $string_object = new WPML_ST_String( $string_id, $wpdb );
342
+ $string_language = $string_object->get_language();
343
 
344
+ }
 
345
 
346
+ if ( ! $string_language ) {
347
+ return 'en';
348
+ }
349
 
350
+ return $string_language;
 
351
 
352
+ }
 
353
 
354
+ function set_string_language( $value, $context, $name, $language ) {
355
+ global $wpdb;
356
 
357
+ $string_id = icl_get_string_id( $value, $context, $name );
 
 
 
 
358
 
359
+ $string_object = new WPML_ST_String( $string_id, $wpdb );
360
+ $string_language = $string_object->set_language( $language );
361
 
362
+ return $string_language;
363
+ }
364
 
 
365
 
366
+ /*
367
+ * Filter breadcrumbs
368
+ *
369
+ */
370
+ function filter_woocommerce_breadcrumbs( $breadcrumbs, $object ) {
371
 
372
+ $current_language = $this->sitepress->get_current_language();
373
+ $default_language = $this->sitepress->get_default_language();
374
 
375
+ $woocommerce_shop_page = wc_get_page_id( 'shop' );
376
 
377
+ if ( isset( $woocommerce_shop_page ) ) {
 
 
 
 
 
378
 
379
+ $is_shop_page_active = get_post_status( $woocommerce_shop_page );
 
 
 
380
 
381
+ if ( ( $current_language != $default_language || $default_language != 'en' ) && $is_shop_page_active === 'publish' ) {
 
 
 
 
 
 
 
382
 
383
+ $shop_page = get_post( $woocommerce_shop_page );
 
 
 
 
384
 
385
+ // If permalinks contain the shop page in the URI prepend the breadcrumb with shop
386
+ // Similar to WC_Breadcrumb::prepend_shop_page
387
+ $trnsl_base = $this->woocommerce_wpml->url_translation->get_base_translation( 'product', $current_language );
388
+ if ( $trnsl_base['translated_base'] === '' ) {
389
+ $trnsl_base['translated_base'] = $trnsl_base['original_value'];
390
+ }
391
 
392
+ if ( is_woocommerce() && $shop_page->ID && strstr( $trnsl_base['translated_base'], urldecode( $shop_page->post_name ) ) && get_option( 'page_on_front' ) != $shop_page->ID ) {
393
+ $breadcrumbs_buff = array();
394
+ $i = 0;
395
+ foreach ( $breadcrumbs as $key => $breadcrumb ) {
396
+
397
+ //Prepend the shop page to shop breadcrumbs
398
+ if ( $key === 0 && $breadcrumbs[1][1] != get_post_type_archive_link( 'product' ) ) {
399
+ $breadcrumbs_buff[ $i ] = array(
400
+ $shop_page->post_title,
401
+ get_post_type_archive_link( 'product' )
402
+ );
403
+ $i ++;
404
+ }
405
+
406
+ if ( ! in_array( $breadcrumb, $breadcrumbs_buff ) ) {
407
+ $breadcrumbs_buff[ $i ] = $breadcrumb;
408
+ }
409
+ $i ++;
410
+ }
411
+
412
+ $breadcrumbs = $breadcrumbs_buff;
413
+
414
+ $breadcrumbs = array_values( $breadcrumbs );
415
+ }
416
 
417
+ }
418
+ }
419
 
420
+ return $breadcrumbs;
421
+ }
422
 
423
+ /*
424
+ * Add notice message to users
425
+ */
426
+ function notice_after_woocommerce_product_options_attributes() {
427
 
428
+ if ( isset( $_GET['post'] ) && $this->sitepress->get_default_language() != $this->sitepress->get_current_language() ) {
429
+ $original_product_id = apply_filters( 'translate_object_id', $_GET['post'], 'product', true, $this->sitepress->get_default_language() );
430
 
431
+ printf( '<p>' . __( 'In order to edit custom attributes you need to use the <a href="%s">custom product translation editor</a>', 'woocommerce-multilingual' ) . '</p>', admin_url( 'admin.php?page=wpml-wcml&tab=products&prid=' . $original_product_id ) );
432
+ }
433
+ }
434
 
435
  function translate_attribute_taxonomies_labels( $attribute_taxonomies ) {
436
 
437
+ foreach ( $attribute_taxonomies as $key => $attribute_taxonomy ) {
438
+ $string_language = $this->get_string_language( $attribute_taxonomy->attribute_label, 'WordPress', 'taxonomy singular name: ' . $attribute_taxonomy->attribute_label );
439
 
440
+ if ( $this->sitepress->get_current_language() == $string_language ) {
441
+ continue;
442
+ }
443
 
444
+ $string_id = icl_get_string_id( $attribute_taxonomy->attribute_label, 'WordPress', 'taxonomy singular name: ' . $attribute_taxonomy->attribute_label );
445
+ $strings = icl_get_string_translations_by_id( $string_id );
 
446
 
447
+ if ( $strings && isset( $strings[ $this->sitepress->get_current_language() ] ) ) {
448
+ $attribute_taxonomies[ $key ]->attribute_label = $strings[ $this->sitepress->get_current_language() ]['value'];
 
 
 
 
449
  }
 
450
  }
451
 
452
  return $attribute_taxonomies;
453
  }
454
 
455
+ function get_translation_from_woocommerce_mo_file( $string, $language, $return_original = true ) {
456
 
457
+ $original_string = $string;
458
 
459
+ if ( ! isset( $this->translations_from_mo_file[ $original_string ][ $language ] ) ) {
460
 
461
+ if ( ! isset( $this->translations_from_mo_file[ $original_string ] ) ) {
462
+ $this->translations_from_mo_file[ $original_string ] = array();
463
+ }
464
 
465
+ if ( ! isset( $this->mo_files[ $language ] ) ) {
466
+ $mo = new MO();
467
+ $mo_file = WP_LANG_DIR . '/plugins/woocommerce-' . $this->sitepress->get_locale( $language ) . '.mo';
468
+ if ( ! file_exists( $mo_file ) ) {
469
+ return $return_original ? $string : null;
470
+ }
471
 
472
+ $mo->import_from_file( $mo_file );
473
+ $this->mo_files[ $language ] = &$mo->entries;
474
+ }
475
 
476
+ if ( in_array( $string, array( 'product', 'product-category', 'product-tag' ) ) ) {
477
+ $string = 'slug' . chr( 4 ) . $string;
478
+ }
479
 
480
+ if ( isset( $this->mo_files[ $language ][ $string ] ) ) {
481
+ $this->translations_from_mo_file[ $original_string ][ $language ] = $this->mo_files[ $language ][ $string ]->translations[0];
482
+ } else {
483
+ $this->translations_from_mo_file[ $original_string ][ $language ] = $return_original ? $original_string : null;
484
+ }
485
+ }
486
 
487
+ return $this->translations_from_mo_file[ $original_string ][ $language ];
488
 
489
+ }
490
 
491
+ function translate_attributes_label_in_wp_taxonomies( $taxonomy, $obj_type, $args ) {
492
+ global $wp_taxonomies;
493
+ $obj_type = array_unique( (array) $obj_type );
494
 
495
+ $current_language = $this->sitepress->get_current_language();
496
 
497
+ if ( $current_language != 'all' && in_array( 'product', $obj_type ) && substr( $taxonomy, 0, 3 ) == 'pa_' && isset( $wp_taxonomies[ $taxonomy ] ) ) {
498
 
499
+ if ( is_array( $args['labels'] ) ) {
500
+ $name = $args['labels']['singular_name'];
501
+ } else {
502
+ $name = $args['labels']->name;
503
+ }
504
 
505
+ $wp_taxonomies[ $taxonomy ]->labels->name = apply_filters( 'wpml_translate_single_string', $name, 'WordPress', 'taxonomy singular name: ' . $name, $current_language );
506
 
507
 
508
+ }
509
 
510
+ }
511
 
512
  }
inc/currencies/class-wcml-multi-currency-orders.php CHANGED
@@ -376,7 +376,9 @@ class WCML_Multi_Currency_Orders {
376
  }
377
  $currency = filter_input( INPUT_POST, 'currency', FILTER_SANITIZE_FULL_SPECIAL_CHARS );
378
 
379
- setcookie( '_wcml_order_currency', $currency, time() + 86400, COOKIEPATH, COOKIE_DOMAIN );
 
 
380
 
381
  $return['currency'] = $currency;
382
 
@@ -463,4 +465,4 @@ class WCML_Multi_Currency_Orders {
463
  return $value;
464
  }
465
 
466
- }
376
  }
377
  $currency = filter_input( INPUT_POST, 'currency', FILTER_SANITIZE_FULL_SPECIAL_CHARS );
378
 
379
+ $cookie_name = '_wcml_order_currency';
380
+ do_action( 'wpsc_add_cookie', $cookie_name );
381
+ setcookie( $cookie_name, $currency, time() + 86400, COOKIEPATH, COOKIE_DOMAIN );
382
 
383
  $return['currency'] = $currency;
384
 
465
  return $value;
466
  }
467
 
468
+ }
inc/currencies/class-wcml-multi-currency-reports.php CHANGED
@@ -145,7 +145,9 @@ class WCML_Multi_Currency_Reports {
145
  die();
146
  }
147
 
148
- setcookie( '_wcml_reports_currency', filter_input( INPUT_POST, 'currency', FILTER_SANITIZE_FULL_SPECIAL_CHARS ),
 
 
149
  time() + 86400, COOKIEPATH, COOKIE_DOMAIN );
150
 
151
  exit;
@@ -223,4 +225,4 @@ class WCML_Multi_Currency_Reports {
223
  return $orders_ids;
224
  }
225
 
226
- }
145
  die();
146
  }
147
 
148
+ $cookie_name = '_wcml_reports_currency';
149
+ do_action( 'wpsc_add_cookie', $cookie_name );
150
+ setcookie( $cookie_name, filter_input( INPUT_POST, 'currency', FILTER_SANITIZE_FULL_SPECIAL_CHARS ),
151
  time() + 86400, COOKIEPATH, COOKIE_DOMAIN );
152
 
153
  exit;
225
  return $orders_ids;
226
  }
227
 
228
+ }
inc/currencies/class-wcml-multi-currency.php CHANGED
@@ -367,7 +367,10 @@ class WCML_Multi_Currency{
367
  global $woocommerce, $sitepress, $wpdb;
368
 
369
  $WCML_REST_API = new WCML_REST_API();
370
- if( $WCML_REST_API->is_rest_api_request() ){
 
 
 
371
  return get_option('woocommerce_currency');
372
  }
373
 
367
  global $woocommerce, $sitepress, $wpdb;
368
 
369
  $WCML_REST_API = new WCML_REST_API();
370
+ if(
371
+ $WCML_REST_API->is_rest_api_request() ||
372
+ ! empty( $_REQUEST['woocommerce_quick_edit'] )
373
+ ){
374
  return get_option('woocommerce_currency');
375
  }
376
 
inc/template-classes/multi-currency/class-wcml-custom-prices-ui.php CHANGED
@@ -32,7 +32,7 @@ class WCML_Custom_Prices_UI extends WPML_Templates_Factory {
32
  'is_variation' => $this->is_variation,
33
  'html_id' => $this->is_variation ? '['.$this->product_id.']' : '',
34
  'strings' => apply_filters( 'wcml_custom_prices_strings', array(
35
- 'not_set' => sprintf( __( 'Multi-currency is enabled but no secondary currencies have been set. %sAdd secondary currencies%s.',
36
  'woocommerce-multilingual' ), '<a href="' . admin_url('admin.php?page=wpml-wcml&tab=multi-currency') . '">', '</a>' ),
37
  'calc_auto' => __( 'Calculate prices in other currencies automatically', 'woocommerce-multilingual' ),
38
  'see_prices' => __( 'Click to see the prices in the other currencies as they are currently shown on the front end.', 'woocommerce-multilingual' ),
32
  'is_variation' => $this->is_variation,
33
  'html_id' => $this->is_variation ? '['.$this->product_id.']' : '',
34
  'strings' => apply_filters( 'wcml_custom_prices_strings', array(
35
+ 'not_set' => sprintf( __( 'Multi-currency is enabled, but no secondary currencies have been set. %sAdd secondary currency%s.',
36
  'woocommerce-multilingual' ), '<a href="' . admin_url('admin.php?page=wpml-wcml&tab=multi-currency') . '">', '</a>' ),
37
  'calc_auto' => __( 'Calculate prices in other currencies automatically', 'woocommerce-multilingual' ),
38
  'see_prices' => __( 'Click to see the prices in the other currencies as they are currently shown on the front end.', 'woocommerce-multilingual' ),
inc/translation-editor/class-wcml-editor-ui-product-job.php CHANGED
@@ -144,7 +144,7 @@ class WCML_Editor_UI_Product_Job extends WPML_Editor_UI_Job {
144
  $group = new WPML_Editor_UI_Field_Group( '', true );
145
  $attribute_field = new WPML_Editor_UI_Single_Line_Field( $attr_key . '_name', __( 'Name', 'woocommerce-multilingual' ), $this->data, false );
146
  $group->add_field( $attribute_field );
147
- $attribute_field = new WPML_Editor_UI_Single_Line_Field( $attr_key , __( 'Value(s)', 'woocommerce-multilingual' ), $this->data, false );
148
  $group->add_field( $attribute_field );
149
  $attributes_section->add_field( $group );
150
  }
144
  $group = new WPML_Editor_UI_Field_Group( '', true );
145
  $attribute_field = new WPML_Editor_UI_Single_Line_Field( $attr_key . '_name', __( 'Name', 'woocommerce-multilingual' ), $this->data, false );
146
  $group->add_field( $attribute_field );
147
+ $attribute_field = new WPML_Editor_UI_TextArea_Field( $attr_key , __( 'Value(s)', 'woocommerce-multilingual' ), $this->data, false );
148
  $group->add_field( $attribute_field );
149
  $attributes_section->add_field( $group );
150
  }
inc/translation-editor/class-wcml-synchronize-product-data.php CHANGED
@@ -376,22 +376,18 @@ class WCML_Synchronize_Product_Data{
376
  }
377
  }
378
 
379
- public function sync_stock_status_for_translations( $id, $status ){
380
 
381
- if( $this->woocommerce_wpml->products->is_original_product( $id ) ){
382
- $type = get_post_type( $id );
383
- $trid = $this->sitepress->get_element_trid( $id, 'post_'.$type );
384
- $translations = $this->sitepress->get_element_translations( $trid, 'post_'.$type, true);
385
-
386
- foreach ( $translations as $translation ) {
387
- if ( !$translation->original ) {
388
- update_post_meta( $translation->element_id, '_stock_status', $status );
389
-
390
- $this->wc_taxonomies_recount_after_stock_change( (int)$translation->element_id );
391
- }
392
- }
393
- }
394
 
 
 
 
 
 
 
395
  }
396
 
397
  /**
376
  }
377
  }
378
 
379
+ public function sync_stock_status_for_translations( $id, $status ) {
380
 
381
+ $type = get_post_type( $id );
382
+ $trid = $this->sitepress->get_element_trid( $id, 'post_' . $type );
383
+ $translations = $this->sitepress->get_element_translations( $trid, 'post_' . $type, true );
 
 
 
 
 
 
 
 
 
 
384
 
385
+ foreach ( $translations as $translation ) {
386
+ if ( $id !== (int) $translation->element_id ) {
387
+ update_post_meta( $translation->element_id, '_stock_status', $status );
388
+ $this->wc_taxonomies_recount_after_stock_change( (int) $translation->element_id );
389
+ }
390
+ }
391
  }
392
 
393
  /**
inc/translation-editor/class-wcml-synchronize-variations-data.php CHANGED
@@ -158,7 +158,7 @@ class WCML_Synchronize_Variations_Data{
158
  }
159
 
160
  //sync media
161
- $this->woocommerce_wpml->media->sync_thumbnail_id( $original_variation_id, $variation_id, $lang );
162
 
163
  //sync file_paths
164
  $this->woocommerce_wpml->downloadable->sync_files_to_translations( $original_variation_id, $variation_id, $data );
158
  }
159
 
160
  //sync media
161
+ $this->woocommerce_wpml->media->sync_variation_thumbnail_id( $original_variation_id, $variation_id, $lang );
162
 
163
  //sync file_paths
164
  $this->woocommerce_wpml->downloadable->sync_files_to_translations( $original_variation_id, $variation_id, $data );
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.9
7
  Tested up to: 4.9.8
8
- Stable tag: 4.3.4
9
 
10
  Allows running fully multilingual e-commerce sites using WooCommerce and WPML.
11
 
@@ -140,10 +140,27 @@ WooCommerce Multilingual is compatible with all major WooCommerce extensions. We
140
 
141
  == Changelog ==
142
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
143
  = 4.3.4 =
144
  * Fixed error: Cannot redeclare woocommerce_wp_text_input
145
  * Fixed error when creating booking from admin without creating order
146
  * Fixed Woocommerce Dynamic Price issue with Advanced category price in second language
 
147
  * Fix situation with filtering WC attributes calling by sku
148
  * Fix a problem that you cannot delete booking from trash
149
  * Fix prevent letters in multicurrency popup for number of decimals
5
  License: GPLv2
6
  Requires at least: 3.9
7
  Tested up to: 4.9.8
8
+ Stable tag: 4.3.5
9
 
10
  Allows running fully multilingual e-commerce sites using WooCommerce and WPML.
11
 
140
 
141
  == Changelog ==
142
 
143
+ = 4.3.5 =
144
+ * Fix rest translation in products creation
145
+ * Fixed incorrect translation matched for Table Rate Shipping title
146
+ * Price is not saved correctly via "Quick Edit" if secondary currency is selected on front
147
+ * Fixed a performance issue when a product has a lot of variations.
148
+ * Fixed variation image synchronization
149
+ * Lower priority of 'woocommerce_cart_item_name' hook for "WooCommerce Product Subtitle" and others to work
150
+ * Fixed performance issues on product listing page with big amount of attributes
151
+ * Fixed fatal error with WPML older than 3.9
152
+ * Fix redirection to wcml dashboard in a specific case if you skip wizard
153
+ * Fixed stock status when purchasing the last product in the second language which does not update status for original
154
+ * WooCommerce Product Bundle synchronizations problems when re-creating bundle product translation
155
+ * Fixed Woo Variations Table Compatibility issue with overwritten product title in specific scenario
156
+ * Fix cosmetic issue with mutli-currency message in product post screen
157
+ * Fixed infinite loop with large product numbers and languages
158
+
159
  = 4.3.4 =
160
  * Fixed error: Cannot redeclare woocommerce_wp_text_input
161
  * Fixed error when creating booking from admin without creating order
162
  * Fixed Woocommerce Dynamic Price issue with Advanced category price in second language
163
+ * Fixed attachments duplication when synchronizing gallery
164
  * Fix situation with filtering WC attributes calling by sku
165
  * Fix a problem that you cannot delete booking from trash
166
  * Fix prevent letters in multicurrency popup for number of decimals
templates/multi-currency/custom-prices.twig CHANGED
@@ -4,7 +4,7 @@
4
 
5
  <div class="wcml_custom_prices_block">
6
  {% if currencies is empty %}
7
- <div class="custom_prices_message_block">
8
  <label>{{ strings.not_set|raw }}</label>
9
  </div>
10
  {% else %}
4
 
5
  <div class="wcml_custom_prices_block">
6
  {% if currencies is empty %}
7
+ <div class="wcml_custom_prices_options_block">
8
  <label>{{ strings.not_set|raw }}</label>
9
  </div>
10
  {% else %}
vendor/autoload.php CHANGED
@@ -4,4 +4,4 @@
4
 
5
  require_once __DIR__ . '/composer/autoload_real.php';
6
 
7
- return ComposerAutoloaderInit0e676152496e9f3b9d6510bdcac1d959::getLoader();
4
 
5
  require_once __DIR__ . '/composer/autoload_real.php';
6
 
7
+ return ComposerAutoloaderInit18f380b175f44489fa989a88f4b96581::getLoader();
vendor/autoload_52.php CHANGED
@@ -4,4 +4,4 @@
4
 
5
  require_once dirname(__FILE__) . '/composer'.'/autoload_real_52.php';
6
 
7
- return ComposerAutoloaderInit0feb850f3953f143979d624e1bc6bbfe::getLoader();
4
 
5
  require_once dirname(__FILE__) . '/composer'.'/autoload_real_52.php';
6
 
7
+ return ComposerAutoloaderInit480afeedc41ce5c618a5bb967ae90a4e::getLoader();
vendor/composer/autoload_classmap.php CHANGED
@@ -469,6 +469,7 @@ return array(
469
  'WCML_WPSEO' => $baseDir . '/compatibility/class-wcml-wpseo.php',
470
  'WCML_Widgets' => $baseDir . '/inc/class-wcml-widgets.php',
471
  'WCML_WooCommerce_Rest_API_Support' => $baseDir . '/inc/class-wcml-woocommerce-rest-api-support.php',
 
472
  'WCML_Wpb_Vc' => $baseDir . '/compatibility/class-wcml-wpb-vc.php',
473
  'WCML_YITH_WCQV' => $baseDir . '/compatibility/class-wcml-yith-wcqv.php',
474
  'WCML_gravityforms' => $baseDir . '/compatibility/class-wcml-gravityforms.php',
469
  'WCML_WPSEO' => $baseDir . '/compatibility/class-wcml-wpseo.php',
470
  'WCML_Widgets' => $baseDir . '/inc/class-wcml-widgets.php',
471
  'WCML_WooCommerce_Rest_API_Support' => $baseDir . '/inc/class-wcml-woocommerce-rest-api-support.php',
472
+ 'WCML_Woo_Var_Table' => $baseDir . '/compatibility/class-wcml-woo-var-table.php',
473
  'WCML_Wpb_Vc' => $baseDir . '/compatibility/class-wcml-wpb-vc.php',
474
  'WCML_YITH_WCQV' => $baseDir . '/compatibility/class-wcml-yith-wcqv.php',
475
  'WCML_gravityforms' => $baseDir . '/compatibility/class-wcml-gravityforms.php',
vendor/composer/autoload_real.php CHANGED
@@ -2,7 +2,7 @@
2
 
3
  // autoload_real.php @generated by Composer
4
 
5
- class ComposerAutoloaderInit0e676152496e9f3b9d6510bdcac1d959
6
  {
7
  private static $loader;
8
 
@@ -19,15 +19,15 @@ class ComposerAutoloaderInit0e676152496e9f3b9d6510bdcac1d959
19
  return self::$loader;
20
  }
21
 
22
- spl_autoload_register(array('ComposerAutoloaderInit0e676152496e9f3b9d6510bdcac1d959', 'loadClassLoader'), true, true);
23
  self::$loader = $loader = new \Composer\Autoload\ClassLoader();
24
- spl_autoload_unregister(array('ComposerAutoloaderInit0e676152496e9f3b9d6510bdcac1d959', 'loadClassLoader'));
25
 
26
  $useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded());
27
  if ($useStaticLoader) {
28
  require_once __DIR__ . '/autoload_static.php';
29
 
30
- call_user_func(\Composer\Autoload\ComposerStaticInit0e676152496e9f3b9d6510bdcac1d959::getInitializer($loader));
31
  } else {
32
  $map = require __DIR__ . '/autoload_namespaces.php';
33
  foreach ($map as $namespace => $path) {
2
 
3
  // autoload_real.php @generated by Composer
4
 
5
+ class ComposerAutoloaderInit18f380b175f44489fa989a88f4b96581
6
  {
7
  private static $loader;
8
 
19
  return self::$loader;
20
  }
21
 
22
+ spl_autoload_register(array('ComposerAutoloaderInit18f380b175f44489fa989a88f4b96581', 'loadClassLoader'), true, true);
23
  self::$loader = $loader = new \Composer\Autoload\ClassLoader();
24
+ spl_autoload_unregister(array('ComposerAutoloaderInit18f380b175f44489fa989a88f4b96581', 'loadClassLoader'));
25
 
26
  $useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded());
27
  if ($useStaticLoader) {
28
  require_once __DIR__ . '/autoload_static.php';
29
 
30
+ call_user_func(\Composer\Autoload\ComposerStaticInit18f380b175f44489fa989a88f4b96581::getInitializer($loader));
31
  } else {
32
  $map = require __DIR__ . '/autoload_namespaces.php';
33
  foreach ($map as $namespace => $path) {
vendor/composer/autoload_real_52.php CHANGED
@@ -2,7 +2,7 @@
2
 
3
  // autoload_real_52.php generated by xrstf/composer-php52
4
 
5
- class ComposerAutoloaderInit0feb850f3953f143979d624e1bc6bbfe {
6
  private static $loader;
7
 
8
  public static function loadClassLoader($class) {
@@ -19,9 +19,9 @@ class ComposerAutoloaderInit0feb850f3953f143979d624e1bc6bbfe {
19
  return self::$loader;
20
  }
21
 
22
- spl_autoload_register(array('ComposerAutoloaderInit0feb850f3953f143979d624e1bc6bbfe', 'loadClassLoader'), true /*, true */);
23
  self::$loader = $loader = new xrstf_Composer52_ClassLoader();
24
- spl_autoload_unregister(array('ComposerAutoloaderInit0feb850f3953f143979d624e1bc6bbfe', 'loadClassLoader'));
25
 
26
  $vendorDir = dirname(dirname(__FILE__));
27
  $baseDir = dirname($vendorDir);
2
 
3
  // autoload_real_52.php generated by xrstf/composer-php52
4
 
5
+ class ComposerAutoloaderInit480afeedc41ce5c618a5bb967ae90a4e {
6
  private static $loader;
7
 
8
  public static function loadClassLoader($class) {
19
  return self::$loader;
20
  }
21
 
22
+ spl_autoload_register(array('ComposerAutoloaderInit480afeedc41ce5c618a5bb967ae90a4e', 'loadClassLoader'), true /*, true */);
23
  self::$loader = $loader = new xrstf_Composer52_ClassLoader();
24
+ spl_autoload_unregister(array('ComposerAutoloaderInit480afeedc41ce5c618a5bb967ae90a4e', 'loadClassLoader'));
25
 
26
  $vendorDir = dirname(dirname(__FILE__));
27
  $baseDir = dirname($vendorDir);
vendor/composer/autoload_static.php CHANGED
@@ -4,7 +4,7 @@
4
 
5
  namespace Composer\Autoload;
6
 
7
- class ComposerStaticInit0e676152496e9f3b9d6510bdcac1d959
8
  {
9
  public static $prefixLengthsPsr4 = array (
10
  'C' =>
@@ -501,6 +501,7 @@ class ComposerStaticInit0e676152496e9f3b9d6510bdcac1d959
501
  'WCML_WPSEO' => __DIR__ . '/../..' . '/compatibility/class-wcml-wpseo.php',
502
  'WCML_Widgets' => __DIR__ . '/../..' . '/inc/class-wcml-widgets.php',
503
  'WCML_WooCommerce_Rest_API_Support' => __DIR__ . '/../..' . '/inc/class-wcml-woocommerce-rest-api-support.php',
 
504
  'WCML_Wpb_Vc' => __DIR__ . '/../..' . '/compatibility/class-wcml-wpb-vc.php',
505
  'WCML_YITH_WCQV' => __DIR__ . '/../..' . '/compatibility/class-wcml-yith-wcqv.php',
506
  'WCML_gravityforms' => __DIR__ . '/../..' . '/compatibility/class-wcml-gravityforms.php',
@@ -515,10 +516,10 @@ class ComposerStaticInit0e676152496e9f3b9d6510bdcac1d959
515
  public static function getInitializer(ClassLoader $loader)
516
  {
517
  return \Closure::bind(function () use ($loader) {
518
- $loader->prefixLengthsPsr4 = ComposerStaticInit0e676152496e9f3b9d6510bdcac1d959::$prefixLengthsPsr4;
519
- $loader->prefixDirsPsr4 = ComposerStaticInit0e676152496e9f3b9d6510bdcac1d959::$prefixDirsPsr4;
520
- $loader->prefixesPsr0 = ComposerStaticInit0e676152496e9f3b9d6510bdcac1d959::$prefixesPsr0;
521
- $loader->classMap = ComposerStaticInit0e676152496e9f3b9d6510bdcac1d959::$classMap;
522
 
523
  }, null, ClassLoader::class);
524
  }
4
 
5
  namespace Composer\Autoload;
6
 
7
+ class ComposerStaticInit18f380b175f44489fa989a88f4b96581
8
  {
9
  public static $prefixLengthsPsr4 = array (
10
  'C' =>
501
  'WCML_WPSEO' => __DIR__ . '/../..' . '/compatibility/class-wcml-wpseo.php',
502
  'WCML_Widgets' => __DIR__ . '/../..' . '/inc/class-wcml-widgets.php',
503
  'WCML_WooCommerce_Rest_API_Support' => __DIR__ . '/../..' . '/inc/class-wcml-woocommerce-rest-api-support.php',
504
+ 'WCML_Woo_Var_Table' => __DIR__ . '/../..' . '/compatibility/class-wcml-woo-var-table.php',
505
  'WCML_Wpb_Vc' => __DIR__ . '/../..' . '/compatibility/class-wcml-wpb-vc.php',
506
  'WCML_YITH_WCQV' => __DIR__ . '/../..' . '/compatibility/class-wcml-yith-wcqv.php',
507
  'WCML_gravityforms' => __DIR__ . '/../..' . '/compatibility/class-wcml-gravityforms.php',
516
  public static function getInitializer(ClassLoader $loader)
517
  {
518
  return \Closure::bind(function () use ($loader) {
519
+ $loader->prefixLengthsPsr4 = ComposerStaticInit18f380b175f44489fa989a88f4b96581::$prefixLengthsPsr4;
520
+ $loader->prefixDirsPsr4 = ComposerStaticInit18f380b175f44489fa989a88f4b96581::$prefixDirsPsr4;
521
+ $loader->prefixesPsr0 = ComposerStaticInit18f380b175f44489fa989a88f4b96581::$prefixesPsr0;
522
+ $loader->classMap = ComposerStaticInit18f380b175f44489fa989a88f4b96581::$classMap;
523
 
524
  }, null, ClassLoader::class);
525
  }
wpml-woocommerce.php CHANGED
@@ -8,7 +8,7 @@
8
  Text Domain: woocommerce-multilingual
9
  Requires at least: 3.9
10
  Tested up to: 4.9.8
11
- Version: 4.3.4
12
  WC requires at least: 2.1.0
13
  WC tested up to: 3.4.4
14
  */
@@ -17,7 +17,7 @@ if ( defined( 'WCML_VERSION' ) ) {
17
  return;
18
  }
19
 
20
- define( 'WCML_VERSION', '4.3.4' );
21
  define( 'WCML_PLUGIN_PATH', dirname( __FILE__ ) );
22
  define( 'WCML_PLUGIN_FOLDER', basename( WCML_PLUGIN_PATH ) );
23
  define( 'WCML_LOCALE_PATH', WCML_PLUGIN_PATH . '/locale' );
@@ -78,8 +78,10 @@ function wcml_loader(){
78
  $loaders[] = 'WCML_Append_Gallery_To_Post_Media_Ids_Factory';
79
  }
80
 
81
- $action_filter_loader = new WPML_Action_Filter_Loader();
82
- $action_filter_loader->load( $loaders );
 
 
83
  }
84
 
85
  $WCML_REST_API = new WCML_REST_API();
8
  Text Domain: woocommerce-multilingual
9
  Requires at least: 3.9
10
  Tested up to: 4.9.8
11
+ Version: 4.3.5
12
  WC requires at least: 2.1.0
13
  WC tested up to: 3.4.4
14
  */
17
  return;
18
  }
19
 
20
+ define( 'WCML_VERSION', '4.3.5' );
21
  define( 'WCML_PLUGIN_PATH', dirname( __FILE__ ) );
22
  define( 'WCML_PLUGIN_FOLDER', basename( WCML_PLUGIN_PATH ) );
23
  define( 'WCML_LOCALE_PATH', WCML_PLUGIN_PATH . '/locale' );
78
  $loaders[] = 'WCML_Append_Gallery_To_Post_Media_Ids_Factory';
79
  }
80
 
81
+ if( version_compare( ICL_SITEPRESS_VERSION, '3.9.0', '>=' ) ){
82
+ $action_filter_loader = new WPML_Action_Filter_Loader();
83
+ $action_filter_loader->load( $loaders );
84
+ }
85
  }
86
 
87
  $WCML_REST_API = new WCML_REST_API();