WooCommerce Multilingual – run WooCommerce with WPML - Version 4.1.4

Version Description

  • Fix: A PHP warning was shown on a product bundle page on the front end (when using WooCommerce Product Bundles)
  • Fix: Added possibility to filter available Currency Switcher templates paths via "wcml_cs_directories_to_scan" filter
  • Fix: The "Copy to a new draft" link was showing two times on the product edit page
  • Fix: For taxonomies having the term_id distinct from term_taxonomy_id, the translations could have been accidentally overwritten
  • Fix: In some conditions, a fatal error could come up when editing a product
  • Fix: In some circustances, disabling currency switcher on product page produced a fatal error
  • Fix: Custom attributes in the translations were reset after editing the original product
  • Fix: Sometimes, the translated product category pages were returning a 404 error
  • Fix: It was not possible to filter products by price on the shop page using the WooCommerce Price Filter widget
Download this release

Release Info

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

Code changes from version 4.1.3 to 4.1.4

changelog/4.1.1.md ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
1
+ # Fixes
2
+ * [wcml-1858] Fixed a pre PHP 5.4 compatibility issue
3
+ * [wcml-1856] Fixed `Notice: Undefined index: switcher_id`
4
+ * [wcml-1855] Fixed `Fatal error: Class ‘WPML_File’ not found` when using an old version of WPML
5
+ * [wcml-1854] Fixed "Invalid or duplicated SKU" error when saving or updating a product with SKU
6
+ * [wcml-1853] Fixed `Fatal error: Call to undefined function WC()` when disabling WooCommerce while WCML is running
changelog/4.1.2.md ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
1
+ # Fixes
2
+ * [wcml-1867] Fixed `Fatal error: Call to undefined method WPML_WP_API::defined`
3
+ * [wcml-1864] Fixed the currency switcher not being displayed correctly when using the Storefront theme
4
+ * [wcml-1863] Fixed `Fatal error: Call to undefined function wc_format_decimal()`
5
+ * [wcml-1862] Fixed a bug causing an error when upgrading WooCommerce Multilingual to version 4.1 with WooCommerce inactive.
6
+ * [wcml-1860] ixed the currency switcher css being loaded when no currency switcher was displayed
changelog/4.1.4.md ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
1
+ # Fixes
2
+ * [wcml-1954] A PHP warning was shown on a product bundle page on the front end (when using WooCommerce Product Bundles)
3
+ * [wcml-1949] Added possibility to filter available Currency Switcher templates paths via "wcml_cs_directories_to_scan" filter
4
+ * [wcml-1948] The "Copy to a new draft" link was showing two times on the product edit page
5
+ * [wcml-1947] For taxonomies having the term_id distinct from term_taxonomy_id, the translations could have been accidentally overwritten
6
+ * [wcml-1945] In some conditions, a fatal error could come up when editing a product
7
+ * [wcml-1944] In some circustances, disabling currency switcher on product page produced a fatal error
8
+ * [wcml-1938] Custom attributes in the translations were reset after editing the original product
9
+ * [wcml-1935] Sometimes, the translated product category pages were returning a 404 error
10
+ * [wcml-1931] It was not possible to filter products by price on the shop page using the WooCommerce Price Filter widget
compatibility/class-wcml-product-bundles.php CHANGED
@@ -1,91 +1,94 @@
1
  <?php
2
 
3
- class WCML_Product_Bundles{
4
 
5
- /**
6
- * @var WPML_Element_Translation_Package
7
- */
8
- public $tp;
9
 
10
- /**
11
- * @var SitePress
12
- */
13
- private $sitepress;
14
 
15
- /**
16
- * @var woocommerce_wpml
17
- */
18
- private $woocommerce_wpml;
19
 
20
  /**
21
  * @var WCML_WC_Product_Bundles_Items
22
  */
23
  private $product_bundles_items;
24
 
25
- /**
26
- * WCML_Product_Bundles constructor.
27
- */
28
- function __construct( &$sitepress, &$woocommerce_wpml, &$product_bundles_items ){
29
 
30
- $this->sitepress = $sitepress;
31
- $this->woocommerce_wpml = $woocommerce_wpml;
32
- $this->product_bundles_items = $product_bundles_items;
33
 
34
  add_action( 'woocommerce_get_cart_item_from_session', array( $this, 'resync_bundle' ), 5, 3 );
35
  add_filter( 'woocommerce_cart_loaded_from_session', array( $this, 'resync_bundle_clean' ), 10 );
36
 
37
- if( is_admin() ){
38
- $this->tp = new WPML_Element_Translation_Package();
39
 
40
- add_filter( 'wpml_tm_translation_job_data', array( $this, 'append_bundle_data_translation_package' ), 10, 2 );
41
- add_action( 'wpml_translation_job_saved', array( $this, 'save_bundle_data_translation' ), 10, 3 );
 
 
 
42
 
43
- add_action( 'wcml_gui_additional_box_html', array( $this, 'custom_box_html' ), 10, 3 );
44
- add_filter( 'wcml_gui_additional_box_data', array( $this, 'custom_box_html_data' ), 10, 4 );
45
 
46
- add_action( 'wcml_after_duplicate_product_post_meta', array( $this, 'sync_bundled_ids' ), 10, 2 );
47
- add_action( 'wcml_update_extra_fields', array( $this, 'bundle_update' ), 10, 4 );
48
 
49
- add_action( 'wp_insert_post', array( $this, 'sync_product_bundle_meta_with_translations' ), 10 );
50
 
51
- }
52
 
53
- // product bundle using separate custom fields for prices
54
- if( wcml_is_multi_currency_on() ){
55
- add_filter( 'wcml_price_custom_fields_filtered', array( $this, 'get_price_custom_fields' ) );
56
- }
57
 
58
- }
59
 
60
- private function get_product_bundle_data( $bundle_id ){
61
  $product_bundle_data = array();
62
 
63
  $bundle_items = $this->product_bundles_items->get_items( $bundle_id );
64
- foreach( $bundle_items as $key => $bundle_item ){
65
  $product_bundle_data[ $bundle_item->item_id ] = $this->product_bundles_items->get_item_data( $bundle_item );
66
  }
67
 
68
  return $product_bundle_data;
69
  }
70
 
71
- private function save_product_bundle_data( $bundle_id, $product_bundle_data ){
72
 
73
  $bundle_items = $this->product_bundles_items->get_items( $bundle_id );
74
 
75
- foreach( $bundle_items as $item_id => $bundle_item ){
76
  $bundled_item_data = $this->product_bundles_items->get_item_data_object( $item_id );
77
 
78
- foreach( $product_bundle_data[ $item_id ] as $key => $value ){
79
- $this->product_bundles_items->update_item_meta( $bundled_item_data, $key, $value );
80
  }
81
  $this->product_bundles_items->save_item_meta( $bundled_item_data );
82
  }
83
 
84
  }
85
 
86
- private function sync_product_bundle_meta( $bundle_id, $translated_bundle_id ){
87
 
88
- $bundle_items = $this->product_bundles_items->get_items( $bundle_id );
89
  $fields_to_sync = array(
90
  'optional',
91
  'stock_status',
@@ -102,20 +105,20 @@ class WCML_Product_Bundles{
102
  'order_price_visibility'
103
  );
104
 
105
- $target_lang = $this->sitepress->get_language_for_element( $translated_bundle_id, 'post_product' );
106
  $translated_item_ids = array();
107
- foreach( $bundle_items as $item_id => $bundle_item ){
108
 
109
- $item_meta = $this->product_bundles_items->get_item_data( $bundle_item );
110
  $translated_product_id = apply_filters( 'translate_object_id', $item_meta['product_id'], get_post_type( $item_meta['product_id'] ), false, $target_lang );
111
 
112
- if( $translated_product_id ){
113
- $translated_item_id = $this->get_item_id_for_product_id( $translated_product_id, $translated_bundle_id );
114
  $translated_item_ids[] = $translated_item_id;
115
 
116
  $translated_item = $this->product_bundles_items->get_item_data_object( $translated_item_id );
117
- foreach( $fields_to_sync as $key ){
118
- $this->product_bundles_items->update_item_meta( $translated_item, $key, $item_meta[$key] );
119
  }
120
  $this->product_bundles_items->save_item_meta( $translated_item );
121
 
@@ -134,11 +137,11 @@ class WCML_Product_Bundles{
134
 
135
  }
136
 
137
- public function sync_product_bundle_meta_with_translations( $bundle_id ){
138
 
139
  if ( WooCommerce_Functions_Wrapper::get_product_type( $bundle_id ) === 'bundle' ) {
140
 
141
- $trid = $this->sitepress->get_element_trid( $bundle_id, 'post_product' );
142
  $translations = $this->sitepress->get_element_translations( $trid, 'post_product' );
143
 
144
  foreach ( $translations as $language => $translation ) {
@@ -159,14 +162,16 @@ class WCML_Product_Bundles{
159
 
160
  }
161
 
162
- private function get_product_id_for_item_id( $item_id ){
163
  global $wpdb;
 
164
  return $wpdb->get_var( $wpdb->prepare(
165
- "SELECT product_id FROM {$wpdb->prefix}woocommerce_bundled_items WHERE bundled_item_id=%d", $item_id) );
166
  }
167
 
168
- private function get_item_id_for_product_id( $product_id, $bundle_id ){
169
  global $wpdb;
 
170
  return $wpdb->get_var( $wpdb->prepare(
171
  "SELECT bundled_item_id FROM {$wpdb->prefix}woocommerce_bundled_items WHERE product_id=%d AND bundle_id=%d",
172
  $product_id, $bundle_id
@@ -174,11 +179,11 @@ class WCML_Product_Bundles{
174
  }
175
 
176
  // Add Bundles Box to WCML Translation GUI
177
- public function custom_box_html( $obj, $bundle_id, $data ){
178
 
179
  $bundle_items = $this->product_bundles_items->get_items( $bundle_id );
180
 
181
- if( empty( $bundle_items ) ){
182
  return false;
183
  }
184
 
@@ -186,16 +191,16 @@ class WCML_Product_Bundles{
186
 
187
  end( $bundle_items );
188
  $last_item_id = key( $bundle_items );
189
- $divider = true;
190
- $flag = false;
191
 
192
  foreach ( $bundle_items as $item_id => $bundle_item ) {
193
 
194
  $translated_product = apply_filters( 'translate_object_id', $bundle_item->product_id, get_post_type( $bundle_item->product_id ), false, $obj->get_target_language() );
195
- if( !is_null($translated_product)) {
196
 
197
  $add_group = false;
198
- if( $item_id == $last_item_id ){
199
  $divider = false;
200
  }
201
 
@@ -203,7 +208,7 @@ class WCML_Product_Bundles{
203
 
204
  $group = new WPML_Editor_UI_Field_Group( get_the_title( $bundle_item->product_id ), $divider );
205
 
206
- if( $bundle_item_data[ 'override_title' ] == 'yes' ) {
207
  $bundle_field = new WPML_Editor_UI_Single_Line_Field(
208
  'bundle_' . $bundle_item->product_id . '_title',
209
  __( 'Name', 'woocommerce-multilingual' ),
@@ -214,9 +219,9 @@ class WCML_Product_Bundles{
214
  $add_group = true;
215
  }
216
 
217
- if( $bundle_item_data[ 'override_description' ] == 'yes' ){
218
  $bundle_field = new WPML_Editor_UI_Single_Line_Field(
219
- 'bundle_'. $bundle_item->product_id . '_desc' ,
220
  __( 'Description', 'woocommerce-multilingual' ),
221
  $data,
222
  false
@@ -225,7 +230,7 @@ class WCML_Product_Bundles{
225
  $add_group = true;
226
  }
227
 
228
- if( $add_group ){
229
  $bundles_section->add_field( $group );
230
  $flag = true;
231
  }
@@ -234,22 +239,22 @@ class WCML_Product_Bundles{
234
 
235
  }
236
 
237
- if( $flag ){
238
  $obj->add_field( $bundles_section );
239
  }
240
 
241
  }
242
 
243
- public function custom_box_html_data( $data, $bundle_id, $translation, $lang ){
244
 
245
  $bundle_data = $this->get_product_bundle_data( $bundle_id );
246
 
247
- if( $translation ) {
248
- $translated_bundle_id = $translation->ID;
249
  $translated_bundle_data = $this->get_product_bundle_data( $translated_bundle_id );
250
  }
251
 
252
- if( empty( $bundle_data ) || $bundle_data == false ){
253
  return $data;
254
  }
255
 
@@ -260,50 +265,51 @@ class WCML_Product_Bundles{
260
  $product_id = $this->get_product_id_for_item_id( $item_id );
261
 
262
  $translated_product_id = apply_filters( 'translate_object_id', $product_id, get_post_type( $product_id ), false, $lang );
263
- if( $translation ){
264
  $translated_item_id = $this->get_item_id_for_product_id( $translated_product_id, $translated_bundle_id );
265
  }
266
 
267
- if( $bundle_data[ $item_id ][ 'override_title' ] == 'yes' ){
268
- $data[ 'bundle_'.$product_id.'_title' ] = array( 'original' => $bundle_data[ $item_id ][ 'title' ] );
269
- if( $translation && isset( $translated_bundle_data[ $translated_item_id ][ 'override_title' ] ) ){
270
- $data[ 'bundle_'.$product_id.'_title' ][ 'translation' ] = $translated_bundle_data[ $translated_item_id ][ 'title' ];
271
- }else{
272
- $data[ 'bundle_'.$product_id.'_title' ][ 'translation' ] = '';
273
  }
274
  }
275
 
276
- if( $bundle_data[ $item_id ][ 'override_description' ] == 'yes' ){
277
- $data[ 'bundle_'.$product_id.'_desc' ] = array( 'original' => $bundle_data[ $item_id ][ 'description' ] );
278
- if( $translation && isset( $translated_bundle_data[ $translated_item_id ][ 'override_description' ] ) ){
279
- $data[ 'bundle_'.$product_id.'_desc' ][ 'translation' ] = $translated_bundle_data[ $translated_item_id ][ 'description' ];
280
- }else{
281
- $data[ 'bundle_'.$product_id.'_desc' ][ 'translation' ] = '';
282
  }
283
  }
284
  }
 
285
  return $data;
286
  }
287
 
288
- public function append_bundle_data_translation_package( $package, $post ){
289
 
290
- if( $post->post_type == 'product' ) {
291
 
292
  $bundle_data = $this->get_product_bundle_data( $post->ID );
293
 
294
- if( $bundle_data ){
295
 
296
  $fields = array( 'title', 'description' );
297
 
298
- foreach( $bundle_data as $item_id => $product_data ){
299
 
300
  $product_id = $this->get_product_id_for_item_id( $item_id );
301
- foreach( $fields as $field ) {
302
- if ( $product_data[ 'override_' . $field ] == 'yes' && !empty( $product_data[ $field ] ) ) {
303
- $package[ 'contents' ][ 'product_bundles:' . $product_id . ':' . $field ] = array(
304
  'translate' => 1,
305
- 'data' => $this->tp->encode_field_data( $product_data[ $field ], 'base64' ),
306
- 'format' => 'base64'
307
  );
308
  }
309
  }
@@ -316,25 +322,25 @@ class WCML_Product_Bundles{
316
  }
317
 
318
  // Update Bundled products title and description after saving the translation
319
- public function bundle_update( $bundle_id, $translated_bundle_id, $data, $lang ){
320
  global $wpdb;
321
 
322
- $bundle_data = $this->get_product_bundle_data( $bundle_id );
323
  $translated_bundle_data = $this->get_product_bundle_data( $translated_bundle_id );
324
 
325
- if( empty( $bundle_data ) ){
326
  return;
327
  }
328
 
329
  $translate_bundled_item_ids = $wpdb->get_col( $wpdb->prepare(
330
- "SELECT product_id FROM {$wpdb->prefix}woocommerce_bundled_items WHERE bundle_id = %d", $translated_bundle_id ));
331
 
332
  foreach ( $bundle_data as $item_id => $bundle_item_data ) {
333
 
334
- $product_id = $this->get_product_id_for_item_id( $item_id );
335
  $translated_product_id = apply_filters( 'translate_object_id', $product_id, get_post_type( $product_id ), false, $lang );
336
 
337
- if( $translated_product_id ) {
338
 
339
  if ( ! in_array( $translated_product_id, $translate_bundled_item_ids ) ) {
340
 
@@ -373,241 +379,243 @@ class WCML_Product_Bundles{
373
  $this->save_product_bundle_data( $translated_bundle_id, $translated_bundle_data );
374
  $this->sync_product_bundle_meta( $bundle_id, $translated_bundle_id );
375
 
376
- $this->sitepress->copy_custom_fields ( $bundle_id, $translated_bundle_id );
377
 
378
  return $translated_bundle_data;
379
  }
380
 
381
  // Sync product bundle data with translated values when the product is duplicated
382
- public function sync_bundled_ids( $bundle_id, $translated_bundle_id ){
383
  global $wpdb;
384
 
385
- $bundle_data = $this->get_product_bundle_data( $bundle_id );
386
- if( $bundle_data ){
387
- $lang = $this->sitepress->get_language_for_element( $translated_bundle_id, 'post_product' );
388
- $translated_bundle_data = $this->get_product_bundle_data( $translated_bundle_id );
389
 
390
- foreach( $bundle_data as $item_id => $product_data ){
391
 
392
- $product_id = $this->get_product_id_for_item_id( $item_id );
393
- $translated_product_id = apply_filters( 'translate_object_id', $product_id, get_post_type( $product_id ), false, $lang );
394
 
395
- if( $translated_product_id ){
396
 
397
- $translated_item_id = $this->get_item_id_for_product_id( $translated_product_id, $translated_bundle_id );
398
- if( !$translated_item_id ){
399
- $menu_order = $wpdb->get_var( $wpdb->prepare( "
400
  SELECT menu_order FROM {$wpdb->prefix}woocommerce_bundled_items
401
  WHERE bundle_id=%d AND product_id=%d
402
  ", $bundle_id, $product_id ) );
403
 
404
- $wpdb->insert( $wpdb->prefix . 'woocommerce_bundled_items',
405
- array(
406
- 'product_id' => $translated_product_id,
407
- 'bundle_id' => $translated_bundle_id,
408
- 'menu_order' => $menu_order,
409
- )
410
- );
411
- $translated_item_id = $wpdb->insert_id;
412
- }
413
-
414
- $translated_bundle_data[ $translated_item_id ] = $product_data;
415
- $translated_bundle_data[ $translated_item_id ]['product_id'] = $translated_product_id;
416
-
417
- if( isset( $bundle_data[ 'title' ] ) ){
418
- if( $bundle_data[ 'override_title' ] != 'yes' ){
419
- $translated_bundle_data[ $translated_item_id ][ 'title' ] = get_the_title( $translated_product_id );
420
- }
421
- }
422
-
423
- if( isset( $bundle_data[ 'title' ] ) ){
424
- if( $bundle_data[ 'override_description' ] != 'yes' ){
425
- $translated_bundle_data[ $translated_item_id ][ 'description' ] = get_the_title( $translated_product_id );
426
- }
427
- }
428
-
429
- if( isset( $bundle_data[ 'filter_variations' ] ) && $bundle_data[ 'filter_variations' ] == 'yes' ){
430
- $allowed_var = $bundle_data[ 'allowed_variations' ];
431
- foreach( $allowed_var as $key => $var_id ){
432
- $translated_var_id = apply_filters( 'translate_object_id', $var_id, get_post_type( $var_id ), true, $lang );
433
- $translated_bundle_data[ $translated_item_id ][ 'allowed_variations' ][ $key ] = $translated_var_id;
434
- }
435
- }
436
-
437
-
438
- if( isset( $bundle_data[ 'bundle_defaults' ] ) && !empty( $bundle_data[ 'bundle_defaults' ] ) ){
439
- foreach( $bundle_data[ 'bundle_defaults' ] as $tax => $term_slug ){
440
-
441
- $term_id = $this->woocommerce_wpml->terms->wcml_get_term_id_by_slug( $tax, $term_slug );
442
- if( $term_id ){
443
- // Global Attribute
444
- $tr_def_id = apply_filters( 'translate_object_id', $term_id, $tax, true, $lang );
445
- $tr_term = $this->woocommerce_wpml->terms->wcml_get_term_by_id( $tr_def_id, $tax );
446
- $translated_bundle_data[ $translated_item_id ][ 'bundle_defaults' ][ $tax ] = $tr_term->slug;
447
- }else{
448
- // Custom Attribute
449
- $args = array(
450
- 'post_type' => 'product_variation',
451
- 'meta_key' => 'attribute_'.$tax,
452
- 'meta_value' => $term_slug,
453
- 'meta_compare' => '='
454
- );
455
- $variationloop = new WP_Query( $args );
456
- while ( $variationloop->have_posts() ) : $variationloop->the_post();
457
- $tr_var_id = apply_filters( 'translate_object_id', get_the_ID(), 'product_variation', true, $lang );
458
- $tr_meta = get_post_meta( $tr_var_id, 'attribute_'.$tax , true );
459
- $translated_bundle_data[ $translated_item_id ][ 'bundle_defaults' ][ $tax ] = $tr_meta;
460
- endwhile;
461
- }
462
- }
463
- }
464
-
465
- }
466
-
467
-
468
- }
469
-
470
- $this->save_product_bundle_data( $translated_bundle_id, $translated_bundle_data );
471
-
472
- return $translated_bundle_data;
473
- }
474
-
475
- }
476
-
477
- public function resync_bundle( $cart_item, $session_values, $cart_item_key ) {
478
-
479
- if ( isset( $cart_item[ 'bundled_items' ] ) && $cart_item[ 'data' ]->product_type === 'bundle' ) {
480
- $current_bundle_id = apply_filters( 'translate_object_id', $cart_item[ 'product_id' ], 'product', true );
481
- if ( $cart_item[ 'product_id' ] != $current_bundle_id ) {
482
- $old_bundled_item_ids = array_keys( $cart_item[ 'data' ]->bundle_data );
483
- $cart_item[ 'data' ] = wc_get_product( $current_bundle_id );
484
- if( isset($cart_item[ 'data' ]->bundle_data) && is_array( $cart_item[ 'data' ]->bundle_data ) ){
485
- $new_bundled_item_ids = array_keys( $cart_item[ 'data' ]->bundle_data );
486
- $remapped_bundled_item_ids = array();
487
- foreach ( $old_bundled_item_ids as $old_item_id_index => $old_item_id ) {
488
- $remapped_bundled_item_ids[ $old_item_id ] = $new_bundled_item_ids[ $old_item_id_index ];
489
- }
490
- $cart_item[ 'remapped_bundled_item_ids' ] = $remapped_bundled_item_ids;
491
- if ( isset( $cart_item[ 'stamp' ] ) ) {
492
- $new_stamp = array();
493
- foreach ( $cart_item[ 'stamp' ] as $bundled_item_id => $stamp_data ) {
494
- $new_stamp[ $remapped_bundled_item_ids[ $bundled_item_id ] ] = $stamp_data;
495
- }
496
- $cart_item[ 'stamp' ] = $new_stamp;
497
- }
498
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
499
  }
500
- }
501
- if ( isset( $cart_item[ 'bundled_by' ] ) && isset( WC()->cart->cart_contents[ $cart_item[ 'bundled_by' ] ] ) ) {
502
- $bundle_cart_item = WC()->cart->cart_contents[ $cart_item[ 'bundled_by' ] ];
503
- if (
504
- isset( $bundle_cart_item[ 'remapped_bundled_item_ids' ] ) &&
505
- isset( $cart_item[ 'bundled_item_id' ] ) &&
506
- isset( $bundle_cart_item[ 'remapped_bundled_item_ids' ][ $cart_item[ 'bundled_item_id' ] ] )
507
- ) {
508
- $old_id = $cart_item[ 'bundled_item_id' ];
509
- $remapped_bundled_item_ids = $bundle_cart_item[ 'remapped_bundled_item_ids' ];
510
- $cart_item[ 'bundled_item_id' ] = $remapped_bundled_item_ids[ $cart_item[ 'bundled_item_id' ] ];
511
- if ( isset( $cart_item[ 'stamp' ] ) ) {
512
- $new_stamp = array();
513
- foreach ( $cart_item[ 'stamp' ] as $bundled_item_id => $stamp_data ) {
514
- $new_stamp[ $remapped_bundled_item_ids[ $bundled_item_id ] ] = $stamp_data;
515
- }
516
- $cart_item[ 'stamp' ] = $new_stamp;
517
- }
518
- }
519
- }
520
-
521
- return $cart_item;
522
- }
523
-
524
- public function resync_bundle_clean( $cart ) {
525
- foreach ( $cart->cart_contents as $cart_item_key => $cart_item ) {
526
- if ( isset( $cart_item[ 'bundled_items' ] ) && WooCommerce_Functions_Wrapper::get_product_type( $cart_item[ 'product_id' ] ) === 'bundle' ) {
527
- if ( isset( $cart_item[ 'remapped_bundled_item_ids' ] ) ) {
528
- unset( WC()->cart->cart_contents[ $cart_item_key ][ 'remapped_bundled_item_ids' ] );
529
- }
530
- }
531
- }
532
- }
533
-
534
- public function save_bundle_data_translation( $translated_bundle_id, $data, $job ){
535
-
536
- remove_action( 'wcml_after_duplicate_product_post_meta', array( $this, 'sync_bundled_ids' ), 10, 2 );
537
-
538
- $translated_bundle_data = $this->get_product_bundle_data( $translated_bundle_id );
539
-
540
- $bundle_id =& $job->original_doc_id;
541
-
542
- $bundle_data = $this->get_product_bundle_data( $bundle_id );
543
-
544
- foreach( $data as $value){
545
-
546
- if( preg_match( '/product_bundles:([0-9]+):(.+)/', $value[ 'field_type' ], $matches ) ){
547
-
548
- $product_id = $matches[1];
549
- $field = $matches[2];
550
-
551
- $translated_product_id = apply_filters( 'translate_object_id', $product_id, get_post_type( $product_id ), false, $job->language_code );
552
- $translated_item_id = $this->get_item_id_for_product_id( $translated_product_id, $translated_bundle_id );
553
- if( empty( $translated_item_id ) ){
554
- $translated_item_id = $this->add_product_to_bundle( $translated_product_id, $translated_bundle_id, $bundle_id, $product_id );
555
- }
556
-
557
- $item_id = $this->get_item_id_for_product_id( $product_id, $bundle_id );
558
-
559
- if( !isset( $translated_bundle_data[ $translated_item_id ] ) ){
560
- $translated_bundle_data[ $translated_item_id ] = array(
561
- 'product_id' => $translated_product_id,
562
- 'hide_thumbnail' => $bundle_data[ $item_id ][ 'hide_thumbnail' ],
563
- 'override_title' => $bundle_data[ $item_id ][ 'override_title' ],
564
- 'product_title' => '',
565
- 'override_description' => $bundle_data[ $item_id ][ 'override_description' ],
566
- 'product_description' => '',
567
- 'optional' => $bundle_data[ $item_id ][ 'optional' ],
568
- 'bundle_quantity' => $bundle_data[ $item_id ][ 'bundle_quantity' ],
569
- 'bundle_quantity_max' => $bundle_data[ $item_id ][ 'bundle_quantity_max' ],
570
- 'bundle_discount' => $bundle_data[ $item_id ][ 'bundle_discount' ],
571
- 'single_product_visibility' => $bundle_data[ $item_id ][ 'single_product_visibility' ],
572
- 'cart_visibility' => $bundle_data[ $item_id ][ 'cart_visibility' ],
573
- 'order_visibility' => $bundle_data[ $item_id ][ 'order_visibility' ],
574
- 'stock_status' => $bundle_data[ $item_id ][ 'stock_status' ],
575
- 'max_stock' => $bundle_data[ $item_id ][ 'max_stock' ],
576
- 'quantity_min' => $bundle_data[ $item_id ][ 'quantity_min' ],
577
- 'quantity_max' => $bundle_data[ $item_id ][ 'quantity_max' ],
578
- 'shipped_individually' => $bundle_data[ $item_id ][ 'shipped_individually' ],
579
- 'priced_individually' => $bundle_data[ $item_id ][ 'priced_individually' ],
580
- 'single_product_price_visibility' => $bundle_data[ $item_id ][ 'single_product_price_visibility' ],
581
- 'cart_price_visibility' => $bundle_data[ $item_id ][ 'cart_price_visibility' ],
582
- 'order_price_visibility' => $bundle_data[ $item_id ][ 'order_price_visibility' ]
583
- );
584
- }
585
-
586
- $translated_bundle_data[ $translated_item_id ][ $field ] = $value[ 'data' ];
587
- }
588
-
589
- }
590
-
591
- $this->save_product_bundle_data( $translated_bundle_id, $translated_bundle_data );
592
- }
593
-
594
- private function add_product_to_bundle( $product_id, $bundle_id, $original_bundle_id, $original_product_id ){
595
- global $wpdb;
596
- $menu_order = $wpdb->get_var( $wpdb->prepare( "
597
  SELECT menu_order FROM {$wpdb->prefix}woocommerce_bundled_items
598
  WHERE bundle_id=%d AND product_id=%d
599
  ", $original_bundle_id, $original_product_id ) );
600
 
601
- $wpdb->insert( $wpdb->prefix . 'woocommerce_bundled_items',
602
- array(
603
- 'product_id' => $product_id,
604
- 'bundle_id' => $bundle_id,
605
- 'menu_order' => $menu_order,
606
- )
607
- );
608
 
609
- return $wpdb->insert_id;
610
- }
611
 
612
  /**
613
  * @param array $custom_fields
1
  <?php
2
 
3
+ class WCML_Product_Bundles {
4
 
5
+ /**
6
+ * @var WPML_Element_Translation_Package
7
+ */
8
+ public $tp;
9
 
10
+ /**
11
+ * @var SitePress
12
+ */
13
+ private $sitepress;
14
 
15
+ /**
16
+ * @var woocommerce_wpml
17
+ */
18
+ private $woocommerce_wpml;
19
 
20
  /**
21
  * @var WCML_WC_Product_Bundles_Items
22
  */
23
  private $product_bundles_items;
24
 
25
+ /**
26
+ * WCML_Product_Bundles constructor.
27
+ */
28
+ function __construct( &$sitepress, &$woocommerce_wpml, &$product_bundles_items ) {
29
 
30
+ $this->sitepress = $sitepress;
31
+ $this->woocommerce_wpml = $woocommerce_wpml;
32
+ $this->product_bundles_items = $product_bundles_items;
33
 
34
  add_action( 'woocommerce_get_cart_item_from_session', array( $this, 'resync_bundle' ), 5, 3 );
35
  add_filter( 'woocommerce_cart_loaded_from_session', array( $this, 'resync_bundle_clean' ), 10 );
36
 
37
+ if ( is_admin() ) {
38
+ $this->tp = new WPML_Element_Translation_Package();
39
 
40
+ add_filter( 'wpml_tm_translation_job_data', array(
41
+ $this,
42
+ 'append_bundle_data_translation_package'
43
+ ), 10, 2 );
44
+ add_action( 'wpml_translation_job_saved', array( $this, 'save_bundle_data_translation' ), 10, 3 );
45
 
46
+ add_action( 'wcml_gui_additional_box_html', array( $this, 'custom_box_html' ), 10, 3 );
47
+ add_filter( 'wcml_gui_additional_box_data', array( $this, 'custom_box_html_data' ), 10, 4 );
48
 
49
+ add_action( 'wcml_after_duplicate_product_post_meta', array( $this, 'sync_bundled_ids' ), 10, 2 );
50
+ add_action( 'wcml_update_extra_fields', array( $this, 'bundle_update' ), 10, 4 );
51
 
52
+ add_action( 'wp_insert_post', array( $this, 'sync_product_bundle_meta_with_translations' ), 10 );
53
 
54
+ }
55
 
56
+ // product bundle using separate custom fields for prices
57
+ if ( wcml_is_multi_currency_on() ) {
58
+ add_filter( 'wcml_price_custom_fields_filtered', array( $this, 'get_price_custom_fields' ) );
59
+ }
60
 
61
+ }
62
 
63
+ private function get_product_bundle_data( $bundle_id ) {
64
  $product_bundle_data = array();
65
 
66
  $bundle_items = $this->product_bundles_items->get_items( $bundle_id );
67
+ foreach ( $bundle_items as $key => $bundle_item ) {
68
  $product_bundle_data[ $bundle_item->item_id ] = $this->product_bundles_items->get_item_data( $bundle_item );
69
  }
70
 
71
  return $product_bundle_data;
72
  }
73
 
74
+ private function save_product_bundle_data( $bundle_id, $product_bundle_data ) {
75
 
76
  $bundle_items = $this->product_bundles_items->get_items( $bundle_id );
77
 
78
+ foreach ( $bundle_items as $item_id => $bundle_item ) {
79
  $bundled_item_data = $this->product_bundles_items->get_item_data_object( $item_id );
80
 
81
+ foreach ( $product_bundle_data[ $item_id ] as $key => $value ) {
82
+ $this->product_bundles_items->update_item_meta( $bundled_item_data, $key, $value );
83
  }
84
  $this->product_bundles_items->save_item_meta( $bundled_item_data );
85
  }
86
 
87
  }
88
 
89
+ private function sync_product_bundle_meta( $bundle_id, $translated_bundle_id ) {
90
 
91
+ $bundle_items = $this->product_bundles_items->get_items( $bundle_id );
92
  $fields_to_sync = array(
93
  'optional',
94
  'stock_status',
105
  'order_price_visibility'
106
  );
107
 
108
+ $target_lang = $this->sitepress->get_language_for_element( $translated_bundle_id, 'post_product' );
109
  $translated_item_ids = array();
110
+ foreach ( $bundle_items as $item_id => $bundle_item ) {
111
 
112
+ $item_meta = $this->product_bundles_items->get_item_data( $bundle_item );
113
  $translated_product_id = apply_filters( 'translate_object_id', $item_meta['product_id'], get_post_type( $item_meta['product_id'] ), false, $target_lang );
114
 
115
+ if ( $translated_product_id ) {
116
+ $translated_item_id = $this->get_item_id_for_product_id( $translated_product_id, $translated_bundle_id );
117
  $translated_item_ids[] = $translated_item_id;
118
 
119
  $translated_item = $this->product_bundles_items->get_item_data_object( $translated_item_id );
120
+ foreach ( $fields_to_sync as $key ) {
121
+ $this->product_bundles_items->update_item_meta( $translated_item, $key, $item_meta[ $key ] );
122
  }
123
  $this->product_bundles_items->save_item_meta( $translated_item );
124
 
137
 
138
  }
139
 
140
+ public function sync_product_bundle_meta_with_translations( $bundle_id ) {
141
 
142
  if ( WooCommerce_Functions_Wrapper::get_product_type( $bundle_id ) === 'bundle' ) {
143
 
144
+ $trid = $this->sitepress->get_element_trid( $bundle_id, 'post_product' );
145
  $translations = $this->sitepress->get_element_translations( $trid, 'post_product' );
146
 
147
  foreach ( $translations as $language => $translation ) {
162
 
163
  }
164
 
165
+ private function get_product_id_for_item_id( $item_id ) {
166
  global $wpdb;
167
+
168
  return $wpdb->get_var( $wpdb->prepare(
169
+ "SELECT product_id FROM {$wpdb->prefix}woocommerce_bundled_items WHERE bundled_item_id=%d", $item_id ) );
170
  }
171
 
172
+ private function get_item_id_for_product_id( $product_id, $bundle_id ) {
173
  global $wpdb;
174
+
175
  return $wpdb->get_var( $wpdb->prepare(
176
  "SELECT bundled_item_id FROM {$wpdb->prefix}woocommerce_bundled_items WHERE product_id=%d AND bundle_id=%d",
177
  $product_id, $bundle_id
179
  }
180
 
181
  // Add Bundles Box to WCML Translation GUI
182
+ public function custom_box_html( $obj, $bundle_id, $data ) {
183
 
184
  $bundle_items = $this->product_bundles_items->get_items( $bundle_id );
185
 
186
+ if ( empty( $bundle_items ) ) {
187
  return false;
188
  }
189
 
191
 
192
  end( $bundle_items );
193
  $last_item_id = key( $bundle_items );
194
+ $divider = true;
195
+ $flag = false;
196
 
197
  foreach ( $bundle_items as $item_id => $bundle_item ) {
198
 
199
  $translated_product = apply_filters( 'translate_object_id', $bundle_item->product_id, get_post_type( $bundle_item->product_id ), false, $obj->get_target_language() );
200
+ if ( ! is_null( $translated_product ) ) {
201
 
202
  $add_group = false;
203
+ if ( $item_id == $last_item_id ) {
204
  $divider = false;
205
  }
206
 
208
 
209
  $group = new WPML_Editor_UI_Field_Group( get_the_title( $bundle_item->product_id ), $divider );
210
 
211
+ if ( $bundle_item_data['override_title'] == 'yes' ) {
212
  $bundle_field = new WPML_Editor_UI_Single_Line_Field(
213
  'bundle_' . $bundle_item->product_id . '_title',
214
  __( 'Name', 'woocommerce-multilingual' ),
219
  $add_group = true;
220
  }
221
 
222
+ if ( $bundle_item_data['override_description'] == 'yes' ) {
223
  $bundle_field = new WPML_Editor_UI_Single_Line_Field(
224
+ 'bundle_' . $bundle_item->product_id . '_desc',
225
  __( 'Description', 'woocommerce-multilingual' ),
226
  $data,
227
  false
230
  $add_group = true;
231
  }
232
 
233
+ if ( $add_group ) {
234
  $bundles_section->add_field( $group );
235
  $flag = true;
236
  }
239
 
240
  }
241
 
242
+ if ( $flag ) {
243
  $obj->add_field( $bundles_section );
244
  }
245
 
246
  }
247
 
248
+ public function custom_box_html_data( $data, $bundle_id, $translation, $lang ) {
249
 
250
  $bundle_data = $this->get_product_bundle_data( $bundle_id );
251
 
252
+ if ( $translation ) {
253
+ $translated_bundle_id = $translation->ID;
254
  $translated_bundle_data = $this->get_product_bundle_data( $translated_bundle_id );
255
  }
256
 
257
+ if ( empty( $bundle_data ) || $bundle_data == false ) {
258
  return $data;
259
  }
260
 
265
  $product_id = $this->get_product_id_for_item_id( $item_id );
266
 
267
  $translated_product_id = apply_filters( 'translate_object_id', $product_id, get_post_type( $product_id ), false, $lang );
268
+ if ( $translation ) {
269
  $translated_item_id = $this->get_item_id_for_product_id( $translated_product_id, $translated_bundle_id );
270
  }
271
 
272
+ if ( $bundle_data[ $item_id ]['override_title'] == 'yes' ) {
273
+ $data[ 'bundle_' . $product_id . '_title' ] = array( 'original' => $bundle_data[ $item_id ]['title'] );
274
+ if ( $translation && isset( $translated_bundle_data[ $translated_item_id ]['override_title'] ) ) {
275
+ $data[ 'bundle_' . $product_id . '_title' ]['translation'] = $translated_bundle_data[ $translated_item_id ]['title'];
276
+ } else {
277
+ $data[ 'bundle_' . $product_id . '_title' ]['translation'] = '';
278
  }
279
  }
280
 
281
+ if ( $bundle_data[ $item_id ]['override_description'] == 'yes' ) {
282
+ $data[ 'bundle_' . $product_id . '_desc' ] = array( 'original' => $bundle_data[ $item_id ]['description'] );
283
+ if ( $translation && isset( $translated_bundle_data[ $translated_item_id ]['override_description'] ) ) {
284
+ $data[ 'bundle_' . $product_id . '_desc' ]['translation'] = $translated_bundle_data[ $translated_item_id ]['description'];
285
+ } else {
286
+ $data[ 'bundle_' . $product_id . '_desc' ]['translation'] = '';
287
  }
288
  }
289
  }
290
+
291
  return $data;
292
  }
293
 
294
+ public function append_bundle_data_translation_package( $package, $post ) {
295
 
296
+ if ( $post->post_type == 'product' ) {
297
 
298
  $bundle_data = $this->get_product_bundle_data( $post->ID );
299
 
300
+ if ( $bundle_data ) {
301
 
302
  $fields = array( 'title', 'description' );
303
 
304
+ foreach ( $bundle_data as $item_id => $product_data ) {
305
 
306
  $product_id = $this->get_product_id_for_item_id( $item_id );
307
+ foreach ( $fields as $field ) {
308
+ if ( $product_data[ 'override_' . $field ] == 'yes' && ! empty( $product_data[ $field ] ) ) {
309
+ $package['contents'][ 'product_bundles:' . $product_id . ':' . $field ] = array(
310
  'translate' => 1,
311
+ 'data' => $this->tp->encode_field_data( $product_data[ $field ], 'base64' ),
312
+ 'format' => 'base64'
313
  );
314
  }
315
  }
322
  }
323
 
324
  // Update Bundled products title and description after saving the translation
325
+ public function bundle_update( $bundle_id, $translated_bundle_id, $data, $lang ) {
326
  global $wpdb;
327
 
328
+ $bundle_data = $this->get_product_bundle_data( $bundle_id );
329
  $translated_bundle_data = $this->get_product_bundle_data( $translated_bundle_id );
330
 
331
+ if ( empty( $bundle_data ) ) {
332
  return;
333
  }
334
 
335
  $translate_bundled_item_ids = $wpdb->get_col( $wpdb->prepare(
336
+ "SELECT product_id FROM {$wpdb->prefix}woocommerce_bundled_items WHERE bundle_id = %d", $translated_bundle_id ) );
337
 
338
  foreach ( $bundle_data as $item_id => $bundle_item_data ) {
339
 
340
+ $product_id = $this->get_product_id_for_item_id( $item_id );
341
  $translated_product_id = apply_filters( 'translate_object_id', $product_id, get_post_type( $product_id ), false, $lang );
342
 
343
+ if ( $translated_product_id ) {
344
 
345
  if ( ! in_array( $translated_product_id, $translate_bundled_item_ids ) ) {
346
 
379
  $this->save_product_bundle_data( $translated_bundle_id, $translated_bundle_data );
380
  $this->sync_product_bundle_meta( $bundle_id, $translated_bundle_id );
381
 
382
+ $this->sitepress->copy_custom_fields( $bundle_id, $translated_bundle_id );
383
 
384
  return $translated_bundle_data;
385
  }
386
 
387
  // Sync product bundle data with translated values when the product is duplicated
388
+ public function sync_bundled_ids( $bundle_id, $translated_bundle_id ) {
389
  global $wpdb;
390
 
391
+ $bundle_data = $this->get_product_bundle_data( $bundle_id );
392
+ if ( $bundle_data ) {
393
+ $lang = $this->sitepress->get_language_for_element( $translated_bundle_id, 'post_product' );
394
+ $translated_bundle_data = $this->get_product_bundle_data( $translated_bundle_id );
395
 
396
+ foreach ( $bundle_data as $item_id => $product_data ) {
397
 
398
+ $product_id = $this->get_product_id_for_item_id( $item_id );
399
+ $translated_product_id = apply_filters( 'translate_object_id', $product_id, get_post_type( $product_id ), false, $lang );
400
 
401
+ if ( $translated_product_id ) {
402
 
403
+ $translated_item_id = $this->get_item_id_for_product_id( $translated_product_id, $translated_bundle_id );
404
+ if ( ! $translated_item_id ) {
405
+ $menu_order = $wpdb->get_var( $wpdb->prepare( "
406
  SELECT menu_order FROM {$wpdb->prefix}woocommerce_bundled_items
407
  WHERE bundle_id=%d AND product_id=%d
408
  ", $bundle_id, $product_id ) );
409
 
410
+ $wpdb->insert( $wpdb->prefix . 'woocommerce_bundled_items',
411
+ array(
412
+ 'product_id' => $translated_product_id,
413
+ 'bundle_id' => $translated_bundle_id,
414
+ 'menu_order' => $menu_order,
415
+ )
416
+ );
417
+ $translated_item_id = $wpdb->insert_id;
418
+ }
419
+
420
+ $translated_bundle_data[ $translated_item_id ] = $product_data;
421
+ $translated_bundle_data[ $translated_item_id ]['product_id'] = $translated_product_id;
422
+
423
+ if ( isset( $bundle_data['title'] ) ) {
424
+ if ( $bundle_data['override_title'] != 'yes' ) {
425
+ $translated_bundle_data[ $translated_item_id ]['title'] = get_the_title( $translated_product_id );
426
+ }
427
+ }
428
+
429
+ if ( isset( $bundle_data['title'] ) ) {
430
+ if ( $bundle_data['override_description'] != 'yes' ) {
431
+ $translated_bundle_data[ $translated_item_id ]['description'] = get_the_title( $translated_product_id );
432
+ }
433
+ }
434
+
435
+ if ( isset( $bundle_data['filter_variations'] ) && $bundle_data['filter_variations'] == 'yes' ) {
436
+ $allowed_var = $bundle_data['allowed_variations'];
437
+ foreach ( $allowed_var as $key => $var_id ) {
438
+ $translated_var_id = apply_filters( 'translate_object_id', $var_id, get_post_type( $var_id ), true, $lang );
439
+ $translated_bundle_data[ $translated_item_id ]['allowed_variations'][ $key ] = $translated_var_id;
440
+ }
441
+ }
442
+
443
+
444
+ if ( isset( $bundle_data['bundle_defaults'] ) && ! empty( $bundle_data['bundle_defaults'] ) ) {
445
+ foreach ( $bundle_data['bundle_defaults'] as $tax => $term_slug ) {
446
+
447
+ $term_id = $this->woocommerce_wpml->terms->wcml_get_term_id_by_slug( $tax, $term_slug );
448
+ if ( $term_id ) {
449
+ // Global Attribute
450
+ $tr_def_id = apply_filters( 'translate_object_id', $term_id, $tax, true, $lang );
451
+ $tr_term = $this->woocommerce_wpml->terms->wcml_get_term_by_id( $tr_def_id, $tax );
452
+ $translated_bundle_data[ $translated_item_id ]['bundle_defaults'][ $tax ] = $tr_term->slug;
453
+ } else {
454
+ // Custom Attribute
455
+ $args = array(
456
+ 'post_type' => 'product_variation',
457
+ 'meta_key' => 'attribute_' . $tax,
458
+ 'meta_value' => $term_slug,
459
+ 'meta_compare' => '='
460
+ );
461
+ $variationloop = new WP_Query( $args );
462
+ while ( $variationloop->have_posts() ) : $variationloop->the_post();
463
+ $tr_var_id = apply_filters( 'translate_object_id', get_the_ID(), 'product_variation', true, $lang );
464
+ $tr_meta = get_post_meta( $tr_var_id, 'attribute_' . $tax, true );
465
+ $translated_bundle_data[ $translated_item_id ]['bundle_defaults'][ $tax ] = $tr_meta;
466
+ endwhile;
467
+ }
468
+ }
469
+ }
470
+
471
+ }
472
+
473
+
474
+ }
475
+
476
+ $this->save_product_bundle_data( $translated_bundle_id, $translated_bundle_data );
477
+
478
+ return $translated_bundle_data;
479
+ }
480
+
481
+ }
482
+
483
+ public function resync_bundle( $cart_item, $session_values, $cart_item_key ) {
484
+
485
+ if ( isset( $cart_item['bundled_items'] ) && $cart_item['data']->product_type === 'bundle' ) {
486
+ $current_bundle_id = apply_filters( 'translate_object_id', $cart_item['product_id'], 'product', true );
487
+ if ( $cart_item['product_id'] != $current_bundle_id ) {
488
+ if ( isset( $cart_item['data']->bundle_data ) && is_array( $cart_item['data']->bundle_data ) ) {
489
+ $old_bundled_item_ids = array_keys( $cart_item['data']->bundle_data );
490
+ $cart_item['data'] = wc_get_product( $current_bundle_id );
491
+ if ( isset( $cart_item['data']->bundle_data ) && is_array( $cart_item['data']->bundle_data ) ) {
492
+ $new_bundled_item_ids = array_keys( $cart_item['data']->bundle_data );
493
+ $remapped_bundled_item_ids = array();
494
+ foreach ( $old_bundled_item_ids as $old_item_id_index => $old_item_id ) {
495
+ $remapped_bundled_item_ids[ $old_item_id ] = $new_bundled_item_ids[ $old_item_id_index ];
496
+ }
497
+ $cart_item['remapped_bundled_item_ids'] = $remapped_bundled_item_ids;
498
+ if ( isset( $cart_item['stamp'] ) ) {
499
+ $new_stamp = array();
500
+ foreach ( $cart_item['stamp'] as $bundled_item_id => $stamp_data ) {
501
+ $new_stamp[ $remapped_bundled_item_ids[ $bundled_item_id ] ] = $stamp_data;
502
+ }
503
+ $cart_item['stamp'] = $new_stamp;
504
+ }
505
+ }
506
+ }
507
+ }
508
+ }
509
+ if ( isset( $cart_item['bundled_by'] ) && isset( WC()->cart->cart_contents[ $cart_item['bundled_by'] ] ) ) {
510
+ $bundle_cart_item = WC()->cart->cart_contents[ $cart_item['bundled_by'] ];
511
+ if (
512
+ isset( $bundle_cart_item['remapped_bundled_item_ids'] ) &&
513
+ isset( $cart_item['bundled_item_id'] ) &&
514
+ isset( $bundle_cart_item['remapped_bundled_item_ids'][ $cart_item['bundled_item_id'] ] )
515
+ ) {
516
+ $old_id = $cart_item['bundled_item_id'];
517
+ $remapped_bundled_item_ids = $bundle_cart_item['remapped_bundled_item_ids'];
518
+ $cart_item['bundled_item_id'] = $remapped_bundled_item_ids[ $cart_item['bundled_item_id'] ];
519
+ if ( isset( $cart_item['stamp'] ) ) {
520
+ $new_stamp = array();
521
+ foreach ( $cart_item['stamp'] as $bundled_item_id => $stamp_data ) {
522
+ $new_stamp[ $remapped_bundled_item_ids[ $bundled_item_id ] ] = $stamp_data;
523
+ }
524
+ $cart_item['stamp'] = $new_stamp;
525
+ }
526
  }
527
+ }
528
+
529
+ return $cart_item;
530
+ }
531
+
532
+ public function resync_bundle_clean( $cart ) {
533
+ foreach ( $cart->cart_contents as $cart_item_key => $cart_item ) {
534
+ if ( isset( $cart_item['bundled_items'] ) && WooCommerce_Functions_Wrapper::get_product_type( $cart_item['product_id'] ) === 'bundle' ) {
535
+ if ( isset( $cart_item['remapped_bundled_item_ids'] ) ) {
536
+ unset( WC()->cart->cart_contents[ $cart_item_key ]['remapped_bundled_item_ids'] );
537
+ }
538
+ }
539
+ }
540
+ }
541
+
542
+ public function save_bundle_data_translation( $translated_bundle_id, $data, $job ) {
543
+
544
+ remove_action( 'wcml_after_duplicate_product_post_meta', array( $this, 'sync_bundled_ids' ), 10, 2 );
545
+
546
+ $translated_bundle_data = $this->get_product_bundle_data( $translated_bundle_id );
547
+
548
+ $bundle_id =& $job->original_doc_id;
549
+
550
+ $bundle_data = $this->get_product_bundle_data( $bundle_id );
551
+
552
+ foreach ( $data as $value ) {
553
+
554
+ if ( preg_match( '/product_bundles:([0-9]+):(.+)/', $value['field_type'], $matches ) ) {
555
+
556
+ $product_id = $matches[1];
557
+ $field = $matches[2];
558
+
559
+ $translated_product_id = apply_filters( 'translate_object_id', $product_id, get_post_type( $product_id ), false, $job->language_code );
560
+ $translated_item_id = $this->get_item_id_for_product_id( $translated_product_id, $translated_bundle_id );
561
+ if ( empty( $translated_item_id ) ) {
562
+ $translated_item_id = $this->add_product_to_bundle( $translated_product_id, $translated_bundle_id, $bundle_id, $product_id );
563
+ }
564
+
565
+ $item_id = $this->get_item_id_for_product_id( $product_id, $bundle_id );
566
+
567
+ if ( ! isset( $translated_bundle_data[ $translated_item_id ] ) ) {
568
+ $translated_bundle_data[ $translated_item_id ] = array(
569
+ 'product_id' => $translated_product_id,
570
+ 'hide_thumbnail' => $bundle_data[ $item_id ]['hide_thumbnail'],
571
+ 'override_title' => $bundle_data[ $item_id ]['override_title'],
572
+ 'product_title' => '',
573
+ 'override_description' => $bundle_data[ $item_id ]['override_description'],
574
+ 'product_description' => '',
575
+ 'optional' => $bundle_data[ $item_id ]['optional'],
576
+ 'bundle_quantity' => $bundle_data[ $item_id ]['bundle_quantity'],
577
+ 'bundle_quantity_max' => $bundle_data[ $item_id ]['bundle_quantity_max'],
578
+ 'bundle_discount' => $bundle_data[ $item_id ]['bundle_discount'],
579
+ 'single_product_visibility' => $bundle_data[ $item_id ]['single_product_visibility'],
580
+ 'cart_visibility' => $bundle_data[ $item_id ]['cart_visibility'],
581
+ 'order_visibility' => $bundle_data[ $item_id ]['order_visibility'],
582
+ 'stock_status' => $bundle_data[ $item_id ]['stock_status'],
583
+ 'max_stock' => $bundle_data[ $item_id ]['max_stock'],
584
+ 'quantity_min' => $bundle_data[ $item_id ]['quantity_min'],
585
+ 'quantity_max' => $bundle_data[ $item_id ]['quantity_max'],
586
+ 'shipped_individually' => $bundle_data[ $item_id ]['shipped_individually'],
587
+ 'priced_individually' => $bundle_data[ $item_id ]['priced_individually'],
588
+ 'single_product_price_visibility' => $bundle_data[ $item_id ]['single_product_price_visibility'],
589
+ 'cart_price_visibility' => $bundle_data[ $item_id ]['cart_price_visibility'],
590
+ 'order_price_visibility' => $bundle_data[ $item_id ]['order_price_visibility']
591
+ );
592
+ }
593
+
594
+ $translated_bundle_data[ $translated_item_id ][ $field ] = $value['data'];
595
+ }
596
+
597
+ }
598
+
599
+ $this->save_product_bundle_data( $translated_bundle_id, $translated_bundle_data );
600
+ }
601
+
602
+ private function add_product_to_bundle( $product_id, $bundle_id, $original_bundle_id, $original_product_id ) {
603
+ global $wpdb;
604
+ $menu_order = $wpdb->get_var( $wpdb->prepare( "
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
605
  SELECT menu_order FROM {$wpdb->prefix}woocommerce_bundled_items
606
  WHERE bundle_id=%d AND product_id=%d
607
  ", $original_bundle_id, $original_product_id ) );
608
 
609
+ $wpdb->insert( $wpdb->prefix . 'woocommerce_bundled_items',
610
+ array(
611
+ 'product_id' => $product_id,
612
+ 'bundle_id' => $bundle_id,
613
+ 'menu_order' => $menu_order,
614
+ )
615
+ );
616
 
617
+ return $wpdb->insert_id;
618
+ }
619
 
620
  /**
621
  * @param array $custom_fields
inc/class-wcml-emails.php CHANGED
@@ -248,7 +248,7 @@ class WCML_Emails{
248
 
249
  function filter_payment_method_string( $title, $object_id, $meta_key, $single ){
250
 
251
- if( '_payment_method_title' === $meta_key ){
252
 
253
  remove_filter( 'get_post_metadata', array( $this, 'filter_payment_method_string' ), 10, 4 );
254
  $payment_gateway = wc_get_payment_gateway_by_order( $object_id );
248
 
249
  function filter_payment_method_string( $title, $object_id, $meta_key, $single ){
250
 
251
+ if( $object_id && 'shop_order' === get_post_type( $object_id ) && '_payment_method_title' === $meta_key ){
252
 
253
  remove_filter( 'get_post_metadata', array( $this, 'filter_payment_method_string' ), 10, 4 );
254
  $payment_gateway = wc_get_payment_gateway_by_order( $object_id );
inc/class-wcml-url-translation.php CHANGED
@@ -527,9 +527,8 @@ class WCML_Url_Translation {
527
  if ( ( $taxonomy == 'product_cat' || $taxonomy == 'product_tag' || ( ! empty( $wc_taxonomies_wc_format ) && in_array( $taxonomy, $wc_taxonomies_wc_format ) ) ) && ! $no_recursion_flag ) {
528
 
529
  $cache_key = 'termlink#' . $taxonomy . '#' . $term->term_id;
530
- if ( false && $link = wp_cache_get( $cache_key, 'terms' ) ) {
531
  $termlink = $link;
532
-
533
  } else {
534
 
535
  $no_recursion_flag = false;
@@ -542,7 +541,7 @@ class WCML_Url_Translation {
542
 
543
  if ( $term_language ) {
544
 
545
- $slug_details = $this->get_translated_tax_slug( $taxonomy, $term_language, true );
546
 
547
  $base = $slug_details['slug'];
548
  $base_translated = $slug_details['translated_slug'];
@@ -597,7 +596,7 @@ class WCML_Url_Translation {
597
  return $termlink;
598
  }
599
 
600
- function get_translated_tax_slug( $taxonomy, $language = false, $return_gettext_slug = false ) {
601
  global $sitepress, $woocommerce_wpml;
602
 
603
  switch ( $taxonomy ) {
@@ -607,9 +606,6 @@ class WCML_Url_Translation {
607
  $slug = $gettext_slug = trim( $this->wc_permalinks['tag_base'], '/' );
608
  } else {
609
  $slug = 'product-tag';
610
- if ( $return_gettext_slug ) {
611
- $gettext_slug = $this->default_product_tag_gettext_base;
612
- }
613
  }
614
 
615
  $string_language = $woocommerce_wpml->strings->get_string_language( $slug, $this->url_strings_context(), $this->url_string_name( $taxonomy ) );
@@ -622,9 +618,6 @@ class WCML_Url_Translation {
622
  $slug = $gettext_slug = trim( $this->wc_permalinks['category_base'], '/' );
623
  } else {
624
  $slug = 'product-category';
625
- if ( $return_gettext_slug ) {
626
- $gettext_slug = $this->default_product_category_gettext_base;
627
- }
628
  }
629
 
630
  $string_language = $woocommerce_wpml->strings->get_string_language( $slug, $this->url_strings_context(), $this->url_string_name( $taxonomy ) );
@@ -632,7 +625,7 @@ class WCML_Url_Translation {
632
  break;
633
 
634
  default:
635
- $slug = $gettext_slug = trim( $this->wc_permalinks['attribute_base'], '/' );
636
 
637
  $string_language = $woocommerce_wpml->strings->get_string_language( $slug, $this->url_strings_context(), $this->url_string_name( 'attribute' ) );
638
 
@@ -650,14 +643,14 @@ class WCML_Url_Translation {
650
  $slug_translation = apply_filters( 'wpml_translate_single_string', $slug, $this->url_strings_context(), $this->url_string_name( $taxonomy ), $language, false );
651
 
652
  return array(
653
- 'slug' => $return_gettext_slug ? $gettext_slug : $slug,
654
  'translated_slug' => $slug_translation
655
  );
656
  }
657
 
658
  return array(
659
- 'slug' => $return_gettext_slug ? $gettext_slug : $slug,
660
- 'translated_slug' => $return_gettext_slug && $language != $string_language ? $gettext_slug : $slug
661
  );
662
 
663
  }
527
  if ( ( $taxonomy == 'product_cat' || $taxonomy == 'product_tag' || ( ! empty( $wc_taxonomies_wc_format ) && in_array( $taxonomy, $wc_taxonomies_wc_format ) ) ) && ! $no_recursion_flag ) {
528
 
529
  $cache_key = 'termlink#' . $taxonomy . '#' . $term->term_id;
530
+ if ( $link = wp_cache_get( $cache_key, 'terms' ) ) {
531
  $termlink = $link;
 
532
  } else {
533
 
534
  $no_recursion_flag = false;
541
 
542
  if ( $term_language ) {
543
 
544
+ $slug_details = $this->get_translated_tax_slug( $taxonomy, $term_language );
545
 
546
  $base = $slug_details['slug'];
547
  $base_translated = $slug_details['translated_slug'];
596
  return $termlink;
597
  }
598
 
599
+ function get_translated_tax_slug( $taxonomy, $language = false ) {
600
  global $sitepress, $woocommerce_wpml;
601
 
602
  switch ( $taxonomy ) {
606
  $slug = $gettext_slug = trim( $this->wc_permalinks['tag_base'], '/' );
607
  } else {
608
  $slug = 'product-tag';
 
 
 
609
  }
610
 
611
  $string_language = $woocommerce_wpml->strings->get_string_language( $slug, $this->url_strings_context(), $this->url_string_name( $taxonomy ) );
618
  $slug = $gettext_slug = trim( $this->wc_permalinks['category_base'], '/' );
619
  } else {
620
  $slug = 'product-category';
 
 
 
621
  }
622
 
623
  $string_language = $woocommerce_wpml->strings->get_string_language( $slug, $this->url_strings_context(), $this->url_string_name( $taxonomy ) );
625
  break;
626
 
627
  default:
628
+ $slug = trim( $this->wc_permalinks['attribute_base'], '/' );
629
 
630
  $string_language = $woocommerce_wpml->strings->get_string_language( $slug, $this->url_strings_context(), $this->url_string_name( 'attribute' ) );
631
 
643
  $slug_translation = apply_filters( 'wpml_translate_single_string', $slug, $this->url_strings_context(), $this->url_string_name( $taxonomy ), $language, false );
644
 
645
  return array(
646
+ 'slug' => $slug,
647
  'translated_slug' => $slug_translation
648
  );
649
  }
650
 
651
  return array(
652
+ 'slug' => $slug,
653
+ 'translated_slug' => $slug
654
  );
655
 
656
  }
inc/class-woocommerce-wpml.php CHANGED
@@ -156,6 +156,8 @@ class woocommerce_wpml {
156
  || ( isset( $_POST[ 'action' ] ) && in_array( $_POST[ 'action' ], $actions_that_need_mc ) )
157
  ){
158
  $this->multi_currency = new WCML_Multi_Currency;
 
 
159
  }else{
160
  add_shortcode('currency_switcher', '__return_empty_string');
161
  }
156
  || ( isset( $_POST[ 'action' ] ) && in_array( $_POST[ 'action' ], $actions_that_need_mc ) )
157
  ){
158
  $this->multi_currency = new WCML_Multi_Currency;
159
+ $wcml_price_filters = new WCML_Price_Filter( $this );
160
+ $wcml_price_filters->add_hooks();
161
  }else{
162
  add_shortcode('currency_switcher', '__return_empty_string');
163
  }
inc/currencies/class-wcml-price-filter.php ADDED
@@ -0,0 +1,52 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class WCML_Price_Filter {
4
+
5
+ /**
6
+ * @var woocommerce_wpml;
7
+ */
8
+ private $woocommerce_wpml;
9
+
10
+ public function __construct( woocommerce_wpml &$woocommerce_wpml ) {
11
+ $this->woocommerce_wpml = $woocommerce_wpml;
12
+ }
13
+
14
+ public function add_hooks() {
15
+ add_action( 'wp_footer', array( $this, 'override_currency_symbol' ), 100 );
16
+
17
+ if ( ! is_admin() ) {
18
+ add_filter( 'woocommerce_product_query_meta_query', array( $this, 'unconvert_price_filter_limits' ) );
19
+ }
20
+
21
+ }
22
+
23
+ public function override_currency_symbol() {
24
+ ?>
25
+ <script type="text/javascript">
26
+ /* <![CDATA[ */
27
+ woocommerce_price_slider_params.currency_format_symbol = wcml_mc_settings.current_currency.symbol;
28
+ /* ]]> */
29
+ </script>
30
+ <?php
31
+ }
32
+
33
+ /**
34
+ * @param array $meta_query
35
+ *
36
+ * @return array
37
+ */
38
+ public function unconvert_price_filter_limits( $meta_query ) {
39
+
40
+ $multi_currency = $this->woocommerce_wpml->multi_currency;
41
+
42
+ if ( $multi_currency->get_client_currency() !== get_option( 'woocommerce_currency' ) ) {
43
+ if ( isset( $meta_query['price_filter'] ) && isset($meta_query['price_filter']['key']) && $meta_query['price_filter']['key'] === '_price' ) {
44
+ $meta_query['price_filter']['value'][0] = $multi_currency->prices->unconvert_price_amount( $meta_query['price_filter']['value'][0] );
45
+ $meta_query['price_filter']['value'][1] = $multi_currency->prices->unconvert_price_amount( $meta_query['price_filter']['value'][1] );
46
+ }
47
+ }
48
+
49
+ return $meta_query;
50
+ }
51
+
52
+ }
inc/currencies/currency-switcher/class-wcml-currency-switcher-templates.php CHANGED
@@ -79,7 +79,7 @@ class WCML_Currency_Switcher_Templates {
79
  }
80
  }
81
  }
82
- }elseif( isset( $wcml_settings[ 'currency_switcher_product_visibility' ] ) && $wcml_settings[ 'currency_switcher_product_visibility' ] === 1 ){
83
  //set default template to active
84
  $templates['wcml-dropdown'] = $this->templates['wcml-dropdown'];
85
  }
@@ -144,13 +144,6 @@ class WCML_Currency_Switcher_Templates {
144
  $templates = array();
145
  $dirs_to_scan = array();
146
 
147
- /**
148
- * Filter the directories to scan
149
- *
150
- * @param array $dirs_to_scan
151
- */
152
- $dirs_to_scan = apply_filters( 'wcml_cs_directories_to_scan', $dirs_to_scan );
153
-
154
  $sub_dir = $this->ds . 'templates' . $this->ds . 'currency-switchers';
155
 
156
  $wcml_core_path = WCML_PLUGIN_PATH . $sub_dir;
@@ -160,6 +153,13 @@ class WCML_Currency_Switcher_Templates {
160
 
161
  array_unshift( $dirs_to_scan, $wcml_core_path, $theme_path, $child_theme_path, $uploads_path );
162
 
 
 
 
 
 
 
 
163
  $templates_paths = $this->scan_template_paths( $dirs_to_scan );
164
 
165
  foreach ( $templates_paths as $template_path ) {
79
  }
80
  }
81
  }
82
+ }else{
83
  //set default template to active
84
  $templates['wcml-dropdown'] = $this->templates['wcml-dropdown'];
85
  }
144
  $templates = array();
145
  $dirs_to_scan = array();
146
 
 
 
 
 
 
 
 
147
  $sub_dir = $this->ds . 'templates' . $this->ds . 'currency-switchers';
148
 
149
  $wcml_core_path = WCML_PLUGIN_PATH . $sub_dir;
153
 
154
  array_unshift( $dirs_to_scan, $wcml_core_path, $theme_path, $child_theme_path, $uploads_path );
155
 
156
+ /**
157
+ * Filter the directories to scan
158
+ *
159
+ * @param array $dirs_to_scan
160
+ */
161
+ $dirs_to_scan = apply_filters( 'wcml_cs_directories_to_scan', $dirs_to_scan );
162
+
163
  $templates_paths = $this->scan_template_paths( $dirs_to_scan );
164
 
165
  foreach ( $templates_paths as $template_path ) {
inc/translation-editor/class-wcml-editor-ui-product-job.php CHANGED
@@ -238,6 +238,21 @@ class WCML_Editor_UI_Product_Job extends WPML_Editor_UI_Job {
238
  }
239
  }
240
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
241
  $taxonomies = get_object_taxonomies( 'product', 'objects' );
242
  foreach( $taxonomies as $taxonomy => $taxonomy_obj ){
243
  if( $taxonomy != 'product_type' && is_taxonomy_translated( $taxonomy ) ){
@@ -251,7 +266,7 @@ class WCML_Editor_UI_Product_Job extends WPML_Editor_UI_Job {
251
  ){
252
  continue;
253
  }
254
- $term_field = new WPML_Editor_UI_Single_Line_Field( 't_'. $term->term_id, '', $this->data, false );
255
  $tax_section->add_field( $term_field );
256
  }
257
  if( isset( $term_field ) ){
@@ -261,15 +276,6 @@ class WCML_Editor_UI_Product_Job extends WPML_Editor_UI_Job {
261
  }
262
  }
263
 
264
- if( $this->product_type === 'external' ){
265
- $external_product_section = new WPML_Editor_UI_Field_Section( __( 'External Product', 'woocommerce-multilingual' ) );
266
- $external_product_section->add_field( new WPML_Editor_UI_Single_Line_Field( '_product_url', __( 'Product url', 'woocommerce-multilingual' ), $this->data, true ) );
267
- $external_product_section->add_field( new WPML_Editor_UI_Single_Line_Field( '_button_text', __( 'Button text', 'woocommerce-multilingual' ), $this->data, true ) );
268
- $this->add_field( $external_product_section );
269
- }
270
-
271
- do_action( 'wcml_gui_additional_box_html', $this, $this->product_id, $this->data );
272
-
273
  }
274
 
275
  public function add_custom_fields_ui_section( $custom_fields_section, $custom_fields, $variation_id = false ){
@@ -374,26 +380,7 @@ class WCML_Editor_UI_Product_Job extends WPML_Editor_UI_Job {
374
  }
375
  }
376
 
377
- $taxonomies = get_object_taxonomies( 'product', 'objects' );
378
- foreach( $taxonomies as $taxonomy => $taxonomy_obj ){
379
- if( $taxonomy != 'product_type' && is_taxonomy_translated( $taxonomy ) ){
380
- $product_terms = wp_get_post_terms( $this->product_id, $taxonomy );
381
- if( $product_terms ){
382
- foreach( $product_terms as $term ){
383
- $translated_term = $this->woocommerce_wpml->terms->wcml_get_translated_term( $term->term_id, $taxonomy, $this->get_target_language() );
384
- if(
385
- $this->sitepress->get_setting( 'tm_block_retranslating_terms' ) &&
386
- $translated_term->term_id != $term->term_id
387
- ){
388
- continue;
389
- }
390
-
391
- $element_data[ 't_'.$term->term_id ] = array( 'original' => $term->name );
392
- $element_data[ 't_'.$term->term_id ][ 'translation' ] = $translated_term->term_id != $term->term_id ? $translated_term->name : '';
393
- }
394
- }
395
- }
396
- }
397
 
398
  $element_data = $this->add_custom_field_to_element_data( $element_data, $this->product_id, isset( $translation->ID ) ? $translation->ID : false, false );
399
 
@@ -449,6 +436,33 @@ class WCML_Editor_UI_Product_Job extends WPML_Editor_UI_Job {
449
  return $element_data;
450
  }
451
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
452
  public function add_custom_field_to_element_data( $element_data, $element_id, $translation_id, $is_variation = false ){
453
  $custom_fields = $this->get_product_custom_fields_to_translate( $element_id );
454
  if( $custom_fields ){
238
  }
239
  }
240
 
241
+ $this->add_taxonomies_ui_section();
242
+
243
+ if( $this->product_type === 'external' ){
244
+ $external_product_section = new WPML_Editor_UI_Field_Section( __( 'External Product', 'woocommerce-multilingual' ) );
245
+ $external_product_section->add_field( new WPML_Editor_UI_Single_Line_Field( '_product_url', __( 'Product url', 'woocommerce-multilingual' ), $this->data, true ) );
246
+ $external_product_section->add_field( new WPML_Editor_UI_Single_Line_Field( '_button_text', __( 'Button text', 'woocommerce-multilingual' ), $this->data, true ) );
247
+ $this->add_field( $external_product_section );
248
+ }
249
+
250
+ do_action( 'wcml_gui_additional_box_html', $this, $this->product_id, $this->data );
251
+
252
+ }
253
+
254
+ public function add_taxonomies_ui_section(){
255
+
256
  $taxonomies = get_object_taxonomies( 'product', 'objects' );
257
  foreach( $taxonomies as $taxonomy => $taxonomy_obj ){
258
  if( $taxonomy != 'product_type' && is_taxonomy_translated( $taxonomy ) ){
266
  ){
267
  continue;
268
  }
269
+ $term_field = new WPML_Editor_UI_Single_Line_Field( 't_'. $term->term_taxonomy_id, '', $this->data, false );
270
  $tax_section->add_field( $term_field );
271
  }
272
  if( isset( $term_field ) ){
276
  }
277
  }
278
 
 
 
 
 
 
 
 
 
 
279
  }
280
 
281
  public function add_custom_fields_ui_section( $custom_fields_section, $custom_fields, $variation_id = false ){
380
  }
381
  }
382
 
383
+ $element_data = $this->add_taxonomies_to_element_data( $element_data );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
384
 
385
  $element_data = $this->add_custom_field_to_element_data( $element_data, $this->product_id, isset( $translation->ID ) ? $translation->ID : false, false );
386
 
436
  return $element_data;
437
  }
438
 
439
+ public function add_taxonomies_to_element_data( $element_data ){
440
+
441
+ $taxonomies = get_object_taxonomies( 'product', 'objects' );
442
+
443
+ foreach( $taxonomies as $taxonomy => $taxonomy_obj ){
444
+ if( $taxonomy != 'product_type' && is_taxonomy_translated( $taxonomy ) ){
445
+ $product_terms = wp_get_post_terms( $this->product_id, $taxonomy );
446
+ if( !is_wp_error( $product_terms ) ){
447
+ foreach( $product_terms as $term ){
448
+ $translated_term = $this->woocommerce_wpml->terms->wcml_get_translated_term( $term->term_id, $taxonomy, $this->get_target_language() );
449
+ if(
450
+ $this->sitepress->get_setting( 'tm_block_retranslating_terms' ) &&
451
+ $translated_term->term_taxonomy_id != $term->term_taxonomy_id
452
+ ){
453
+ continue;
454
+ }
455
+
456
+ $element_data[ 't_'.$term->term_taxonomy_id ] = array( 'original' => $term->name );
457
+ $element_data[ 't_'.$term->term_taxonomy_id ][ 'translation' ] = $translated_term->term_taxonomy_id != $term->term_taxonomy_id ? $translated_term->name : '';
458
+ }
459
+ }
460
+ }
461
+ }
462
+
463
+ return $element_data;
464
+ }
465
+
466
  public function add_custom_field_to_element_data( $element_data, $element_id, $translation_id, $is_variation = false ){
467
  $custom_fields = $this->get_product_custom_fields_to_translate( $element_id );
468
  if( $custom_fields ){
inc/translation-editor/class-wcml-wc-admin-duplicate-product.php CHANGED
@@ -1,6 +1,6 @@
1
  <?php
2
 
3
- class WCML_WC_Admin_Duplicate_Product extends WC_Admin_Duplicate_Product{
4
 
5
  /**
6
  * @var woocommerce_wpml
@@ -68,6 +68,7 @@ class WCML_WC_Admin_Duplicate_Product extends WC_Admin_Duplicate_Product{
68
  $translations = $this->sitepress->get_element_translations( $trid, 'post_' . $post->post_type );
69
  $duplicated_products[ 'translations' ] = array();
70
  if( $translations ){
 
71
  foreach( $translations as $translation ){
72
  if( !$translation->original && $translation->element_id != $product_id ){
73
  $post_to_duplicate = $this->wpdb->get_row( $this->wpdb->prepare( "SELECT * FROM {$this->wpdb->posts} WHERE ID=%d", $translation->element_id ) );
@@ -105,11 +106,12 @@ class WCML_WC_Admin_Duplicate_Product extends WC_Admin_Duplicate_Product{
105
  public function wc_duplicate_product( $post_to_duplicate ){
106
 
107
  $product = wc_get_product( $post_to_duplicate->ID );
108
-
 
109
  if( WooCommerce_Functions_Wrapper::is_deprecated() ){
110
- $new_orig_id = $this->duplicate_product( $product );
111
  }else{
112
- $duplicate = $this->product_duplicate( $product );
113
  $new_orig_id = $duplicate->get_id();
114
  }
115
 
1
  <?php
2
 
3
+ class WCML_WC_Admin_Duplicate_Product{
4
 
5
  /**
6
  * @var woocommerce_wpml
68
  $translations = $this->sitepress->get_element_translations( $trid, 'post_' . $post->post_type );
69
  $duplicated_products[ 'translations' ] = array();
70
  if( $translations ){
71
+
72
  foreach( $translations as $translation ){
73
  if( !$translation->original && $translation->element_id != $product_id ){
74
  $post_to_duplicate = $this->wpdb->get_row( $this->wpdb->prepare( "SELECT * FROM {$this->wpdb->posts} WHERE ID=%d", $translation->element_id ) );
106
  public function wc_duplicate_product( $post_to_duplicate ){
107
 
108
  $product = wc_get_product( $post_to_duplicate->ID );
109
+ $wc_duplicate_product_instance = new WC_Admin_Duplicate_Product();;
110
+
111
  if( WooCommerce_Functions_Wrapper::is_deprecated() ){
112
+ $new_orig_id = $wc_duplicate_product_instance->duplicate_product( $product );
113
  }else{
114
+ $duplicate = $wc_duplicate_product_instance->product_duplicate( $product );
115
  $new_orig_id = $duplicate->get_id();
116
  }
117
 
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: 3.9
7
- Tested up to: 4.7.3
8
- Stable tag: 4.1.3
9
 
10
  Allows running fully multilingual e-commerce sites using WooCommerce and WPML.
11
 
@@ -142,6 +142,17 @@ WooCommerce Multilingual is compatible with all major WooCommerce extensions. We
142
 
143
  == Changelog ==
144
 
 
 
 
 
 
 
 
 
 
 
 
145
  = 4.1.3 =
146
  * Improvements for the REST API support (compliant with WooCommerce REST API v2)
147
  * Bug fix: Order confirmation emails were not translated correctly when using WooCommerce 3.0
@@ -172,17 +183,19 @@ WooCommerce Multilingual is compatible with all major WooCommerce extensions. We
172
  * Fixed compatibility issues with Aelia Currency Switcher and Aelia Foundation
173
  * Fixed a compatibility issue with Visual Composer: shortcodes were not parsed in the translation editor
174
 
175
-
176
  = 4.1.2 =
 
177
  * Fixed the currency switcher not being displayed correctly when using the Storefront theme
178
- * Fixed an incompatibility with an older WPML version leading to a fatal error
179
- * Fixed the currency switcher css being loaded when no currency switcher was displayed
180
  * Fixed a bug causing an error when upgrading WooCommerce Multilingual to version 4.1 with WooCommerce inactive.
 
181
 
182
  = 4.1.1 =
183
- * Fixed fatal error that was occurring when using an older version of WPML (introduced in version 4.1.0)
184
- * Fixed a bug causing a 'Invalid or duplicated SKU when saving or updating product' warning when editing a product
185
- * Fixed a bug causing a fatal error when deactivating WooCommerce while WooCommerce Multilingual was active
 
 
186
 
187
  = 4.1.0 =
188
  * Enhanced language switchers
4
  Tags: CMS, woocommerce, commerce, ecommerce, e-commerce, products, WPML, multilingual, e-shop, shop
5
  License: GPLv2
6
  Requires at least: 3.9
7
+ Tested up to: 4.8.0
8
+ Stable tag: 4.1.4
9
 
10
  Allows running fully multilingual e-commerce sites using WooCommerce and WPML.
11
 
142
 
143
  == Changelog ==
144
 
145
+ = 4.1.4 =
146
+ * Fix: A PHP warning was shown on a product bundle page on the front end (when using WooCommerce Product Bundles)
147
+ * Fix: Added possibility to filter available Currency Switcher templates paths via "wcml_cs_directories_to_scan" filter
148
+ * Fix: The "Copy to a new draft" link was showing two times on the product edit page
149
+ * Fix: For taxonomies having the term_id distinct from term_taxonomy_id, the translations could have been accidentally overwritten
150
+ * Fix: In some conditions, a fatal error could come up when editing a product
151
+ * Fix: In some circustances, disabling currency switcher on product page produced a fatal error
152
+ * Fix: Custom attributes in the translations were reset after editing the original product
153
+ * Fix: Sometimes, the translated product category pages were returning a 404 error
154
+ * Fix: It was not possible to filter products by price on the shop page using the WooCommerce Price Filter widget
155
+
156
  = 4.1.3 =
157
  * Improvements for the REST API support (compliant with WooCommerce REST API v2)
158
  * Bug fix: Order confirmation emails were not translated correctly when using WooCommerce 3.0
183
  * Fixed compatibility issues with Aelia Currency Switcher and Aelia Foundation
184
  * Fixed a compatibility issue with Visual Composer: shortcodes were not parsed in the translation editor
185
 
 
186
  = 4.1.2 =
187
+ * Fixed `Fatal error: Call to undefined method WPML_WP_API::defined`
188
  * Fixed the currency switcher not being displayed correctly when using the Storefront theme
189
+ * Fixed `Fatal error: Call to undefined function wc_format_decimal()`
 
190
  * Fixed a bug causing an error when upgrading WooCommerce Multilingual to version 4.1 with WooCommerce inactive.
191
+ * Fixed the currency switcher css being loaded when no currency switcher was displayed
192
 
193
  = 4.1.1 =
194
+ * Fixed a pre PHP 5.4 compatibility issue
195
+ * Fixed `Notice: Undefined index: switcher_id`
196
+ * Fixed `Fatal error: Class ‘WPML_File’ not found` when using an old version of WPML
197
+ * Fixed "Invalid or duplicated SKU" error when saving or updating a product with SKU
198
+ * Fixed `Fatal error: Call to undefined function WC()` when disabling WooCommerce while WCML is running
199
 
200
  = 4.1.0 =
201
  * Enhanced language switchers
vendor/autoload.php CHANGED
@@ -4,4 +4,4 @@
4
 
5
  require_once __DIR__ . '/composer/autoload_real.php';
6
 
7
- return ComposerAutoloaderInitb9ffed287a5b4e2fcc802a91254f114a::getLoader();
4
 
5
  require_once __DIR__ . '/composer/autoload_real.php';
6
 
7
+ return ComposerAutoloaderInit3d46cc8388475e6b99b9a4c2356d4330::getLoader();
vendor/autoload_52.php CHANGED
@@ -4,4 +4,4 @@
4
 
5
  require_once dirname(__FILE__) . '/composer'.'/autoload_real_52.php';
6
 
7
- return ComposerAutoloaderInit38be79df74f6b23b0833390c6a01eb02::getLoader();
4
 
5
  require_once dirname(__FILE__) . '/composer'.'/autoload_real_52.php';
6
 
7
+ return ComposerAutoloaderInit226a7f3fe2d604eac20e142d7118628a::getLoader();
vendor/composer/autoload_classmap.php CHANGED
@@ -356,6 +356,7 @@ return array(
356
  'WCML_Plugins_Wrap' => $baseDir . '/inc/template-classes/class-wcml-plugins-wrap.php',
357
  'WCML_Pointer_UI' => $baseDir . '/inc/template-classes/class-wcml-pointer-ui.php',
358
  'WCML_Pointers' => $baseDir . '/inc/admin-menus/class-wcml-pointers.php',
 
359
  'WCML_Product_Addons' => $baseDir . '/compatibility/class-wcml-product-addons.php',
360
  'WCML_Product_Bundles' => $baseDir . '/compatibility/class-wcml-product-bundles.php',
361
  'WCML_Product_Bundles_Legacy' => $baseDir . '/compatibility/class-wcml-product-bundles-legacy.php',
356
  'WCML_Plugins_Wrap' => $baseDir . '/inc/template-classes/class-wcml-plugins-wrap.php',
357
  'WCML_Pointer_UI' => $baseDir . '/inc/template-classes/class-wcml-pointer-ui.php',
358
  'WCML_Pointers' => $baseDir . '/inc/admin-menus/class-wcml-pointers.php',
359
+ 'WCML_Price_Filter' => $baseDir . '/inc/currencies/class-wcml-price-filter.php',
360
  'WCML_Product_Addons' => $baseDir . '/compatibility/class-wcml-product-addons.php',
361
  'WCML_Product_Bundles' => $baseDir . '/compatibility/class-wcml-product-bundles.php',
362
  'WCML_Product_Bundles_Legacy' => $baseDir . '/compatibility/class-wcml-product-bundles-legacy.php',
vendor/composer/autoload_real.php CHANGED
@@ -2,7 +2,7 @@
2
 
3
  // autoload_real.php @generated by Composer
4
 
5
- class ComposerAutoloaderInitb9ffed287a5b4e2fcc802a91254f114a
6
  {
7
  private static $loader;
8
 
@@ -19,15 +19,15 @@ class ComposerAutoloaderInitb9ffed287a5b4e2fcc802a91254f114a
19
  return self::$loader;
20
  }
21
 
22
- spl_autoload_register(array('ComposerAutoloaderInitb9ffed287a5b4e2fcc802a91254f114a', 'loadClassLoader'), true, true);
23
  self::$loader = $loader = new \Composer\Autoload\ClassLoader();
24
- spl_autoload_unregister(array('ComposerAutoloaderInitb9ffed287a5b4e2fcc802a91254f114a', '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\ComposerStaticInitb9ffed287a5b4e2fcc802a91254f114a::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 ComposerAutoloaderInit3d46cc8388475e6b99b9a4c2356d4330
6
  {
7
  private static $loader;
8
 
19
  return self::$loader;
20
  }
21
 
22
+ spl_autoload_register(array('ComposerAutoloaderInit3d46cc8388475e6b99b9a4c2356d4330', 'loadClassLoader'), true, true);
23
  self::$loader = $loader = new \Composer\Autoload\ClassLoader();
24
+ spl_autoload_unregister(array('ComposerAutoloaderInit3d46cc8388475e6b99b9a4c2356d4330', '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\ComposerStaticInit3d46cc8388475e6b99b9a4c2356d4330::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 ComposerAutoloaderInit38be79df74f6b23b0833390c6a01eb02 {
6
  private static $loader;
7
 
8
  public static function loadClassLoader($class) {
@@ -19,9 +19,9 @@ class ComposerAutoloaderInit38be79df74f6b23b0833390c6a01eb02 {
19
  return self::$loader;
20
  }
21
 
22
- spl_autoload_register(array('ComposerAutoloaderInit38be79df74f6b23b0833390c6a01eb02', 'loadClassLoader'), true /*, true */);
23
  self::$loader = $loader = new xrstf_Composer52_ClassLoader();
24
- spl_autoload_unregister(array('ComposerAutoloaderInit38be79df74f6b23b0833390c6a01eb02', '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 ComposerAutoloaderInit226a7f3fe2d604eac20e142d7118628a {
6
  private static $loader;
7
 
8
  public static function loadClassLoader($class) {
19
  return self::$loader;
20
  }
21
 
22
+ spl_autoload_register(array('ComposerAutoloaderInit226a7f3fe2d604eac20e142d7118628a', 'loadClassLoader'), true /*, true */);
23
  self::$loader = $loader = new xrstf_Composer52_ClassLoader();
24
+ spl_autoload_unregister(array('ComposerAutoloaderInit226a7f3fe2d604eac20e142d7118628a', '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 ComposerStaticInitb9ffed287a5b4e2fcc802a91254f114a
8
  {
9
  public static $prefixLengthsPsr4 = array (
10
  'C' =>
@@ -388,6 +388,7 @@ class ComposerStaticInitb9ffed287a5b4e2fcc802a91254f114a
388
  'WCML_Plugins_Wrap' => __DIR__ . '/../..' . '/inc/template-classes/class-wcml-plugins-wrap.php',
389
  'WCML_Pointer_UI' => __DIR__ . '/../..' . '/inc/template-classes/class-wcml-pointer-ui.php',
390
  'WCML_Pointers' => __DIR__ . '/../..' . '/inc/admin-menus/class-wcml-pointers.php',
 
391
  'WCML_Product_Addons' => __DIR__ . '/../..' . '/compatibility/class-wcml-product-addons.php',
392
  'WCML_Product_Bundles' => __DIR__ . '/../..' . '/compatibility/class-wcml-product-bundles.php',
393
  'WCML_Product_Bundles_Legacy' => __DIR__ . '/../..' . '/compatibility/class-wcml-product-bundles-legacy.php',
@@ -462,10 +463,10 @@ class ComposerStaticInitb9ffed287a5b4e2fcc802a91254f114a
462
  public static function getInitializer(ClassLoader $loader)
463
  {
464
  return \Closure::bind(function () use ($loader) {
465
- $loader->prefixLengthsPsr4 = ComposerStaticInitb9ffed287a5b4e2fcc802a91254f114a::$prefixLengthsPsr4;
466
- $loader->prefixDirsPsr4 = ComposerStaticInitb9ffed287a5b4e2fcc802a91254f114a::$prefixDirsPsr4;
467
- $loader->prefixesPsr0 = ComposerStaticInitb9ffed287a5b4e2fcc802a91254f114a::$prefixesPsr0;
468
- $loader->classMap = ComposerStaticInitb9ffed287a5b4e2fcc802a91254f114a::$classMap;
469
 
470
  }, null, ClassLoader::class);
471
  }
4
 
5
  namespace Composer\Autoload;
6
 
7
+ class ComposerStaticInit3d46cc8388475e6b99b9a4c2356d4330
8
  {
9
  public static $prefixLengthsPsr4 = array (
10
  'C' =>
388
  'WCML_Plugins_Wrap' => __DIR__ . '/../..' . '/inc/template-classes/class-wcml-plugins-wrap.php',
389
  'WCML_Pointer_UI' => __DIR__ . '/../..' . '/inc/template-classes/class-wcml-pointer-ui.php',
390
  'WCML_Pointers' => __DIR__ . '/../..' . '/inc/admin-menus/class-wcml-pointers.php',
391
+ 'WCML_Price_Filter' => __DIR__ . '/../..' . '/inc/currencies/class-wcml-price-filter.php',
392
  'WCML_Product_Addons' => __DIR__ . '/../..' . '/compatibility/class-wcml-product-addons.php',
393
  'WCML_Product_Bundles' => __DIR__ . '/../..' . '/compatibility/class-wcml-product-bundles.php',
394
  'WCML_Product_Bundles_Legacy' => __DIR__ . '/../..' . '/compatibility/class-wcml-product-bundles-legacy.php',
463
  public static function getInitializer(ClassLoader $loader)
464
  {
465
  return \Closure::bind(function () use ($loader) {
466
+ $loader->prefixLengthsPsr4 = ComposerStaticInit3d46cc8388475e6b99b9a4c2356d4330::$prefixLengthsPsr4;
467
+ $loader->prefixDirsPsr4 = ComposerStaticInit3d46cc8388475e6b99b9a4c2356d4330::$prefixDirsPsr4;
468
+ $loader->prefixesPsr0 = ComposerStaticInit3d46cc8388475e6b99b9a4c2356d4330::$prefixesPsr0;
469
+ $loader->classMap = ComposerStaticInit3d46cc8388475e6b99b9a4c2356d4330::$classMap;
470
 
471
  }, null, ClassLoader::class);
472
  }
vendor/otgs/installer/includes/class-installer-dependencies.php CHANGED
@@ -42,7 +42,7 @@ class Installer_Dependencies{
42
 
43
  $installer_settings = WP_Installer()->settings;
44
 
45
- if ( is_array( $installer_settings['repositories'][$repository_id]['data']['downloads']['plugins'] ) ) {
46
  $a_plugin = current( $installer_settings['repositories'][$repository_id]['data']['downloads']['plugins'] );
47
  $url = WP_Installer()->append_site_key_to_download_url( $a_plugin['url'], 'xxxxxx', $repository_id );
48
  $tmpfname = wp_tempnam( $url );
42
 
43
  $installer_settings = WP_Installer()->settings;
44
 
45
+ if ( isset($installer_settings['repositories'][$repository_id]['data']) && is_array( $installer_settings['repositories'][$repository_id]['data']['downloads']['plugins'] ) ) {
46
  $a_plugin = current( $installer_settings['repositories'][$repository_id]['data']['downloads']['plugins'] );
47
  $url = WP_Installer()->append_site_key_to_download_url( $a_plugin['url'], 'xxxxxx', $repository_id );
48
  $tmpfname = wp_tempnam( $url );
vendor/otgs/installer/includes/installer.class.php CHANGED
@@ -471,11 +471,14 @@ final class WP_Installer{
471
  $this->settings = unserialize($_settings);
472
  }
473
 
474
- if ( ! array_key_exists( 'repositories', $this->settings ) ) {
475
- $this->settings['repositories'] = array();
476
- }
 
 
 
477
 
478
- if (is_multisite() && isset($this->settings['repositories'])) {
479
  $network_settings = maybe_unserialize(get_site_option('wp_installer_network'));
480
  if ($network_settings) {
481
  foreach ($this->settings['repositories'] as $rep_id => $repository) {
@@ -559,20 +562,16 @@ final class WP_Installer{
559
  private function _pre_1_6_backwards_compatibility($settings){
560
 
561
  if( version_compare($this->version(), '1.8', '<') && !empty($settings['repositories']) ){
562
-
563
  foreach ($settings['repositories'] as $repository_id => $repository) {
564
-
565
- foreach ($repository['data']['downloads']['plugins'] as $slug => $download) {
566
-
567
- $settings['repositories'][$repository_id]['data']['downloads']['plugins'][$slug]['slug'] = $download['basename'];
568
-
569
  }
570
  }
571
-
572
  }
573
 
574
  return $settings;
575
-
576
  }
577
 
578
  //backward compatibility - support old products list format (downloads under products instead of global downloads list)
@@ -581,61 +580,41 @@ final class WP_Installer{
581
  if( version_compare($this->version(), '1.8', '<') && !empty($settings['repositories']) && empty($this->_old_products_format_backwards_compatibility) ) {
582
 
583
  foreach ($settings['repositories'] as $repository_id => $repository) {
584
-
585
  $populate_downloads = false;
586
-
587
- foreach ($repository['data']['packages'] as $package_id => $package) {
588
-
589
- foreach ($package['products'] as $product_id => $product) {
590
-
591
- if (!isset($product['plugins'])) {
592
-
593
- $populate_downloads = true;
594
-
595
- foreach ($product['downloads'] as $download_id => $download) {
596
-
597
- $settings['repositories'][$repository_id]['data']['packages'][$package_id]['products'][$product_id]['plugins'][] = $download['slug'];
598
-
599
- }
600
-
601
- }
602
-
603
- }
604
-
605
- }
606
-
607
- if ($populate_downloads) {
608
-
609
- // Add downloads branch
610
- foreach ($repository['data']['packages'] as $package_id => $package) {
611
-
612
- foreach ($package['products'] as $product_id => $product) {
613
-
614
- foreach ($product['downloads'] as $download_id => $download) {
615
-
616
- if (!isset($settings['repositories'][$repository_id]['data']['downloads']['plugins'][$download['slug']])) {
617
- $settings['repositories'][$repository_id]['data']['downloads']['plugins'][$download['slug']] = $download;
618
- }
619
-
620
- $settings['repositories'][$repository_id]['data']['packages'][$package_id]['products'][$product_id]['plugins'][] = $download['slug'];
621
- }
622
-
623
- unset($settings['repositories'][$repository_id]['data']['packages'][$package_id]['products'][$product_id]['downloads']);
624
-
625
- }
626
-
627
- }
628
-
629
- }
630
-
631
  }
632
 
633
  $this->_old_products_format_backwards_compatibility = true;
634
-
635
  }
636
 
637
  return $settings;
638
-
639
  }
640
 
641
  public function get_installer_site_url( $repository_id = false ){
471
  $this->settings = unserialize($_settings);
472
  }
473
 
474
+ // Initialize
475
+ if( empty( $this->settings ) ){
476
+ $this->settings = array(
477
+ 'repositories' => array()
478
+ );
479
+ }
480
 
481
+ if ( is_multisite() ) {
482
  $network_settings = maybe_unserialize(get_site_option('wp_installer_network'));
483
  if ($network_settings) {
484
  foreach ($this->settings['repositories'] as $rep_id => $repository) {
562
  private function _pre_1_6_backwards_compatibility($settings){
563
 
564
  if( version_compare($this->version(), '1.8', '<') && !empty($settings['repositories']) ){
 
565
  foreach ($settings['repositories'] as $repository_id => $repository) {
566
+ if( isset( $repository['data'] ) ) {
567
+ foreach ( $repository['data']['downloads']['plugins'] as $slug => $download ) {
568
+ $settings['repositories'][ $repository_id ]['data']['downloads']['plugins'][ $slug ]['slug'] = $download['basename'];
569
+ }
 
570
  }
571
  }
 
572
  }
573
 
574
  return $settings;
 
575
  }
576
 
577
  //backward compatibility - support old products list format (downloads under products instead of global downloads list)
580
  if( version_compare($this->version(), '1.8', '<') && !empty($settings['repositories']) && empty($this->_old_products_format_backwards_compatibility) ) {
581
 
582
  foreach ($settings['repositories'] as $repository_id => $repository) {
 
583
  $populate_downloads = false;
584
+ if( isset( $repository['data'] ) ) {
585
+
586
+ foreach ( $repository['data']['packages'] as $package_id => $package ) {
587
+ foreach ( $package['products'] as $product_id => $product ) {
588
+ if ( ! isset( $product['plugins'] ) ) {
589
+ $populate_downloads = true;
590
+ foreach ( $product['downloads'] as $download_id => $download ) {
591
+ $settings['repositories'][ $repository_id ]['data']['packages'][ $package_id ]['products'][ $product_id ]['plugins'][] = $download['slug'];
592
+ }
593
+ }
594
+ }
595
+ }
596
+
597
+ if ( $populate_downloads ) {
598
+ // Add downloads branch
599
+ foreach ( $repository['data']['packages'] as $package_id => $package ) {
600
+ foreach ( $package['products'] as $product_id => $product ) {
601
+ foreach ( $product['downloads'] as $download_id => $download ) {
602
+ if ( ! isset( $settings['repositories'][ $repository_id ]['data']['downloads']['plugins'][ $download['slug'] ] ) ) {
603
+ $settings['repositories'][ $repository_id ]['data']['downloads']['plugins'][ $download['slug'] ] = $download;
604
+ }
605
+ $settings['repositories'][ $repository_id ]['data']['packages'][ $package_id ]['products'][ $product_id ]['plugins'][] = $download['slug'];
606
+ }
607
+ unset( $settings['repositories'][ $repository_id ]['data']['packages'][ $package_id ]['products'][ $product_id ]['downloads'] );
608
+ }
609
+ }
610
+ }
611
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
612
  }
613
 
614
  $this->_old_products_format_backwards_compatibility = true;
 
615
  }
616
 
617
  return $settings;
 
618
  }
619
 
620
  public function get_installer_site_url( $repository_id = false ){
vendor/otgs/installer/installer.php CHANGED
@@ -1,5 +1,5 @@
1
  <?php
2
- define('WP_INSTALLER_VERSION', '1.7.16');
3
 
4
  include_once dirname(__FILE__) . '/includes/installer.class.php';
5
 
1
  <?php
2
+ define('WP_INSTALLER_VERSION', '1.7.17');
3
 
4
  include_once dirname(__FILE__) . '/includes/installer.class.php';
5
 
vendor/otgs/installer/loader.php CHANGED
@@ -19,7 +19,7 @@ $wp_installer_instance = dirname(__FILE__) . '/installer.php';
19
  global $wp_installer_instances;
20
  $wp_installer_instances[$wp_installer_instance] = array(
21
  'bootfile' => $wp_installer_instance,
22
- 'version' => '1.7.16'
23
  );
24
 
25
 
19
  global $wp_installer_instances;
20
  $wp_installer_instances[$wp_installer_instance] = array(
21
  'bootfile' => $wp_installer_instance,
22
+ 'version' => '1.7.17'
23
  );
24
 
25
 
vendor/twig/twig/CHANGELOG CHANGED
@@ -1,7 +1,16 @@
1
- * 1.32.1 (2017-XX-XX)
2
 
3
  * n/a
4
 
 
 
 
 
 
 
 
 
 
5
  * 1.32.0 (2017-02-26)
6
 
7
  * fixed deprecation notice in Twig_Util_DeprecationCollector
1
+ * 1.33.1 (2017-XX-XX)
2
 
3
  * n/a
4
 
5
+ * 1.33.0 (2017-03-22)
6
+
7
+ * fixed a race condition handling when writing cache files
8
+ * "length" filter now returns string length when applied to an object that does
9
+ not implement \Countable but provides __toString()
10
+ * "empty" test will now consider the return value of the __toString() method for
11
+ objects implement __toString() but not \Countable
12
+ * fixed JS escaping for unicode characters with higher code points
13
+
14
  * 1.32.0 (2017-02-26)
15
 
16
  * fixed deprecation notice in Twig_Util_DeprecationCollector
vendor/twig/twig/ext/twig/php_twig.h CHANGED
@@ -15,7 +15,7 @@
15
  #ifndef PHP_TWIG_H
16
  #define PHP_TWIG_H
17
 
18
- #define PHP_TWIG_VERSION "1.32.1-DEV"
19
 
20
  #include "php.h"
21
 
15
  #ifndef PHP_TWIG_H
16
  #define PHP_TWIG_H
17
 
18
+ #define PHP_TWIG_VERSION "1.33.1-DEV"
19
 
20
  #include "php.h"
21
 
vendor/twig/twig/lib/Twig/Cache/Filesystem.php CHANGED
@@ -49,8 +49,13 @@ class Twig_Cache_Filesystem implements Twig_CacheInterface
49
  {
50
  $dir = dirname($key);
51
  if (!is_dir($dir)) {
52
- if (false === @mkdir($dir, 0777, true) && !is_dir($dir)) {
53
- throw new RuntimeException(sprintf('Unable to create the cache directory (%s).', $dir));
 
 
 
 
 
54
  }
55
  } elseif (!is_writable($dir)) {
56
  throw new RuntimeException(sprintf('Unable to write in the cache directory (%s).', $dir));
49
  {
50
  $dir = dirname($key);
51
  if (!is_dir($dir)) {
52
+ if (false === @mkdir($dir, 0777, true)) {
53
+ if (PHP_VERSION_ID >= 50300) {
54
+ clearstatcache(true, $dir);
55
+ }
56
+ if (!is_dir($dir)) {
57
+ throw new RuntimeException(sprintf('Unable to create the cache directory (%s).', $dir));
58
+ }
59
  }
60
  } elseif (!is_writable($dir)) {
61
  throw new RuntimeException(sprintf('Unable to write in the cache directory (%s).', $dir));
vendor/twig/twig/lib/Twig/Environment.php CHANGED
@@ -16,10 +16,10 @@
16
  */
17
  class Twig_Environment
18
  {
19
- const VERSION = '1.32.1';
20
- const VERSION_ID = 13201;
21
  const MAJOR_VERSION = 1;
22
- const MINOR_VERSION = 32;
23
  const RELEASE_VERSION = 1;
24
  const EXTRA_VERSION = 'DEV';
25
 
16
  */
17
  class Twig_Environment
18
  {
19
+ const VERSION = '1.33.1';
20
+ const VERSION_ID = 13301;
21
  const MAJOR_VERSION = 1;
22
+ const MINOR_VERSION = 33;
23
  const RELEASE_VERSION = 1;
24
  const EXTRA_VERSION = 'DEV';
25
 
vendor/twig/twig/lib/Twig/Extension/Core.php CHANGED
@@ -1168,8 +1168,13 @@ function _twig_escape_js_callback($matches)
1168
 
1169
  // \uHHHH
1170
  $char = twig_convert_encoding($char, 'UTF-16BE', 'UTF-8');
 
1171
 
1172
- return '\\u'.strtoupper(substr('0000'.bin2hex($char), -4));
 
 
 
 
1173
  }
1174
 
1175
  function _twig_escape_css_callback($matches)
@@ -1259,7 +1264,15 @@ if (function_exists('mb_get_info')) {
1259
  */
1260
  function twig_length_filter(Twig_Environment $env, $thing)
1261
  {
1262
- return is_scalar($thing) ? mb_strlen($thing, $env->getCharset()) : count($thing);
 
 
 
 
 
 
 
 
1263
  }
1264
 
1265
  /**
@@ -1342,7 +1355,15 @@ else {
1342
  */
1343
  function twig_length_filter(Twig_Environment $env, $thing)
1344
  {
1345
- return is_scalar($thing) ? strlen($thing) : count($thing);
 
 
 
 
 
 
 
 
1346
  }
1347
 
1348
  /**
@@ -1404,6 +1425,10 @@ function twig_test_empty($value)
1404
  return 0 == count($value);
1405
  }
1406
 
 
 
 
 
1407
  return '' === $value || false === $value || null === $value || array() === $value;
1408
  }
1409
 
1168
 
1169
  // \uHHHH
1170
  $char = twig_convert_encoding($char, 'UTF-16BE', 'UTF-8');
1171
+ $char = strtoupper(bin2hex($char));
1172
 
1173
+ if (4 >= strlen($char)) {
1174
+ return sprintf('\u%04s', $char);
1175
+ }
1176
+
1177
+ return sprintf('\u%04s\u%04s', substr($char, 0, -4), substr($char, -4));
1178
  }
1179
 
1180
  function _twig_escape_css_callback($matches)
1264
  */
1265
  function twig_length_filter(Twig_Environment $env, $thing)
1266
  {
1267
+ if (is_scalar($thing)) {
1268
+ return mb_strlen($thing, $env->getCharset());
1269
+ }
1270
+
1271
+ if (is_object($thing) && method_exists($thing, '__toString') && !$thing instanceof \Countable) {
1272
+ return mb_strlen((string) $thing, $env->getCharset());
1273
+ }
1274
+
1275
+ return count($thing);
1276
  }
1277
 
1278
  /**
1355
  */
1356
  function twig_length_filter(Twig_Environment $env, $thing)
1357
  {
1358
+ if (is_scalar($thing)) {
1359
+ return strlen($thing);
1360
+ }
1361
+
1362
+ if (is_object($thing) && method_exists($thing, '__toString') && !$thing instanceof \Countable) {
1363
+ return strlen((string) $thing);
1364
+ }
1365
+
1366
+ return count($thing);
1367
  }
1368
 
1369
  /**
1425
  return 0 == count($value);
1426
  }
1427
 
1428
+ if (is_object($value) && method_exists($value, '__toString')) {
1429
+ return '' === (string) $value;
1430
+ }
1431
+
1432
  return '' === $value || false === $value || null === $value || array() === $value;
1433
  }
1434
 
vendor/twig/twig/lib/Twig/Loader/Array.php CHANGED
@@ -80,7 +80,7 @@ class Twig_Loader_Array implements Twig_LoaderInterface, Twig_ExistsLoaderInterf
80
  throw new Twig_Error_Loader(sprintf('Template "%s" is not defined.', $name));
81
  }
82
 
83
- return $this->templates[$name];
84
  }
85
 
86
  public function isFresh($name, $time)
80
  throw new Twig_Error_Loader(sprintf('Template "%s" is not defined.', $name));
81
  }
82
 
83
+ return $name.':'.$this->templates[$name];
84
  }
85
 
86
  public function isFresh($name, $time)
vendor/twig/twig/lib/Twig/Profiler/Dumper/Blackfire.php CHANGED
@@ -22,7 +22,7 @@ class Twig_Profiler_Dumper_Blackfire
22
  $this->dumpProfile('main()', $profile, $data);
23
  $this->dumpChildren('main()', $profile, $data);
24
 
25
- $start = microtime(true);
26
  $str = <<<EOF
27
  file-format: BlackfireProbe
28
  cost-dimensions: wt mu pmu
22
  $this->dumpProfile('main()', $profile, $data);
23
  $this->dumpChildren('main()', $profile, $data);
24
 
25
+ $start = sprintf('%f', microtime(true));
26
  $str = <<<EOF
27
  file-format: BlackfireProbe
28
  cost-dimensions: wt mu pmu
vendor/twig/twig/lib/Twig/Test/IntegrationTestCase.php CHANGED
@@ -121,6 +121,10 @@ abstract class Twig_Test_IntegrationTestCase extends PHPUnit_Framework_TestCase
121
 
122
  protected function doIntegrationTest($file, $message, $condition, $templates, $exception, $outputs)
123
  {
 
 
 
 
124
  if ($condition) {
125
  eval('$ret = '.$condition.';');
126
  if (!$ret) {
121
 
122
  protected function doIntegrationTest($file, $message, $condition, $templates, $exception, $outputs)
123
  {
124
+ if (!$outputs) {
125
+ $this->markTestSkipped('no legacy tests to run');
126
+ }
127
+
128
  if ($condition) {
129
  eval('$ret = '.$condition.';');
130
  if (!$ret) {
wpml-config.xml CHANGED
@@ -61,6 +61,7 @@
61
  <custom-field action="translate">_variation_description</custom-field>
62
  <custom-field action="ignore">wcml_sync_hash</custom-field>
63
  <custom-field action="ignore">wpml_language</custom-field>
 
64
  </custom-fields>
65
  <custom-types>
66
  <custom-type translate="1">product</custom-type>
61
  <custom-field action="translate">_variation_description</custom-field>
62
  <custom-field action="ignore">wcml_sync_hash</custom-field>
63
  <custom-field action="ignore">wpml_language</custom-field>
64
+ <custom-field action="ignore">_product_attributes</custom-field>
65
  </custom-fields>
66
  <custom-types>
67
  <custom-type translate="1">product</custom-type>
wpml-woocommerce.php CHANGED
@@ -6,12 +6,14 @@
6
  Author: OnTheGoSystems
7
  Author URI: http://www.onthegosystems.com/
8
  Text Domain: woocommerce-multilingual
9
- Version: 4.1.3
10
  */
11
 
12
- if( defined( 'WCML_VERSION' ) ) return;
 
 
13
 
14
- define( 'WCML_VERSION', '4.1.3' );
15
  define( 'WCML_PLUGIN_PATH', dirname( __FILE__ ) );
16
  define( 'WCML_PLUGIN_FOLDER', basename( WCML_PLUGIN_PATH ) );
17
  define( 'WCML_LOCALE_PATH', WCML_PLUGIN_PATH . '/locale' );
@@ -26,18 +28,18 @@ include WCML_PLUGIN_PATH . '/inc/wcml-core-functions.php';
26
  include WCML_PLUGIN_PATH . '/inc/wcml-switch-lang-request.php';
27
  include WCML_PLUGIN_PATH . '/inc/wcml-cart-switch-lang-functions.php';
28
 
29
- if( defined( 'ICL_SITEPRESS_VERSION' ) && !ICL_PLUGIN_INACTIVE && class_exists( 'SitePress' ) ){
30
- //detecting language switching
31
- $wcml_switch_lang_request = new WCML_Switch_Lang_Request( new WPML_Cookie(), new WPML_WP_API() );
32
 
33
- //cart related language switching functions
34
- $wcml_cart_switch_lang_functions = new WCML_Cart_Switch_Lang_Functions();
35
  }
36
 
37
  if ( version_compare( PHP_VERSION, '5.3.0' ) >= 0 ) {
38
- require WCML_PLUGIN_PATH . '/vendor/autoload.php';
39
  } else {
40
- require WCML_PLUGIN_PATH . '/vendor/autoload_52.php';
41
  }
42
 
43
  // Load WooCommerce Multilingual when WPML is active
@@ -49,10 +51,10 @@ if( WCML_REST_API_Support::is_rest_api_request() ){
49
 
50
 
51
  // Load WooCommerce Multilingual when WPML is NOT active
52
- add_action('plugins_loaded', 'load_wcml_without_wpml', 10000);
53
- function load_wcml_without_wpml(){
54
- if( !did_action( 'wpml_loaded' ) ){
55
- global $woocommerce_wpml;
56
- $woocommerce_wpml = new woocommerce_wpml();
57
- }
58
- }
6
  Author: OnTheGoSystems
7
  Author URI: http://www.onthegosystems.com/
8
  Text Domain: woocommerce-multilingual
9
+ Version: 4.1.4
10
  */
11
 
12
+ if ( defined( 'WCML_VERSION' ) ) {
13
+ return;
14
+ }
15
 
16
+ define( 'WCML_VERSION', '4.1.4' );
17
  define( 'WCML_PLUGIN_PATH', dirname( __FILE__ ) );
18
  define( 'WCML_PLUGIN_FOLDER', basename( WCML_PLUGIN_PATH ) );
19
  define( 'WCML_LOCALE_PATH', WCML_PLUGIN_PATH . '/locale' );
28
  include WCML_PLUGIN_PATH . '/inc/wcml-switch-lang-request.php';
29
  include WCML_PLUGIN_PATH . '/inc/wcml-cart-switch-lang-functions.php';
30
 
31
+ if ( defined( 'ICL_SITEPRESS_VERSION' ) && ! ICL_PLUGIN_INACTIVE && class_exists( 'SitePress' ) ) {
32
+ //detecting language switching
33
+ $wcml_switch_lang_request = new WCML_Switch_Lang_Request( new WPML_Cookie(), new WPML_WP_API() );
34
 
35
+ //cart related language switching functions
36
+ $wcml_cart_switch_lang_functions = new WCML_Cart_Switch_Lang_Functions();
37
  }
38
 
39
  if ( version_compare( PHP_VERSION, '5.3.0' ) >= 0 ) {
40
+ require WCML_PLUGIN_PATH . '/vendor/autoload.php';
41
  } else {
42
+ require WCML_PLUGIN_PATH . '/vendor/autoload_52.php';
43
  }
44
 
45
  // Load WooCommerce Multilingual when WPML is active
51
 
52
 
53
  // Load WooCommerce Multilingual when WPML is NOT active
54
+ add_action( 'plugins_loaded', 'load_wcml_without_wpml', 10000 );
55
+ function load_wcml_without_wpml() {
56
+ if ( ! did_action( 'wpml_loaded' ) ) {
57
+ global $woocommerce_wpml;
58
+ $woocommerce_wpml = new woocommerce_wpml();
59
+ }
60
+ }