WooCommerce Multilingual – run WooCommerce with WPML - Version 4.8.0

Version Description

  • Fixed JS SyntaxError on Products listing page.
  • Fixed not registered 'Additional Content' emails setting text after first saving.
  • Remove extra slash from the end of the translated base slug if a user added it.
  • Fix custom fields translation in Translation Editor for Variations post type.
  • Fixed customer Completed email has not translated heading and subject with WooCommerce 4.0.
  • Fixed duplicated currency code in "Default currency" drop-down on Multi-currency settings page.
  • Fixed language selector displayed in wrong place on Permalinks settings page.
  • Fix customer order status email language when sent the shop manager use english language and english is not an active language.
  • Fixed attributes synchronization may break variations relationships.
  • Fixed not saved custom prices if translation is duplicated and Native screen editor selected.
  • Fixed multiple same post meta keys translations.
  • Add variation single "translatable" custom fields to translation package.
  • Fixed error on Subscription renewal via PayPal.
  • Fixed not saved The Events Calendar ticket meta if translation done by Translation Service.
Download this release

Release Info

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

Code changes from version 4.7.9 to 4.8.0

changelog/4.3.0.md DELETED
@@ -1,18 +0,0 @@
1
- # Features
2
- * [wcml-309] Added ability to filtering comments by language
3
- * [wcml-2314] Use display-as-translated for product images and product galleries
4
-
5
- # Fixes
6
- * [wcml-2423] Fixed issue when deleting a currency in Safari
7
- * [wcml-2421] Fixed issue causing fatal error when activating WCML and WPML String Translation
8
- * [wcml-2410] Changes in the Fixer.io API
9
- * [wcml-2394] Added a fix where in some situation the product slug URL is not translated correctly
10
- * [wcml-2390] Variable product removed from cart when switching language on the cart page
11
- * [wcml-2376] Multicurrency in defaults not calculated correctly when creating manual order
12
- * [wcml-2364] Product Bundles - search products returned wrong values
13
- * [wcml-2362] Translating custom product category base leads to products returning error 404 when both bases contains the same string
14
- * [wcml-2356] Table Rate Shipping - products with different classes produce no shipping method on cart page
15
- * [wcml-2355] New order admin email subject and heading were overwrites with wrong data
16
- * [wcml-2353] Fix small issue in product stock sync
17
- * [wcml-2351] Refund and restock - not working properly when refunding the variation in second language
18
- * [wcml-2349] WooCommerce Product Bundles -> original overwrites translation (visible when using title/description override)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
changelog/4.7.8.md DELETED
@@ -1,31 +0,0 @@
1
- # Features
2
- * [wcml-2950] Make `Additional content` field translatable for Emails.
3
-
4
- # Fixes
5
- * [wcml-3103] Fixed stock synchronization issue for some extra plugins.
6
- * [wcml-3100] Fixed cart item not deleted from cart page in some cases.
7
- * [wcml-3098] Fixed Average Rating Widget Filter in all languages.
8
- * [wcml-3096] Fixed a fatal error when applying a translation job on a product with tabs on PHP 7.1+.
9
- * [wcml-3075] Fixed admin order note language after order status change.
10
- * [wcml-3059] Fixed not showing products when shop page is a child page of the front/home page.
11
- * [wcml-3051] Fixed display glitch of displaying current currency while adding new one.
12
- * [wcml-3032] Fixed compatibility plugins additional content appears not translated when using ATE.
13
- * [wcml-3007] Fixed inability to edit 'before discount' field on edit order page.
14
- * [wcml-2962] Fixed products in all languages displayed on new booking admin page.
15
- * [wcml-2956] Fixed language icon not updated in real-time when using Advanced Translation Editor.
16
- * [wcml-2570] Fixed warning message displayed at the wrong moment.
17
-
18
- # Compatibility
19
- * [wcml-3091] Fixed wrong language of custom attributes on cart page with display as translated mode enabled for products.
20
- * [wcml-3080] Fixed multiple ajax calls on the front page if few tabs opened in different languages for non-logged users.
21
- * [wcml-2952] Fixed Subscriptions early renewal price if not subscription price selected in the shop.
22
- * [wcml-2837] Fixed Top Rated product widget displaying wrong products on the second language.
23
- * [wcml-2737] Fixed Variable subscription "From" from price display auto converted price instead of custom one.
24
- * [wcml-2676] Fixed the dynamic WooCommerce blocks which were not converted in the current language.
25
-
26
- # Usability
27
- * [wcml-3019] Fixed product in wrong language selected on new order admin page.
28
- * [wcml-3015] WP Super Cache enable cache for switching currency.
29
- * [wcml-2925] Lock attributes select on second language native edit screen.
30
- * [wcml-2808] Fixed price not shown issue with WooCommerce Bookings.
31
- * [wcml-2535] Removed limitation of decimals in multi-currency settings.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
changelog/4.8.0.md ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Fixes
2
+ * [wcml-3148] Fixed JS SyntaxError on Products listing page.
3
+ * [wcml-3146] Fixed not registered 'Additional Content' emails setting text after first saving.
4
+ * [wcml-3134] Remove extra slash from the end of the translated base slug if a user added it.
5
+ * [wcml-3131] Fix custom fields translation in Translation Editor for Variations post type.
6
+ * [wcml-3127] Fixed customer Completed email has not translated heading and subject with WooCommerce 4.0.
7
+ * [wcml-3117] Fixed duplicated currency code in "Default currency" drop-down on Multi-currency settings page.
8
+ * [wcml-3116] Fixed language selector displayed in wrong place on Permalinks settings page.
9
+ * [wcml-3112] Fix customer order status email language when sent the shop manager use english language and english is not an active language.
10
+ * [wcml-3110] Fixed attributes synchronization may break variations relationships.
11
+ * [wcml-3106] Fixed not saved custom prices if translation is duplicated and Native screen editor selected.
12
+ * [wcml-3105] Fixed multiple same post meta keys translations.
13
+
14
+ # Compatibility
15
+ * [wcml-3124] Add variation single "translatable" custom fields to translation package.
16
+ * [wcml-3123] Fixed error on Subscription renewal via PayPal.
17
+ * [wcml-3095] Fixed not saved The Events Calendar ticket meta if translation done by Translation Service.
classes/Email/Settings/Hooks.php CHANGED
@@ -83,7 +83,7 @@ class Hooks implements IWPML_Backend_Action, IWPML_DIC_Action {
83
 
84
  if ( isset( $_GET['section'] ) && $_GET['section'] === $sectionName ) {
85
 
86
- $emailSettings = get_option( $emailOption );
87
 
88
  if ( $emailSettings ) {
89
 
@@ -143,7 +143,7 @@ class Hooks implements IWPML_Backend_Action, IWPML_DIC_Action {
143
  list( , $emailType, $emailElement ) = $keyParts;
144
 
145
  $emailInputKey = self::getEmailInputKey( $emailType, $emailElement );
146
- $emailSettings = get_option( $emailType, true );
147
  $optionStringValue = $emailSettings[ $emailElement ];
148
 
149
  $stringValue = isset( $_POST[ $emailInputKey ] ) ? $_POST[ $emailInputKey ] : $optionStringValue;
@@ -158,6 +158,21 @@ class Hooks implements IWPML_Backend_Action, IWPML_DIC_Action {
158
  }
159
  }
160
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
161
  /**
162
  * @param string $emailType
163
  * @param string $emailElement
83
 
84
  if ( isset( $_GET['section'] ) && $_GET['section'] === $sectionName ) {
85
 
86
+ $emailSettings = $this->get_email_option( $emailOption );
87
 
88
  if ( $emailSettings ) {
89
 
143
  list( , $emailType, $emailElement ) = $keyParts;
144
 
145
  $emailInputKey = self::getEmailInputKey( $emailType, $emailElement );
146
+ $emailSettings = $this->get_email_option( $emailType, true );
147
  $optionStringValue = $emailSettings[ $emailElement ];
148
 
149
  $stringValue = isset( $_POST[ $emailInputKey ] ) ? $_POST[ $emailInputKey ] : $optionStringValue;
158
  }
159
  }
160
 
161
+ /**
162
+ * @param string $option
163
+ * @param bool $default
164
+ *
165
+ * @return mixed
166
+ */
167
+ private function get_email_option( $option, $default = false ) {
168
+ $emailSettings = get_option( $option, $default );
169
+ if ( $emailSettings && is_array( $emailSettings ) && ! isset( $emailSettings['additional_content'] ) ) {
170
+ $emailSettings['additional_content'] = '';
171
+ }
172
+
173
+ return $emailSettings;
174
+ }
175
+
176
  /**
177
  * @param string $emailType
178
  * @param string $emailElement
classes/MO/Hooks.php ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace WCML\MO;
4
+
5
+ class Hooks implements \IWPML_Backend_Action, \IWPML_Frontend_Action {
6
+
7
+ public function add_hooks() {
8
+ add_action( 'wpml_language_has_switched', [ $this, 'forceRemoveUnloadedDomain' ], 0 );
9
+ }
10
+
11
+ public function forceRemoveUnloadedDomain() {
12
+ if ( isset( $GLOBALS['l10n_unloaded']['woocommerce'] ) ) {
13
+ unset( $GLOBALS['l10n_unloaded']['woocommerce'] );
14
+ }
15
+ }
16
+ }
classes/class-woocommerce-wpml.php CHANGED
@@ -199,7 +199,7 @@ class woocommerce_wpml {
199
  if ( is_admin() || wpml_is_rest_request() ) {
200
  $this->translation_editor = new WCML_Translation_Editor( $this, $sitepress, $wpdb );
201
  $this->translation_editor->add_hooks();
202
- $tp_support = new WCML_TP_Support( $this, $wpdb, new WPML_Element_Translation_Package() );
203
  $tp_support->add_hooks();
204
  $this->sync_variations_data = new WCML_Synchronize_Variations_Data( $this, $sitepress, $wpdb );
205
  }
199
  if ( is_admin() || wpml_is_rest_request() ) {
200
  $this->translation_editor = new WCML_Translation_Editor( $this, $sitepress, $wpdb );
201
  $this->translation_editor->add_hooks();
202
+ $tp_support = new WCML_TP_Support( $this, $wpdb, new WPML_Element_Translation_Package(), $sitepress->get_setting( 'translation-management', [] ) );
203
  $tp_support->add_hooks();
204
  $this->sync_variations_data = new WCML_Synchronize_Variations_Data( $this, $sitepress, $wpdb );
205
  }
compatibility/class-wcml-the-events-calendar.php CHANGED
@@ -207,7 +207,7 @@ class WCML_The_Events_Calendar {
207
 
208
  $this->sync_custom_fields( $rsvp_post_id, $translated_rsvp_post_id );
209
 
210
- $this->save_ticket_meta_translations( $rsvp_post_id, $translated_rsvp_post_id );
211
 
212
  }
213
  }
@@ -301,7 +301,7 @@ class WCML_The_Events_Calendar {
301
 
302
  $this->sync_custom_fields( $ticket_post_id, $translated_ticket_post_id );
303
 
304
- $this->save_ticket_meta_translations( $ticket_post_id, $translated_ticket_post_id );
305
  }
306
  }
307
 
@@ -337,7 +337,12 @@ class WCML_The_Events_Calendar {
337
  return $package;
338
  }
339
 
340
- private function save_ticket_meta_translations( $ticket_id, $translated_ticket_id ) {
 
 
 
 
 
341
  $ticket_meta = get_post_meta( $ticket_id, '_tribe_tickets_meta', true );
342
  $translated_ticket_meta = $ticket_meta;
343
  if ( is_array( $ticket_meta ) ) {
207
 
208
  $this->sync_custom_fields( $rsvp_post_id, $translated_rsvp_post_id );
209
 
210
+ $this->save_ticket_meta_translations( $rsvp_post_id, $translated_rsvp_post_id, $data );
211
 
212
  }
213
  }
301
 
302
  $this->sync_custom_fields( $ticket_post_id, $translated_ticket_post_id );
303
 
304
+ $this->save_ticket_meta_translations( $ticket_post_id, $translated_ticket_post_id, $data );
305
  }
306
  }
307
 
337
  return $package;
338
  }
339
 
340
+ /**
341
+ * @param int $ticket_id
342
+ * @param int $translated_ticket_id
343
+ * @param array $data
344
+ */
345
+ private function save_ticket_meta_translations( $ticket_id, $translated_ticket_id, $data ) {
346
  $ticket_meta = get_post_meta( $ticket_id, '_tribe_tickets_meta', true );
347
  $translated_ticket_meta = $ticket_meta;
348
  if ( is_array( $ticket_meta ) ) {
compatibility/class-wcml-wc-subscriptions.php CHANGED
@@ -426,13 +426,15 @@ class WCML_WC_Subscriptions {
426
  }
427
 
428
  /**
429
- * @param WC_Subscription $subscription
430
  *
431
- * @return WC_Subscription
432
  */
433
  public function filter_subscription_items( $subscription ) {
434
 
435
- $this->woocommerce_wpml->orders->adjust_order_item_in_language( $subscription->get_items() );
 
 
436
 
437
  return $subscription;
438
  }
426
  }
427
 
428
  /**
429
+ * @param mixed $subscription
430
  *
431
+ * @return mixed
432
  */
433
  public function filter_subscription_items( $subscription ) {
434
 
435
+ if ( $subscription instanceof WC_Subscription ) {
436
+ $this->woocommerce_wpml->orders->adjust_order_item_in_language( $subscription->get_items() );
437
+ }
438
 
439
  return $subscription;
440
  }
inc/admin-menus/class-wcml-admin-menus.php CHANGED
@@ -161,7 +161,7 @@ class WCML_Admin_Menus {
161
  // phpcs:disable WordPress.Security.EscapeOutput.OutputNotEscaped
162
  ?>
163
  <script type="text/javascript">
164
- jQuery( '.subsubsub' ).append( '<?php echo wp_kses_post( $quick_edit_notice ); ?>' );
165
  jQuery( '.subsubsub' ).append( ' <?php echo $quick_edit_notice_prod_link; ?> ' );
166
  jQuery( '.quick_hide a' ).on( 'click', function() {
167
  jQuery( '.quick_product_trnsl_link' ).attr( 'href', jQuery( '#wcml_product_trnsl_link' ).val() + jQuery( this ).closest( 'tr' ).attr( 'id' ).replace( /post-/, '' ) );
161
  // phpcs:disable WordPress.Security.EscapeOutput.OutputNotEscaped
162
  ?>
163
  <script type="text/javascript">
164
+ jQuery( '.subsubsub' ).append( '<?php echo wp_filter_post_kses( $quick_edit_notice ); ?>' );
165
  jQuery( '.subsubsub' ).append( ' <?php echo $quick_edit_notice_prod_link; ?> ' );
166
  jQuery( '.quick_hide a' ).on( 'click', function() {
167
  jQuery( '.quick_product_trnsl_link' ).attr( 'href', jQuery( '#wcml_product_trnsl_link' ).val() + jQuery( this ).closest( 'tr' ).attr( 'id' ).replace( /post-/, '' ) );
inc/class-wcml-emails.php CHANGED
@@ -344,8 +344,12 @@ class WCML_Emails {
344
 
345
  $translated_value = false;
346
  $emailStrings = wpml_collect( [
 
 
347
  'subject_partial',
348
  'subject_full',
 
 
349
  'heading_partial',
350
  'heading_full',
351
  'additional_content'
344
 
345
  $translated_value = false;
346
  $emailStrings = wpml_collect( [
347
+ 'subject',
348
+ 'subject_downloadable',
349
  'subject_partial',
350
  'subject_full',
351
+ 'heading',
352
+ 'heading_downloadable',
353
  'heading_partial',
354
  'heading_full',
355
  'additional_content'
inc/class-wcml-terms.php CHANGED
@@ -440,12 +440,11 @@ class WCML_Terms {
440
  JOIN {$this->wpdb->term_taxonomy} tx on tr.term_taxonomy_id = tx.term_taxonomy_id
441
  JOIN {$this->wpdb->posts} p ON tr.object_id = p.ID
442
  JOIN {$this->wpdb->prefix}icl_translations t ON t.element_id = p.ID
443
- WHERE {$where} tx.taxonomy = %s AND p.post_type = 'product' AND t.element_type='post_product' AND t.language_code = %s
444
  ORDER BY ID ASC
445
 
446
  ",
447
- $taxonomy,
448
- $this->sitepress->get_default_language()
449
  )
450
  );
451
 
440
  JOIN {$this->wpdb->term_taxonomy} tx on tr.term_taxonomy_id = tx.term_taxonomy_id
441
  JOIN {$this->wpdb->posts} p ON tr.object_id = p.ID
442
  JOIN {$this->wpdb->prefix}icl_translations t ON t.element_id = p.ID
443
+ WHERE {$where} tx.taxonomy = %s AND p.post_type = 'product' AND t.element_type='post_product' AND t.source_language_code IS NULL
444
  ORDER BY ID ASC
445
 
446
  ",
447
+ $taxonomy
 
448
  )
449
  );
450
 
inc/class-wcml-tp-support.php CHANGED
@@ -2,12 +2,16 @@
2
 
3
  class WCML_TP_Support {
4
 
 
 
5
  /** @var woocommerce_wpml */
6
  private $woocommerce_wpml;
7
  /** @var wpdb */
8
  private $wpdb;
9
  /** @var WPML_Element_Translation_Package */
10
  private $tp;
 
 
11
 
12
  /**
13
  * WCML_Attributes constructor.
@@ -15,12 +19,14 @@ class WCML_TP_Support {
15
  * @param woocommerce_wpml $woocommerce_wpml
16
  * @param wpdb $wpdb
17
  * @param WPML_Element_Translation_Package $tp
 
18
  */
19
- public function __construct( woocommerce_wpml $woocommerce_wpml, wpdb $wpdb, WPML_Element_Translation_Package $tp ) {
20
 
21
  $this->woocommerce_wpml = $woocommerce_wpml;
22
  $this->wpdb = $wpdb;
23
  $this->tp = $tp;
 
24
  }
25
 
26
  public function add_hooks() {
@@ -32,11 +38,11 @@ class WCML_TP_Support {
32
 
33
  add_filter( 'wpml_tm_translation_job_data', array(
34
  $this,
35
- 'append_variation_descriptions_translation_package'
36
  ), 10, 2 );
37
  add_action( 'wpml_pro_translation_completed', array(
38
  $this,
39
- 'save_variation_descriptions_translations'
40
  ), 20, 3 ); //after WCML_Products
41
 
42
  add_filter( 'wpml_tm_translation_job_data', array( $this, 'append_slug_to_translation_package' ), 10, 2 );
@@ -145,7 +151,23 @@ class WCML_TP_Support {
145
 
146
  }
147
 
148
- public function append_variation_descriptions_translation_package( $package, $post ) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
149
 
150
  if ( 'product' === $post->post_type ) {
151
 
@@ -160,16 +182,19 @@ class WCML_TP_Support {
160
 
161
  foreach ( $variations as $variation ) {
162
 
163
- $description = get_post_meta( $variation->ID, '_variation_description', true );
164
 
165
- if ( $description ) {
166
- $package['contents'][ 'wc_variation_description:' . $variation->ID ] = array(
167
- 'translate' => 1,
168
- 'data' => $this->tp->encode_field_data( $description, 'base64' ),
169
- 'format' => 'base64'
170
- );
171
- }
172
 
 
 
 
 
 
 
 
 
173
  }
174
 
175
  }
@@ -180,34 +205,30 @@ class WCML_TP_Support {
180
 
181
  }
182
 
183
- public function save_variation_descriptions_translations( $post_id, $data, $job ) {
184
 
185
  $language = $job->language_code;
186
 
187
  foreach ( $data as $data_key => $value ) {
188
 
189
- if ( $value['finished'] && isset( $value['field_type'] ) && strpos( $value['field_type'], 'wc_variation_description:' ) === 0 ) {
190
 
191
- $variation_id = substr( $value['field_type'], strpos( $value['field_type'], ':' ) + 1 );
 
 
192
 
193
  if ( is_post_type_translated( 'product_variation' ) ) {
194
-
195
  $translated_variation_id = apply_filters( 'translate_object_id', $variation_id, 'product_variation', false, $language );
196
-
197
  } else {
198
  global $wpml_post_translations;
199
  $translations = $wpml_post_translations->get_element_translations( $variation_id );
200
  $translated_variation_id = isset( $translations[ $language ] ) ? $translations[ $language ] : false;
201
-
202
  }
203
 
204
  if ( $translated_variation_id ) {
205
- update_post_meta( $translated_variation_id, '_variation_description', $value['data'] );
206
  }
207
-
208
-
209
  }
210
-
211
  }
212
 
213
  }
@@ -324,5 +345,3 @@ class WCML_TP_Support {
324
 
325
  }
326
  }
327
-
328
-
2
 
3
  class WCML_TP_Support {
4
 
5
+ const CUSTOM_FIELD_NAME = 'wc_variation_field:';
6
+
7
  /** @var woocommerce_wpml */
8
  private $woocommerce_wpml;
9
  /** @var wpdb */
10
  private $wpdb;
11
  /** @var WPML_Element_Translation_Package */
12
  private $tp;
13
+ /** @var array */
14
+ private $tm_settings;
15
 
16
  /**
17
  * WCML_Attributes constructor.
19
  * @param woocommerce_wpml $woocommerce_wpml
20
  * @param wpdb $wpdb
21
  * @param WPML_Element_Translation_Package $tp
22
+ * @param array $tm_settings
23
  */
24
+ public function __construct( woocommerce_wpml $woocommerce_wpml, wpdb $wpdb, WPML_Element_Translation_Package $tp, array $tm_settings ) {
25
 
26
  $this->woocommerce_wpml = $woocommerce_wpml;
27
  $this->wpdb = $wpdb;
28
  $this->tp = $tp;
29
+ $this->tm_settings = $tm_settings;
30
  }
31
 
32
  public function add_hooks() {
38
 
39
  add_filter( 'wpml_tm_translation_job_data', array(
40
  $this,
41
+ 'append_variation_custom_fields_to_translation_package'
42
  ), 10, 2 );
43
  add_action( 'wpml_pro_translation_completed', array(
44
  $this,
45
+ 'save_variation_custom_fields_translations'
46
  ), 20, 3 ); //after WCML_Products
47
 
48
  add_filter( 'wpml_tm_translation_job_data', array( $this, 'append_slug_to_translation_package' ), 10, 2 );
151
 
152
  }
153
 
154
+ /**
155
+ * @param int $variation_id
156
+ *
157
+ * @return array
158
+ */
159
+ private function get_variation_custom_fields_to_translate( $variation_id ) {
160
+ $is_field_translatable = function ( $meta_key ) {
161
+ return isset( $this->tm_settings['custom_fields_translation'][ $meta_key ] )
162
+ && (int) $this->tm_settings['custom_fields_translation'][ $meta_key ] === WPML_TRANSLATE_CUSTOM_FIELD;
163
+ };
164
+
165
+ return wpml_collect( (array) get_post_custom_keys( $variation_id ) )
166
+ ->filter( $is_field_translatable )
167
+ ->toArray();
168
+ }
169
+
170
+ public function append_variation_custom_fields_to_translation_package( $package, $post ) {
171
 
172
  if ( 'product' === $post->post_type ) {
173
 
182
 
183
  foreach ( $variations as $variation ) {
184
 
185
+ $meta_keys_to_translate = $this->get_variation_custom_fields_to_translate( $variation->ID );
186
 
187
+ foreach ( $meta_keys_to_translate as $meta_key ){
188
+ $meta_value = get_post_meta( $variation->ID, $meta_key, true );
 
 
 
 
 
189
 
190
+ if ( $meta_value && !is_array( $meta_value ) ) {
191
+ $package['contents'][ self::CUSTOM_FIELD_NAME.$meta_key.':' . $variation->ID ] = array(
192
+ 'translate' => 1,
193
+ 'data' => $this->tp->encode_field_data( $meta_value, 'base64' ),
194
+ 'format' => 'base64'
195
+ );
196
+ }
197
+ }
198
  }
199
 
200
  }
205
 
206
  }
207
 
208
+ public function save_variation_custom_fields_translations( $post_id, $data, $job ) {
209
 
210
  $language = $job->language_code;
211
 
212
  foreach ( $data as $data_key => $value ) {
213
 
214
+ if ( $value['finished'] && isset( $value['field_type'] ) && strpos( $value['field_type'], self::CUSTOM_FIELD_NAME ) === 0 ) {
215
 
216
+ $exp = explode( ':', $value['field_type'], 3 );
217
+ $meta_key = $exp[1];
218
+ $variation_id = $exp[2];
219
 
220
  if ( is_post_type_translated( 'product_variation' ) ) {
 
221
  $translated_variation_id = apply_filters( 'translate_object_id', $variation_id, 'product_variation', false, $language );
 
222
  } else {
223
  global $wpml_post_translations;
224
  $translations = $wpml_post_translations->get_element_translations( $variation_id );
225
  $translated_variation_id = isset( $translations[ $language ] ) ? $translations[ $language ] : false;
 
226
  }
227
 
228
  if ( $translated_variation_id ) {
229
+ update_post_meta( $translated_variation_id, $meta_key, $value['data'] );
230
  }
 
 
231
  }
 
232
  }
233
 
234
  }
345
 
346
  }
347
  }
 
 
inc/class-wcml-url-translation.php CHANGED
@@ -834,7 +834,7 @@ class WCML_Url_Translation {
834
 
835
  $original_base = $_POST['base'];
836
  $original_base_value = $_POST['base_value'];
837
- $base_translation = $_POST['base_translation'];
838
  $language = $_POST['language'];
839
 
840
  if ( $original_base == 'shop' ) {
834
 
835
  $original_base = $_POST['base'];
836
  $original_base_value = $_POST['base_value'];
837
+ $base_translation = trim( $_POST['base_translation'], '/' );
838
  $language = $_POST['language'];
839
 
840
  if ( $original_base == 'shop' ) {
inc/class-wcml-wc-strings.php CHANGED
@@ -296,11 +296,7 @@ class WCML_WC_Strings {
296
  input.parent().find('.translation_controls').append('&nbsp;');
297
 
298
  } else {
299
- input.parent().find('.translation_controls').append('<a href="
300
- <?php
301
- echo admin_url( 'admin.php?page=wpml-wcml&tab=slugs' )
302
- ?>
303
- "><?php _e( 'translations', 'woocommerce-multilingual' ); ?></a>');
304
  }
305
 
306
  jQuery('#<?php echo $key; ?>_language_selector').prependTo(input.parent().find('.translation_controls'));
296
  input.parent().find('.translation_controls').append('&nbsp;');
297
 
298
  } else {
299
+ input.parent().find('.translation_controls').append('<a href="<?php echo admin_url( 'admin.php?page=wpml-wcml&tab=slugs' ); ?>"><?php _e( 'translations', 'woocommerce-multilingual' ); ?></a>');
 
 
 
 
300
  }
301
 
302
  jQuery('#<?php echo $key; ?>_language_selector').prependTo(input.parent().find('.translation_controls'));
inc/translation-editor/class-wcml-editor-ui-product-job.php CHANGED
@@ -208,7 +208,7 @@ class WCML_Editor_UI_Product_Job extends WPML_Editor_UI_Job {
208
 
209
  } else {
210
 
211
- $custom_fields_values = array_values( array_filter( maybe_unserialize( get_post_meta( $this->product_id, $custom_field, true ) ) ) );
212
 
213
  if ( $custom_fields_values ) {
214
  $cf_fields_group = new WPML_Editor_UI_Field_Group();
@@ -358,31 +358,34 @@ class WCML_Editor_UI_Product_Job extends WPML_Editor_UI_Job {
358
 
359
  }
360
 
361
- public function add_custom_fields_ui_section( $custom_fields_section, $custom_fields, $variation_id = false ) {
362
 
363
  foreach ( $custom_fields as $custom_field ) {
364
 
365
- $custom_field_id = $variation_id ? $custom_field . $variation_id : $custom_field;
366
 
367
- if ( key( $this->data[ $custom_field_id ] ) !== 'original' ) {
368
- $group = new WPML_Editor_UI_Field_Group( $this->get_product_custom_field_label( $custom_field, $variation_id ), true );
369
- foreach ( $this->data[ $custom_field_id ] as $custom_field_key => $custom_field_array ) {
 
 
 
 
 
 
 
 
 
 
 
 
370
  if ( '_variation_description' === $custom_field ) {
371
- $custom_field_input = new WPML_Editor_UI_TextArea_Field( $custom_field_key, '', $this->data[ $custom_field_id ], false );
372
  } else {
373
- $custom_field_input = new WPML_Editor_UI_Single_Line_Field( $custom_field_key, '', $this->data[ $custom_field_id ], false );
374
  }
375
-
376
- $group->add_field( $custom_field_input );
377
  }
378
- $custom_fields_section->add_field( $group );
379
- } else {
380
- if ( '_variation_description' === $custom_field ) {
381
- $custom_field_input = new WPML_Editor_UI_TextArea_Field( $custom_field_id, $this->get_product_custom_field_label( $custom_field, $variation_id ), $this->data, true );
382
- } else {
383
- $custom_field_input = new WPML_Editor_UI_Single_Line_Field( $custom_field_id, $this->get_product_custom_field_label( $custom_field, $variation_id ), $this->data, true );
384
- }
385
- $custom_fields_section->add_field( $custom_field_input );
386
  }
387
  }
388
 
@@ -567,8 +570,9 @@ class WCML_Editor_UI_Product_Job extends WPML_Editor_UI_Job {
567
  $trnsl_mid_ids = $this->woocommerce_wpml->products->get_mid_ids_by_key( $translation_id, $custom_field );
568
  }
569
 
 
570
  if ( $is_variation ) {
571
- $custom_field .= $element_id;
572
  }
573
 
574
  foreach ( $orig_custom_field_values as $val_key => $orig_custom_field_value ) {
@@ -576,31 +580,31 @@ class WCML_Editor_UI_Product_Job extends WPML_Editor_UI_Job {
576
  if ( $this->check_custom_field_is_single_value( $element_id, $custom_field ) ) {
577
 
578
  if ( count( $orig_custom_field_values ) == 1 ) {
579
- $element_data[ $custom_field ] = [ 'original' => $orig_custom_field_value ];
580
- $element_data[ $custom_field ]['translation'] = ( $translation_id && isset( $translated_custom_field_value[ $val_key ] ) ) ? $translated_custom_field_value[ $val_key ] : '';
581
  } else {
582
 
583
- $custom_field_key = $custom_field . ':' . ( isset( $trnsl_mid_ids[ $val_key ] ) ? $trnsl_mid_ids[ $val_key ] : 'new_' . $val_key );
584
 
585
- $element_data[ $custom_field ][ $custom_field_key ] = [ 'original' => $orig_custom_field_value ];
586
- $element_data[ $custom_field ][ $custom_field_key ]['translation'] = ( $translation_id && isset( $translated_custom_field_value[ $val_key ] ) ) ? $translated_custom_field_value[ $val_key ] : '';
587
  }
588
  } else {
589
 
590
- $custom_fields = maybe_unserialize( get_post_meta( $this->product_id, $custom_field, true ) );
591
  $translated_custom_fields = [];
592
 
593
  if ( $custom_fields ) {
594
 
595
  if ( $translation_id ) {
596
- $translated_custom_fields = maybe_unserialize( get_post_meta( $translation_id, $custom_field, true ) );
597
  }
598
 
599
  $i = 0;
600
  foreach ( $custom_fields as $key => $field_value ) {
601
  if ( ! empty( $field_value ) ) {
602
  $translated_custom_field_value = isset( $translated_custom_fields[ $key ] ) ? $translated_custom_fields[ $key ] : '';
603
- $element_data = $this->add_single_custom_field_content_value( $element_data, $custom_field, $i, $field_value, $translated_custom_field_value );
604
  $i ++;
605
  }
606
  }
@@ -947,9 +951,8 @@ class WCML_Editor_UI_Product_Job extends WPML_Editor_UI_Job {
947
  }
948
 
949
  public function check_custom_field_is_single_value( $product_id, $meta_key ) {
950
- $meta_value = maybe_unserialize( get_post_meta( $product_id, $meta_key, true ) );
951
 
952
- if ( is_array( $meta_value ) ) {
953
  return false;
954
  } else {
955
  return apply_filters( 'wcml_check_is_single', true, $product_id, $meta_key );
@@ -972,4 +975,23 @@ class WCML_Editor_UI_Product_Job extends WPML_Editor_UI_Job {
972
  return true;
973
  }
974
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
975
  }
208
 
209
  } else {
210
 
211
+ $custom_fields_values = array_values( $this->get_custom_field_values( $this->product_id, $custom_field ) );
212
 
213
  if ( $custom_fields_values ) {
214
  $cf_fields_group = new WPML_Editor_UI_Field_Group();
358
 
359
  }
360
 
361
+ public function add_custom_fields_ui_section( $custom_fields_section, $custom_fields, $variation_id ) {
362
 
363
  foreach ( $custom_fields as $custom_field ) {
364
 
365
+ if ( '_variation_description' === $custom_field || $this->get_custom_field_values( $variation_id, $custom_field ) ) {
366
 
367
+ $custom_field_id = $custom_field . $variation_id;
368
+
369
+ if ( key( $this->data[ $custom_field_id ] ) !== 'original' ) {
370
+ $group = new WPML_Editor_UI_Field_Group( $this->get_product_custom_field_label( $custom_field, $variation_id ), true );
371
+ foreach ( $this->data[ $custom_field_id ] as $custom_field_key => $custom_field_array ) {
372
+ if ( '_variation_description' === $custom_field ) {
373
+ $custom_field_input = new WPML_Editor_UI_TextArea_Field( $custom_field_key, '', $this->data[ $custom_field_id ], false );
374
+ } else {
375
+ $custom_field_input = new WPML_Editor_UI_Single_Line_Field( $custom_field_key, '', $this->data[ $custom_field_id ], false );
376
+ }
377
+
378
+ $group->add_field( $custom_field_input );
379
+ }
380
+ $custom_fields_section->add_field( $group );
381
+ } else {
382
  if ( '_variation_description' === $custom_field ) {
383
+ $custom_field_input = new WPML_Editor_UI_TextArea_Field( $custom_field_id, $this->get_product_custom_field_label( $custom_field, $variation_id ), $this->data, true );
384
  } else {
385
+ $custom_field_input = new WPML_Editor_UI_Single_Line_Field( $custom_field_id, $this->get_product_custom_field_label( $custom_field, $variation_id ), $this->data, true );
386
  }
387
+ $custom_fields_section->add_field( $custom_field_input );
 
388
  }
 
 
 
 
 
 
 
 
389
  }
390
  }
391
 
570
  $trnsl_mid_ids = $this->woocommerce_wpml->products->get_mid_ids_by_key( $translation_id, $custom_field );
571
  }
572
 
573
+ $data_custom_field_key = $custom_field;
574
  if ( $is_variation ) {
575
+ $data_custom_field_key .= $element_id;
576
  }
577
 
578
  foreach ( $orig_custom_field_values as $val_key => $orig_custom_field_value ) {
580
  if ( $this->check_custom_field_is_single_value( $element_id, $custom_field ) ) {
581
 
582
  if ( count( $orig_custom_field_values ) == 1 ) {
583
+ $element_data[ $data_custom_field_key ] = [ 'original' => $orig_custom_field_value ];
584
+ $element_data[ $data_custom_field_key ]['translation'] = ( $translation_id && isset( $translated_custom_field_value[ $val_key ] ) ) ? $translated_custom_field_value[ $val_key ] : '';
585
  } else {
586
 
587
+ $custom_field_key = $data_custom_field_key . ':' . ( isset( $trnsl_mid_ids[ $val_key ] ) ? $trnsl_mid_ids[ $val_key ] : 'new_' . $val_key );
588
 
589
+ $element_data[ $data_custom_field_key ][ $custom_field_key ] = [ 'original' => $orig_custom_field_value ];
590
+ $element_data[ $data_custom_field_key ][ $custom_field_key ]['translation'] = ( $translation_id && isset( $translated_custom_field_value[ $val_key ] ) ) ? $translated_custom_field_value[ $val_key ] : '';
591
  }
592
  } else {
593
 
594
+ $custom_fields = $this->get_custom_field_values( $this->product_id, $custom_field );
595
  $translated_custom_fields = [];
596
 
597
  if ( $custom_fields ) {
598
 
599
  if ( $translation_id ) {
600
+ $translated_custom_fields = $this->get_custom_field_values( $translation_id, $custom_field );
601
  }
602
 
603
  $i = 0;
604
  foreach ( $custom_fields as $key => $field_value ) {
605
  if ( ! empty( $field_value ) ) {
606
  $translated_custom_field_value = isset( $translated_custom_fields[ $key ] ) ? $translated_custom_fields[ $key ] : '';
607
+ $element_data = $this->add_single_custom_field_content_value( $element_data, $data_custom_field_key, $i, $field_value, $translated_custom_field_value );
608
  $i ++;
609
  }
610
  }
951
  }
952
 
953
  public function check_custom_field_is_single_value( $product_id, $meta_key ) {
 
954
 
955
+ if ( is_array( $this->get_custom_field_values( $product_id, $meta_key ) ) ) {
956
  return false;
957
  } else {
958
  return apply_filters( 'wcml_check_is_single', true, $product_id, $meta_key );
975
  return true;
976
  }
977
 
978
+ /**
979
+ * @param int $product_id
980
+ * @param string $field_key
981
+ *
982
+ * @return array|string
983
+ */
984
+ private function get_custom_field_values( $product_id, $field_key ) {
985
+ $maybe_double_unserialize = function ( $value ) {
986
+ return maybe_unserialize( $value );
987
+ };
988
+
989
+ $values = array_map(
990
+ $maybe_double_unserialize,
991
+ array_filter( get_post_meta( $product_id, $field_key ) )
992
+ );
993
+
994
+ return count( $values ) === 1 ? $values[0] : $values;
995
+ }
996
+
997
  }
inc/translation-editor/class-wcml-synchronize-product-data.php CHANGED
@@ -101,8 +101,6 @@ class WCML_Synchronize_Product_Data {
101
  ) {
102
  return;
103
  }
104
- // Remove filter to avoid double sync
105
- remove_action( 'save_post', [ $this, 'synchronize_products' ], PHP_INT_MAX, 2 );
106
 
107
  do_action( 'wcml_before_sync_product', $original_product_id, $post_id );
108
 
@@ -596,7 +594,12 @@ class WCML_Synchronize_Product_Data {
596
  foreach ( $post_fields as $post_field_key => $post_field ) {
597
 
598
  if ( 1 === preg_match( '/field-' . $custom_field . '-.*?/', $post_field_key ) ) {
599
- $custom_fields = get_post_meta( $original_product_id, $custom_field, true );
 
 
 
 
 
600
  $filtered_custom_fields = array_filter( $custom_fields );
601
  $custom_fields_values = array_values( $filtered_custom_fields );
602
  $custom_fields_keys = array_keys( $filtered_custom_fields );
@@ -615,10 +618,15 @@ class WCML_Synchronize_Product_Data {
615
  $custom_fields_translated = $custom_fields;
616
 
617
  foreach ( $custom_fields_values as $index => $value ) {
618
- $custom_fields_translated[ $custom_fields_keys[ $index ] ] = $value;
 
 
 
 
 
 
 
619
  }
620
-
621
- update_post_meta( $trnsl_product_id, $custom_field, $custom_fields_translated );
622
  } else {
623
  $meta_value = $translation_data[ md5( $post_field_key ) ];
624
  $field_key = explode( ':', $post_field_key );
101
  ) {
102
  return;
103
  }
 
 
104
 
105
  do_action( 'wcml_before_sync_product', $original_product_id, $post_id );
106
 
594
  foreach ( $post_fields as $post_field_key => $post_field ) {
595
 
596
  if ( 1 === preg_match( '/field-' . $custom_field . '-.*?/', $post_field_key ) ) {
597
+ delete_post_meta( $trnsl_product_id, $custom_field );
598
+
599
+ $custom_fields = get_post_meta( $original_product_id, $custom_field );
600
+ $single = count( $custom_fields ) === 1;
601
+ $custom_fields = $single ? $custom_fields[0] : $custom_fields;
602
+
603
  $filtered_custom_fields = array_filter( $custom_fields );
604
  $custom_fields_values = array_values( $filtered_custom_fields );
605
  $custom_fields_keys = array_keys( $filtered_custom_fields );
618
  $custom_fields_translated = $custom_fields;
619
 
620
  foreach ( $custom_fields_values as $index => $value ) {
621
+ if ( ! $single ) {
622
+ add_post_meta( $trnsl_product_id, $custom_field, $value, $single );
623
+ } else {
624
+ $custom_fields_translated[ $custom_fields_keys[ $index ] ] = $value;
625
+ }
626
+ }
627
+ if ( $single ) {
628
+ update_post_meta( $trnsl_product_id, $custom_field, $custom_fields_translated );
629
  }
 
 
630
  } else {
631
  $meta_value = $translation_data[ md5( $post_field_key ) ];
632
  $field_key = explode( ':', $post_field_key );
readme.txt CHANGED
@@ -4,8 +4,8 @@ Donate link: http://wpml.org/documentation/related-projects/woocommerce-multilin
4
  Tags: CMS, woocommerce, commerce, ecommerce, e-commerce, products, WPML, multilingual, e-shop, shop
5
  License: GPLv2
6
  Requires at least: 4.7
7
- Tested up to: 5.3
8
- Stable tag: 4.7.9
9
  Requires PHP: 5.6
10
 
11
  Allows running fully multilingual e-commerce sites using WooCommerce and WPML.
@@ -137,31 +137,21 @@ WooCommerce Multilingual is compatible with all major WooCommerce extensions. We
137
 
138
  == Changelog ==
139
 
140
- = 4.7.8 =
141
- * Make `Additional content` field translatable for Emails.
142
- * Fixed stock synchronization issue for some extra plugins.
143
- * Fixed cart item not deleted from cart page in some cases.
144
- * Fixed Average Rating Widget Filter in all languages.
145
- * Fixed a fatal error when applying a translation job on a product with tabs on PHP 7.1+.
146
- * Fixed admin order note language after order status change.
147
- * Fixed not showing products when shop page is a child page of the front/home page.
148
- * Fixed display glitch of displaying current currency while adding new one.
149
- * Fixed compatibility plugins additional content appears not translated when using ATE.
150
- * Fixed inability to edit 'before discount' field on edit order page.
151
- * Fixed products in all languages displayed on new booking admin page.
152
- * Fixed language icon not updated in real-time when using Advanced Translation Editor.
153
- * Fixed warning message displayed at the wrong moment.
154
- * Fixed wrong language of custom attributes on cart page with display as translated mode enabled for products.
155
- * Fixed multiple ajax calls on the front page if few tabs opened in different languages for non-logged users.
156
- * Fixed Subscriptions early renewal price if not subscription price selected in the shop.
157
- * Fixed Top Rated product widget displaying wrong products on the second language.
158
- * Fixed Variable subscription "From" from price display auto converted price instead of custom one.
159
- * Fixed the dynamic WooCommerce blocks which were not converted in the current language.
160
- * Fixed product in wrong language selected on new order admin page.
161
- * WP Super Cache enable cache for switching currency.
162
- * Lock attributes select on second language native edit screen.
163
- * Fixed price not shown issue with WooCommerce Bookings.
164
- * Removed limitation of decimals in multi-currency settings.
165
 
166
  = 4.7.0 =
167
  * Replaced some Twig templates with pure PHP templates as the first step towards the removal of Twig dependencies.
@@ -277,20 +267,3 @@ WooCommerce Multilingual is compatible with all major WooCommerce extensions. We
277
  * Added ability to set custom prices for secondary currencies in WC Product Add-Ons
278
  * Update minimum requirements
279
  * Added ability to add custom payment methods for each currency
280
-
281
- = 4.3.0 =
282
- * Added ability to filtering comments by language
283
- * Use display-as-translated for product images and product galleries
284
- * Fixed issue when deleting a currency in Safari
285
- * Fixed issue causing fatal error when activating WCML and WPML String Translation
286
- * Changes in the Fixer.io API
287
- * Added a fix where in some situation the product slug URL is not translated correctly
288
- * Variable product removed from cart when switching language on the cart page
289
- * Multicurrency in defaults not calculated correctly when creating manual order
290
- * Product Bundles - search products returned wrong values
291
- * Translating custom product category base leads to products returning error 404 when both bases contains the same string
292
- * Table Rate Shipping - products with different classes produce no shipping method on cart page
293
- * New order admin email subject and heading were overwrites with wrong data
294
- * Fix small issue in product stock sync
295
- * Refund and restock - not working properly when refunding the variation in second language
296
- * WooCommerce Product Bundles -> original overwrites translation (visible when using title/description override)
4
  Tags: CMS, woocommerce, commerce, ecommerce, e-commerce, products, WPML, multilingual, e-shop, shop
5
  License: GPLv2
6
  Requires at least: 4.7
7
+ Tested up to: 5.4
8
+ Stable tag: 4.8.0
9
  Requires PHP: 5.6
10
 
11
  Allows running fully multilingual e-commerce sites using WooCommerce and WPML.
137
 
138
  == Changelog ==
139
 
140
+ = 4.8.0 =
141
+ * Fixed JS SyntaxError on Products listing page.
142
+ * Fixed not registered 'Additional Content' emails setting text after first saving.
143
+ * Remove extra slash from the end of the translated base slug if a user added it.
144
+ * Fix custom fields translation in Translation Editor for Variations post type.
145
+ * Fixed customer Completed email has not translated heading and subject with WooCommerce 4.0.
146
+ * Fixed duplicated currency code in "Default currency" drop-down on Multi-currency settings page.
147
+ * Fixed language selector displayed in wrong place on Permalinks settings page.
148
+ * Fix customer order status email language when sent the shop manager use english language and english is not an active language.
149
+ * Fixed attributes synchronization may break variations relationships.
150
+ * Fixed not saved custom prices if translation is duplicated and Native screen editor selected.
151
+ * Fixed multiple same post meta keys translations.
152
+ * Add variation single "translatable" custom fields to translation package.
153
+ * Fixed error on Subscription renewal via PayPal.
154
+ * Fixed not saved The Events Calendar ticket meta if translation done by Translation Service.
 
 
 
 
 
 
 
 
 
 
155
 
156
  = 4.7.0 =
157
  * Replaced some Twig templates with pure PHP templates as the first step towards the removal of Twig dependencies.
267
  * Added ability to set custom prices for secondary currencies in WC Product Add-Ons
268
  * Update minimum requirements
269
  * Added ability to add custom payment methods for each currency
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
templates/multi-currency/multi-currency.twig CHANGED
@@ -153,11 +153,6 @@
153
  <select rel="{{ language.code }}">
154
  <option value="0"
155
  {% if get_language_currency(language.code) == 0 %}selected="selected"{% endif %}>{{ strings.currencies_table.keep_currency }}</option>
156
- {% if is_currency_on(wc_currency, language.code) %}
157
- <option value="{{ wc_currency }}"
158
- {% if get_language_currency(language.code) == wc_currency %}selected="selected"{% endif %}>{{ wc_currency }}</option>
159
- {% endif %}
160
-
161
  {% for code, currency in currencies %}
162
  {% if is_currency_on(code, language.code) %}
163
  <option value="{{ code }}"
153
  <select rel="{{ language.code }}">
154
  <option value="0"
155
  {% if get_language_currency(language.code) == 0 %}selected="selected"{% endif %}>{{ strings.currencies_table.keep_currency }}</option>
 
 
 
 
 
156
  {% for code, currency in currencies %}
157
  {% if is_currency_on(code, language.code) %}
158
  <option value="{{ code }}"
vendor/autoload.php CHANGED
@@ -4,4 +4,4 @@
4
 
5
  require_once __DIR__ . '/composer/autoload_real.php';
6
 
7
- return ComposerAutoloaderInit62ab66f0f70e43b2aa15047590cd4f85::getLoader();
4
 
5
  require_once __DIR__ . '/composer/autoload_real.php';
6
 
7
+ return ComposerAutoloaderInit2b24f5ddc335620015ade0eba62103e1::getLoader();
vendor/composer/autoload_classmap.php CHANGED
@@ -11,6 +11,7 @@ return array(
11
  'WCML\\Block\\Convert\\Hooks' => $baseDir . '/classes/Block/Convert/Hooks.php',
12
  'WCML\\Container\\Config' => $baseDir . '/classes/Container/Config.php',
13
  'WCML\\Email\\Settings\\Hooks' => $baseDir . '/classes/Email/Settings/Hooks.php',
 
14
  'WCML\\Media\\Wrapper\\Factory' => $baseDir . '/classes/media/Wrapper/Factory.php',
15
  'WCML\\Media\\Wrapper\\IMedia' => $baseDir . '/classes/media/Wrapper/IMedia.php',
16
  'WCML\\Media\\Wrapper\\NonTranslatable' => $baseDir . '/classes/media/Wrapper/NonTranslatable.php',
11
  'WCML\\Block\\Convert\\Hooks' => $baseDir . '/classes/Block/Convert/Hooks.php',
12
  'WCML\\Container\\Config' => $baseDir . '/classes/Container/Config.php',
13
  'WCML\\Email\\Settings\\Hooks' => $baseDir . '/classes/Email/Settings/Hooks.php',
14
+ 'WCML\\MO\\Hooks' => $baseDir . '/classes/MO/Hooks.php',
15
  'WCML\\Media\\Wrapper\\Factory' => $baseDir . '/classes/media/Wrapper/Factory.php',
16
  'WCML\\Media\\Wrapper\\IMedia' => $baseDir . '/classes/media/Wrapper/IMedia.php',
17
  'WCML\\Media\\Wrapper\\NonTranslatable' => $baseDir . '/classes/media/Wrapper/NonTranslatable.php',
vendor/composer/autoload_real.php CHANGED
@@ -2,7 +2,7 @@
2
 
3
  // autoload_real.php @generated by Composer
4
 
5
- class ComposerAutoloaderInit62ab66f0f70e43b2aa15047590cd4f85
6
  {
7
  private static $loader;
8
 
@@ -13,21 +13,24 @@ class ComposerAutoloaderInit62ab66f0f70e43b2aa15047590cd4f85
13
  }
14
  }
15
 
 
 
 
16
  public static function getLoader()
17
  {
18
  if (null !== self::$loader) {
19
  return self::$loader;
20
  }
21
 
22
- spl_autoload_register(array('ComposerAutoloaderInit62ab66f0f70e43b2aa15047590cd4f85', 'loadClassLoader'), true, true);
23
  self::$loader = $loader = new \Composer\Autoload\ClassLoader();
24
- spl_autoload_unregister(array('ComposerAutoloaderInit62ab66f0f70e43b2aa15047590cd4f85', '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\ComposerStaticInit62ab66f0f70e43b2aa15047590cd4f85::getInitializer($loader));
31
  } else {
32
  $map = require __DIR__ . '/autoload_namespaces.php';
33
  foreach ($map as $namespace => $path) {
@@ -48,19 +51,19 @@ class ComposerAutoloaderInit62ab66f0f70e43b2aa15047590cd4f85
48
  $loader->register(true);
49
 
50
  if ($useStaticLoader) {
51
- $includeFiles = Composer\Autoload\ComposerStaticInit62ab66f0f70e43b2aa15047590cd4f85::$files;
52
  } else {
53
  $includeFiles = require __DIR__ . '/autoload_files.php';
54
  }
55
  foreach ($includeFiles as $fileIdentifier => $file) {
56
- composerRequire62ab66f0f70e43b2aa15047590cd4f85($fileIdentifier, $file);
57
  }
58
 
59
  return $loader;
60
  }
61
  }
62
 
63
- function composerRequire62ab66f0f70e43b2aa15047590cd4f85($fileIdentifier, $file)
64
  {
65
  if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) {
66
  require $file;
2
 
3
  // autoload_real.php @generated by Composer
4
 
5
+ class ComposerAutoloaderInit2b24f5ddc335620015ade0eba62103e1
6
  {
7
  private static $loader;
8
 
13
  }
14
  }
15
 
16
+ /**
17
+ * @return \Composer\Autoload\ClassLoader
18
+ */
19
  public static function getLoader()
20
  {
21
  if (null !== self::$loader) {
22
  return self::$loader;
23
  }
24
 
25
+ spl_autoload_register(array('ComposerAutoloaderInit2b24f5ddc335620015ade0eba62103e1', 'loadClassLoader'), true, true);
26
  self::$loader = $loader = new \Composer\Autoload\ClassLoader();
27
+ spl_autoload_unregister(array('ComposerAutoloaderInit2b24f5ddc335620015ade0eba62103e1', 'loadClassLoader'));
28
 
29
  $useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded());
30
  if ($useStaticLoader) {
31
  require_once __DIR__ . '/autoload_static.php';
32
 
33
+ call_user_func(\Composer\Autoload\ComposerStaticInit2b24f5ddc335620015ade0eba62103e1::getInitializer($loader));
34
  } else {
35
  $map = require __DIR__ . '/autoload_namespaces.php';
36
  foreach ($map as $namespace => $path) {
51
  $loader->register(true);
52
 
53
  if ($useStaticLoader) {
54
+ $includeFiles = Composer\Autoload\ComposerStaticInit2b24f5ddc335620015ade0eba62103e1::$files;
55
  } else {
56
  $includeFiles = require __DIR__ . '/autoload_files.php';
57
  }
58
  foreach ($includeFiles as $fileIdentifier => $file) {
59
+ composerRequire2b24f5ddc335620015ade0eba62103e1($fileIdentifier, $file);
60
  }
61
 
62
  return $loader;
63
  }
64
  }
65
 
66
+ function composerRequire2b24f5ddc335620015ade0eba62103e1($fileIdentifier, $file)
67
  {
68
  if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) {
69
  require $file;
vendor/composer/autoload_static.php CHANGED
@@ -4,7 +4,7 @@
4
 
5
  namespace Composer\Autoload;
6
 
7
- class ComposerStaticInit62ab66f0f70e43b2aa15047590cd4f85
8
  {
9
  public static $files = array (
10
  'b45b351e6b6f7487d819961fef2fda77' => __DIR__ . '/..' . '/jakeasmith/http_build_url/src/http_build_url.php',
@@ -30,6 +30,7 @@ class ComposerStaticInit62ab66f0f70e43b2aa15047590cd4f85
30
  'WCML\\Block\\Convert\\Hooks' => __DIR__ . '/../..' . '/classes/Block/Convert/Hooks.php',
31
  'WCML\\Container\\Config' => __DIR__ . '/../..' . '/classes/Container/Config.php',
32
  'WCML\\Email\\Settings\\Hooks' => __DIR__ . '/../..' . '/classes/Email/Settings/Hooks.php',
 
33
  'WCML\\Media\\Wrapper\\Factory' => __DIR__ . '/../..' . '/classes/media/Wrapper/Factory.php',
34
  'WCML\\Media\\Wrapper\\IMedia' => __DIR__ . '/../..' . '/classes/media/Wrapper/IMedia.php',
35
  'WCML\\Media\\Wrapper\\NonTranslatable' => __DIR__ . '/../..' . '/classes/media/Wrapper/NonTranslatable.php',
@@ -237,9 +238,9 @@ class ComposerStaticInit62ab66f0f70e43b2aa15047590cd4f85
237
  public static function getInitializer(ClassLoader $loader)
238
  {
239
  return \Closure::bind(function () use ($loader) {
240
- $loader->prefixLengthsPsr4 = ComposerStaticInit62ab66f0f70e43b2aa15047590cd4f85::$prefixLengthsPsr4;
241
- $loader->prefixDirsPsr4 = ComposerStaticInit62ab66f0f70e43b2aa15047590cd4f85::$prefixDirsPsr4;
242
- $loader->classMap = ComposerStaticInit62ab66f0f70e43b2aa15047590cd4f85::$classMap;
243
 
244
  }, null, ClassLoader::class);
245
  }
4
 
5
  namespace Composer\Autoload;
6
 
7
+ class ComposerStaticInit2b24f5ddc335620015ade0eba62103e1
8
  {
9
  public static $files = array (
10
  'b45b351e6b6f7487d819961fef2fda77' => __DIR__ . '/..' . '/jakeasmith/http_build_url/src/http_build_url.php',
30
  'WCML\\Block\\Convert\\Hooks' => __DIR__ . '/../..' . '/classes/Block/Convert/Hooks.php',
31
  'WCML\\Container\\Config' => __DIR__ . '/../..' . '/classes/Container/Config.php',
32
  'WCML\\Email\\Settings\\Hooks' => __DIR__ . '/../..' . '/classes/Email/Settings/Hooks.php',
33
+ 'WCML\\MO\\Hooks' => __DIR__ . '/../..' . '/classes/MO/Hooks.php',
34
  'WCML\\Media\\Wrapper\\Factory' => __DIR__ . '/../..' . '/classes/media/Wrapper/Factory.php',
35
  'WCML\\Media\\Wrapper\\IMedia' => __DIR__ . '/../..' . '/classes/media/Wrapper/IMedia.php',
36
  'WCML\\Media\\Wrapper\\NonTranslatable' => __DIR__ . '/../..' . '/classes/media/Wrapper/NonTranslatable.php',
238
  public static function getInitializer(ClassLoader $loader)
239
  {
240
  return \Closure::bind(function () use ($loader) {
241
+ $loader->prefixLengthsPsr4 = ComposerStaticInit2b24f5ddc335620015ade0eba62103e1::$prefixLengthsPsr4;
242
+ $loader->prefixDirsPsr4 = ComposerStaticInit2b24f5ddc335620015ade0eba62103e1::$prefixDirsPsr4;
243
+ $loader->classMap = ComposerStaticInit2b24f5ddc335620015ade0eba62103e1::$classMap;
244
 
245
  }, null, ClassLoader::class);
246
  }
vendor/otgs/installer/loader.php CHANGED
@@ -51,7 +51,7 @@ $wp_installer_instance = dirname( __FILE__ ) . '/installer.php';
51
  global $wp_installer_instances;
52
  $wp_installer_instances[ $wp_installer_instance ] = array(
53
  'bootfile' => $wp_installer_instance,
54
- 'version' => '2.2.6'
55
  );
56
 
57
 
51
  global $wp_installer_instances;
52
  $wp_installer_instances[ $wp_installer_instance ] = array(
53
  'bootfile' => $wp_installer_instance,
54
+ 'version' => '2.2.7'
55
  );
56
 
57
 
vendor/otgs/installer/templates/repository-register.php CHANGED
@@ -11,7 +11,7 @@ class Register {
11
  xmlns="http://www.w3.org/1999/html">
12
  <div class="otgs-installer-notice-content">
13
  <h2>
14
- <?php echo esc_html( sprintf( __( 'You are using an unregistered version of %s and are not receiving compatibility and security updates.', 'installer' ), $model->productName ) ); ?>
15
  <a class="enter_site_key_js otgs-installer-notice-link-register"
16
  href="#"
17
  <?php
11
  xmlns="http://www.w3.org/1999/html">
12
  <div class="otgs-installer-notice-content">
13
  <h2>
14
+ <?php echo esc_html( sprintf( __( 'Already purchased %s?', 'installer' ), $model->productName ) ); ?>
15
  <a class="enter_site_key_js otgs-installer-notice-link-register"
16
  href="#"
17
  <?php
wpml-woocommerce.php CHANGED
@@ -7,11 +7,11 @@
7
  * Author URI: http://www.onthegosystems.com/
8
  * Text Domain: woocommerce-multilingual
9
  * Requires at least: 4.7
10
- * Tested up to: 5.3
11
- * Version: 4.7.9
12
  * Plugin Slug: woocommerce-multilingual
13
  * WC requires at least: 3.3.0
14
- * WC tested up to: 3.8.0
15
  *
16
  * @package WCML
17
  * @author OnTheGoSystems
@@ -33,7 +33,7 @@ if ( ! $wpml_php_version_check->is_ok() ) {
33
  return;
34
  }
35
 
36
- define( 'WCML_VERSION', '4.7.9' );
37
  define( 'WCML_PLUGIN_PATH', dirname( __FILE__ ) );
38
  define( 'WCML_PLUGIN_FOLDER', basename( WCML_PLUGIN_PATH ) );
39
  define( 'WCML_LOCALE_PATH', WCML_PLUGIN_PATH . '/locale' );
@@ -82,6 +82,7 @@ function wcml_loader() {
82
  \WCML\RewriteRules\Hooks::class,
83
  \WCML\Email\Settings\Hooks::class,
84
  \WCML\Block\Convert\Hooks::class,
 
85
  ];
86
 
87
  if (
7
  * Author URI: http://www.onthegosystems.com/
8
  * Text Domain: woocommerce-multilingual
9
  * Requires at least: 4.7
10
+ * Tested up to: 5.4
11
+ * Version: 4.8.0
12
  * Plugin Slug: woocommerce-multilingual
13
  * WC requires at least: 3.3.0
14
+ * WC tested up to: 4.0.1
15
  *
16
  * @package WCML
17
  * @author OnTheGoSystems
33
  return;
34
  }
35
 
36
+ define( 'WCML_VERSION', '4.8.0' );
37
  define( 'WCML_PLUGIN_PATH', dirname( __FILE__ ) );
38
  define( 'WCML_PLUGIN_FOLDER', basename( WCML_PLUGIN_PATH ) );
39
  define( 'WCML_LOCALE_PATH', WCML_PLUGIN_PATH . '/locale' );
82
  \WCML\RewriteRules\Hooks::class,
83
  \WCML\Email\Settings\Hooks::class,
84
  \WCML\Block\Convert\Hooks::class,
85
+ \WCML\MO\Hooks::class,
86
  ];
87
 
88
  if (