WooCommerce Multilingual – run WooCommerce with WPML - Version 4.7.7

Version Description

  • Fixed not linked order_id for Bookable products.
  • Fixed not filtering of currencies accounts on order confirmation page.
  • Fixed "Break and Abort" rules not applying in secondary language for Table Rate Shipping.
  • Fixed wrong order item id in some special cases.
  • Fixed customer order email strings sent in wrong language.
  • Fixed sale price in original product when checkout via PayPal in some cases.
  • Fixed wrong count for parent product categories in the second language.
  • Fixed wrong "Add to cart" button URL on archive pages in secondary language when "language as parameter set".
  • Fixed default currency wasn't removed from Multi-currency settings after changing in WooCommerce settings.
  • Fixed custom attribute label translation displayed on product view page instead of attribute taxonomy label.
  • Fixed console errors on Multi-Currency settings page if site under https.
  • Fixed wrong shipping rate applying on the cart page for Table Rate Shipping ( Bolder Elements ).
  • Fixed currency not switched with Siteground optimizer 5.0.* version and enabled memcache.
  • Fixed deprecated 'calculate_booking_cost' function in WooCommerce Bookings since 1.15.0.
  • Hide admin language switcher from Dynamic Prices settings page.
  • Fixed shop pages assignment on pages listing in second language.
  • Fixed not synchronized default value for Composite Products.
  • Fixed product total sales meta synchronization.
  • Fixed PHP Notices for Product Addons when 'options' doesn't set for addon.
  • Fixed wcml_formatted_price filter not displaying a converted price when current currency is default one.
  • Fixed category names on Shop page when object caching is enabled.
  • Fixed styles on product view page when WPML not active.
  • Fixed unable to switch currency on the reports page.
  • Fixed not translated shipping method title in admin email.
  • Fixed Rest API request for getting products in 'all' languages.
Download this release

Release Info

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

Code changes from version 4.7.6 to 4.7.7

Files changed (41) hide show
  1. changelog/4.7.0.md +2 -0
  2. changelog/4.7.6.md +0 -16
  3. changelog/4.7.7.md +32 -0
  4. classes/Email/OrderItems/Hooks.php +0 -83
  5. classes/class-woocommerce-wpml.php +14 -9
  6. classes/currencies/class-wcml-currencies.php +11 -3
  7. classes/multi-currency/payment-gateways/class-wcml-currencies-payment-gateways.php +2 -0
  8. classes/multi-currency/payment-gateways/class-wcml-payment-gateway.php +1 -1
  9. classes/rest-api-support/filters/class-wcml-rest-api-query-filters-products.php +1 -0
  10. compatibility/class-wcml-bookings.php +22 -12
  11. compatibility/class-wcml-composite-products.php +43 -18
  12. compatibility/class-wcml-dynamic-pricing.php +23 -1
  13. compatibility/class-wcml-product-addons.php +55 -31
  14. compatibility/class-wcml-table-rate-shipping.php +17 -19
  15. compatibility/class-wcml-wc-subscriptions.php +14 -0
  16. inc/class-wcml-attributes.php +541 -525
  17. inc/class-wcml-cart.php +18 -25
  18. inc/class-wcml-emails.php +14 -21
  19. inc/class-wcml-orders.php +46 -27
  20. inc/class-wcml-products.php +29 -0
  21. inc/class-wcml-store-pages.php +3 -1
  22. inc/class-wcml-terms.php +12 -2
  23. inc/class-wcml-upgrade.php +12 -0
  24. inc/class-wcml-wc-shipping.php +23 -15
  25. inc/class-wcml-wc-strings.php +18 -5
  26. inc/currencies/class-wcml-multi-currency-prices.php +1 -2
  27. inc/currencies/class-wcml-multi-currency-reports.php +0 -3
  28. inc/currencies/class-wcml-multi-currency-resources.php +5 -2
  29. inc/currencies/currency-switcher/class-wcml-currency-switcher-templates.php +3 -8
  30. inc/currencies/currency-switcher/class-wcml-file.php +0 -59
  31. inc/translation-editor/class-wcml-synchronize-product-data.php +5 -9
  32. readme.txt +29 -13
  33. vendor/autoload.php +1 -1
  34. vendor/composer/autoload_classmap.php +0 -2
  35. vendor/composer/autoload_real.php +7 -7
  36. vendor/composer/autoload_static.php +4 -6
  37. vendor/otgs/installer/includes/class-wp-installer-channels.php +1 -3
  38. vendor/otgs/installer/includes/class-wp-installer.php +4 -5
  39. vendor/otgs/installer/loader.php +1 -1
  40. vendor/wpml-shared/wpml-lib-dependencies/src/dependencies/class-wpml-dependencies.php +8 -2
  41. wpml-woocommerce.php +2 -3
changelog/4.7.0.md CHANGED
@@ -8,6 +8,7 @@
8
  * [wcml-2929] Fixed an issue with the cache flush during language switching.
9
  * [wcml-2928] Fixed in the original ticket.
10
  * [wcml-2923] Fixed an issue where the gateway strings would always register in English instead of the site's default language.
 
11
 
12
  # Compatibility
13
  * [wcml-2965] Fixed PHP Notice for WC Variations Swatches And Photos compatibility.
@@ -24,6 +25,7 @@
24
  * [wcml-2864] Fixed an issue where customers would not receive notifications in the correct language.
25
  * [wcml-2854] Fixed an issue where the Products shortcode was not working in the secondary language.
26
  * [wcml-2827] Fixed error while sending WooCoomerce Bookings email for bookings which didn't have orders assigned.
 
27
  * [wcml-2792] Updated compatibility class for WC Checkout Addons
28
  * [wcml-2612] Fixed the images that were wrongly inserted in the translation job when attachments are not translatable.
29
 
8
  * [wcml-2929] Fixed an issue with the cache flush during language switching.
9
  * [wcml-2928] Fixed in the original ticket.
10
  * [wcml-2923] Fixed an issue where the gateway strings would always register in English instead of the site's default language.
11
+ * [wcml-2481] Fixed languages column width on products table.
12
 
13
  # Compatibility
14
  * [wcml-2965] Fixed PHP Notice for WC Variations Swatches And Photos compatibility.
25
  * [wcml-2864] Fixed an issue where customers would not receive notifications in the correct language.
26
  * [wcml-2854] Fixed an issue where the Products shortcode was not working in the secondary language.
27
  * [wcml-2827] Fixed error while sending WooCoomerce Bookings email for bookings which didn't have orders assigned.
28
+ * [wcml-2807] Added compatibility for free version of YIKES Custom Product Tabs.
29
  * [wcml-2792] Updated compatibility class for WC Checkout Addons
30
  * [wcml-2612] Fixed the images that were wrongly inserted in the translation job when attachments are not translatable.
31
 
changelog/4.7.6.md DELETED
@@ -1,16 +0,0 @@
1
- # Fixes
2
- * [wcml-3060] Fix php warning in WCML custom prices module.
3
- * [wcml-3057] Fixed unable to add variation to cart for products with more than 30 variations.
4
- * [wcml-3040] Remove legacy code for downloading the language pack.
5
- * [wcml-3023] Fixed string translation while adding "sold individual" product more than ones from second language.
6
-
7
- # Compatibility
8
- * [wcml-3055] Fixed notices thrown with php 7.4 with multi-currency.
9
- * [wcml-3054] Fixed notices thrown with php 7.4 when using multi-currency.
10
- * [wcml-3053] Fixed notices thrown with php 7.4 when using WCML with WC Variation Swatches and Photos.
11
- * [wcml-3039] Fixed deprecation notices (`Function get_magic_quotes_gpc() is deprecated`) when running PHP 7.4.
12
- * [wcml-3037] Fixed a few fatal errors thrown when running PHP 7.4 (e.g. `Fatal error: Uncaught Error: Call to a member function get_setting() on null`) and caused by legacy code passing objects by reference.
13
- * [wcml-2544] Fixed language for "Low Stock" and "No Stock" admin emails.
14
-
15
- # Usability
16
- * [wcml-3017] Fixed not converted pre-selected price widget prices when switching currency.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
changelog/4.7.7.md ADDED
@@ -0,0 +1,32 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Fixes
2
+ * [wcml-3079] Fixed not linked order_id for Bookable products.
3
+ * [wcml-3077] Fixed not filtering of currencies accounts on order confirmation page.
4
+ * [wcml-3069] Fixed "Break and Abort" rules not applying in secondary language for Table Rate Shipping.
5
+ * [wcml-3067] Fixed wrong order item id in some special cases.
6
+ * [wcml-3063] Fixed customer order email strings sent in wrong language.
7
+ * [wcml-3050] Fixed sale price in original product when checkout via PayPal in some cases.
8
+ * [wcml-3042] Fixed wrong count for parent product categories in the second language.
9
+ * [wcml-3035] Fixed wrong "Add to cart" button URL on archive pages in secondary language when "language as parameter set".
10
+ * [wcml-3026] Fixed default currency wasn't removed from Multi-currency settings after changing in WooCommerce settings.
11
+ * [wcml-3018] Fixed custom attribute label translation displayed on product view page instead of attribute taxonomy label.
12
+ * [wcml-2996] Fixed console errors on Multi-Currency settings page if site under https.
13
+
14
+ # Compatibility
15
+ * [wcml-3046] Fixed wrong shipping rate applying on the cart page for Table Rate Shipping ( Bolder Elements ).
16
+ * [wcml-3016] Fixed currency not switched with Siteground optimizer 5.0.* version and enabled memcache.
17
+ * [wcml-2989] Fixed deprecated 'calculate_booking_cost' function in WooCommerce Bookings since 1.15.0.
18
+ * [wcml-2986] Hide admin language switcher from Dynamic Prices settings page.
19
+ * [wcml-2955] Fixed shop pages assignment on pages listing in second language.
20
+ * [wcml-2945] Fixed not synchronized default value for Composite Products.
21
+ * [wcml-2924] Fixed product total sales meta synchronization.
22
+ * [wcml-2920] Fixed PHP Notices for Product Addons when 'options' doesn't set for addon.
23
+ * [wcml-2877] Fixed `wcml_formatted_price` filter not displaying a converted price when current currency is default one.
24
+ * [wcml-2731] Fixed category names on Shop page when object caching is enabled.
25
+ * [wcml-2593] Fixed styles on product view page when WPML not active.
26
+
27
+ # Usability
28
+ * [wcml-3058] Fixed unable to switch currency on the reports page.
29
+ * [wcml-3033] Fixed not translated shipping method title in admin email.
30
+
31
+ # API
32
+ * [wcml-2705] Fixed Rest API request for getting products in 'all' languages.
classes/Email/OrderItems/Hooks.php DELETED
@@ -1,83 +0,0 @@
1
- <?php
2
-
3
- namespace WCML\Email\OrderItems;
4
-
5
- use IWPML_Backend_Action;
6
- use IWPML_DIC_Action;
7
- use IWPML_Frontend_Action;
8
- use SitePress;
9
- use WCML_Attributes;
10
- use WCML_Terms;
11
-
12
- class Hooks implements IWPML_Backend_Action, IWPML_Frontend_Action, IWPML_DIC_Action {
13
-
14
- /** @var SitePress */
15
- private $sitepress;
16
-
17
- /** @var WCML_Terms */
18
- private $wcmlTerms;
19
-
20
- /** @var WCML_Attributes */
21
- private $wcmlAttributes;
22
-
23
- public function __construct( SitePress $sitepress, WCML_Terms $wcmlTerms, WCML_Attributes $wcmlAttributes ) {
24
- $this->sitepress = $sitepress;
25
- $this->wcmlTerms = $wcmlTerms;
26
- $this->wcmlAttributes = $wcmlAttributes;
27
- }
28
-
29
- public function add_hooks() {
30
- if ( ! $this->isMarkingStatusForShopOrder() ) {
31
- add_filter( 'woocommerce_order_items_meta_get_formatted', [ $this, 'filterFormattedItems' ], 10, 2 );
32
- }
33
- }
34
-
35
- private function isMarkingStatusForShopOrder() {
36
- return filter_input( INPUT_GET, 'post_type' ) === 'shop_order'
37
- && filter_input( INPUT_GET, 'action' ) === 'woocommerce_mark_order_status';
38
- }
39
-
40
- /**
41
- * @param array $formattedMeta
42
- * @param object $object Should be an instance of \WC_Order_Item_Meta (but not explicitly defined)
43
- *
44
- * @return array
45
- */
46
- function filterFormattedItems( array $formattedMeta, $object ) {
47
-
48
- if ( isset( $object->product->variation_id ) ) {
49
-
50
- $currentProductVariationId = $this->sitepress->get_object_id( $object->product->variation_id, 'product_variation' );
51
-
52
- if ( ! is_null( $currentProductVariationId ) ) {
53
-
54
- foreach ( $formattedMeta as $key => $formattedItem ) {
55
-
56
- if ( substr( $formattedItem['key'], 0, 3 ) ) {
57
-
58
- $attribute = wc_sanitize_taxonomy_name( $formattedItem['key'] );
59
-
60
- if ( taxonomy_exists( $attribute ) ) {
61
- $attributeTerm = get_term_by( 'name', $formattedMeta[ $key ]['value'], $attribute );
62
- $translatedTermId = $this->sitepress->get_object_id( $attributeTerm->term_id, $attribute );
63
-
64
- if ( $translatedTermId ) {
65
- $translatedTerm = $this->wcmlTerms->wcml_get_term_by_id( $translatedTermId, $attribute );
66
- $formattedMeta[ $key ]['value'] = $translatedTerm->name;
67
- }
68
-
69
- } else {
70
- $customAttrTranslation = $this->wcmlAttributes->get_custom_attribute_translation( $object->product->id, $formattedItem['key'], [ 'is_taxonomy' => false ], $this->sitepress->get_current_language() );
71
-
72
- if ( false !== $customAttrTranslation ) {
73
- $formattedMeta[ $key ]['label'] = $customAttrTranslation['name'];
74
- }
75
- }
76
- }
77
- }
78
- }
79
- }
80
-
81
- return $formattedMeta;
82
- }
83
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
classes/class-woocommerce-wpml.php CHANGED
@@ -91,7 +91,8 @@ class woocommerce_wpml {
91
 
92
  if ( defined( 'ICL_SITEPRESS_VERSION' ) && ! ICL_PLUGIN_INACTIVE && class_exists( 'SitePress' ) ) {
93
  $this->cs_properties = new WCML_Currency_Switcher_Properties();
94
- $this->cs_templates = new WCML_Currency_Switcher_Templates( $this, $sitepress->get_wp_api() );
 
95
  $this->cs_templates->init_hooks();
96
 
97
  $wc_shortccode_product_category = new WCML_WC_Shortcode_Product_Category( $sitepress );
@@ -148,13 +149,16 @@ class woocommerce_wpml {
148
  WCML_Admin_Menus::set_up_menus( $this, $sitepress, $wpdb );
149
 
150
  if ( ! $this->dependencies_are_ok ) {
151
- WCML_Capabilities::set_up_capabilities();
 
 
152
 
153
- wp_register_style( 'otgs-ico', WCML_PLUGIN_URL . '/res/css/otgs-ico.css', null, WCML_VERSION );
154
- wp_enqueue_style( 'otgs-ico' );
155
 
156
- WCML_Resources::load_management_css();
157
- WCML_Resources::load_tooltip_resources();
 
158
  return false;
159
  }
160
 
@@ -217,16 +221,17 @@ class woocommerce_wpml {
217
  $this->products->add_hooks();
218
  $this->store = new WCML_Store_Pages( $this, $sitepress );
219
  $this->store->add_hooks();
220
- $this->strings = new WCML_WC_Strings( $this, $sitepress );
221
  $this->strings->add_hooks();
222
- $this->emails = new WCML_Emails( $this->strings, $sitepress, WC_Emails::instance(), $wpdb );
 
223
  $this->emails->add_hooks();
224
  $this->terms = new WCML_Terms( $this, $sitepress, $wpdb );
225
  $this->terms->add_hooks();
226
  $this->attributes = new WCML_Attributes( $this, $sitepress, $wpml_post_translations, $wpml_term_translations, $wpdb );
227
  $this->attributes->add_hooks();
228
  $this->orders = new WCML_Orders( $this, $sitepress );
229
- $this->shipping = new WCML_WC_Shipping( $sitepress );
230
  $this->shipping->add_hooks();
231
  $this->gateways = new WCML_WC_Gateways( $this, $sitepress );
232
  $this->gateways->add_hooks();
91
 
92
  if ( defined( 'ICL_SITEPRESS_VERSION' ) && ! ICL_PLUGIN_INACTIVE && class_exists( 'SitePress' ) ) {
93
  $this->cs_properties = new WCML_Currency_Switcher_Properties();
94
+ $wpml_wp_api = $sitepress->get_wp_api();
95
+ $this->cs_templates = new WCML_Currency_Switcher_Templates( $this, $wpml_wp_api, new WPML_File( $wpml_wp_api ) );
96
  $this->cs_templates->init_hooks();
97
 
98
  $wc_shortccode_product_category = new WCML_WC_Shortcode_Product_Category( $sitepress );
149
  WCML_Admin_Menus::set_up_menus( $this, $sitepress, $wpdb );
150
 
151
  if ( ! $this->dependencies_are_ok ) {
152
+ $is_dashboard_page = isset( $_GET['page'] ) && 'wpml-wcml' === $_GET['page'];
153
+ if( is_admin() && $is_dashboard_page ){
154
+ WCML_Capabilities::set_up_capabilities();
155
 
156
+ wp_register_style( 'otgs-ico', WCML_PLUGIN_URL . '/res/css/otgs-ico.css', null, WCML_VERSION );
157
+ wp_enqueue_style( 'otgs-ico' );
158
 
159
+ WCML_Resources::load_management_css();
160
+ WCML_Resources::load_tooltip_resources();
161
+ }
162
  return false;
163
  }
164
 
221
  $this->products->add_hooks();
222
  $this->store = new WCML_Store_Pages( $this, $sitepress );
223
  $this->store->add_hooks();
224
+ $this->strings = new WCML_WC_Strings( $this, $sitepress, $wpdb );
225
  $this->strings->add_hooks();
226
+ //do not pass mailer instance instead of $woocommerce
227
+ $this->emails = new WCML_Emails( $this->strings, $sitepress, $woocommerce, $wpdb );
228
  $this->emails->add_hooks();
229
  $this->terms = new WCML_Terms( $this, $sitepress, $wpdb );
230
  $this->terms->add_hooks();
231
  $this->attributes = new WCML_Attributes( $this, $sitepress, $wpml_post_translations, $wpml_term_translations, $wpdb );
232
  $this->attributes->add_hooks();
233
  $this->orders = new WCML_Orders( $this, $sitepress );
234
+ $this->shipping = new WCML_WC_Shipping( $sitepress, $this->strings );
235
  $this->shipping->add_hooks();
236
  $this->gateways = new WCML_WC_Gateways( $this, $sitepress );
237
  $this->gateways->add_hooks();
classes/currencies/class-wcml-currencies.php CHANGED
@@ -25,7 +25,7 @@ class WCML_Currencies {
25
  * It hooks to `update_option_woocommerce_currency` if the conditions are right.
26
  */
27
  public function add_hooks() {
28
- if ( is_admin() && wcml_is_multi_currency_on() ) {
29
  add_action( 'update_option_woocommerce_currency', array(
30
  $this,
31
  'setup_multi_currency_on_currency_update',
@@ -40,8 +40,16 @@ class WCML_Currencies {
40
  * @param string $new_value The new value of the option.
41
  */
42
  public function setup_multi_currency_on_currency_update( $old_value, $new_value ) {
43
- $multi_currency_install = new WCML_Multi_Currency_Install( new WCML_Multi_Currency(), $this->woocommerce_wpml );
44
- $multi_currency_install->set_default_currencies_languages( $old_value, $new_value );
 
 
 
 
 
 
 
 
45
  }
46
 
47
  }
25
  * It hooks to `update_option_woocommerce_currency` if the conditions are right.
26
  */
27
  public function add_hooks() {
28
+ if ( is_admin() ) {
29
  add_action( 'update_option_woocommerce_currency', array(
30
  $this,
31
  'setup_multi_currency_on_currency_update',
40
  * @param string $new_value The new value of the option.
41
  */
42
  public function setup_multi_currency_on_currency_update( $old_value, $new_value ) {
43
+ if ( wcml_is_multi_currency_on() ) {
44
+ $multi_currency_install = new WCML_Multi_Currency_Install( new WCML_Multi_Currency(), $this->woocommerce_wpml );
45
+ $multi_currency_install->set_default_currencies_languages( $old_value, $new_value );
46
+ } else {
47
+ $currency_options = $this->woocommerce_wpml->get_setting( 'currency_options' );
48
+ $currency_options[ $new_value ] = $currency_options[ $old_value ];
49
+ unset( $currency_options[ $old_value ] );
50
+ $this->woocommerce_wpml->update_setting( 'currency_options', $currency_options );
51
+ }
52
+
53
  }
54
 
55
  }
classes/multi-currency/payment-gateways/class-wcml-currencies-payment-gateways.php CHANGED
@@ -33,6 +33,8 @@ class WCML_Currencies_Payment_Gateways {
33
  }
34
 
35
  public function add_hooks() {
 
 
36
  add_filter( 'woocommerce_gateway_description', [ $this, 'filter_gateway_description' ], 10, 2 );
37
  add_filter( 'option_woocommerce_stripe_settings', [ 'WCML_Payment_Gateway_Stripe', 'filter_stripe_settings' ] );
38
 
33
  }
34
 
35
  public function add_hooks() {
36
+ add_action( 'init', array( $this, 'init_gateways' ) );
37
+
38
  add_filter( 'woocommerce_gateway_description', [ $this, 'filter_gateway_description' ], 10, 2 );
39
  add_filter( 'option_woocommerce_stripe_settings', [ 'WCML_Payment_Gateway_Stripe', 'filter_stripe_settings' ] );
40
 
classes/multi-currency/payment-gateways/class-wcml-payment-gateway.php CHANGED
@@ -56,7 +56,7 @@ abstract class WCML_Payment_Gateway {
56
  }
57
 
58
  public function show() {
59
- return $this->get_settings_output();
60
  }
61
 
62
  abstract protected function get_output_model();
56
  }
57
 
58
  public function show() {
59
+ return $this->get_settings_output( $this->current_currency, $this->default_currency );
60
  }
61
 
62
  abstract protected function get_output_model();
classes/rest-api-support/filters/class-wcml-rest-api-query-filters-products.php CHANGED
@@ -15,6 +15,7 @@ class WCML_REST_API_Query_Filters_Products{
15
 
16
  public function add_hooks(){
17
  add_filter( 'woocommerce_rest_product_query', array( $this, 'filter_products_query' ), 10, 2 );
 
18
  }
19
 
20
  /**
15
 
16
  public function add_hooks(){
17
  add_filter( 'woocommerce_rest_product_query', array( $this, 'filter_products_query' ), 10, 2 );
18
+ add_filter( 'woocommerce_rest_product_object_query', array( $this, 'filter_products_query' ), 10, 2 );
19
  }
20
 
21
  /**
compatibility/class-wcml-bookings.php CHANGED
@@ -852,7 +852,7 @@ class WCML_Bookings {
852
  '_resource_block_costs'
853
  ) ) ) {
854
 
855
- if ( $this->woocommerce_wpml->settings['enable_multi_currency'] == WCML_MULTI_CURRENCIES_INDEPENDENT ) {
856
 
857
  $original_id = $this->woocommerce_wpml->products->get_original_product_id( $object_id );
858
 
@@ -1149,7 +1149,7 @@ class WCML_Bookings {
1149
  return $actions;
1150
  }
1151
 
1152
- function filter_bundled_product_in_cart_contents( $cart_item, $key, $current_language ) {
1153
 
1154
  if ( $cart_item['data'] instanceof WC_Product_Booking && isset( $cart_item['booking'] ) ) {
1155
 
@@ -1190,9 +1190,10 @@ class WCML_Bookings {
1190
  $booking_info['wc_bookings_field_start_date_time'] = $cart_item['booking']['_time'];
1191
  }
1192
 
1193
- $booking_form = new WC_Booking_Form( wc_get_product( $current_id ) );
 
 
1194
 
1195
- $cost = $booking_form->calculate_booking_cost( $booking_info );
1196
  if ( ! is_wp_error( $cost ) ) {
1197
  $cart_item['data']->set_price( $cost );
1198
  }
@@ -1203,6 +1204,17 @@ class WCML_Bookings {
1203
  return $cart_item;
1204
  }
1205
 
 
 
 
 
 
 
 
 
 
 
 
1206
  function booking_currency_dropdown() {
1207
 
1208
 
@@ -1881,9 +1893,8 @@ class WCML_Bookings {
1881
 
1882
  }
1883
 
1884
- function append_persons_to_translation_package( $package, $post ) {
1885
-
1886
- if ( $post->post_type == 'product' ) {
1887
  if ( $this->is_booking( $post->ID ) ) {
1888
 
1889
  $bookable_product = new WC_Product_Booking( $post->ID );
@@ -1913,7 +1924,6 @@ class WCML_Bookings {
1913
  }
1914
 
1915
  return $package;
1916
-
1917
  }
1918
 
1919
  function save_person_translation( $post_id, $data, $job ) {
@@ -2589,10 +2599,10 @@ class WCML_Bookings {
2589
  *
2590
  * @return bool
2591
  */
2592
- private function is_booking( $product ){
2593
- if( !$product instanceof WC_Product ){
2594
- $product = wc_get_product( $product );
2595
- }
2596
 
2597
  return $product ? $product->get_type() === 'booking' : false;
2598
  }
852
  '_resource_block_costs'
853
  ) ) ) {
854
 
855
+ if ( WCML_MULTI_CURRENCIES_INDEPENDENT === $this->woocommerce_wpml->settings['enable_multi_currency'] ) {
856
 
857
  $original_id = $this->woocommerce_wpml->products->get_original_product_id( $object_id );
858
 
1149
  return $actions;
1150
  }
1151
 
1152
+ public function filter_bundled_product_in_cart_contents( $cart_item, $key, $current_language ) {
1153
 
1154
  if ( $cart_item['data'] instanceof WC_Product_Booking && isset( $cart_item['booking'] ) ) {
1155
 
1190
  $booking_info['wc_bookings_field_start_date_time'] = $cart_item['booking']['_time'];
1191
  }
1192
 
1193
+ $current_product = wc_get_product( $current_id );
1194
+
1195
+ $cost = $this->get_booking_cost( $booking_info, $current_product );
1196
 
 
1197
  if ( ! is_wp_error( $cost ) ) {
1198
  $cart_item['data']->set_price( $cost );
1199
  }
1204
  return $cart_item;
1205
  }
1206
 
1207
+ private function get_booking_cost( $booking_info, $current_product ) {
1208
+ if ( class_exists( 'WC_Bookings_Cost_Calculation' ) ) {
1209
+ $cost = WC_Bookings_Cost_Calculation::calculate_booking_cost( wc_bookings_get_posted_data( $booking_info, $current_product ), $current_product );
1210
+ } else {
1211
+ $booking_form = new WC_Booking_Form( $current_product );
1212
+ $cost = $booking_form->calculate_booking_cost( $booking_info );
1213
+ }
1214
+
1215
+ return $cost;
1216
+ }
1217
+
1218
  function booking_currency_dropdown() {
1219
 
1220
 
1893
 
1894
  }
1895
 
1896
+ public function append_persons_to_translation_package( $package, $post ) {
1897
+ if ( 'product' === $post->post_type ) {
 
1898
  if ( $this->is_booking( $post->ID ) ) {
1899
 
1900
  $bookable_product = new WC_Product_Booking( $post->ID );
1924
  }
1925
 
1926
  return $package;
 
1927
  }
1928
 
1929
  function save_person_translation( $post_id, $data, $job ) {
2599
  *
2600
  * @return bool
2601
  */
2602
+ private function is_booking( $product ) {
2603
+ if ( ! $product instanceof WC_Product ) {
2604
+ $product = wc_get_product( $product );
2605
+ }
2606
 
2607
  return $product ? $product->get_type() === 'booking' : false;
2608
  }
compatibility/class-wcml-composite-products.php CHANGED
@@ -41,7 +41,8 @@ class WCML_Composite_Products extends WCML_Compatibility_Helper{
41
 
42
  add_action( 'wcml_gui_additional_box_html', array( $this, 'custom_box_html' ), 10, 3 );
43
  add_filter( 'wcml_gui_additional_box_data', array( $this, 'custom_box_html_data' ), 10, 4 );
44
- add_action( 'wcml_update_extra_fields', array( $this, 'components_update' ), 10, 4 );
 
45
  add_filter( 'woocommerce_json_search_found_products', array( $this, 'woocommerce_json_search_found_products' ) );
46
 
47
  add_filter( 'wpml_tm_translation_job_data', array( $this, 'append_composite_data_translation_package' ), 10, 2 );
@@ -278,20 +279,12 @@ class WCML_Composite_Products extends WCML_Compatibility_Helper{
278
  return $data;
279
  }
280
 
281
- function components_update( $original_product_id, $product_id, $data, $language ){
282
 
283
  $composite_data = $this->get_composite_data( $original_product_id );
284
 
285
  foreach( $composite_data as $component_id => $component ) {
286
 
287
- if(!empty($data[ md5( 'composite_'.$component_id.'_title' ) ] ) ){
288
- $composite_data[$component_id]['title'] = $data[ md5( 'composite_'.$component_id.'_title' ) ];
289
- }
290
-
291
- if(!empty($data[ md5( 'composite_'.$component_id.'_description' ) ])) {
292
- $composite_data[$component_id]['description'] = $data[ md5( 'composite_'.$component_id.'_description' ) ];
293
- }
294
-
295
  //sync product ids
296
  if( $component[ 'query_type' ] == 'product_ids' ){
297
  foreach( $component[ 'assigned_ids' ] as $key => $assigned_id ){
@@ -324,14 +317,6 @@ class WCML_Composite_Products extends WCML_Compatibility_Helper{
324
  $composite_scenarios_meta = $this->get_composite_scenarios_meta( $original_product_id );
325
  if( $composite_scenarios_meta ){
326
  foreach( $composite_scenarios_meta as $scenario_key => $scenario_meta ){
327
- if( !empty( $data[ md5( 'composite_scenario_'.$scenario_key.'_title' ) ] ) ){
328
- $composite_scenarios_meta[ $scenario_key ][ 'title' ] = $data[ md5( 'composite_scenario_'.$scenario_key.'_title' ) ];
329
- }
330
-
331
- if( !empty( $data[ md5( 'composite_scenario_'.$scenario_key.'_description' ) ])) {
332
- $composite_scenarios_meta[ $scenario_key ][ 'description' ] = $data[ md5( 'composite_scenario_'.$scenario_key.'_description' ) ];
333
- }
334
-
335
  //sync product ids
336
  foreach( $scenario_meta[ 'component_data' ] as $compon_id => $component_data ){
337
  if( isset( $composite_data[ $compon_id ] ) && $composite_data[ $compon_id ][ 'query_type' ] == 'product_ids' ){
@@ -361,6 +346,46 @@ class WCML_Composite_Products extends WCML_Compatibility_Helper{
361
  );
362
  }
363
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
364
  function append_composite_data_translation_package( $package, $post ){
365
 
366
  if( $post->post_type == 'product' ) {
41
 
42
  add_action( 'wcml_gui_additional_box_html', array( $this, 'custom_box_html' ), 10, 3 );
43
  add_filter( 'wcml_gui_additional_box_data', array( $this, 'custom_box_html_data' ), 10, 4 );
44
+ add_action( 'wcml_before_sync_product_data', array( $this, 'components_update' ), 10, 3 );
45
+ add_action( 'wcml_update_extra_fields', array( $this, 'update_component_strings' ), 10, 4 );
46
  add_filter( 'woocommerce_json_search_found_products', array( $this, 'woocommerce_json_search_found_products' ) );
47
 
48
  add_filter( 'wpml_tm_translation_job_data', array( $this, 'append_composite_data_translation_package' ), 10, 2 );
279
  return $data;
280
  }
281
 
282
+ public function components_update( $original_product_id, $product_id, $language ){
283
 
284
  $composite_data = $this->get_composite_data( $original_product_id );
285
 
286
  foreach( $composite_data as $component_id => $component ) {
287
 
 
 
 
 
 
 
 
 
288
  //sync product ids
289
  if( $component[ 'query_type' ] == 'product_ids' ){
290
  foreach( $component[ 'assigned_ids' ] as $key => $assigned_id ){
317
  $composite_scenarios_meta = $this->get_composite_scenarios_meta( $original_product_id );
318
  if( $composite_scenarios_meta ){
319
  foreach( $composite_scenarios_meta as $scenario_key => $scenario_meta ){
 
 
 
 
 
 
 
 
320
  //sync product ids
321
  foreach( $scenario_meta[ 'component_data' ] as $compon_id => $component_data ){
322
  if( isset( $composite_data[ $compon_id ] ) && $composite_data[ $compon_id ][ 'query_type' ] == 'product_ids' ){
346
  );
347
  }
348
 
349
+
350
+ public function update_component_strings( $original_product_id, $product_id, $data, $language ){
351
+
352
+ $composite_data = $this->get_composite_data( $product_id );
353
+
354
+ foreach( $composite_data as $component_id => $component ) {
355
+
356
+ if(!empty($data[ md5( 'composite_'.$component_id.'_title' ) ] ) ){
357
+ $composite_data[$component_id]['title'] = $data[ md5( 'composite_'.$component_id.'_title' ) ];
358
+ }
359
+
360
+ if(!empty($data[ md5( 'composite_'.$component_id.'_description' ) ])) {
361
+ $composite_data[$component_id]['description'] = $data[ md5( 'composite_'.$component_id.'_description' ) ];
362
+ }
363
+
364
+ }
365
+
366
+ update_post_meta( $product_id, '_bto_data', $composite_data );
367
+
368
+ $composite_scenarios_meta = $this->get_composite_scenarios_meta( $product_id );
369
+ if( $composite_scenarios_meta ){
370
+ foreach( $composite_scenarios_meta as $scenario_key => $scenario_meta ){
371
+ if( !empty( $data[ md5( 'composite_scenario_'.$scenario_key.'_title' ) ] ) ){
372
+ $composite_scenarios_meta[ $scenario_key ][ 'title' ] = $data[ md5( 'composite_scenario_'.$scenario_key.'_title' ) ];
373
+ }
374
+
375
+ if( !empty( $data[ md5( 'composite_scenario_'.$scenario_key.'_description' ) ])) {
376
+ $composite_scenarios_meta[ $scenario_key ][ 'description' ] = $data[ md5( 'composite_scenario_'.$scenario_key.'_description' ) ];
377
+ }
378
+ }
379
+ }
380
+
381
+ update_post_meta( $product_id, '_bto_scenario_data', $composite_scenarios_meta );
382
+
383
+ return array(
384
+ 'components' => $composite_data,
385
+ 'scenarios' => $composite_scenarios_meta,
386
+ );
387
+ }
388
+
389
  function append_composite_data_translation_package( $package, $post ){
390
 
391
  if( $post->post_type == 'product' ) {
compatibility/class-wcml-dynamic-pricing.php CHANGED
@@ -5,6 +5,20 @@
5
  */
6
  class WCML_Dynamic_Pricing {
7
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
8
  public function add_hooks() {
9
 
10
  if ( ! is_admin() ) {
@@ -15,6 +29,8 @@ class WCML_Dynamic_Pricing {
15
  add_filter( 'woocommerce_dynamic_pricing_get_rule_amount', [ $this, 'woocommerce_dynamic_pricing_get_rule_amount' ], 10, 2 );
16
  add_filter( 'dynamic_pricing_product_rules', [ $this, 'dynamic_pricing_product_rules' ] );
17
  add_filter( 'wcml_calculate_totals_exception', [ $this, 'calculate_totals_exception' ] );
 
 
18
  }
19
  add_filter( 'woocommerce_product_get__pricing_rules', array( $this, 'translate_variations_in_rules' ) );
20
 
@@ -224,4 +240,10 @@ class WCML_Dynamic_Pricing {
224
  return $rules;
225
  }
226
 
227
- }
 
 
 
 
 
 
5
  */
6
  class WCML_Dynamic_Pricing {
7
 
8
+ /**
9
+ * @var SitePress
10
+ */
11
+ private $sitepress;
12
+
13
+ /**
14
+ * WCML_Dynamic_Pricing constructor.
15
+ *
16
+ * @param SitePress $sitepress
17
+ */
18
+ function __construct( SitePress $sitepress ) {
19
+ $this->sitepress = $sitepress;
20
+ }
21
+
22
  public function add_hooks() {
23
 
24
  if ( ! is_admin() ) {
29
  add_filter( 'woocommerce_dynamic_pricing_get_rule_amount', [ $this, 'woocommerce_dynamic_pricing_get_rule_amount' ], 10, 2 );
30
  add_filter( 'dynamic_pricing_product_rules', [ $this, 'dynamic_pricing_product_rules' ] );
31
  add_filter( 'wcml_calculate_totals_exception', [ $this, 'calculate_totals_exception' ] );
32
+ }else{
33
+ $this->hide_language_switcher_for_settings_page();
34
  }
35
  add_filter( 'woocommerce_product_get__pricing_rules', array( $this, 'translate_variations_in_rules' ) );
36
 
240
  return $rules;
241
  }
242
 
243
+ public function hide_language_switcher_for_settings_page() {
244
+ if ( 'wc_dynamic_pricing' === filter_input( INPUT_GET, 'page' ) ) {
245
+ remove_action( 'wp_before_admin_bar_render', [ $this->sitepress, 'admin_language_switcher' ] );
246
+ }
247
+ }
248
+
249
+ }
compatibility/class-wcml-product-addons.php CHANGED
@@ -113,13 +113,19 @@ class WCML_Product_Addons {
113
  if ( '_product_addons' === $meta_key && 'global_product_addon' === get_post_type( $id ) ) {
114
  $this->update_custom_prices_values( $id );
115
  foreach ( $addons as $addon ) {
 
 
 
116
  //register name
117
- do_action( 'wpml_register_single_string', 'wc_product_addons_strings', $id . '_addon_' . $addon['type'] . '_' . $addon['position'] . '_name', $addon['name'] );
118
  //register description
119
- do_action( 'wpml_register_single_string', 'wc_product_addons_strings', $id . '_addon_' . $addon['type'] . '_' . $addon['position'] . '_description', $addon['description'] );
120
  //register options labels
121
- foreach ( $addon['options'] as $key => $option ) {
122
- do_action( 'wpml_register_single_string', 'wc_product_addons_strings', $id . '_addon_' . $addon['type'] . '_' . $addon['position'] . '_option_label_' . $key, $option['label'] );
 
 
 
123
  }
124
  }
125
  }
@@ -143,13 +149,18 @@ class WCML_Product_Addons {
143
 
144
  if ( is_array( $addons ) ) {
145
  foreach ( $addons as $key => $addon ) {
 
 
 
146
  //register name
147
- $addons[ $key ]['name'] = apply_filters( 'wpml_translate_single_string', $addon['name'], 'wc_product_addons_strings', $object_id . '_addon_' . $addon['type'] . '_' . $addon['position'] . '_name' );
148
  //register description
149
- $addons[ $key ]['description'] = apply_filters( 'wpml_translate_single_string', $addon['description'], 'wc_product_addons_strings', $object_id . '_addon_' . $addon['type'] . '_' . $addon['position'] . '_description' );
150
  //register options labels
151
- foreach ( $addon['options'] as $opt_key => $option ) {
152
- $addons[ $key ]['options'][ $opt_key ]['label'] = apply_filters( 'wpml_translate_single_string', $option['label'], 'wc_product_addons_strings', $object_id . '_addon_' . $addon['type'] . '_' . $addon['position'] . '_option_label_' . $opt_key );
 
 
153
  }
154
  }
155
  }
@@ -172,13 +183,19 @@ class WCML_Product_Addons {
172
  if ( $this->is_multi_currency_on() ) {
173
 
174
  foreach ( $addons as $add_id => $addon ) {
175
- if ( isset( $addon['price'] ) && $addon['price'] ) {
 
 
 
176
  $addons[ $add_id ]['price'] = $this->converted_addon_price( $addon, $post_id );
177
  }
178
 
179
- foreach ( $addon['options'] as $key => $option ) {
180
- $addons[ $add_id ]['options'][ $key ]['price'] = $this->converted_addon_price( $option, $post_id );
 
 
181
  }
 
182
  }
183
  }
184
 
@@ -247,8 +264,9 @@ class WCML_Product_Addons {
247
 
248
  if ( ! empty( $product_addons ) ) {
249
  foreach ( $product_addons as $addon_id => $product_addon ) {
 
250
 
251
- $addons_section = new WPML_Editor_UI_Field_Section( sprintf( __( 'Product Add-ons Group "%s"', 'woocommerce-multilingual' ), $product_addon['name'] ) );
252
 
253
  $group = new WPML_Editor_UI_Field_Group( '' , true );
254
  $addon_field = new WPML_Editor_UI_Single_Line_Field( 'addon_'.$addon_id.'_name', __( 'Name', 'woocommerce-multilingual' ), $data, false );
@@ -258,11 +276,11 @@ class WCML_Product_Addons {
258
 
259
  $addons_section->add_field( $group );
260
 
261
- if ( ! empty( $product_addon['options'] ) ) {
262
 
263
  $labels_group = new WPML_Editor_UI_Field_Group( __( 'Options', 'woocommerce-multilingual' ) , true );
264
 
265
- foreach ( $product_addon['options'] as $option_id => $option ) {
266
  $option_label_field = new WPML_Editor_UI_Single_Line_Field( 'addon_'.$addon_id.'_option_'.$option_id.'_label', __( 'Label', 'woocommerce-multilingual' ), $data, false );
267
  $labels_group->add_field( $option_label_field );
268
  }
@@ -286,11 +304,12 @@ class WCML_Product_Addons {
286
 
287
  if ( ! empty( $product_addons ) ) {
288
  foreach ( $product_addons as $addon_id => $product_addon ) {
289
- $data[ 'addon_' . $addon_id . '_name' ] = array( 'original' => $product_addon['name'] );
290
- $data[ 'addon_' . $addon_id . '_description' ] = array( 'original' => $product_addon['description'] );
291
- if ( ! empty( $product_addon['options'] ) ) {
292
- foreach ( $product_addon['options'] as $option_id => $option ) {
293
- $data[ 'addon_' . $addon_id . '_option_' . $option_id . '_label' ] = array( 'original' => $option['label'] );
 
294
  }
295
  }
296
  }
@@ -299,11 +318,12 @@ class WCML_Product_Addons {
299
  $translated_product_addons = $this->get_product_addons( $translation->ID );
300
  if ( ! empty( $translated_product_addons ) ) {
301
  foreach ( $translated_product_addons as $addon_id => $transalted_product_addon ) {
302
- $data[ 'addon_' . $addon_id . '_name' ]['translation'] = $transalted_product_addon['name'];
303
- $data[ 'addon_' . $addon_id . '_description' ]['translation'] = $transalted_product_addon['description'];
304
- if ( ! empty( $transalted_product_addon['options'] ) ) {
305
- foreach ( $transalted_product_addon['options'] as $option_id => $option ) {
306
- $data[ 'addon_' . $addon_id . '_option_' . $option_id . '_label' ]['translation'] = $option['label'];
 
307
  }
308
  }
309
  }
@@ -326,13 +346,12 @@ class WCML_Product_Addons {
326
  if ( ! empty( $product_addons ) ) {
327
 
328
  foreach ( $product_addons as $addon_id => $product_addon ) {
329
-
330
  $product_addons[ $addon_id ]['name'] = $data[ md5( 'addon_' . $addon_id . '_name' ) ];
331
  $product_addons[ $addon_id ]['description'] = $data[ md5( 'addon_' . $addon_id . '_description' ) ];
332
 
333
- if ( ! empty( $product_addon['options'] ) ) {
334
-
335
- foreach ( $product_addon['options'] as $option_id => $option ) {
336
  $product_addons[ $addon_id ]['options'][ $option_id ]['label'] = $data[ md5( 'addon_'.$addon_id.'_option_'.$option_id.'_label' ) ];
337
  }
338
  }
@@ -561,9 +580,14 @@ class WCML_Product_Addons {
561
  * @return array
562
  */
563
  private function update_multiple_options_prices( $product_addons, $price_option_key, $addon_key, $code ){
564
- foreach ( $product_addons[ $addon_key ]['options'] as $option_key => $option ) {
565
- if ( isset( $_POST[ $price_option_key ][ $addon_key ][ 'price_'.$code ][ $option_key ] ) ) {
566
- $product_addons[ $addon_key ]['options'][ $option_key ][ 'price_' . $code ] = wc_format_decimal( $_POST[ $price_option_key ][ $addon_key ][ 'price_'.$code ][ $option_key ] );
 
 
 
 
 
567
  }
568
  }
569
 
113
  if ( '_product_addons' === $meta_key && 'global_product_addon' === get_post_type( $id ) ) {
114
  $this->update_custom_prices_values( $id );
115
  foreach ( $addons as $addon ) {
116
+ $addon_data = wpml_collect( $addon );
117
+ $addon_type = $addon_data->get('type');
118
+ $addon_position = $addon_data->get('position');
119
  //register name
120
+ do_action( 'wpml_register_single_string', 'wc_product_addons_strings', $id . '_addon_' . $addon_type . '_' . $addon_position . '_name', $addon_data->get('name') );
121
  //register description
122
+ do_action( 'wpml_register_single_string', 'wc_product_addons_strings', $id . '_addon_' . $addon_type . '_' . $addon_position . '_description', $addon_data->get('description') );
123
  //register options labels
124
+
125
+ if ( $addon_data->offsetExists('options') ) {
126
+ foreach ( $addon_data->get('options') as $key => $option ) {
127
+ do_action( 'wpml_register_single_string', 'wc_product_addons_strings', $id . '_addon_' . $addon_type . '_' . $addon_position . '_option_label_' . $key, wpml_collect( $option )->get('label') );
128
+ }
129
  }
130
  }
131
  }
149
 
150
  if ( is_array( $addons ) ) {
151
  foreach ( $addons as $key => $addon ) {
152
+ $addon_data = wpml_collect( $addon );
153
+ $addon_type = $addon_data->get('type');
154
+ $addon_position = $addon_data->get('position');
155
  //register name
156
+ $addons[ $key ]['name'] = apply_filters( 'wpml_translate_single_string', $addon_data->get('name'), 'wc_product_addons_strings', $object_id . '_addon_' . $addon_type . '_' . $addon_position . '_name' );
157
  //register description
158
+ $addons[ $key ]['description'] = apply_filters( 'wpml_translate_single_string', $addon_data->get('description'), 'wc_product_addons_strings', $object_id . '_addon_' . $addon_type . '_' . $addon_position . '_description' );
159
  //register options labels
160
+ if ( $addon_data->offsetExists('options') ) {
161
+ foreach ( $addon['options'] as $opt_key => $option ) {
162
+ $addons[ $key ]['options'][ $opt_key ]['label'] = apply_filters( 'wpml_translate_single_string', wpml_collect( $option )->get('label'), 'wc_product_addons_strings', $object_id . '_addon_' . $addon_type . '_' . $addon_position . '_option_label_' . $opt_key );
163
+ }
164
  }
165
  }
166
  }
183
  if ( $this->is_multi_currency_on() ) {
184
 
185
  foreach ( $addons as $add_id => $addon ) {
186
+
187
+ $addon_data = wpml_collect( $addon );
188
+
189
+ if ( $addon_data->offsetExists('price') && $addon_data->get('price') ) {
190
  $addons[ $add_id ]['price'] = $this->converted_addon_price( $addon, $post_id );
191
  }
192
 
193
+ if ( $addon_data->offsetExists('options') ) {
194
+ foreach ( $addon_data->get('options') as $key => $option ) {
195
+ $addons[ $add_id ]['options'][ $key ]['price'] = $this->converted_addon_price( $option, $post_id );
196
+ }
197
  }
198
+
199
  }
200
  }
201
 
264
 
265
  if ( ! empty( $product_addons ) ) {
266
  foreach ( $product_addons as $addon_id => $product_addon ) {
267
+ $addon_data = wpml_collect( $product_addon );
268
 
269
+ $addons_section = new WPML_Editor_UI_Field_Section( sprintf( __( 'Product Add-ons Group "%s"', 'woocommerce-multilingual' ), $addon_data->get('name') ) );
270
 
271
  $group = new WPML_Editor_UI_Field_Group( '' , true );
272
  $addon_field = new WPML_Editor_UI_Single_Line_Field( 'addon_'.$addon_id.'_name', __( 'Name', 'woocommerce-multilingual' ), $data, false );
276
 
277
  $addons_section->add_field( $group );
278
 
279
+ if ( $addon_data->offsetExists('options') && $addon_data->get('options') ) {
280
 
281
  $labels_group = new WPML_Editor_UI_Field_Group( __( 'Options', 'woocommerce-multilingual' ) , true );
282
 
283
+ foreach ( $addon_data->get('options') as $option_id => $option ) {
284
  $option_label_field = new WPML_Editor_UI_Single_Line_Field( 'addon_'.$addon_id.'_option_'.$option_id.'_label', __( 'Label', 'woocommerce-multilingual' ), $data, false );
285
  $labels_group->add_field( $option_label_field );
286
  }
304
 
305
  if ( ! empty( $product_addons ) ) {
306
  foreach ( $product_addons as $addon_id => $product_addon ) {
307
+ $addon_data = wpml_collect( $product_addon );
308
+ $data[ 'addon_' . $addon_id . '_name' ] = array( 'original' => $addon_data->get('name') );
309
+ $data[ 'addon_' . $addon_id . '_description' ] = array( 'original' => $addon_data->get('description') );
310
+ if ( $addon_data->offsetExists('options') && $addon_data->get('options') ) {
311
+ foreach ( $addon_data->get('options') as $option_id => $option ) {
312
+ $data[ 'addon_' . $addon_id . '_option_' . $option_id . '_label' ] = array( 'original' => wpml_collect( $option )->get('label') );
313
  }
314
  }
315
  }
318
  $translated_product_addons = $this->get_product_addons( $translation->ID );
319
  if ( ! empty( $translated_product_addons ) ) {
320
  foreach ( $translated_product_addons as $addon_id => $transalted_product_addon ) {
321
+ $translated_addon_data = wpml_collect( $transalted_product_addon );
322
+ $data[ 'addon_' . $addon_id . '_name' ]['translation'] = $translated_addon_data->get('name');
323
+ $data[ 'addon_' . $addon_id . '_description' ]['translation'] = $translated_addon_data->get('description');
324
+ if ( $translated_addon_data->offsetExists('options') && $translated_addon_data->get('options') ) {
325
+ foreach ( $translated_addon_data->get('options') as $option_id => $option ) {
326
+ $data[ 'addon_' . $addon_id . '_option_' . $option_id . '_label' ]['translation'] = wpml_collect( $option )->get('label');
327
  }
328
  }
329
  }
346
  if ( ! empty( $product_addons ) ) {
347
 
348
  foreach ( $product_addons as $addon_id => $product_addon ) {
349
+ $addon_data = wpml_collect( $product_addon );
350
  $product_addons[ $addon_id ]['name'] = $data[ md5( 'addon_' . $addon_id . '_name' ) ];
351
  $product_addons[ $addon_id ]['description'] = $data[ md5( 'addon_' . $addon_id . '_description' ) ];
352
 
353
+ if ( $addon_data->offsetExists('options') && $addon_data->get('options') ) {
354
+ foreach ( $addon_data->get('options') as $option_id => $option ) {
 
355
  $product_addons[ $addon_id ]['options'][ $option_id ]['label'] = $data[ md5( 'addon_'.$addon_id.'_option_'.$option_id.'_label' ) ];
356
  }
357
  }
580
  * @return array
581
  */
582
  private function update_multiple_options_prices( $product_addons, $price_option_key, $addon_key, $code ){
583
+
584
+ $addon_data = wpml_collect( $product_addons[ $addon_key ] );
585
+
586
+ if ( $addon_data->offsetExists('options') ) {
587
+ foreach ( $addon_data->get('options') as $option_key => $option ) {
588
+ if ( isset( $_POST[ $price_option_key ][ $addon_key ][ 'price_'.$code ][ $option_key ] ) ) {
589
+ $product_addons[ $addon_key ]['options'][ $option_key ][ 'price_' . $code ] = wc_format_decimal( $_POST[ $price_option_key ][ $addon_key ][ 'price_'.$code ][ $option_key ] );
590
+ }
591
  }
592
  }
593
 
compatibility/class-wcml-table-rate-shipping.php CHANGED
@@ -70,12 +70,12 @@ class WCML_Table_Rate_Shipping {
70
 
71
  if( isset( $_POST[ 'shipping_label' ] ) &&
72
  isset( $_POST[ 'woocommerce_table_rate_title' ] ) ){
73
- do_action( 'wpml_register_single_string', 'woocommerce', sanitize_text_field( $_POST[ 'woocommerce_table_rate_title' ] ) . '_shipping_method_title', sanitize_text_field( $_POST[ 'woocommerce_table_rate_title' ] ) );
74
 
75
  $shipping_labels = array_map( 'wc_clean', $_POST[ 'shipping_label' ] );
76
  foreach ( $shipping_labels as $key => $shipping_label ) {
77
  $rate_key = isset( $_GET[ 'instance_id' ] ) ? 'table_rate'.$_GET[ 'instance_id' ].$_POST[ 'rate_id' ][ $key ] : $shipping_label;
78
- do_action( 'wpml_register_single_string', 'woocommerce', $rate_key. '_shipping_method_title', $shipping_label );
79
  }
80
  }
81
  }
@@ -184,23 +184,21 @@ class WCML_Table_Rate_Shipping {
184
  */
185
  public function shipping_table_rate_is_available( $available, $package, $object ) {
186
 
187
- if ( ! $available ) {
188
- add_filter( 'option_woocommerce_table_rate_priorities_' . $object->instance_id, array(
189
- $this,
190
- 'filter_table_rate_priorities'
191
- ) );
192
- remove_filter( 'woocommerce_shipping_table_rate_is_available', array(
193
- $this,
194
- 'shipping_table_rate_is_available'
195
- ), 10, 3 );
196
-
197
- $available = $object->is_available( $package );
198
-
199
- add_filter( 'woocommerce_shipping_table_rate_is_available', array(
200
- $this,
201
- 'shipping_table_rate_is_available'
202
- ), 10, 3 );
203
- }
204
 
205
  return $available;
206
  }
70
 
71
  if( isset( $_POST[ 'shipping_label' ] ) &&
72
  isset( $_POST[ 'woocommerce_table_rate_title' ] ) ){
73
+ do_action( 'wpml_register_single_string', WCML_WC_Shipping::STRINGS_CONTEXT, sanitize_text_field( $_POST[ 'woocommerce_table_rate_title' ] ) . '_shipping_method_title', sanitize_text_field( $_POST[ 'woocommerce_table_rate_title' ] ) );
74
 
75
  $shipping_labels = array_map( 'wc_clean', $_POST[ 'shipping_label' ] );
76
  foreach ( $shipping_labels as $key => $shipping_label ) {
77
  $rate_key = isset( $_GET[ 'instance_id' ] ) ? 'table_rate'.$_GET[ 'instance_id' ].$_POST[ 'rate_id' ][ $key ] : $shipping_label;
78
+ do_action( 'wpml_register_single_string', WCML_WC_Shipping::STRINGS_CONTEXT, $rate_key. '_shipping_method_title', $shipping_label );
79
  }
80
  }
81
  }
184
  */
185
  public function shipping_table_rate_is_available( $available, $package, $object ) {
186
 
187
+ add_filter( 'option_woocommerce_table_rate_priorities_' . $object->instance_id, array(
188
+ $this,
189
+ 'filter_table_rate_priorities'
190
+ ) );
191
+ remove_filter( 'woocommerce_shipping_table_rate_is_available', array(
192
+ $this,
193
+ 'shipping_table_rate_is_available'
194
+ ), 10, 3 );
195
+
196
+ $available = $object->is_available( $package );
197
+
198
+ add_filter( 'woocommerce_shipping_table_rate_is_available', array(
199
+ $this,
200
+ 'shipping_table_rate_is_available'
201
+ ), 10, 3 );
 
 
202
 
203
  return $available;
204
  }
compatibility/class-wcml-wc-subscriptions.php CHANGED
@@ -57,6 +57,8 @@ class WCML_WC_Subscriptions{
57
  add_action( 'woocommerce_after_calculate_totals', array( $this, 'maybe_restore_recurring_carts'), 200 );
58
 
59
  $this->maybe_force_client_currency_for_resubscribe_subscription();
 
 
60
  }
61
 
62
  //Translate emails
@@ -381,4 +383,16 @@ class WCML_WC_Subscriptions{
381
 
382
  return $section_prefix;
383
  }
 
 
 
 
 
 
 
 
 
 
 
 
384
  }
57
  add_action( 'woocommerce_after_calculate_totals', array( $this, 'maybe_restore_recurring_carts'), 200 );
58
 
59
  $this->maybe_force_client_currency_for_resubscribe_subscription();
60
+
61
+ add_filter( 'wcs_get_subscription', array( $this, 'filter_subscription_items' ) );
62
  }
63
 
64
  //Translate emails
383
 
384
  return $section_prefix;
385
  }
386
+
387
+ /**
388
+ * @param WC_Subscription $subscription
389
+ *
390
+ * @return WC_Subscription
391
+ */
392
+ public function filter_subscription_items( $subscription ){
393
+
394
+ $this->woocommerce_wpml->orders->adjust_order_item_in_language( $subscription->get_items() );
395
+
396
+ return $subscription;
397
+ }
398
  }
inc/class-wcml-attributes.php CHANGED
@@ -1,6 +1,6 @@
1
  <?php
2
 
3
- class WCML_Attributes{
4
 
5
  const PRIORITY_AFTER_WC_INIT = 100;
6
 
@@ -32,43 +32,52 @@ class WCML_Attributes{
32
  $this->wpdb = $wpdb;
33
  }
34
 
35
- private function get_wcml_terms_instance(){
36
  return $this->woocommerce_wpml->terms;
37
  }
38
 
39
- private function get_wcml_products_instance(){
40
  return $this->woocommerce_wpml->products;
41
  }
42
 
43
- public function add_hooks(){
44
-
45
- add_action( 'init', array( $this, 'init' ) );
46
-
47
- add_filter( 'wpml_translation_job_post_meta_value_translated', array($this, 'filter_product_attributes_for_translation'), 10, 2 );
48
- add_filter( 'woocommerce_dropdown_variation_attribute_options_args', array($this, 'filter_dropdown_variation_attribute_options_args') );
49
-
50
- if( isset( $_POST['icl_ajx_action'] ) && $_POST['icl_ajx_action'] == 'icl_custom_tax_sync_options' ){
51
- $this->icl_custom_tax_sync_options();
52
- }
53
- add_filter( 'woocommerce_product_get_attributes', array( $this, 'filter_adding_to_cart_product_attributes_names' ) );
54
-
55
- if ( $this->get_wcml_products_instance()->is_product_display_as_translated_post_type() ) {
56
- add_filter( 'woocommerce_available_variation', array(
57
- $this,
58
- 'filter_available_variation_attribute_values_in_current_language'
59
- ) );
60
- add_filter( 'get_post_metadata', array(
61
- $this,
62
- 'filter_product_variation_post_meta_attribute_values_in_current_language'
63
- ), 10, 4 );
64
- add_filter( 'woocommerce_product_get_default_attributes', array(
65
- $this,
66
- 'filter_product_variation_default_attributes'
67
- ) );
68
- }
69
- add_action( 'update_post_meta', array( $this, 'set_translation_status_as_needs_update' ), 10, 3 );
70
- add_action( 'wc_ajax_get_variation', array( $this, 'maybe_filter_get_variation' ), 9 );
71
- }
 
 
 
 
 
 
 
 
 
72
 
73
  public function init() {
74
 
@@ -78,59 +87,65 @@ class WCML_Attributes{
78
 
79
  if ( apply_filters( 'wcml_is_attributes_page', $is_attr_page ) ) {
80
  add_action( 'admin_init', array( $this, 'not_translatable_html' ) );
81
- add_action( 'woocommerce_attribute_added', array( $this, 'set_attribute_readonly_config' ), self::PRIORITY_AFTER_WC_INIT, 2 );
82
- add_action( 'woocommerce_attribute_updated', array( $this, 'set_attribute_readonly_config' ), self::PRIORITY_AFTER_WC_INIT, 3 );
 
 
 
 
 
 
83
  }
84
 
85
  }
86
 
87
- public function not_translatable_html(){
88
- $attr_id = isset( $_GET[ 'edit' ] ) ? absint( $_GET[ 'edit' ] ) : false;
89
 
90
- $attr_is_tnaslt = new WCML_Not_Translatable_Attributes( $attr_id, $this->woocommerce_wpml );
91
- $attr_is_tnaslt->show();
92
- }
93
 
94
- public function get_attribute_terms( $attribute ){
95
 
96
- return $this->wpdb->get_results($this->wpdb->prepare("
97
  SELECT * FROM {$this->wpdb->term_taxonomy} x JOIN {$this->wpdb->terms} t ON x.term_id = t.term_id WHERE x.taxonomy = %s", $attribute ) );
98
 
99
- }
100
 
101
  /**
102
  * @param int $id
103
  * @param array $data
104
  * @param bool $old_slug
105
  */
106
- public function set_attribute_readonly_config( $id, $data, $old_slug = false ){
107
 
108
- if( isset( $_POST[ 'save_attribute' ] ) || isset( $_POST[ 'add_new_attribute' ] ) ) {
109
 
110
- $is_translatable = (int)isset( $_POST['wcml-is-translatable-attr'] );
111
 
112
- if( $_POST['attribute_name'] ){
113
- $attribute_name = wc_sanitize_taxonomy_name( wp_unslash( $_POST['attribute_name'] ) );
114
- }else{
115
- $attribute_name = wc_sanitize_taxonomy_name( wc_clean( wp_unslash( $_POST['attribute_label'] ) ) );
116
- }
117
 
118
- $attribute_name = wc_attribute_taxonomy_name( $attribute_name );
119
 
120
- if ( $is_translatable === 0 ) {
121
- //delete all translated attributes terms if "Translatable?" option un-checked
122
- $this->delete_translated_attribute_terms( $attribute_name );
123
- $this->set_variations_to_use_original_attributes( $attribute_name );
124
- $this->set_original_attributes_for_products( $attribute_name );
125
- }
126
 
127
- if( $old_slug !== $data[ 'attribute_name' ] ){
128
- $this->fix_attribute_slug_in_translations_table( wc_attribute_taxonomy_name( $old_slug ), $attribute_name );
129
- }
130
 
131
- $this->set_attribute_config_in_settings( $attribute_name, $is_translatable );
132
- }
133
- }
134
 
135
  /**
136
  * @param string $old_attribute_name
@@ -144,456 +159,457 @@ class WCML_Attributes{
144
  );
145
  }
146
 
147
- public function set_attribute_config_in_settings( $attribute_name, $is_translatable ){
148
- $this->set_attribute_config_in_wcml_settings( $attribute_name, $is_translatable );
149
- $this->set_attribute_config_in_wpml_settings( $attribute_name, $is_translatable );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
150
 
151
- $this->get_wcml_terms_instance()->update_terms_translated_status( $attribute_name );
152
- }
153
-
154
- public function set_attribute_config_in_wcml_settings( $attribute_name, $is_translatable ){
155
- $wcml_settings = $this->woocommerce_wpml->get_settings();
156
- $wcml_settings[ 'attributes_settings' ][ $attribute_name ] = $is_translatable;
157
- $this->woocommerce_wpml->update_settings( $wcml_settings );
158
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
159
 
160
- public function set_attribute_config_in_wpml_settings( $attribute_name, $is_translatable ){
 
 
 
161
 
162
- $sync_settings = $this->sitepress->get_setting( 'taxonomies_sync_option', array() );
163
- $sync_settings[ $attribute_name ] = $is_translatable;
164
- $this->sitepress->set_setting( 'taxonomies_sync_option', $sync_settings, true );
165
- $this->sitepress->verify_taxonomy_translations( $attribute_name );
166
- }
167
 
168
- public function delete_translated_attribute_terms( $attribute ){
169
- $terms = $this->get_attribute_terms( $attribute );
 
 
 
 
170
 
171
- foreach( $terms as $term ){
172
- if( $this->term_translations->get_source_lang_code( $term->term_id ) ){
173
- wp_delete_term( $term->term_id, $attribute );
174
- }
175
- }
176
 
177
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
178
 
179
- public function set_variations_to_use_original_attributes( $attribute ){
180
- $terms = $this->get_attribute_terms( $attribute );
181
 
182
- foreach( $terms as $term ){
183
- if( is_null( $this->term_translations->get_source_lang_code( $term->term_id ) ) ){
184
- $variations = $this->wpdb->get_results( $this->wpdb->prepare( "SELECT post_id FROM {$this->wpdb->postmeta} WHERE meta_key=%s AND meta_value = %s", 'attribute_'.$attribute, $term->slug ) );
185
 
186
- foreach( $variations as $variation ){
187
- //update taxonomy in translation of variation
188
- foreach( $this->sitepress->get_active_languages() as $language ){
189
-
190
- $trnsl_variation_id = apply_filters( 'translate_object_id', $variation->post_id, 'product_variation', false, $language['code'] );
191
- if( !is_null( $trnsl_variation_id ) ){
192
- update_post_meta( $trnsl_variation_id, 'attribute_'.$attribute, $term->slug );
193
- }
194
- }
195
- }
196
- }
197
- }
198
- }
199
-
200
- public function set_original_attributes_for_products( $attribute ){
201
-
202
- $terms = $this->get_attribute_terms( $attribute );
203
- $cleared_products = array();
204
- foreach( $terms as $term ) {
205
- if( is_null( $this->term_translations->get_source_lang_code( $term->term_id ) ) ){
206
- $args = array(
207
- 'tax_query' => array(
208
- array(
209
- 'taxonomy' => $attribute,
210
- 'field' => 'slug',
211
- 'terms' => $term->slug
212
- )
213
- )
214
- );
215
-
216
- $products = get_posts($args);
217
-
218
- foreach( $products as $product ){
219
-
220
- foreach( $this->sitepress->get_active_languages() as $language ) {
221
-
222
- $trnsl_product_id = apply_filters( 'translate_object_id', $product->ID, 'product', false, $language['code'] );
223
-
224
- if ( !is_null( $trnsl_product_id ) ) {
225
- if( !in_array( $trnsl_product_id, $trnsl_product_id ) ){
226
- wp_delete_object_term_relationships( $trnsl_product_id, $attribute );
227
- $cleared_products[] = $trnsl_product_id;
228
- }
229
- wp_set_object_terms( $trnsl_product_id, $term->slug, $attribute, true );
230
- }
231
- }
232
- }
233
- }
234
- }
235
- }
236
-
237
-
238
- public function is_translatable_attribute( $attr_name ){
239
-
240
- if( !isset( $this->woocommerce_wpml->settings[ 'attributes_settings' ][ $attr_name ] ) ){
241
- $this->set_attribute_config_in_settings( $attr_name, 1 );
242
- }
243
-
244
- return isset( $this->woocommerce_wpml->settings[ 'attributes_settings' ][ $attr_name ] ) ? $this->woocommerce_wpml->settings[ 'attributes_settings' ][ $attr_name ] : 1;
245
- }
246
-
247
- public function get_translatable_attributes(){
248
- $attributes = wc_get_attribute_taxonomies();
249
-
250
- $translatable_attributes = array();
251
- foreach( $attributes as $attribute ){
252
- if( $this->is_translatable_attribute( wc_attribute_taxonomy_name( $attribute->attribute_name ) ) ){
253
- $translatable_attributes[] = $attribute;
254
- }
255
- }
256
-
257
- return $translatable_attributes;
258
- }
259
-
260
- public function set_translatable_attributes( $attributes ){
261
-
262
- foreach( $attributes as $name => $is_translatable ){
263
-
264
- $attribute_name = wc_attribute_taxonomy_name( $name );
265
- $this->set_attribute_config_in_settings( $attribute_name, $is_translatable );
266
-
267
- }
268
- }
269
-
270
- public function sync_product_attr( $original_product_id, $tr_product_id, $language = false, $data = false ){
271
-
272
- //get "_product_attributes" from original product
273
- $orig_product_attrs = $this->get_product_attributes( $original_product_id );
274
- $trnsl_product_attrs = $this->get_product_attributes( $tr_product_id );
275
-
276
- $trnsl_labels = $this->get_attr_label_translations( $tr_product_id );
277
-
278
- foreach ( $orig_product_attrs as $key => $orig_product_attr ) {
279
- $sanitized_key = $this->filter_attribute_name( $orig_product_attr[ 'name' ], $original_product_id, true );
280
- if( $sanitized_key != $key ) {
281
- $orig_product_attrs_buff = $orig_product_attrs[ $key ];
282
- unset( $orig_product_attrs[ $key ] );
283
- $orig_product_attrs[ $sanitized_key ] = $orig_product_attrs_buff;
284
- $key_to_save = $sanitized_key;
285
- }else{
286
- $key_to_save = $key;
287
- }
288
- if ( $data ){
289
- if ( isset( $data[ md5( $key ) ] ) && !empty( $data[ md5( $key ) ] ) && !is_array( $data[ md5( $key ) ] ) ) {
290
- //get translation values from $data
291
- $orig_product_attrs[ $key_to_save ][ 'value' ] = $data[ md5( $key ) ];
292
- } else {
293
- $orig_product_attrs[ $key_to_save ][ 'value' ] = '';
294
- }
295
-
296
- if ( isset( $data[ md5( $key . '_name' ) ] ) && !empty( $data[ md5( $key . '_name' ) ] ) && !is_array( $data[ md5( $key . '_name' ) ] ) ) {
297
- //get translation values from $data
298
- $trnsl_labels[ $language ][ $key_to_save ] = stripslashes( $data[ md5( $key . '_name' ) ] );
299
- } else {
300
- $trnsl_labels[ $language ][ $key_to_save ] = '';
301
- }
302
- }elseif( !$orig_product_attr[ 'is_taxonomy' ] ){
303
- $duplicate_of = get_post_meta( $tr_product_id, '_icl_lang_duplicate_of', true );
304
-
305
- if( !$duplicate_of ){
306
- if( isset( $trnsl_product_attrs[ $key ] ) ){
307
- $orig_product_attrs[ $key_to_save ][ 'value' ] = $trnsl_product_attrs[ $key ][ 'value' ];
308
- }elseif( !empty( $trnsl_product_attrs ) ){
309
- unset ( $orig_product_attrs[ $key_to_save ] );
310
- }
311
- }
312
- }
313
- }
314
-
315
- update_post_meta( $tr_product_id, 'attr_label_translations', $trnsl_labels );
316
- //update "_product_attributes"
317
- update_post_meta( $tr_product_id, '_product_attributes', $orig_product_attrs );
318
- }
319
-
320
- public function get_product_attributes( $product_id ){
321
- $attributes = get_post_meta( $product_id, '_product_attributes', true );
322
- if( !is_array( $attributes ) ){
323
- $attributes = array();
324
- }
325
- return $attributes;
326
- }
327
-
328
- public function get_attr_label_translations( $product_id, $lang = false ){
329
- $trnsl_labels = get_post_meta( $product_id, 'attr_label_translations', true );
330
-
331
- if( !is_array( $trnsl_labels ) ){
332
- $trnsl_labels = array();
333
- }
334
-
335
- if( isset( $trnsl_labels[ $lang ] ) ){
336
- return $trnsl_labels[ $lang ];
337
- }
338
-
339
- return $trnsl_labels;
340
- }
341
-
342
- public function sync_default_product_attr( $orig_post_id, $transl_post_id, $lang ){
343
- $original_default_attributes = get_post_meta( $orig_post_id, '_default_attributes', true );
344
-
345
- if( !empty( $original_default_attributes ) ){
346
- $unserialized_default_attributes = array();
347
- foreach(maybe_unserialize( $original_default_attributes ) as $attribute => $default_term_slug ){
348
- // get the correct language
349
- if ( substr( $attribute, 0, 3 ) == 'pa_' ) {
350
- //attr is taxonomy
351
- if( $this->is_translatable_attribute( $attribute ) ){
352
- $sanitized_attribute_name = wc_sanitize_taxonomy_name( $attribute );
353
- $default_term_id = $this->get_wcml_terms_instance()->wcml_get_term_id_by_slug( $sanitized_attribute_name, $default_term_slug );
354
- $tr_id = apply_filters( 'translate_object_id', $default_term_id, $sanitized_attribute_name, false, $lang );
355
-
356
- if( $tr_id ){
357
- $translated_term = $this->get_wcml_terms_instance()->wcml_get_term_by_id( $tr_id, $sanitized_attribute_name );
358
- $unserialized_default_attributes[ $attribute ] = $translated_term->slug;
359
- }
360
- }else{
361
- $unserialized_default_attributes[ $attribute ] = $default_term_slug;
362
- }
363
- }else{
364
- //custom attr
365
- $orig_product_attributes = get_post_meta( $orig_post_id, '_product_attributes', true );
366
- $unserialized_orig_product_attributes = maybe_unserialize( $orig_product_attributes );
367
-
368
- if( isset( $unserialized_orig_product_attributes[ $attribute ] ) ){
369
- $orig_attr_values = explode( '|', $unserialized_orig_product_attributes[ $attribute ][ 'value' ] );
370
- $orig_attr_values = array_map( 'trim', $orig_attr_values );
371
-
372
- foreach( $orig_attr_values as $key => $orig_attr_value ){
373
- $orig_attr_value_sanitized = strtolower( sanitize_title ( $orig_attr_value ) );
374
-
375
- if( $orig_attr_value_sanitized == $default_term_slug || trim( $orig_attr_value ) == trim( $default_term_slug ) ){
376
- $tnsl_product_attributes = get_post_meta( $transl_post_id, '_product_attributes', true );
377
- $unserialized_tnsl_product_attributes = maybe_unserialize( $tnsl_product_attributes );
378
-
379
- if( isset( $unserialized_tnsl_product_attributes[ $attribute ] ) ){
380
- $trnsl_attr_values = explode( '|', $unserialized_tnsl_product_attributes[ $attribute ][ 'value' ] );
381
-
382
- if( $orig_attr_value_sanitized == $default_term_slug ){
383
- $trnsl_attr_value = strtolower( sanitize_title( trim( $trnsl_attr_values[ $key ] ) ) );
384
- }else{
385
- $trnsl_attr_value = trim( $trnsl_attr_values[ $key ] );
386
- }
387
- $unserialized_default_attributes[ $attribute ] = $trnsl_attr_value;
388
- }
389
- }
390
- }
391
- }
392
- }
393
- }
394
-
395
- $data = array( 'meta_value' => maybe_serialize( $unserialized_default_attributes ) );
396
- }else{
397
- $data = array( 'meta_value' => maybe_serialize( array() ) );
398
- }
399
-
400
- $where = array( 'post_id' => $transl_post_id, 'meta_key' => '_default_attributes' );
401
-
402
- $translated_product_meta = get_post_meta( $transl_post_id );
403
- if ( isset( $translated_product_meta['_default_attributes'] ) ) {
404
- $this->wpdb->update( $this->wpdb->postmeta, $data, $where );
405
- } else {
406
- $this->wpdb->insert( $this->wpdb->postmeta, array_merge( $data, $where ) );
407
- }
408
-
409
- }
410
-
411
- /*
412
- * get attribute translation
413
- */
414
- public function get_custom_attribute_translation( $product_id, $attribute_key, $attribute, $lang_code ){
415
- $tr_post_id = apply_filters( 'translate_object_id', $product_id, 'product', false, $lang_code );
416
- $transl = array();
417
- if( $tr_post_id ){
418
- if( !$attribute[ 'is_taxonomy' ] ){
419
- $tr_attrs = get_post_meta($tr_post_id, '_product_attributes', true);
420
- if( $tr_attrs ){
421
- foreach( $tr_attrs as $key => $tr_attr ) {
422
- if( $attribute_key == $key ){
423
- $transl[ 'value' ] = $tr_attr[ 'value' ];
424
- $trnsl_labels = $this->get_attr_label_translations( $tr_post_id );
425
-
426
- if( isset( $trnsl_labels[ $lang_code ][ $attribute_key ] ) ){
427
- $transl[ 'name' ] = $trnsl_labels[ $lang_code ][ $attribute_key ];
428
- }else{
429
- $transl[ 'name' ] = $tr_attr[ 'name' ];
430
- }
431
- return $transl;
432
- }
433
- }
434
- }
435
- return false;
436
- }
437
- }
438
- return false;
439
- }
440
-
441
- /*
442
- * Get custom attribute translation
443
- * Returned translated attribute or original if missed
444
- */
445
- public function get_custom_attr_translation( $product_id, $tr_product_id, $taxonomy, $attribute ){
446
- $orig_product_attributes = get_post_meta( $product_id, '_product_attributes', true );
447
- $unserialized_orig_product_attributes = maybe_unserialize( $orig_product_attributes );
448
-
449
- foreach( $unserialized_orig_product_attributes as $orig_attr_key => $orig_product_attribute ){
450
- $orig_attr_key = urldecode( $orig_attr_key );
451
- if( strtolower( $taxonomy ) == $orig_attr_key ){
452
- $values = explode( '|', $orig_product_attribute[ 'value' ] );
453
-
454
- foreach( $values as $key_id => $value ){
455
- if( trim( $value," " ) == $attribute ){
456
- $attr_key_id = $key_id;
457
- }
458
- }
459
- }
460
- }
461
-
462
- $trnsl_product_attributes = get_post_meta( $tr_product_id, '_product_attributes', true );
463
- $unserialized_trnsl_product_attributes = maybe_unserialize( $trnsl_product_attributes );
464
- $taxonomy = sanitize_title( $taxonomy );
465
- $trnsl_attr_values = explode( '|', $unserialized_trnsl_product_attributes[ $taxonomy ][ 'value' ] );
466
-
467
- if( isset( $attr_key_id ) && isset( $trnsl_attr_values[ $attr_key_id ] ) ){
468
- return trim( $trnsl_attr_values[ $attr_key_id ] );
469
- }
470
-
471
- return $attribute;
472
- }
473
-
474
- public function filter_product_attributes_for_translation( $translated, $key ){
475
- $translated = $translated
476
- ? preg_match('#^(?!field-_product_attributes-(.+)-(.+)-(?!value|name))#', $key) : 0;
477
-
478
- return $translated;
479
- }
480
-
481
- public function icl_custom_tax_sync_options(){
482
- foreach( $_POST['icl_sync_tax'] as $taxonomy => $value){
483
- if ( substr( $taxonomy, 0, 3 ) == 'pa_' ) {
484
- $this->set_attribute_config_in_wcml_settings( $taxonomy , $value);
485
- }
486
- }
487
-
488
- }
489
-
490
- public function is_attributes_fully_translated(){
491
-
492
- $product_attributes = $this->get_translatable_attributes();
493
-
494
- $fully_translated = true;
495
-
496
- if( $product_attributes ){
497
- foreach( $product_attributes as $attribute ){
498
- $is_fully_translated = $this->get_wcml_terms_instance()->is_fully_translated( 'pa_' . $attribute->attribute_name );
499
- if( !$is_fully_translated ){
500
- $fully_translated = false;
501
- break;
502
- }
503
- }
504
- }
505
-
506
- return $fully_translated;
507
- }
508
-
509
- public function get_translated_variation_attribute_post_meta( $meta_value, $meta_key, $original_variation_id, $variation_id, $lang ){
510
-
511
- $original_product_attr = get_post_meta( wp_get_post_parent_id( $original_variation_id ), '_product_attributes', true );
512
- $tr_product_attr = get_post_meta( wp_get_post_parent_id( $variation_id ), '_product_attributes', true );
513
-
514
- $tax = wc_sanitize_taxonomy_name ( substr( $meta_key, 10 ) );
515
- if( taxonomy_exists( $tax ) ){
516
- $attid = $this->get_wcml_terms_instance()->wcml_get_term_id_by_slug( $tax, $meta_value );
517
- if( $this->is_translatable_attribute( $tax ) && $attid ){
518
-
519
- $term_obj = $this->get_wcml_terms_instance()->wcml_get_term_by_id( $attid, $tax );
520
- $trnsl_term_id = apply_filters( 'translate_object_id', $term_obj->term_id, $tax, false, $lang );
521
-
522
- if( $trnsl_term_id ) {
523
- $trnsl_term_obj = $this->get_wcml_terms_instance()->wcml_get_term_by_id( $trnsl_term_id, $tax );
524
- $meta_value = $trnsl_term_obj->slug;
525
- }
526
- }
527
- }else{
528
- if( !isset( $original_product_attr[ $tax ] ) ){
529
- $tax = sanitize_title( $tax );
530
- }
531
-
532
- if( isset( $original_product_attr[ $tax ] ) ){
533
- if( isset( $tr_product_attr[ $tax ] ) ){
534
- $values_arrs = array_map( 'trim', explode( '|', $original_product_attr[ $tax ][ 'value' ] ) );
535
- $values_arrs_tr = array_map( 'trim', explode( '|', $tr_product_attr[ $tax ][ 'value' ] ) );
536
-
537
- foreach( $values_arrs as $key => $value ){
538
- $value_sanitized = sanitize_title( $value );
539
- if(
540
- ( $value_sanitized == strtolower( urldecode( $meta_value ) ) ||
541
- strtolower( $value_sanitized ) == $meta_value ||
542
- $value == $meta_value )
543
- && isset( $values_arrs_tr[ $key ] ) )
544
- {
545
- $meta_value = $values_arrs_tr[ $key ];
546
- }
547
- }
548
- }
549
- }
550
- $meta_key = 'attribute_'.$tax;
551
- }
552
-
553
- return array(
554
- 'meta_value' => $meta_value,
555
- 'meta_key' => $meta_key
556
- );
557
- }
558
-
559
- function filter_dropdown_variation_attribute_options_args( $args ){
560
-
561
- if( isset( $args['attribute'] ) && isset( $args['product'] ) ){
562
- $args['attribute'] = $this->filter_attribute_name( $args['attribute'], $args['product']->get_id() );
563
-
564
- if( $this->get_wcml_products_instance()->is_product_display_as_translated_post_type() ){
565
- foreach( $args[ 'options' ] as $key => $attribute_value ){
566
- $args[ 'options' ][ $key ] = $this->get_attribute_term_translation_in_current_language( $args[ 'attribute' ], $attribute_value );
567
- }
568
- }
569
- }
570
-
571
- return $args;
572
- }
573
-
574
- /*
575
- * special case when original attribute language is German or Danish,
576
- * needs handle special chars accordingly
577
- * https://onthegosystems.myjetbrains.com/youtrack/issue/wcml-1785
578
- */
579
- function filter_attribute_name( $attribute_name, $product_id, $return_sanitized = false ) {
580
-
581
- if ( $product_id ) {
582
- $orig_lang = $this->get_wcml_products_instance()->get_original_product_language( $product_id );
583
- $current_language = $this->sitepress->get_current_language();
584
-
585
- if ( in_array( $orig_lang, array( 'de', 'da' ) ) && $current_language !== $orig_lang ) {
586
- $attribute_name = $this->sitepress->locale_utils->filter_sanitize_title( remove_accents( $attribute_name ), $attribute_name );
587
- remove_filter( 'sanitize_title', array( $this->sitepress->locale_utils, 'filter_sanitize_title' ), 10 );
588
- }
589
- }
590
-
591
- if ( $return_sanitized ) {
592
- $attribute_name = sanitize_title( $attribute_name );
593
- }
594
-
595
- return $attribute_name;
596
- }
597
 
598
  public function filter_adding_to_cart_product_attributes_names( $attributes ) {
599
 
@@ -617,23 +633,23 @@ class WCML_Attributes{
617
  return $attributes;
618
  }
619
 
620
- public function is_a_taxonomy( $attribute ){
621
 
622
- if(
623
- (
624
- $attribute instanceof WC_Product_Attribute &&
625
- $attribute->is_taxonomy()
626
- ) ||
627
- (
628
- is_array( $attribute ) &&
629
- $attribute['is_taxonomy']
630
- )
631
- ){
632
- return true;
633
- }
634
 
635
- return false;
636
- }
637
 
638
  /**
639
  *
@@ -664,7 +680,7 @@ class WCML_Attributes{
664
  if ( '' === $meta_key && 'product_variation' === get_post_type( $object_id ) ) {
665
 
666
  $cache_group = 'wpml-all-meta-product-variation';
667
- $cache_key = $this->sitepress->get_current_language() . $object_id;
668
  $cached_value = wp_cache_get( $cache_key, $cache_group );
669
 
670
  if ( $cached_value ) {
@@ -709,11 +725,11 @@ class WCML_Attributes{
709
  *
710
  * @return array
711
  */
712
- public function filter_product_variation_default_attributes( $default_attributes ){
713
 
714
- if( $default_attributes ){
715
 
716
- foreach( $default_attributes as $attribute_key => $attribute_value ){
717
 
718
  $default_attributes[ $attribute_key ] = $this->get_attribute_term_translation_in_current_language( $attribute_key, $attribute_value );
719
 
@@ -733,9 +749,9 @@ class WCML_Attributes{
733
  */
734
  private function get_attribute_term_translation_in_current_language( $attribute_taxonomy, $attribute_value ) {
735
 
736
- if( taxonomy_exists( $attribute_taxonomy ) ){
737
  $term = get_term_by( 'slug', $attribute_value, $attribute_taxonomy );
738
- if( $term ){
739
  $attribute_value = $term->slug;
740
  }
741
  }
1
  <?php
2
 
3
+ class WCML_Attributes {
4
 
5
  const PRIORITY_AFTER_WC_INIT = 100;
6
 
32
  $this->wpdb = $wpdb;
33
  }
34
 
35
+ private function get_wcml_terms_instance() {
36
  return $this->woocommerce_wpml->terms;
37
  }
38
 
39
+ private function get_wcml_products_instance() {
40
  return $this->woocommerce_wpml->products;
41
  }
42
 
43
+ public function add_hooks() {
44
+
45
+ add_action( 'init', array( $this, 'init' ) );
46
+
47
+ add_filter( 'wpml_translation_job_post_meta_value_translated', array(
48
+ $this,
49
+ 'filter_product_attributes_for_translation'
50
+ ), 10, 2 );
51
+ add_filter( 'woocommerce_dropdown_variation_attribute_options_args', array(
52
+ $this,
53
+ 'filter_dropdown_variation_attribute_options_args'
54
+ ) );
55
+
56
+ if ( isset( $_POST['icl_ajx_action'] ) && $_POST['icl_ajx_action'] == 'icl_custom_tax_sync_options' ) {
57
+ $this->icl_custom_tax_sync_options();
58
+ }
59
+ add_filter( 'woocommerce_product_get_attributes', array(
60
+ $this,
61
+ 'filter_adding_to_cart_product_attributes_names'
62
+ ) );
63
+
64
+ if ( $this->get_wcml_products_instance()->is_product_display_as_translated_post_type() ) {
65
+ add_filter( 'woocommerce_available_variation', array(
66
+ $this,
67
+ 'filter_available_variation_attribute_values_in_current_language'
68
+ ) );
69
+ add_filter( 'get_post_metadata', array(
70
+ $this,
71
+ 'filter_product_variation_post_meta_attribute_values_in_current_language'
72
+ ), 10, 4 );
73
+ add_filter( 'woocommerce_product_get_default_attributes', array(
74
+ $this,
75
+ 'filter_product_variation_default_attributes'
76
+ ) );
77
+ }
78
+ add_action( 'update_post_meta', array( $this, 'set_translation_status_as_needs_update' ), 10, 3 );
79
+ add_action( 'wc_ajax_get_variation', array( $this, 'maybe_filter_get_variation' ), 9 );
80
+ }
81
 
82
  public function init() {
83
 
87
 
88
  if ( apply_filters( 'wcml_is_attributes_page', $is_attr_page ) ) {
89
  add_action( 'admin_init', array( $this, 'not_translatable_html' ) );
90
+ add_action( 'woocommerce_attribute_added', array(
91
+ $this,
92
+ 'set_attribute_readonly_config'
93
+ ), self::PRIORITY_AFTER_WC_INIT, 2 );
94
+ add_action( 'woocommerce_attribute_updated', array(
95
+ $this,
96
+ 'set_attribute_readonly_config'
97
+ ), self::PRIORITY_AFTER_WC_INIT, 3 );
98
  }
99
 
100
  }
101
 
102
+ public function not_translatable_html() {
103
+ $attr_id = isset( $_GET['edit'] ) ? absint( $_GET['edit'] ) : false;
104
 
105
+ $attr_is_tnaslt = new WCML_Not_Translatable_Attributes( $attr_id, $this->woocommerce_wpml );
106
+ $attr_is_tnaslt->show();
107
+ }
108
 
109
+ public function get_attribute_terms( $attribute ) {
110
 
111
+ return $this->wpdb->get_results( $this->wpdb->prepare( "
112
  SELECT * FROM {$this->wpdb->term_taxonomy} x JOIN {$this->wpdb->terms} t ON x.term_id = t.term_id WHERE x.taxonomy = %s", $attribute ) );
113
 
114
+ }
115
 
116
  /**
117
  * @param int $id
118
  * @param array $data
119
  * @param bool $old_slug
120
  */
121
+ public function set_attribute_readonly_config( $id, $data, $old_slug = false ) {
122
 
123
+ if ( isset( $_POST['save_attribute'] ) || isset( $_POST['add_new_attribute'] ) ) {
124
 
125
+ $is_translatable = (int) isset( $_POST['wcml-is-translatable-attr'] );
126
 
127
+ if ( $_POST['attribute_name'] ) {
128
+ $attribute_name = wc_sanitize_taxonomy_name( wp_unslash( $_POST['attribute_name'] ) );
129
+ } else {
130
+ $attribute_name = wc_sanitize_taxonomy_name( wc_clean( wp_unslash( $_POST['attribute_label'] ) ) );
131
+ }
132
 
133
+ $attribute_name = wc_attribute_taxonomy_name( $attribute_name );
134
 
135
+ if ( $is_translatable === 0 ) {
136
+ //delete all translated attributes terms if "Translatable?" option un-checked
137
+ $this->delete_translated_attribute_terms( $attribute_name );
138
+ $this->set_variations_to_use_original_attributes( $attribute_name );
139
+ $this->set_original_attributes_for_products( $attribute_name );
140
+ }
141
 
142
+ if ( $old_slug !== $data['attribute_name'] ) {
143
+ $this->fix_attribute_slug_in_translations_table( wc_attribute_taxonomy_name( $old_slug ), $attribute_name );
144
+ }
145
 
146
+ $this->set_attribute_config_in_settings( $attribute_name, $is_translatable );
147
+ }
148
+ }
149
 
150
  /**
151
  * @param string $old_attribute_name
159
  );
160
  }
161
 
162
+ public function set_attribute_config_in_settings( $attribute_name, $is_translatable ) {
163
+ $this->set_attribute_config_in_wcml_settings( $attribute_name, $is_translatable );
164
+ $this->set_attribute_config_in_wpml_settings( $attribute_name, $is_translatable );
165
+
166
+ $this->get_wcml_terms_instance()->update_terms_translated_status( $attribute_name );
167
+ }
168
+
169
+ public function set_attribute_config_in_wcml_settings( $attribute_name, $is_translatable ) {
170
+ $wcml_settings = $this->woocommerce_wpml->get_settings();
171
+ $wcml_settings['attributes_settings'][ $attribute_name ] = $is_translatable;
172
+ $this->woocommerce_wpml->update_settings( $wcml_settings );
173
+ }
174
+
175
+ public function set_attribute_config_in_wpml_settings( $attribute_name, $is_translatable ) {
176
+
177
+ $sync_settings = $this->sitepress->get_setting( 'taxonomies_sync_option', array() );
178
+ $sync_settings[ $attribute_name ] = $is_translatable;
179
+ $this->sitepress->set_setting( 'taxonomies_sync_option', $sync_settings, true );
180
+ $this->sitepress->verify_taxonomy_translations( $attribute_name );
181
+ }
182
+
183
+ public function delete_translated_attribute_terms( $attribute ) {
184
+ $terms = $this->get_attribute_terms( $attribute );
185
+
186
+ foreach ( $terms as $term ) {
187
+ if ( $this->term_translations->get_source_lang_code( $term->term_id ) ) {
188
+ wp_delete_term( $term->term_id, $attribute );
189
+ }
190
+ }
191
+
192
+ }
193
+
194
+ public function set_variations_to_use_original_attributes( $attribute ) {
195
+ $terms = $this->get_attribute_terms( $attribute );
196
+
197
+ foreach ( $terms as $term ) {
198
+ if ( is_null( $this->term_translations->get_source_lang_code( $term->term_id ) ) ) {
199
+ $variations = $this->wpdb->get_results( $this->wpdb->prepare( "SELECT post_id FROM {$this->wpdb->postmeta} WHERE meta_key=%s AND meta_value = %s", 'attribute_' . $attribute, $term->slug ) );
200
+
201
+ foreach ( $variations as $variation ) {
202
+ //update taxonomy in translation of variation
203
+ foreach ( $this->sitepress->get_active_languages() as $language ) {
204
+
205
+ $trnsl_variation_id = apply_filters( 'translate_object_id', $variation->post_id, 'product_variation', false, $language['code'] );
206
+ if ( ! is_null( $trnsl_variation_id ) ) {
207
+ update_post_meta( $trnsl_variation_id, 'attribute_' . $attribute, $term->slug );
208
+ }
209
+ }
210
+ }
211
+ }
212
+ }
213
+ }
214
+
215
+ public function set_original_attributes_for_products( $attribute ) {
216
+
217
+ $terms = $this->get_attribute_terms( $attribute );
218
+ $cleared_products = array();
219
+ foreach ( $terms as $term ) {
220
+ if ( is_null( $this->term_translations->get_source_lang_code( $term->term_id ) ) ) {
221
+ $args = array(
222
+ 'tax_query' => array(
223
+ array(
224
+ 'taxonomy' => $attribute,
225
+ 'field' => 'slug',
226
+ 'terms' => $term->slug
227
+ )
228
+ )
229
+ );
230
+
231
+ $products = get_posts( $args );
232
+
233
+ foreach ( $products as $product ) {
234
+
235
+ foreach ( $this->sitepress->get_active_languages() as $language ) {
236
+
237
+ $trnsl_product_id = apply_filters( 'translate_object_id', $product->ID, 'product', false, $language['code'] );
238
+
239
+ if ( ! is_null( $trnsl_product_id ) ) {
240
+ if ( ! in_array( $trnsl_product_id, $trnsl_product_id ) ) {
241
+ wp_delete_object_term_relationships( $trnsl_product_id, $attribute );
242
+ $cleared_products[] = $trnsl_product_id;
243
+ }
244
+ wp_set_object_terms( $trnsl_product_id, $term->slug, $attribute, true );
245
+ }
246
+ }
247
+ }
248
+ }
249
+ }
250
+ }
251
+
252
+
253
+ public function is_translatable_attribute( $attr_name ) {
254
+
255
+ if ( ! isset( $this->woocommerce_wpml->settings['attributes_settings'][ $attr_name ] ) ) {
256
+ $this->set_attribute_config_in_settings( $attr_name, 1 );
257
+ }
258
+
259
+ return isset( $this->woocommerce_wpml->settings['attributes_settings'][ $attr_name ] ) ? $this->woocommerce_wpml->settings['attributes_settings'][ $attr_name ] : 1;
260
+ }
261
+
262
+ public function get_translatable_attributes() {
263
+ $attributes = wc_get_attribute_taxonomies();
264
+
265
+ $translatable_attributes = array();
266
+ foreach ( $attributes as $attribute ) {
267
+ if ( $this->is_translatable_attribute( wc_attribute_taxonomy_name( $attribute->attribute_name ) ) ) {
268
+ $translatable_attributes[] = $attribute;
269
+ }
270
+ }
271
+
272
+ return $translatable_attributes;
273
+ }
274
+
275
+ public function set_translatable_attributes( $attributes ) {
276
+
277
+ foreach ( $attributes as $name => $is_translatable ) {
278
+
279
+ $attribute_name = wc_attribute_taxonomy_name( $name );
280
+ $this->set_attribute_config_in_settings( $attribute_name, $is_translatable );
281
+
282
+ }
283
+ }
284
+
285
+ public function sync_product_attr( $original_product_id, $tr_product_id, $language = false, $data = false ) {
286
+
287
+ //get "_product_attributes" from original product
288
+ $orig_product_attrs = $this->get_product_attributes( $original_product_id );
289
+ $trnsl_product_attrs = $this->get_product_attributes( $tr_product_id );
290
+
291
+ $translated_labels = [];
292
+
293
+ foreach ( $orig_product_attrs as $key => $orig_product_attr ) {
294
+ $sanitized_key = $this->filter_attribute_name( $orig_product_attr['name'], $original_product_id, true );
295
+ if ( $sanitized_key != $key ) {
296
+ $orig_product_attrs_buff = $orig_product_attrs[ $key ];
297
+ unset( $orig_product_attrs[ $key ] );
298
+ $orig_product_attrs[ $sanitized_key ] = $orig_product_attrs_buff;
299
+ $key_to_save = $sanitized_key;
300
+ } else {
301
+ $key_to_save = $key;
302
+ }
303
+ if ( $data ) {
304
+ if ( isset( $data[ md5( $key ) ] ) && ! empty( $data[ md5( $key ) ] ) && ! is_array( $data[ md5( $key ) ] ) ) {
305
+ //get translation values from $data
306
+ $orig_product_attrs[ $key_to_save ]['value'] = $data[ md5( $key ) ];
307
+ } else {
308
+ $orig_product_attrs[ $key_to_save ]['value'] = '';
309
+ }
310
+
311
+ if ( isset( $data[ md5( $key . '_name' ) ] ) && ! empty( $data[ md5( $key . '_name' ) ] ) && ! is_array( $data[ md5( $key . '_name' ) ] ) ) {
312
+ //get translation values from $data
313
+ $translated_labels[ $language ][ $key_to_save ] = stripslashes( $data[ md5( $key . '_name' ) ] );
314
+ }
315
+ } elseif ( ! $orig_product_attr['is_taxonomy'] ) {
316
+ $duplicate_of = get_post_meta( $tr_product_id, '_icl_lang_duplicate_of', true );
317
+
318
+ if ( ! $duplicate_of ) {
319
+ if ( isset( $trnsl_product_attrs[ $key ] ) ) {
320
+ $orig_product_attrs[ $key_to_save ]['value'] = $trnsl_product_attrs[ $key ]['value'];
321
+ } elseif ( ! empty( $trnsl_product_attrs ) ) {
322
+ unset ( $orig_product_attrs[ $key_to_save ] );
323
+ }
324
+ }
325
+ }
326
+ }
327
+
328
+ update_post_meta( $tr_product_id, 'attr_label_translations', $translated_labels );
329
+ //update "_product_attributes"
330
+ update_post_meta( $tr_product_id, '_product_attributes', $orig_product_attrs );
331
+ }
332
+
333
+ public function get_product_attributes( $product_id ) {
334
+ $attributes = get_post_meta( $product_id, '_product_attributes', true );
335
+ if ( ! is_array( $attributes ) ) {
336
+ $attributes = array();
337
+ }
338
+
339
+ return $attributes;
340
+ }
341
+
342
+ public function get_attr_label_translations( $product_id, $lang = false ) {
343
+ $trnsl_labels = get_post_meta( $product_id, 'attr_label_translations', true );
344
+
345
+ if ( ! is_array( $trnsl_labels ) ) {
346
+ $trnsl_labels = array();
347
+ }
348
+
349
+ if ( isset( $trnsl_labels[ $lang ] ) ) {
350
+ return $trnsl_labels[ $lang ];
351
+ }
352
 
353
+ return $trnsl_labels;
354
+ }
355
+
356
+ public function sync_default_product_attr( $orig_post_id, $transl_post_id, $lang ) {
357
+ $original_default_attributes = get_post_meta( $orig_post_id, '_default_attributes', true );
358
+
359
+ if ( ! empty( $original_default_attributes ) ) {
360
+ $unserialized_default_attributes = array();
361
+ foreach ( maybe_unserialize( $original_default_attributes ) as $attribute => $default_term_slug ) {
362
+ // get the correct language
363
+ if ( substr( $attribute, 0, 3 ) == 'pa_' ) {
364
+ //attr is taxonomy
365
+ if ( $this->is_translatable_attribute( $attribute ) ) {
366
+ $sanitized_attribute_name = wc_sanitize_taxonomy_name( $attribute );
367
+ $default_term_id = $this->get_wcml_terms_instance()->wcml_get_term_id_by_slug( $sanitized_attribute_name, $default_term_slug );
368
+ $tr_id = apply_filters( 'translate_object_id', $default_term_id, $sanitized_attribute_name, false, $lang );
369
+
370
+ if ( $tr_id ) {
371
+ $translated_term = $this->get_wcml_terms_instance()->wcml_get_term_by_id( $tr_id, $sanitized_attribute_name );
372
+ $unserialized_default_attributes[ $attribute ] = $translated_term->slug;
373
+ }
374
+ } else {
375
+ $unserialized_default_attributes[ $attribute ] = $default_term_slug;
376
+ }
377
+ } else {
378
+ //custom attr
379
+ $orig_product_attributes = get_post_meta( $orig_post_id, '_product_attributes', true );
380
+ $unserialized_orig_product_attributes = maybe_unserialize( $orig_product_attributes );
381
+
382
+ if ( isset( $unserialized_orig_product_attributes[ $attribute ] ) ) {
383
+ $orig_attr_values = explode( '|', $unserialized_orig_product_attributes[ $attribute ]['value'] );
384
+ $orig_attr_values = array_map( 'trim', $orig_attr_values );
385
+
386
+ foreach ( $orig_attr_values as $key => $orig_attr_value ) {
387
+ $orig_attr_value_sanitized = strtolower( sanitize_title( $orig_attr_value ) );
388
+
389
+ if ( $orig_attr_value_sanitized == $default_term_slug || trim( $orig_attr_value ) == trim( $default_term_slug ) ) {
390
+ $tnsl_product_attributes = get_post_meta( $transl_post_id, '_product_attributes', true );
391
+ $unserialized_tnsl_product_attributes = maybe_unserialize( $tnsl_product_attributes );
392
+
393
+ if ( isset( $unserialized_tnsl_product_attributes[ $attribute ] ) ) {
394
+ $trnsl_attr_values = explode( '|', $unserialized_tnsl_product_attributes[ $attribute ]['value'] );
395
+
396
+ if ( $orig_attr_value_sanitized == $default_term_slug ) {
397
+ $trnsl_attr_value = strtolower( sanitize_title( trim( $trnsl_attr_values[ $key ] ) ) );
398
+ } else {
399
+ $trnsl_attr_value = trim( $trnsl_attr_values[ $key ] );
400
+ }
401
+ $unserialized_default_attributes[ $attribute ] = $trnsl_attr_value;
402
+ }
403
+ }
404
+ }
405
+ }
406
+ }
407
+ }
408
 
409
+ $data = array( 'meta_value' => maybe_serialize( $unserialized_default_attributes ) );
410
+ } else {
411
+ $data = array( 'meta_value' => maybe_serialize( array() ) );
412
+ }
413
 
414
+ $where = array( 'post_id' => $transl_post_id, 'meta_key' => '_default_attributes' );
 
 
 
 
415
 
416
+ $translated_product_meta = get_post_meta( $transl_post_id );
417
+ if ( isset( $translated_product_meta['_default_attributes'] ) ) {
418
+ $this->wpdb->update( $this->wpdb->postmeta, $data, $where );
419
+ } else {
420
+ $this->wpdb->insert( $this->wpdb->postmeta, array_merge( $data, $where ) );
421
+ }
422
 
423
+ }
 
 
 
 
424
 
425
+ /*
426
+ * get attribute translation
427
+ */
428
+ public function get_custom_attribute_translation( $product_id, $attribute_key, $attribute, $lang_code ) {
429
+ $tr_post_id = apply_filters( 'translate_object_id', $product_id, 'product', false, $lang_code );
430
+ $transl = array();
431
+ if ( $tr_post_id ) {
432
+ if ( ! $attribute['is_taxonomy'] ) {
433
+ $tr_attrs = get_post_meta( $tr_post_id, '_product_attributes', true );
434
+ if ( $tr_attrs ) {
435
+ foreach ( $tr_attrs as $key => $tr_attr ) {
436
+ if ( $attribute_key == $key ) {
437
+ $transl['value'] = $tr_attr['value'];
438
+ $trnsl_labels = $this->get_attr_label_translations( $tr_post_id );
439
+
440
+ if ( isset( $trnsl_labels[ $lang_code ][ $attribute_key ] ) ) {
441
+ $transl['name'] = $trnsl_labels[ $lang_code ][ $attribute_key ];
442
+ } else {
443
+ $transl['name'] = $tr_attr['name'];
444
+ }
445
+
446
+ return $transl;
447
+ }
448
+ }
449
+ }
450
+
451
+ return false;
452
+ }
453
+ }
454
+
455
+ return false;
456
+ }
457
+
458
+ /*
459
+ * Get custom attribute translation
460
+ * Returned translated attribute or original if missed
461
+ */
462
+ public function get_custom_attr_translation( $product_id, $tr_product_id, $taxonomy, $attribute ) {
463
+ $orig_product_attributes = get_post_meta( $product_id, '_product_attributes', true );
464
+ $unserialized_orig_product_attributes = maybe_unserialize( $orig_product_attributes );
465
+
466
+ foreach ( $unserialized_orig_product_attributes as $orig_attr_key => $orig_product_attribute ) {
467
+ $orig_attr_key = urldecode( $orig_attr_key );
468
+ if ( strtolower( $taxonomy ) == $orig_attr_key ) {
469
+ $values = explode( '|', $orig_product_attribute['value'] );
470
+
471
+ foreach ( $values as $key_id => $value ) {
472
+ if ( trim( $value, " " ) == $attribute ) {
473
+ $attr_key_id = $key_id;
474
+ }
475
+ }
476
+ }
477
+ }
478
+
479
+ $trnsl_product_attributes = get_post_meta( $tr_product_id, '_product_attributes', true );
480
+ $unserialized_trnsl_product_attributes = maybe_unserialize( $trnsl_product_attributes );
481
+ $taxonomy = sanitize_title( $taxonomy );
482
+ $trnsl_attr_values = explode( '|', $unserialized_trnsl_product_attributes[ $taxonomy ]['value'] );
483
+
484
+ if ( isset( $attr_key_id ) && isset( $trnsl_attr_values[ $attr_key_id ] ) ) {
485
+ return trim( $trnsl_attr_values[ $attr_key_id ] );
486
+ }
487
+
488
+ return $attribute;
489
+ }
490
+
491
+ public function filter_product_attributes_for_translation( $translated, $key ) {
492
+ $translated = $translated
493
+ ? preg_match( '#^(?!field-_product_attributes-(.+)-(.+)-(?!value|name))#', $key ) : 0;
494
+
495
+ return $translated;
496
+ }
497
+
498
+ public function icl_custom_tax_sync_options() {
499
+ foreach ( $_POST['icl_sync_tax'] as $taxonomy => $value ) {
500
+ if ( substr( $taxonomy, 0, 3 ) == 'pa_' ) {
501
+ $this->set_attribute_config_in_wcml_settings( $taxonomy, $value );
502
+ }
503
+ }
504
+
505
+ }
506
 
507
+ public function is_attributes_fully_translated() {
 
508
 
509
+ $product_attributes = $this->get_translatable_attributes();
 
 
510
 
511
+ $fully_translated = true;
512
+
513
+ if ( $product_attributes ) {
514
+ foreach ( $product_attributes as $attribute ) {
515
+ $is_fully_translated = $this->get_wcml_terms_instance()->is_fully_translated( 'pa_' . $attribute->attribute_name );
516
+ if ( ! $is_fully_translated ) {
517
+ $fully_translated = false;
518
+ break;
519
+ }
520
+ }
521
+ }
522
+
523
+ return $fully_translated;
524
+ }
525
+
526
+ public function get_translated_variation_attribute_post_meta( $meta_value, $meta_key, $original_variation_id, $variation_id, $lang ) {
527
+
528
+ $original_product_attr = get_post_meta( wp_get_post_parent_id( $original_variation_id ), '_product_attributes', true );
529
+ $tr_product_attr = get_post_meta( wp_get_post_parent_id( $variation_id ), '_product_attributes', true );
530
+
531
+ $tax = wc_sanitize_taxonomy_name( substr( $meta_key, 10 ) );
532
+ if ( taxonomy_exists( $tax ) ) {
533
+ $attid = $this->get_wcml_terms_instance()->wcml_get_term_id_by_slug( $tax, $meta_value );
534
+ if ( $this->is_translatable_attribute( $tax ) && $attid ) {
535
+
536
+ $term_obj = $this->get_wcml_terms_instance()->wcml_get_term_by_id( $attid, $tax );
537
+ $trnsl_term_id = apply_filters( 'translate_object_id', $term_obj->term_id, $tax, false, $lang );
538
+
539
+ if ( $trnsl_term_id ) {
540
+ $trnsl_term_obj = $this->get_wcml_terms_instance()->wcml_get_term_by_id( $trnsl_term_id, $tax );
541
+ $meta_value = $trnsl_term_obj->slug;
542
+ }
543
+ }
544
+ } else {
545
+ if ( ! isset( $original_product_attr[ $tax ] ) ) {
546
+ $tax = sanitize_title( $tax );
547
+ }
548
+
549
+ if ( isset( $original_product_attr[ $tax ] ) ) {
550
+ if ( isset( $tr_product_attr[ $tax ] ) ) {
551
+ $values_arrs = array_map( 'trim', explode( '|', $original_product_attr[ $tax ]['value'] ) );
552
+ $values_arrs_tr = array_map( 'trim', explode( '|', $tr_product_attr[ $tax ]['value'] ) );
553
+
554
+ foreach ( $values_arrs as $key => $value ) {
555
+ $value_sanitized = sanitize_title( $value );
556
+ if (
557
+ ( $value_sanitized == strtolower( urldecode( $meta_value ) ) ||
558
+ strtolower( $value_sanitized ) == $meta_value ||
559
+ $value == $meta_value )
560
+ && isset( $values_arrs_tr[ $key ] ) ) {
561
+ $meta_value = $values_arrs_tr[ $key ];
562
+ }
563
+ }
564
+ }
565
+ }
566
+ $meta_key = 'attribute_' . $tax;
567
+ }
568
+
569
+ return array(
570
+ 'meta_value' => $meta_value,
571
+ 'meta_key' => $meta_key
572
+ );
573
+ }
574
+
575
+ function filter_dropdown_variation_attribute_options_args( $args ) {
576
+
577
+ if ( isset( $args['attribute'] ) && isset( $args['product'] ) ) {
578
+ $args['attribute'] = $this->filter_attribute_name( $args['attribute'], $args['product']->get_id() );
579
+
580
+ if ( $this->get_wcml_products_instance()->is_product_display_as_translated_post_type() ) {
581
+ foreach ( $args['options'] as $key => $attribute_value ) {
582
+ $args['options'][ $key ] = $this->get_attribute_term_translation_in_current_language( $args['attribute'], $attribute_value );
583
+ }
584
+ }
585
+ }
586
+
587
+ return $args;
588
+ }
589
+
590
+ /*
591
+ * special case when original attribute language is German or Danish,
592
+ * needs handle special chars accordingly
593
+ * https://onthegosystems.myjetbrains.com/youtrack/issue/wcml-1785
594
+ */
595
+ function filter_attribute_name( $attribute_name, $product_id, $return_sanitized = false ) {
596
+
597
+ if ( $product_id ) {
598
+ $orig_lang = $this->get_wcml_products_instance()->get_original_product_language( $product_id );
599
+ $current_language = $this->sitepress->get_current_language();
600
+
601
+ if ( in_array( $orig_lang, array( 'de', 'da' ) ) && $current_language !== $orig_lang ) {
602
+ $attribute_name = $this->sitepress->locale_utils->filter_sanitize_title( remove_accents( $attribute_name ), $attribute_name );
603
+ remove_filter( 'sanitize_title', array( $this->sitepress->locale_utils, 'filter_sanitize_title' ), 10 );
604
+ }
605
+ }
606
+
607
+ if ( $return_sanitized ) {
608
+ $attribute_name = sanitize_title( $attribute_name );
609
+ }
610
+
611
+ return $attribute_name;
612
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
613
 
614
  public function filter_adding_to_cart_product_attributes_names( $attributes ) {
615
 
633
  return $attributes;
634
  }
635
 
636
+ public function is_a_taxonomy( $attribute ) {
637
 
638
+ if (
639
+ (
640
+ $attribute instanceof WC_Product_Attribute &&
641
+ $attribute->is_taxonomy()
642
+ ) ||
643
+ (
644
+ is_array( $attribute ) &&
645
+ $attribute['is_taxonomy']
646
+ )
647
+ ) {
648
+ return true;
649
+ }
650
 
651
+ return false;
652
+ }
653
 
654
  /**
655
  *
680
  if ( '' === $meta_key && 'product_variation' === get_post_type( $object_id ) ) {
681
 
682
  $cache_group = 'wpml-all-meta-product-variation';
683
+ $cache_key = $this->sitepress->get_current_language() . $object_id;
684
  $cached_value = wp_cache_get( $cache_key, $cache_group );
685
 
686
  if ( $cached_value ) {
725
  *
726
  * @return array
727
  */
728
+ public function filter_product_variation_default_attributes( $default_attributes ) {
729
 
730
+ if ( $default_attributes ) {
731
 
732
+ foreach ( $default_attributes as $attribute_key => $attribute_value ) {
733
 
734
  $default_attributes[ $attribute_key ] = $this->get_attribute_term_translation_in_current_language( $attribute_key, $attribute_value );
735
 
749
  */
750
  private function get_attribute_term_translation_in_current_language( $attribute_taxonomy, $attribute_value ) {
751
 
752
+ if ( taxonomy_exists( $attribute_taxonomy ) ) {
753
  $term = get_term_by( 'slug', $attribute_value, $attribute_taxonomy );
754
+ if ( $term ) {
755
  $attribute_value = $term->slug;
756
  }
757
  }
inc/class-wcml-cart.php CHANGED
@@ -53,10 +53,10 @@ class WCML_Cart {
53
 
54
  //cart
55
  add_action( 'woocommerce_before_calculate_totals', array( $this, 'woocommerce_calculate_totals' ), 100 );
56
- add_action( 'woocommerce_get_cart_item_from_session', array( $this, 'translate_cart_contents' ) );
57
  add_action( 'woocommerce_cart_loaded_from_session', array( $this, 'translate_cart_subtotal' ) );
58
  add_action( 'woocommerce_before_checkout_process', array( $this, 'wcml_refresh_cart_total' ) );
59
  add_filter( 'woocommerce_cart_item_data_to_validate', array( $this, 'validate_cart_item_data' ), 10, 2 );
 
60
 
61
  add_filter( 'woocommerce_cart_item_permalink', array( $this, 'cart_item_permalink' ), 10, 2 );
62
  add_filter( 'woocommerce_paypal_args', array( $this, 'filter_paypal_args' ) );
@@ -489,29 +489,6 @@ class WCML_Cart {
489
  return apply_filters( 'wcml_filter_cart_item_data', $cart_contents );
490
  }
491
 
492
- public function translate_cart_contents( $item ) {
493
-
494
- // translate the product id and product data
495
- $translated_product_id = apply_filters( 'translate_object_id', $item['product_id'], 'product', true );
496
- if( $item['product_id'] !== $translated_product_id ){
497
- $item['product_id'] = $translated_product_id;
498
- }
499
-
500
- if ( $item['variation_id'] ) {
501
- $translated_variation_id = apply_filters( 'translate_object_id', $item['variation_id'], 'product_variation', true );
502
-
503
- if( $item['variation_id'] !== $translated_variation_id ){
504
- $item['variation_id'] = $translated_variation_id;
505
- }
506
- }
507
-
508
- $item_product_title = $item['variation_id'] ? get_the_title( $translated_variation_id ) : get_the_title( $translated_product_id );
509
- $item['data']->set_name( $item_product_title );
510
- $item['data_hash'] = $this->get_data_cart_hash( $item );
511
-
512
- return $item;
513
- }
514
-
515
  public function translate_cart_subtotal( $cart ) {
516
 
517
  if ( isset( $_SERVER['REQUEST_URI'] ) ) {
@@ -529,7 +506,6 @@ class WCML_Cart {
529
  if ( apply_filters( 'wcml_calculate_totals_exception', true, $cart ) ) {
530
  $cart->calculate_totals();
531
  }
532
-
533
  }
534
 
535
  // refresh cart total to return correct price from WC object
@@ -676,5 +652,22 @@ class WCML_Cart {
676
  return $this->woocommerce_wpml->multi_currency->prices->convert_price_amount( $shipping_amount_in_default_currency, $currency );
677
  }
678
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
679
 
680
  }
53
 
54
  //cart
55
  add_action( 'woocommerce_before_calculate_totals', array( $this, 'woocommerce_calculate_totals' ), 100 );
 
56
  add_action( 'woocommerce_cart_loaded_from_session', array( $this, 'translate_cart_subtotal' ) );
57
  add_action( 'woocommerce_before_checkout_process', array( $this, 'wcml_refresh_cart_total' ) );
58
  add_filter( 'woocommerce_cart_item_data_to_validate', array( $this, 'validate_cart_item_data' ), 10, 2 );
59
+ add_filter( 'woocommerce_cart_item_product', array( $this, 'adjust_cart_item_product_name' ) );
60
 
61
  add_filter( 'woocommerce_cart_item_permalink', array( $this, 'cart_item_permalink' ), 10, 2 );
62
  add_filter( 'woocommerce_paypal_args', array( $this, 'filter_paypal_args' ) );
489
  return apply_filters( 'wcml_filter_cart_item_data', $cart_contents );
490
  }
491
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
492
  public function translate_cart_subtotal( $cart ) {
493
 
494
  if ( isset( $_SERVER['REQUEST_URI'] ) ) {
506
  if ( apply_filters( 'wcml_calculate_totals_exception', true, $cart ) ) {
507
  $cart->calculate_totals();
508
  }
 
509
  }
510
 
511
  // refresh cart total to return correct price from WC object
652
  return $this->woocommerce_wpml->multi_currency->prices->convert_price_amount( $shipping_amount_in_default_currency, $currency );
653
  }
654
 
655
+ /**
656
+ * @param WC_Product $product
657
+ *
658
+ * @return WC_Product
659
+ */
660
+ public function adjust_cart_item_product_name( $product ) {
661
+
662
+ $product_id = $product->get_id();
663
+
664
+ $current_product_id = wpml_object_id_filter( $product_id, get_post_type( $product_id ) );
665
+
666
+ if ( $current_product_id ) {
667
+ $product->set_name( wc_get_product( $current_product_id )->get_name() );
668
+ }
669
+
670
+ return $product;
671
+ }
672
 
673
  }
inc/class-wcml-emails.php CHANGED
@@ -9,15 +9,15 @@ class WCML_Emails {
9
  private $wcmlStrings;
10
  /** @var Sitepress */
11
  private $sitepress;
12
- /** @var \WC_Emails $wcEmails */
13
- private $wcEmails;
14
  /** @var wpdb */
15
  private $wpdb;
16
 
17
- function __construct( WCML_WC_Strings $wcmlStrings, SitePress $sitepress, WC_Emails $wcEmails, wpdb $wpdb ) {
18
  $this->wcmlStrings = $wcmlStrings;
19
  $this->sitepress = $sitepress;
20
- $this->wcEmails = $wcEmails;
21
  $this->wpdb = $wpdb;
22
  }
23
 
@@ -81,8 +81,6 @@ class WCML_Emails {
81
 
82
  add_action( 'woocommerce_before_resend_order_emails', array( $this, 'backend_new_order_admin_email' ), 9 );
83
 
84
- add_filter( 'icl_st_admin_string_return_cached', array( $this, 'admin_string_return_cached' ), 10, 2 );
85
-
86
  add_filter( 'plugin_locale', array( $this, 'set_locale_for_emails' ), 10, 2 );
87
  add_filter( 'woocommerce_countries', array( $this, 'translate_woocommerce_countries' ) );
88
 
@@ -201,7 +199,8 @@ class WCML_Emails {
201
  if ( $email ) {
202
  $translate = $this->getTranslatorFor(
203
  'admin_texts_woocommerce_customer_completed_order_settings',
204
- '[woocommerce_customer_completed_order_settings]'
 
205
  );
206
 
207
  $email->heading = $translate( 'heading' );
@@ -401,14 +400,6 @@ class WCML_Emails {
401
  $this->locale = $this->sitepress->get_locale( $lang );
402
  }
403
 
404
- function admin_string_return_cached( $value, $option ) {
405
- if ( in_array( $option, array( 'woocommerce_email_from_address', 'woocommerce_email_from_name' ) ) ) {
406
- return false;
407
- }
408
-
409
- return $value;
410
- }
411
-
412
  function wcml_get_translated_email_string( $context, $name, $order_id = false, $language_code = null ) {
413
 
414
  if ( $order_id && ! $language_code ) {
@@ -417,9 +408,8 @@ class WCML_Emails {
417
  $language_code = $order_language;
418
  }
419
  }
420
- $result = $this->wpdb->get_var( $this->wpdb->prepare( "SELECT value FROM {$this->wpdb->prefix}icl_strings WHERE context = %s AND name = %s ", $context, $name ) );
421
 
422
- return apply_filters( 'wpml_translate_single_string', $result, $context, $name, $language_code );
423
  }
424
 
425
  function icl_current_string_language( $current_language, $name ) {
@@ -495,11 +485,13 @@ class WCML_Emails {
495
  * @return WC_Email|null
496
  */
497
  private function getEmailObject( $emailClass, $ignoreClassExists = false ) {
 
 
498
  if (
499
  ( $ignoreClassExists || class_exists( $emailClass ) )
500
- && isset( $this->wcEmails->emails[ $emailClass ] )
501
  ) {
502
- return $this->wcEmails->emails[ $emailClass ];
503
  }
504
 
505
  return null;
@@ -540,7 +532,8 @@ class WCML_Emails {
540
  */
541
  private function admin_notification( $product, $action, $method ) {
542
 
543
- $is_action_removed = remove_action( $action, [ $this->wcEmails, $method ] );
 
544
 
545
  if ( $is_action_removed ) {
546
  $admin_language = $this->get_admin_language_by_email( get_option( 'woocommerce_stock_email_recipient' ) );
@@ -552,7 +545,7 @@ class WCML_Emails {
552
  );
553
 
554
  $this->sitepress->switch_lang( $admin_language );
555
- $this->wcEmails->$method( wc_get_product( $product_id_in_admin_language ) );
556
  $this->sitepress->switch_lang();
557
  }
558
  }
9
  private $wcmlStrings;
10
  /** @var Sitepress */
11
  private $sitepress;
12
+ /** @var woocommerce $woocommerce */
13
+ private $woocommerce;
14
  /** @var wpdb */
15
  private $wpdb;
16
 
17
+ function __construct( WCML_WC_Strings $wcmlStrings, SitePress $sitepress, woocommerce $woocommerce, wpdb $wpdb ) {
18
  $this->wcmlStrings = $wcmlStrings;
19
  $this->sitepress = $sitepress;
20
+ $this->woocommerce = $woocommerce;
21
  $this->wpdb = $wpdb;
22
  }
23
 
81
 
82
  add_action( 'woocommerce_before_resend_order_emails', array( $this, 'backend_new_order_admin_email' ), 9 );
83
 
 
 
84
  add_filter( 'plugin_locale', array( $this, 'set_locale_for_emails' ), 10, 2 );
85
  add_filter( 'woocommerce_countries', array( $this, 'translate_woocommerce_countries' ) );
86
 
199
  if ( $email ) {
200
  $translate = $this->getTranslatorFor(
201
  'admin_texts_woocommerce_customer_completed_order_settings',
202
+ '[woocommerce_customer_completed_order_settings]',
203
+ $order_id
204
  );
205
 
206
  $email->heading = $translate( 'heading' );
400
  $this->locale = $this->sitepress->get_locale( $lang );
401
  }
402
 
 
 
 
 
 
 
 
 
403
  function wcml_get_translated_email_string( $context, $name, $order_id = false, $language_code = null ) {
404
 
405
  if ( $order_id && ! $language_code ) {
408
  $language_code = $order_language;
409
  }
410
  }
 
411
 
412
+ return $this->wcmlStrings->get_translated_string_by_name_and_context( $context, $name, $language_code );
413
  }
414
 
415
  function icl_current_string_language( $current_language, $name ) {
485
  * @return WC_Email|null
486
  */
487
  private function getEmailObject( $emailClass, $ignoreClassExists = false ) {
488
+
489
+ $wcEmails = $this->woocommerce->mailer();
490
  if (
491
  ( $ignoreClassExists || class_exists( $emailClass ) )
492
+ && isset( $wcEmails->emails[ $emailClass ] )
493
  ) {
494
+ return $wcEmails->emails[ $emailClass ];
495
  }
496
 
497
  return null;
532
  */
533
  private function admin_notification( $product, $action, $method ) {
534
 
535
+ $wcEmails = $this->woocommerce->mailer();
536
+ $is_action_removed = remove_action( $action, [ $wcEmails, $method ] );
537
 
538
  if ( $is_action_removed ) {
539
  $admin_language = $this->get_admin_language_by_email( get_option( 'woocommerce_stock_email_recipient' ) );
545
  );
546
 
547
  $this->sitepress->switch_lang( $admin_language );
548
+ $wcEmails->$method( wc_get_product( $product_id_in_admin_language ) );
549
  $this->sitepress->switch_lang();
550
  }
551
  }
inc/class-wcml-orders.php CHANGED
@@ -122,38 +122,51 @@ class WCML_Orders {
122
 
123
  public function woocommerce_order_get_items( $items, $order ) {
124
 
125
- if ( $items ) {
126
 
127
  $language_to_filter = $this->get_order_items_language_to_filter( $order );
128
 
129
- foreach ( $items as $index => $item ) {
130
- if ( $item instanceof WC_Order_Item_Product ) {
131
- if ( 'line_item' === $item->get_type() ) {
132
- $this->adjust_product_item_if_translated( $item, $language_to_filter );
133
- $this->adjust_variation_item_if_translated( $item, $language_to_filter );
134
- }
135
- } elseif ( $item instanceof WC_Order_Item_Shipping ) {
136
- $shipping_id = $item->get_method_id();
137
- if ( $shipping_id ) {
138
-
139
- if ( method_exists( $item, 'get_instance_id' ) ) {
140
- $shipping_id .= $item->get_instance_id();
141
- }
142
-
143
- $item->set_method_title(
144
- $this->woocommerce_wpml->shipping->translate_shipping_method_title(
145
- $item->get_method_title(),
146
- $shipping_id,
147
- $language_to_filter
148
- )
149
- );
 
 
 
 
 
 
 
150
  }
 
 
 
 
 
 
 
 
151
  }
152
- $item->save();
153
  }
 
154
  }
155
-
156
- return $items;
157
  }
158
 
159
  /**
@@ -416,9 +429,15 @@ class WCML_Orders {
416
  $order_language = get_post_meta( $object->get_id(), 'wpml_language', true );
417
 
418
  if ( $item->get_variation_id() > 0 ) {
419
- $item->set_variation_id( apply_filters( 'translate_object_id', $item->get_variation_id(), 'product_variation', false, $order_language ) );
 
 
 
420
  } else {
421
- $item->set_product_id( apply_filters( 'translate_object_id', $item->get_product_id(), 'product', false, $order_language ) );
 
 
 
422
  }
423
 
424
  remove_filter( 'woocommerce_get_item_downloads', array( $this, 'filter_downloadable_product_items' ), 10, 3 );
122
 
123
  public function woocommerce_order_get_items( $items, $order ) {
124
 
125
+ if ( $items && ( is_admin() || is_view_order_page() ) ) {
126
 
127
  $language_to_filter = $this->get_order_items_language_to_filter( $order );
128
 
129
+ $this->adjust_order_item_in_language( $items, $language_to_filter );
130
+ }
131
+
132
+ return $items;
133
+ }
134
+
135
+ /**
136
+ * @param array $items
137
+ * @param string|bool $language_to_filter
138
+ */
139
+ public function adjust_order_item_in_language( $items, $language_to_filter = false ) {
140
+
141
+ if( !$language_to_filter ){
142
+ $language_to_filter = $this->sitepress->get_current_language();
143
+ }
144
+
145
+ foreach ( $items as $index => $item ) {
146
+ if ( $item instanceof WC_Order_Item_Product ) {
147
+ if ( 'line_item' === $item->get_type() ) {
148
+ $this->adjust_product_item_if_translated( $item, $language_to_filter );
149
+ $this->adjust_variation_item_if_translated( $item, $language_to_filter );
150
+ }
151
+ } elseif ( $item instanceof WC_Order_Item_Shipping ) {
152
+ $shipping_id = $item->get_method_id();
153
+ if ( $shipping_id ) {
154
+
155
+ if ( method_exists( $item, 'get_instance_id' ) ) {
156
+ $shipping_id .= $item->get_instance_id();
157
  }
158
+
159
+ $item->set_method_title(
160
+ $this->woocommerce_wpml->shipping->translate_shipping_method_title(
161
+ $item->get_method_title(),
162
+ $shipping_id,
163
+ $language_to_filter
164
+ )
165
+ );
166
  }
 
167
  }
168
+ $item->save();
169
  }
 
 
170
  }
171
 
172
  /**
429
  $order_language = get_post_meta( $object->get_id(), 'wpml_language', true );
430
 
431
  if ( $item->get_variation_id() > 0 ) {
432
+ $translated_variation_id = apply_filters( 'translate_object_id', $item->get_variation_id(), 'product_variation', false, $order_language );
433
+ if( ! is_null( $translated_variation_id ) ){
434
+ $item->set_variation_id( $translated_variation_id );
435
+ }
436
  } else {
437
+ $translated_product_id = apply_filters( 'translate_object_id', $item->get_product_id(), 'product', false, $order_language );
438
+ if( ! is_null( $translated_product_id ) ){
439
+ $item->set_product_id( $translated_product_id );
440
+ }
441
  }
442
 
443
  remove_filter( 'woocommerce_get_item_downloads', array( $this, 'filter_downloadable_product_items' ), 10, 3 );
inc/class-wcml-products.php CHANGED
@@ -52,6 +52,7 @@ class WCML_Products{
52
  ) );
53
 
54
  add_filter( 'woocommerce_product_file_download_path', array( $this, 'filter_file_download_path' ) );
 
55
  }
56
 
57
  add_filter( 'woocommerce_upsell_crosssell_search_products', array(
@@ -801,4 +802,32 @@ class WCML_Products{
801
  }
802
  return $reduce_stock;
803
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
804
  }
52
  ) );
53
 
54
  add_filter( 'woocommerce_product_file_download_path', array( $this, 'filter_file_download_path' ) );
55
+ add_filter( 'woocommerce_product_add_to_cart_url', array( $this, 'maybe_add_language_parameter' ) );
56
  }
57
 
58
  add_filter( 'woocommerce_upsell_crosssell_search_products', array(
802
  }
803
  return $reduce_stock;
804
  }
805
+
806
+ public function maybe_add_language_parameter( $url ) {
807
+
808
+ if (
809
+ 'no' === get_option( 'woocommerce_enable_ajax_add_to_cart' ) &&
810
+ constant( 'WPML_LANGUAGE_NEGOTIATION_TYPE_PARAMETER' ) === (int) $this->sitepress->get_setting( 'language_negotiation_type' )
811
+ ) {
812
+ $current_language = $this->sitepress->get_current_language();
813
+ if( $current_language !== $this->sitepress->get_default_language() ){
814
+ $url .= '&lang=' . $this->sitepress->get_current_language();
815
+ }
816
+ }
817
+
818
+ return $url;
819
+ }
820
+
821
+ /**
822
+ * @param int $product_id
823
+ * @param string $status
824
+ */
825
+ public function update_stock_status( $product_id, $status ) {
826
+ update_post_meta( $product_id, '_stock_status', $status );
827
+ $this->wpdb->query(
828
+ $this->wpdb->prepare(
829
+ "UPDATE {$this->wpdb->wc_product_meta_lookup} SET stock_status = %s WHERE product_id = %d",
830
+ $status, $product_id )
831
+ );
832
+ }
833
  }
inc/class-wcml-store-pages.php CHANGED
@@ -35,9 +35,11 @@ class WCML_Store_Pages {
35
  add_action( 'icl_post_languages_options_before', array( $this, 'show_translate_shop_pages_notice' ) );
36
  }
37
 
 
38
  if (
39
  ! $is_admin ||
40
- ( 'admin.php' === $pagenow && isset( $_GET['page'] ) && 'wc-settings' === $_GET['page'] )
 
41
  ) {
42
  // Translate shop page ids
43
  $this->add_filter_to_get_shop_translated_page_id();
35
  add_action( 'icl_post_languages_options_before', array( $this, 'show_translate_shop_pages_notice' ) );
36
  }
37
 
38
+ $getData = wpml_collect( $_GET );
39
  if (
40
  ! $is_admin ||
41
+ ( 'admin.php' === $pagenow && 'wc-settings' === $getData->get( 'page' ) ) ||
42
+ ( 'edit.php' === $pagenow && 'page' === $getData->get( 'post_type' ) )
43
  ) {
44
  // Translate shop page ids
45
  $this->add_filter_to_get_shop_translated_page_id();
inc/class-wcml-terms.php CHANGED
@@ -54,16 +54,17 @@ class WCML_Terms{
54
 
55
  add_filter( 'pre_option_default_product_cat', array( $this, 'pre_option_default_product_cat' ) );
56
  add_filter( 'update_option_default_product_cat', array( $this, 'update_option_default_product_cat' ), 1, 2 );
57
- }else{
58
- add_action( 'update_term_meta', array( $this, 'update_category_count_meta' ), 10, 4 );
59
  }
60
 
 
61
  add_action( 'delete_term', array( $this, 'wcml_delete_term' ), 10, 4 );
62
  add_filter( 'get_the_terms', array( $this, 'shipping_terms' ), 10, 3 );
63
  add_filter( 'get_terms', array( $this, 'filter_shipping_classes_terms' ), 10, 3 );
64
 
65
  add_filter( 'woocommerce_get_product_terms', array( $this, 'get_product_terms_filter' ), 10, 4 );
66
  add_action( 'created_term_translation', array( $this, 'set_flag_to_sync' ), 10, 3 );
 
 
67
  }
68
 
69
  function admin_menu_setup(){
@@ -1013,4 +1014,13 @@ class WCML_Terms{
1013
  }
1014
  }
1015
 
 
 
 
 
 
 
 
 
 
1016
  }
54
 
55
  add_filter( 'pre_option_default_product_cat', array( $this, 'pre_option_default_product_cat' ) );
56
  add_filter( 'update_option_default_product_cat', array( $this, 'update_option_default_product_cat' ), 1, 2 );
 
 
57
  }
58
 
59
+ add_action( 'update_term_meta', array( $this, 'update_category_count_meta' ), 10, 4 );
60
  add_action( 'delete_term', array( $this, 'wcml_delete_term' ), 10, 4 );
61
  add_filter( 'get_the_terms', array( $this, 'shipping_terms' ), 10, 3 );
62
  add_filter( 'get_terms', array( $this, 'filter_shipping_classes_terms' ), 10, 3 );
63
 
64
  add_filter( 'woocommerce_get_product_terms', array( $this, 'get_product_terms_filter' ), 10, 4 );
65
  add_action( 'created_term_translation', array( $this, 'set_flag_to_sync' ), 10, 3 );
66
+
67
+ add_filter( 'woocommerce_get_product_subcategories_cache_key', array( $this, 'add_lang_parameter_to_cache_key' ) );
68
  }
69
 
70
  function admin_menu_setup(){
1014
  }
1015
  }
1016
 
1017
+ /**
1018
+ * @param string $key
1019
+ *
1020
+ * @return string
1021
+ */
1022
+ public function add_lang_parameter_to_cache_key( $key ){
1023
+ return $key.'-'.$this->sitepress->get_current_language();
1024
+ }
1025
+
1026
  }
inc/class-wcml-upgrade.php CHANGED
@@ -31,6 +31,7 @@ class WCML_Upgrade {
31
  '4.4.3',
32
  '4.6.8',
33
  '4.7.3',
 
34
  ];
35
 
36
  public function __construct() {
@@ -785,4 +786,15 @@ class WCML_Upgrade {
785
  private function upgrade_4_7_3() {
786
  delete_option( 'wcml_currency_switcher_template_objects' );
787
  }
 
 
 
 
 
 
 
 
 
 
 
788
  }
31
  '4.4.3',
32
  '4.6.8',
33
  '4.7.3',
34
+ '4.7.6',
35
  ];
36
 
37
  public function __construct() {
786
  private function upgrade_4_7_3() {
787
  delete_option( 'wcml_currency_switcher_template_objects' );
788
  }
789
+
790
+ private function upgrade_4_7_6() {
791
+ global $wpdb;
792
+
793
+ $wpdb->query(
794
+ "UPDATE {$wpdb->prefix}icl_strings
795
+ SET `context` = 'admin_texts_woocommerce_shipping',
796
+ `domain_name_context_md5` = MD5( CONCAT( 'admin_texts_woocommerce_shipping', `name`, `gettext_context` ) )
797
+ WHERE `context` = 'woocommerce' AND `name` LIKE '%_shipping_method_title'"
798
+ );
799
+ }
800
  }
inc/class-wcml-wc-shipping.php CHANGED
@@ -2,22 +2,31 @@
2
 
3
  class WCML_WC_Shipping{
4
 
 
 
5
  private $current_language;
6
- private $sitepress;
 
 
 
7
 
8
  /**
9
  * WCML_WC_Shipping constructor.
10
  *
11
  * @param SitePress $sitepress
 
12
  */
13
- public function __construct( $sitepress ) {
14
- $this->sitepress = $sitepress;
15
 
16
- $this->current_language = $this->sitepress->get_current_language();
17
- if ( 'all' === $this->current_language ) {
18
- $this->current_language = $this->sitepress->get_default_language();
19
- }
20
- }
 
 
 
 
21
 
22
  function add_hooks(){
23
 
@@ -70,6 +79,7 @@ class WCML_WC_Shipping{
70
  }
71
 
72
  function register_zone_shipping_strings( $instance_settings, $object ){
 
73
  if( !empty( $instance_settings['title'] ) ){
74
  $this->register_shipping_title( $object->id.$object->instance_id, $instance_settings['title'] );
75
 
@@ -80,7 +90,7 @@ class WCML_WC_Shipping{
80
  }
81
 
82
  function register_shipping_title( $shipping_method_id, $title ){
83
- do_action( 'wpml_register_single_string', 'woocommerce', $shipping_method_id .'_shipping_method_title', $title );
84
  }
85
 
86
  function translate_shipping_strings( $value, $option = false ){
@@ -131,19 +141,17 @@ class WCML_WC_Shipping{
131
 
132
  if ( ! is_admin() || $is_edit_order ) {
133
 
134
- $shipping_id = str_replace( ':', '', $shipping_id );
 
135
  $translated_title = apply_filters(
136
  'wpml_translate_single_string',
137
  $title,
138
- 'woocommerce',
139
  $shipping_id . '_shipping_method_title',
140
  $language ? $language : $this->current_language
141
  );
142
 
143
- if ( $translated_title ) {
144
- $title = $translated_title;
145
- }
146
-
147
  }
148
 
149
  return $title;
2
 
3
  class WCML_WC_Shipping{
4
 
5
+ const STRINGS_CONTEXT = 'admin_texts_woocommerce_shipping';
6
+
7
  private $current_language;
8
+ /** @var Sitepress */
9
+ private $sitepress;
10
+ /** @var WCML_WC_Strings */
11
+ private $wcmlStrings;
12
 
13
  /**
14
  * WCML_WC_Shipping constructor.
15
  *
16
  * @param SitePress $sitepress
17
+ * @param WCML_WC_Strings $wcmlStrings
18
  */
19
+ function __construct( SitePress $sitepress, WCML_WC_Strings $wcmlStrings ){
 
20
 
21
+ $this->sitepress = $sitepress;
22
+ $this->wcmlStrings = $wcmlStrings;
23
+
24
+ $this->current_language = $this->sitepress->get_current_language();
25
+ if( $this->current_language == 'all' ){
26
+ $this->current_language = $this->sitepress->get_default_language();
27
+ }
28
+
29
+ }
30
 
31
  function add_hooks(){
32
 
79
  }
80
 
81
  function register_zone_shipping_strings( $instance_settings, $object ){
82
+
83
  if( !empty( $instance_settings['title'] ) ){
84
  $this->register_shipping_title( $object->id.$object->instance_id, $instance_settings['title'] );
85
 
90
  }
91
 
92
  function register_shipping_title( $shipping_method_id, $title ){
93
+ do_action( 'wpml_register_single_string', self::STRINGS_CONTEXT, $shipping_method_id .'_shipping_method_title', $title );
94
  }
95
 
96
  function translate_shipping_strings( $value, $option = false ){
141
 
142
  if ( ! is_admin() || $is_edit_order ) {
143
 
144
+ $shipping_id = str_replace( ':', '', $shipping_id );
145
+
146
  $translated_title = apply_filters(
147
  'wpml_translate_single_string',
148
  $title,
149
+ self::STRINGS_CONTEXT,
150
  $shipping_id . '_shipping_method_title',
151
  $language ? $language : $this->current_language
152
  );
153
 
154
+ return $translated_title ?: $title;
 
 
 
155
  }
156
 
157
  return $title;
inc/class-wcml-wc-strings.php CHANGED
@@ -10,6 +10,8 @@ class WCML_WC_Strings {
10
  private $woocommerce_wpml;
11
  /** @var Sitepress */
12
  private $sitepress;
 
 
13
 
14
  public $settings = array();
15
 
@@ -18,10 +20,12 @@ class WCML_WC_Strings {
18
  *
19
  * @param woocommerce_wpml $woocommerce_wpml
20
  * @param SitePress $sitepress
 
21
  */
22
- public function __construct( woocommerce_wpml $woocommerce_wpml, SitePress $sitepress ) {
23
  $this->woocommerce_wpml = $woocommerce_wpml;
24
  $this->sitepress = $sitepress;
 
25
  }
26
 
27
  function add_hooks() {
@@ -324,7 +328,6 @@ class WCML_WC_Strings {
324
  }
325
 
326
  function get_string_language( $value, $context, $name = false ) {
327
- global $wpdb;
328
 
329
  if ( $name !== false ) {
330
 
@@ -338,7 +341,7 @@ class WCML_WC_Strings {
338
  return 'en';
339
  }
340
 
341
- $string_object = new WPML_ST_String( $string_id, $wpdb );
342
  $string_language = $string_object->get_language();
343
 
344
  }
@@ -352,11 +355,10 @@ class WCML_WC_Strings {
352
  }
353
 
354
  function set_string_language( $value, $context, $name, $language ) {
355
- global $wpdb;
356
 
357
  $string_id = icl_get_string_id( $value, $context, $name );
358
 
359
- $string_object = new WPML_ST_String( $string_id, $wpdb );
360
  $string_language = $string_object->set_language( $language );
361
 
362
  return $string_language;
@@ -519,4 +521,15 @@ class WCML_WC_Strings {
519
 
520
  }
521
 
 
 
 
 
 
 
 
 
 
 
 
522
  }
10
  private $woocommerce_wpml;
11
  /** @var Sitepress */
12
  private $sitepress;
13
+ /** @var wpdb */
14
+ private $wpdb;
15
 
16
  public $settings = array();
17
 
20
  *
21
  * @param woocommerce_wpml $woocommerce_wpml
22
  * @param SitePress $sitepress
23
+ * @param wpdb $wpdb
24
  */
25
+ public function __construct( woocommerce_wpml $woocommerce_wpml, SitePress $sitepress, wpdb $wpdb ) {
26
  $this->woocommerce_wpml = $woocommerce_wpml;
27
  $this->sitepress = $sitepress;
28
+ $this->wpdb = $wpdb;
29
  }
30
 
31
  function add_hooks() {
328
  }
329
 
330
  function get_string_language( $value, $context, $name = false ) {
 
331
 
332
  if ( $name !== false ) {
333
 
341
  return 'en';
342
  }
343
 
344
+ $string_object = new WPML_ST_String( $string_id, $this->wpdb );
345
  $string_language = $string_object->get_language();
346
 
347
  }
355
  }
356
 
357
  function set_string_language( $value, $context, $name, $language ) {
 
358
 
359
  $string_id = icl_get_string_id( $value, $context, $name );
360
 
361
+ $string_object = new WPML_ST_String( $string_id, $this->wpdb );
362
  $string_language = $string_object->set_language( $language );
363
 
364
  return $string_language;
521
 
522
  }
523
 
524
+ /**
525
+ * @param string $context
526
+ * @param string $name
527
+ * @param string $language
528
+ *
529
+ * @return string
530
+ */
531
+ public function get_translated_string_by_name_and_context( $context, $name, $language ){
532
+ return apply_filters( 'wpml_translate_single_string', false, $context, $name, $language );
533
+ }
534
+
535
  }
inc/currencies/class-wcml-multi-currency-prices.php CHANGED
@@ -29,6 +29,7 @@ class WCML_Multi_Currency_Prices {
29
  add_filter( 'wcml_price_currency', array( $this, 'price_currency_filter' ) );
30
  add_filter( 'get_post_metadata', array( $this, 'product_price_filter' ), 10, 4 );
31
  add_filter( 'get_post_metadata', array( $this, 'variation_prices_filter' ), 12, 4 );
 
32
 
33
  if ( $this->multi_currency->load_filters ) {
34
  add_filter( 'wcml_product_price_by_currency', array(
@@ -40,8 +41,6 @@ class WCML_Multi_Currency_Prices {
40
 
41
  add_filter( 'woocommerce_adjust_price', array( $this, 'raw_price_filter' ), 10 );
42
 
43
- add_filter( 'wcml_formatted_price', array( $this, 'formatted_price' ), 10, 2 ); // WCML filters
44
-
45
  // Shipping prices
46
  add_filter( 'woocommerce_paypal_args', array( $this, 'filter_price_woocommerce_paypal_args' ) );
47
  add_filter( 'woocommerce_get_variation_prices_hash', array(
29
  add_filter( 'wcml_price_currency', array( $this, 'price_currency_filter' ) );
30
  add_filter( 'get_post_metadata', array( $this, 'product_price_filter' ), 10, 4 );
31
  add_filter( 'get_post_metadata', array( $this, 'variation_prices_filter' ), 12, 4 );
32
+ add_filter( 'wcml_formatted_price', array( $this, 'formatted_price' ), 10, 2 );
33
 
34
  if ( $this->multi_currency->load_filters ) {
35
  add_filter( 'wcml_product_price_by_currency', array(
41
 
42
  add_filter( 'woocommerce_adjust_price', array( $this, 'raw_price_filter' ), 10 );
43
 
 
 
44
  // Shipping prices
45
  add_filter( 'woocommerce_paypal_args', array( $this, 'filter_price_woocommerce_paypal_args' ) );
46
  add_filter( 'woocommerce_get_variation_prices_hash', array(
inc/currencies/class-wcml-multi-currency-reports.php CHANGED
@@ -105,9 +105,6 @@ class WCML_Multi_Currency_Reports {
105
 
106
  $this->reports_currency = isset( $_COOKIE['_wcml_reports_currency'] ) ? $_COOKIE['_wcml_reports_currency'] : wcml_get_woocommerce_currency_option();
107
 
108
- // Validation.
109
- $this->reports_currency = $this->woocommerce_wpml->multi_currency->get_currency_code();
110
-
111
  add_filter( 'woocommerce_currency_symbol', array( $this, '_set_reports_currency_symbol' ) );
112
  }
113
  }
105
 
106
  $this->reports_currency = isset( $_COOKIE['_wcml_reports_currency'] ) ? $_COOKIE['_wcml_reports_currency'] : wcml_get_woocommerce_currency_option();
107
 
 
 
 
108
  add_filter( 'woocommerce_currency_symbol', array( $this, '_set_reports_currency_symbol' ) );
109
  }
110
  }
inc/currencies/class-wcml-multi-currency-resources.php CHANGED
@@ -43,13 +43,16 @@ class WCML_Multi_Currency_Resources{
43
  }
44
 
45
  private static function set_cache_compatibility_variables( $script_vars ) {
46
- global $sg_cachepress_environment;
47
 
48
  $script_vars['cache_enabled'] = false;
49
 
50
  $w3tc_enabled = ! empty( self::$multi_currency->W3TC ) || ( function_exists( 'wp_cache_is_enabled' ) && wp_cache_is_enabled() );
51
  $nginx_enabled = class_exists( 'NginxCache' );
52
- $sg_cache_enabled = $sg_cachepress_environment && $sg_cachepress_environment->cache_is_enabled();
 
 
 
53
 
54
  if ( $w3tc_enabled || $nginx_enabled || $sg_cache_enabled ) {
55
  $script_vars['cache_enabled'] = true;
43
  }
44
 
45
  private static function set_cache_compatibility_variables( $script_vars ) {
46
+ global $sg_cachepress_environment, $siteground_optimizer_helper;
47
 
48
  $script_vars['cache_enabled'] = false;
49
 
50
  $w3tc_enabled = ! empty( self::$multi_currency->W3TC ) || ( function_exists( 'wp_cache_is_enabled' ) && wp_cache_is_enabled() );
51
  $nginx_enabled = class_exists( 'NginxCache' );
52
+
53
+ $sg_cache_enabled =
54
+ ( $sg_cachepress_environment && $sg_cachepress_environment->cache_is_enabled() ) ||
55
+ ( $siteground_optimizer_helper && get_option( 'siteground_optimizer_enable_memcached', false ) );
56
 
57
  if ( $w3tc_enabled || $nginx_enabled || $sg_cache_enabled ) {
58
  $script_vars['cache_enabled'] = true;
inc/currencies/currency-switcher/class-wcml-currency-switcher-templates.php CHANGED
@@ -39,16 +39,10 @@ class WCML_Currency_Switcher_Templates {
39
  */
40
  private $ds = DIRECTORY_SEPARATOR;
41
 
42
- public function __construct( woocommerce_wpml $woocommerce_wpml, WPML_WP_API $wp_api, WCML_File $wpml_file = null ) {
43
  $this->woocommerce_wpml = $woocommerce_wpml;
44
  $this->wp_api = $wp_api;
45
-
46
- if ( ! $wpml_file ) {
47
- // @todo: use WPML_FILE class instead after changing requirements for WPML >= 3.6.0.
48
- $wpml_file = new WCML_File();
49
- }
50
-
51
- $this->wpml_file = $wpml_file;
52
  }
53
 
54
  public function init_hooks() {
@@ -298,6 +292,7 @@ class WCML_Currency_Switcher_Templates {
298
  }
299
  } else {
300
  $search_path = $template_path . $this->ds . '*.' . $ext;
 
301
  if ( glob( $search_path ) ) {
302
  foreach ( glob( $search_path ) as $file ) {
303
  $resources[] = $this->wpml_file->get_uri_from_path( $file );
39
  */
40
  private $ds = DIRECTORY_SEPARATOR;
41
 
42
+ public function __construct( woocommerce_wpml $woocommerce_wpml, WPML_WP_API $wp_api, WPML_File $wpml_file = null ) {
43
  $this->woocommerce_wpml = $woocommerce_wpml;
44
  $this->wp_api = $wp_api;
45
+ $this->wpml_file = $wpml_file;
 
 
 
 
 
 
46
  }
47
 
48
  public function init_hooks() {
292
  }
293
  } else {
294
  $search_path = $template_path . $this->ds . '*.' . $ext;
295
+
296
  if ( glob( $search_path ) ) {
297
  foreach ( glob( $search_path ) as $file ) {
298
  $resources[] = $this->wpml_file->get_uri_from_path( $file );
inc/currencies/currency-switcher/class-wcml-file.php DELETED
@@ -1,59 +0,0 @@
1
- <?php
2
-
3
- class WCML_File {
4
- /* @var WPML_WP_API $wp_api */
5
- private $wp_api;
6
-
7
- /**
8
- * @param WPML_WP_API|null $wp_api
9
- */
10
- public function __construct( WPML_WP_API $wp_api = null ) {
11
- if ( ! $wp_api ) {
12
- $wp_api = new WPML_WP_API();
13
- }
14
-
15
- $this->wp_api = $wp_api;
16
- }
17
-
18
- /**
19
- * @param string $path
20
- *
21
- * @return string
22
- */
23
- public function fix_dir_separator( $path ) {
24
- $directory_separator = $this->wp_api->constant( 'DIRECTORY_SEPARATOR' );
25
- return ( '\\' === $directory_separator ) ? str_replace( '/', '\\', $path ) : str_replace( '\\', '/', $path );
26
- }
27
-
28
- /**
29
- * @param string $path
30
- *
31
- * @return string
32
- */
33
- public function get_uri_from_path( $path ) {
34
- $base = null;
35
-
36
- if ( $this->wp_api->constant( 'WP_CONTENT_DIR' ) && $this->wp_api->constant( 'WP_CONTENT_URL' ) ) {
37
- $base_path = $this->fix_dir_separator( $this->wp_api->constant( 'WP_CONTENT_DIR' ) );
38
-
39
- if ( 0 === strpos( $path, $base_path ) ) {
40
- $base = array(
41
- 'path' => $base_path,
42
- 'uri' => $this->wp_api->constant( 'WP_CONTENT_URL' ),
43
- );
44
- }
45
- }
46
-
47
- if ( ! $base ) {
48
- $base = array(
49
- 'path' => $this->wp_api->constant( 'ABSPATH' ),
50
- 'uri' => site_url(),
51
- );
52
- }
53
-
54
- $relative_path = substr( $path, strlen( $base['path'] ) );
55
- $relative_path = str_replace( array( '/', '\\' ), '/', $relative_path );
56
- $relative_path = ltrim( $relative_path, '/' );
57
- return trailingslashit( $base['uri'] ) . $relative_path;
58
- }
59
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
inc/translation-editor/class-wcml-synchronize-product-data.php CHANGED
@@ -345,14 +345,14 @@ class WCML_Synchronize_Product_Data{
345
 
346
  if( $translated_product ){
347
  $this->update_stock_value( $translated_product, $stock );
348
- wc_update_product_stock_status( $translated_product->get_id(), $product->get_stock_status() );
349
  }else{
350
  $translations = $this->post_translations->get_element_translations( $product_id );
351
  foreach( $translations as $translation ){
352
  if( $product_id !== $translation ){
353
  $_product = wc_get_product( $translation );
354
  $this->update_stock_value( $_product, $stock );
355
- wc_update_product_stock_status( $translation, $product->get_stock_status() );
356
  }
357
  }
358
  }
@@ -406,10 +406,6 @@ class WCML_Synchronize_Product_Data{
406
 
407
  $order = wc_get_order( $order_id );
408
 
409
- if ( ! $order || $order->get_data_store()->get_recorded_sales( $order ) ) {
410
- return;
411
- }
412
-
413
  foreach ( $order->get_items() as $item ) {
414
 
415
  if ( $item instanceof WC_Order_Item_Product ) {
@@ -425,8 +421,8 @@ class WCML_Synchronize_Product_Data{
425
  $translations = $this->post_translations->get_element_translations( $product_id );
426
  $data_store = WC_Data_Store::load( 'product' );
427
  foreach ( $translations as $translation ) {
428
- if ( $product_id !== $translation ) {
429
- $data_store->update_product_sales( $translation, absint( $qty ), 'increase' );
430
  }
431
  }
432
  }
@@ -439,7 +435,7 @@ class WCML_Synchronize_Product_Data{
439
  $translations = $this->post_translations->get_element_translations( $product_id, false, true );
440
 
441
  foreach ( $translations as $translation ) {
442
- wc_update_product_stock_status( $translation, $status );
443
  $this->wc_taxonomies_recount_after_stock_change( $translation );
444
  }
445
  }
345
 
346
  if( $translated_product ){
347
  $this->update_stock_value( $translated_product, $stock );
348
+ $this->woocommerce_wpml->products->update_stock_status( $translated_product->get_id(), $product->get_stock_status() );
349
  }else{
350
  $translations = $this->post_translations->get_element_translations( $product_id );
351
  foreach( $translations as $translation ){
352
  if( $product_id !== $translation ){
353
  $_product = wc_get_product( $translation );
354
  $this->update_stock_value( $_product, $stock );
355
+ $this->woocommerce_wpml->products->update_stock_status( $translation, $product->get_stock_status() );
356
  }
357
  }
358
  }
406
 
407
  $order = wc_get_order( $order_id );
408
 
 
 
 
 
409
  foreach ( $order->get_items() as $item ) {
410
 
411
  if ( $item instanceof WC_Order_Item_Product ) {
421
  $translations = $this->post_translations->get_element_translations( $product_id );
422
  $data_store = WC_Data_Store::load( 'product' );
423
  foreach ( $translations as $translation ) {
424
+ if ( $product_id !== (int)$translation ) {
425
+ $data_store->update_product_sales( (int)$translation, absint( $qty ), 'increase' );
426
  }
427
  }
428
  }
435
  $translations = $this->post_translations->get_element_translations( $product_id, false, true );
436
 
437
  foreach ( $translations as $translation ) {
438
+ $this->woocommerce_wpml->products->update_stock_status( $translation, $status );
439
  $this->wc_taxonomies_recount_after_stock_change( $translation );
440
  }
441
  }
readme.txt CHANGED
@@ -5,7 +5,7 @@ Tags: CMS, woocommerce, commerce, ecommerce, e-commerce, products, WPML, multili
5
  License: GPLv2
6
  Requires at least: 4.7
7
  Tested up to: 5.3
8
- Stable tag: 4.7.6
9
  Requires PHP: 5.6
10
 
11
  Allows running fully multilingual e-commerce sites using WooCommerce and WPML.
@@ -137,18 +137,32 @@ WooCommerce Multilingual is compatible with all major WooCommerce extensions. We
137
 
138
  == Changelog ==
139
 
140
- = 4.7.6 =
141
- * Fix php warning in WCML custom prices module.
142
- * Fixed unable to add variation to cart for products with more than 30 variations.
143
- * Remove legacy code for downloading the language pack.
144
- * Fixed string translation while adding "sold individual" product more than ones from second language.
145
- * Fixed notices thrown with php 7.4 with multi-currency.
146
- * Fixed notices thrown with php 7.4 when using multi-currency.
147
- * Fixed notices thrown with php 7.4 when using WCML with WC Variation Swatches and Photos.
148
- * Fixed deprecation notices (`Function get_magic_quotes_gpc() is deprecated`) when running PHP 7.4.
149
- * Fixed a few fatal errors thrown when running PHP 7.4 (e.g. `Fatal error: Uncaught Error: Call to a member function get_setting() on null`) and caused by legacy code passing objects by reference.
150
- * Fixed language for "Low Stock" and "No Stock" admin emails.
151
- * Fixed not converted pre-selected price widget prices when switching currency.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
152
 
153
  = 4.7.0 =
154
  * Replaced some Twig templates with pure PHP templates as the first step towards the removal of Twig dependencies.
@@ -158,6 +172,7 @@ WooCommerce Multilingual is compatible with all major WooCommerce extensions. We
158
  * Fixed an issue with the cache flush during language switching.
159
  * Fixed in the original ticket.
160
  * Fixed an issue where the gateway strings would always register in English instead of the site's default language.
 
161
  * Fixed PHP Notice for WC Variations Swatches And Photos compatibility.
162
  * WooCommerce Bookings compatibility : Fixed notice when trying to cancel booking.
163
  * Fixed an issue where the total price on the Composite product page was not rounded.
@@ -172,6 +187,7 @@ WooCommerce Multilingual is compatible with all major WooCommerce extensions. We
172
  * Fixed an issue where customers would not receive notifications in the correct language.
173
  * Fixed an issue where the Products shortcode was not working in the secondary language.
174
  * Fixed error while sending WooCoomerce Bookings email for bookings which didn't have orders assigned.
 
175
  * Updated compatibility class for WC Checkout Addons
176
  * Fixed the images that were wrongly inserted in the translation job when attachments are not translatable.
177
  * Significantly improved the site performance on when updating the page, post, or a WooCommerce product page in the admin.
5
  License: GPLv2
6
  Requires at least: 4.7
7
  Tested up to: 5.3
8
+ Stable tag: 4.7.7
9
  Requires PHP: 5.6
10
 
11
  Allows running fully multilingual e-commerce sites using WooCommerce and WPML.
137
 
138
  == Changelog ==
139
 
140
+ = 4.7.7 =
141
+ * Fixed not linked order_id for Bookable products.
142
+ * Fixed not filtering of currencies accounts on order confirmation page.
143
+ * Fixed "Break and Abort" rules not applying in secondary language for Table Rate Shipping.
144
+ * Fixed wrong order item id in some special cases.
145
+ * Fixed customer order email strings sent in wrong language.
146
+ * Fixed sale price in original product when checkout via PayPal in some cases.
147
+ * Fixed wrong count for parent product categories in the second language.
148
+ * Fixed wrong "Add to cart" button URL on archive pages in secondary language when "language as parameter set".
149
+ * Fixed default currency wasn't removed from Multi-currency settings after changing in WooCommerce settings.
150
+ * Fixed custom attribute label translation displayed on product view page instead of attribute taxonomy label.
151
+ * Fixed console errors on Multi-Currency settings page if site under https.
152
+ * Fixed wrong shipping rate applying on the cart page for Table Rate Shipping ( Bolder Elements ).
153
+ * Fixed currency not switched with Siteground optimizer 5.0.* version and enabled memcache.
154
+ * Fixed deprecated 'calculate_booking_cost' function in WooCommerce Bookings since 1.15.0.
155
+ * Hide admin language switcher from Dynamic Prices settings page.
156
+ * Fixed shop pages assignment on pages listing in second language.
157
+ * Fixed not synchronized default value for Composite Products.
158
+ * Fixed product total sales meta synchronization.
159
+ * Fixed PHP Notices for Product Addons when 'options' doesn't set for addon.
160
+ * Fixed `wcml_formatted_price` filter not displaying a converted price when current currency is default one.
161
+ * Fixed category names on Shop page when object caching is enabled.
162
+ * Fixed styles on product view page when WPML not active.
163
+ * Fixed unable to switch currency on the reports page.
164
+ * Fixed not translated shipping method title in admin email.
165
+ * Fixed Rest API request for getting products in 'all' languages.
166
 
167
  = 4.7.0 =
168
  * Replaced some Twig templates with pure PHP templates as the first step towards the removal of Twig dependencies.
172
  * Fixed an issue with the cache flush during language switching.
173
  * Fixed in the original ticket.
174
  * Fixed an issue where the gateway strings would always register in English instead of the site's default language.
175
+ * Fixed languages column width on products table.
176
  * Fixed PHP Notice for WC Variations Swatches And Photos compatibility.
177
  * WooCommerce Bookings compatibility : Fixed notice when trying to cancel booking.
178
  * Fixed an issue where the total price on the Composite product page was not rounded.
187
  * Fixed an issue where customers would not receive notifications in the correct language.
188
  * Fixed an issue where the Products shortcode was not working in the secondary language.
189
  * Fixed error while sending WooCoomerce Bookings email for bookings which didn't have orders assigned.
190
+ * Added compatibility for free version of YIKES Custom Product Tabs.
191
  * Updated compatibility class for WC Checkout Addons
192
  * Fixed the images that were wrongly inserted in the translation job when attachments are not translatable.
193
  * Significantly improved the site performance on when updating the page, post, or a WooCommerce product page in the admin.
vendor/autoload.php CHANGED
@@ -4,4 +4,4 @@
4
 
5
  require_once __DIR__ . '/composer/autoload_real.php';
6
 
7
- return ComposerAutoloaderInit1c06ba8112cf30696ed81802be9382a7::getLoader();
4
 
5
  require_once __DIR__ . '/composer/autoload_real.php';
6
 
7
+ return ComposerAutoloaderInit9194a01e3b7341913deb206154fe289f::getLoader();
vendor/composer/autoload_classmap.php CHANGED
@@ -7,7 +7,6 @@ $baseDir = dirname($vendorDir);
7
 
8
  return array(
9
  'WCML\\Container\\Config' => $baseDir . '/classes/Container/Config.php',
10
- 'WCML\\Email\\OrderItems\\Hooks' => $baseDir . '/classes/Email/OrderItems/Hooks.php',
11
  'WCML\\Email\\Settings\\Hooks' => $baseDir . '/classes/Email/Settings/Hooks.php',
12
  'WCML\\Media\\Wrapper\\Factory' => $baseDir . '/classes/media/Wrapper/Factory.php',
13
  'WCML\\Media\\Wrapper\\IMedia' => $baseDir . '/classes/media/Wrapper/IMedia.php',
@@ -72,7 +71,6 @@ return array(
72
  'WCML_Exchange_Rates_Fixerio' => $baseDir . '/classes/multi-currency/exchange-rate-services/class-wcml-exchange-rates-fixerio.php',
73
  'WCML_Exchange_Rates_UI' => $baseDir . '/inc/template-classes/multi-currency/class-wcml-exchange-rates-ui.php',
74
  'WCML_Extra_Product_Options' => $baseDir . '/compatibility/class-wcml-extra-product-options.php',
75
- 'WCML_File' => $baseDir . '/inc/currencies/currency-switcher/class-wcml-file.php',
76
  'WCML_Flatsome' => $baseDir . '/compatibility/class-wcml-flatsome.php',
77
  'WCML_Install' => $baseDir . '/inc/class-wcml-install.php',
78
  'WCML_JCK_WSSV' => $baseDir . '/compatibility/class-wcml-jck-wssv.php',
7
 
8
  return array(
9
  'WCML\\Container\\Config' => $baseDir . '/classes/Container/Config.php',
 
10
  'WCML\\Email\\Settings\\Hooks' => $baseDir . '/classes/Email/Settings/Hooks.php',
11
  'WCML\\Media\\Wrapper\\Factory' => $baseDir . '/classes/media/Wrapper/Factory.php',
12
  'WCML\\Media\\Wrapper\\IMedia' => $baseDir . '/classes/media/Wrapper/IMedia.php',
71
  'WCML_Exchange_Rates_Fixerio' => $baseDir . '/classes/multi-currency/exchange-rate-services/class-wcml-exchange-rates-fixerio.php',
72
  'WCML_Exchange_Rates_UI' => $baseDir . '/inc/template-classes/multi-currency/class-wcml-exchange-rates-ui.php',
73
  'WCML_Extra_Product_Options' => $baseDir . '/compatibility/class-wcml-extra-product-options.php',
 
74
  'WCML_Flatsome' => $baseDir . '/compatibility/class-wcml-flatsome.php',
75
  'WCML_Install' => $baseDir . '/inc/class-wcml-install.php',
76
  'WCML_JCK_WSSV' => $baseDir . '/compatibility/class-wcml-jck-wssv.php',
vendor/composer/autoload_real.php CHANGED
@@ -2,7 +2,7 @@
2
 
3
  // autoload_real.php @generated by Composer
4
 
5
- class ComposerAutoloaderInit1c06ba8112cf30696ed81802be9382a7
6
  {
7
  private static $loader;
8
 
@@ -19,15 +19,15 @@ class ComposerAutoloaderInit1c06ba8112cf30696ed81802be9382a7
19
  return self::$loader;
20
  }
21
 
22
- spl_autoload_register(array('ComposerAutoloaderInit1c06ba8112cf30696ed81802be9382a7', 'loadClassLoader'), true, true);
23
  self::$loader = $loader = new \Composer\Autoload\ClassLoader();
24
- spl_autoload_unregister(array('ComposerAutoloaderInit1c06ba8112cf30696ed81802be9382a7', '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\ComposerStaticInit1c06ba8112cf30696ed81802be9382a7::getInitializer($loader));
31
  } else {
32
  $map = require __DIR__ . '/autoload_namespaces.php';
33
  foreach ($map as $namespace => $path) {
@@ -48,19 +48,19 @@ class ComposerAutoloaderInit1c06ba8112cf30696ed81802be9382a7
48
  $loader->register(true);
49
 
50
  if ($useStaticLoader) {
51
- $includeFiles = Composer\Autoload\ComposerStaticInit1c06ba8112cf30696ed81802be9382a7::$files;
52
  } else {
53
  $includeFiles = require __DIR__ . '/autoload_files.php';
54
  }
55
  foreach ($includeFiles as $fileIdentifier => $file) {
56
- composerRequire1c06ba8112cf30696ed81802be9382a7($fileIdentifier, $file);
57
  }
58
 
59
  return $loader;
60
  }
61
  }
62
 
63
- function composerRequire1c06ba8112cf30696ed81802be9382a7($fileIdentifier, $file)
64
  {
65
  if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) {
66
  require $file;
2
 
3
  // autoload_real.php @generated by Composer
4
 
5
+ class ComposerAutoloaderInit9194a01e3b7341913deb206154fe289f
6
  {
7
  private static $loader;
8
 
19
  return self::$loader;
20
  }
21
 
22
+ spl_autoload_register(array('ComposerAutoloaderInit9194a01e3b7341913deb206154fe289f', 'loadClassLoader'), true, true);
23
  self::$loader = $loader = new \Composer\Autoload\ClassLoader();
24
+ spl_autoload_unregister(array('ComposerAutoloaderInit9194a01e3b7341913deb206154fe289f', '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\ComposerStaticInit9194a01e3b7341913deb206154fe289f::getInitializer($loader));
31
  } else {
32
  $map = require __DIR__ . '/autoload_namespaces.php';
33
  foreach ($map as $namespace => $path) {
48
  $loader->register(true);
49
 
50
  if ($useStaticLoader) {
51
+ $includeFiles = Composer\Autoload\ComposerStaticInit9194a01e3b7341913deb206154fe289f::$files;
52
  } else {
53
  $includeFiles = require __DIR__ . '/autoload_files.php';
54
  }
55
  foreach ($includeFiles as $fileIdentifier => $file) {
56
+ composerRequire9194a01e3b7341913deb206154fe289f($fileIdentifier, $file);
57
  }
58
 
59
  return $loader;
60
  }
61
  }
62
 
63
+ function composerRequire9194a01e3b7341913deb206154fe289f($fileIdentifier, $file)
64
  {
65
  if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) {
66
  require $file;
vendor/composer/autoload_static.php CHANGED
@@ -4,7 +4,7 @@
4
 
5
  namespace Composer\Autoload;
6
 
7
- class ComposerStaticInit1c06ba8112cf30696ed81802be9382a7
8
  {
9
  public static $files = array (
10
  'b45b351e6b6f7487d819961fef2fda77' => __DIR__ . '/..' . '/jakeasmith/http_build_url/src/http_build_url.php',
@@ -26,7 +26,6 @@ class ComposerStaticInit1c06ba8112cf30696ed81802be9382a7
26
 
27
  public static $classMap = array (
28
  'WCML\\Container\\Config' => __DIR__ . '/../..' . '/classes/Container/Config.php',
29
- 'WCML\\Email\\OrderItems\\Hooks' => __DIR__ . '/../..' . '/classes/Email/OrderItems/Hooks.php',
30
  'WCML\\Email\\Settings\\Hooks' => __DIR__ . '/../..' . '/classes/Email/Settings/Hooks.php',
31
  'WCML\\Media\\Wrapper\\Factory' => __DIR__ . '/../..' . '/classes/media/Wrapper/Factory.php',
32
  'WCML\\Media\\Wrapper\\IMedia' => __DIR__ . '/../..' . '/classes/media/Wrapper/IMedia.php',
@@ -91,7 +90,6 @@ class ComposerStaticInit1c06ba8112cf30696ed81802be9382a7
91
  'WCML_Exchange_Rates_Fixerio' => __DIR__ . '/../..' . '/classes/multi-currency/exchange-rate-services/class-wcml-exchange-rates-fixerio.php',
92
  'WCML_Exchange_Rates_UI' => __DIR__ . '/../..' . '/inc/template-classes/multi-currency/class-wcml-exchange-rates-ui.php',
93
  'WCML_Extra_Product_Options' => __DIR__ . '/../..' . '/compatibility/class-wcml-extra-product-options.php',
94
- 'WCML_File' => __DIR__ . '/../..' . '/inc/currencies/currency-switcher/class-wcml-file.php',
95
  'WCML_Flatsome' => __DIR__ . '/../..' . '/compatibility/class-wcml-flatsome.php',
96
  'WCML_Install' => __DIR__ . '/../..' . '/inc/class-wcml-install.php',
97
  'WCML_JCK_WSSV' => __DIR__ . '/../..' . '/compatibility/class-wcml-jck-wssv.php',
@@ -238,9 +236,9 @@ class ComposerStaticInit1c06ba8112cf30696ed81802be9382a7
238
  public static function getInitializer(ClassLoader $loader)
239
  {
240
  return \Closure::bind(function () use ($loader) {
241
- $loader->prefixLengthsPsr4 = ComposerStaticInit1c06ba8112cf30696ed81802be9382a7::$prefixLengthsPsr4;
242
- $loader->prefixDirsPsr4 = ComposerStaticInit1c06ba8112cf30696ed81802be9382a7::$prefixDirsPsr4;
243
- $loader->classMap = ComposerStaticInit1c06ba8112cf30696ed81802be9382a7::$classMap;
244
 
245
  }, null, ClassLoader::class);
246
  }
4
 
5
  namespace Composer\Autoload;
6
 
7
+ class ComposerStaticInit9194a01e3b7341913deb206154fe289f
8
  {
9
  public static $files = array (
10
  'b45b351e6b6f7487d819961fef2fda77' => __DIR__ . '/..' . '/jakeasmith/http_build_url/src/http_build_url.php',
26
 
27
  public static $classMap = array (
28
  'WCML\\Container\\Config' => __DIR__ . '/../..' . '/classes/Container/Config.php',
 
29
  'WCML\\Email\\Settings\\Hooks' => __DIR__ . '/../..' . '/classes/Email/Settings/Hooks.php',
30
  'WCML\\Media\\Wrapper\\Factory' => __DIR__ . '/../..' . '/classes/media/Wrapper/Factory.php',
31
  'WCML\\Media\\Wrapper\\IMedia' => __DIR__ . '/../..' . '/classes/media/Wrapper/IMedia.php',
90
  'WCML_Exchange_Rates_Fixerio' => __DIR__ . '/../..' . '/classes/multi-currency/exchange-rate-services/class-wcml-exchange-rates-fixerio.php',
91
  'WCML_Exchange_Rates_UI' => __DIR__ . '/../..' . '/inc/template-classes/multi-currency/class-wcml-exchange-rates-ui.php',
92
  'WCML_Extra_Product_Options' => __DIR__ . '/../..' . '/compatibility/class-wcml-extra-product-options.php',
 
93
  'WCML_Flatsome' => __DIR__ . '/../..' . '/compatibility/class-wcml-flatsome.php',
94
  'WCML_Install' => __DIR__ . '/../..' . '/inc/class-wcml-install.php',
95
  'WCML_JCK_WSSV' => __DIR__ . '/../..' . '/compatibility/class-wcml-jck-wssv.php',
236
  public static function getInitializer(ClassLoader $loader)
237
  {
238
  return \Closure::bind(function () use ($loader) {
239
+ $loader->prefixLengthsPsr4 = ComposerStaticInit9194a01e3b7341913deb206154fe289f::$prefixLengthsPsr4;
240
+ $loader->prefixDirsPsr4 = ComposerStaticInit9194a01e3b7341913deb206154fe289f::$prefixDirsPsr4;
241
+ $loader->classMap = ComposerStaticInit9194a01e3b7341913deb206154fe289f::$classMap;
242
 
243
  }, null, ClassLoader::class);
244
  }
vendor/otgs/installer/includes/class-wp-installer-channels.php CHANGED
@@ -71,9 +71,7 @@ class WP_Installer_Channels{
71
  $channel = sanitize_text_field( $_POST['channel'] );
72
 
73
  $response = array();
74
-
75
- if( $_POST['nonce'] === wp_create_nonce( 'installer_set_channel:' . $repository_id ) ){
76
-
77
  if( isset( WP_Installer()->settings['repositories'][$repository_id] ) ){
78
  WP_Installer()->settings['repositories'][$repository_id]['channel'] = $channel;
79
  WP_Installer()->settings['repositories'][$repository_id]['no-prompt'] = $_POST['noprompt'] === 'true';
71
  $channel = sanitize_text_field( $_POST['channel'] );
72
 
73
  $response = array();
74
+ if ( wp_verify_nonce( $_POST['nonce'], 'installer_set_channel:' . $repository_id ) ) {
 
 
75
  if( isset( WP_Installer()->settings['repositories'][$repository_id] ) ){
76
  WP_Installer()->settings['repositories'][$repository_id]['channel'] = $channel;
77
  WP_Installer()->settings['repositories'][$repository_id]['no-prompt'] = $_POST['noprompt'] === 'true';
vendor/otgs/installer/includes/class-wp-installer.php CHANGED
@@ -1311,7 +1311,7 @@ class WP_Installer {
1311
  }
1312
  $site_key = preg_replace( "/[^A-Za-z0-9]/", '', $site_key );
1313
 
1314
- if ( $repository_id && $nonce && wp_create_nonce( 'save_site_key_' . $repository_id ) === $nonce ) {
1315
 
1316
  try {
1317
  $subscription_data = $this->fetch_subscription_data( $repository_id, $site_key, self::SITE_KEY_VALIDATION_SOURCE_REGISTRATION );
@@ -2022,9 +2022,7 @@ class WP_Installer {
2022
  }
2023
 
2024
  if ( $subscription_data && ! is_wp_error( $subscription_data ) && $this->repository_has_valid_subscription( $data['repository_id'] ) ) {
2025
-
2026
- if ( $data['nonce'] == wp_create_nonce( 'install_plugin_' . $data['url'] ) ) {
2027
-
2028
  $upgrader_skins = new Installer_Upgrader_Skins(); //use our custom (mute) Skin
2029
  $upgrader = new Plugin_Upgrader( $upgrader_skins );
2030
 
@@ -2172,7 +2170,8 @@ class WP_Installer {
2172
  $error = '';
2173
 
2174
  $plugin_id = sanitize_text_field( $_POST['plugin_id'] );
2175
- if ( isset( $_POST['nonce'] ) && $plugin_id && $_POST['nonce'] == wp_create_nonce( 'activate_' . $plugin_id ) ) {
 
2176
 
2177
  // Deactivate any embedded version
2178
  $plugin_slug = dirname( $plugin_id );
1311
  }
1312
  $site_key = preg_replace( "/[^A-Za-z0-9]/", '', $site_key );
1313
 
1314
+ if ( $repository_id && $nonce && wp_verify_nonce( $nonce, 'save_site_key_' . $repository_id ) ) {
1315
 
1316
  try {
1317
  $subscription_data = $this->fetch_subscription_data( $repository_id, $site_key, self::SITE_KEY_VALIDATION_SOURCE_REGISTRATION );
2022
  }
2023
 
2024
  if ( $subscription_data && ! is_wp_error( $subscription_data ) && $this->repository_has_valid_subscription( $data['repository_id'] ) ) {
2025
+ if ( wp_verify_nonce( $data['nonce'], 'install_plugin_' . $data['url'] ) ) {
 
 
2026
  $upgrader_skins = new Installer_Upgrader_Skins(); //use our custom (mute) Skin
2027
  $upgrader = new Plugin_Upgrader( $upgrader_skins );
2028
 
2170
  $error = '';
2171
 
2172
  $plugin_id = sanitize_text_field( $_POST['plugin_id'] );
2173
+
2174
+ if ( isset( $_POST['nonce'] ) && $plugin_id && wp_verify_nonce( $_POST['nonce'], 'activate_' . $plugin_id ) ) {
2175
 
2176
  // Deactivate any embedded version
2177
  $plugin_slug = dirname( $plugin_id );
vendor/otgs/installer/loader.php CHANGED
@@ -51,7 +51,7 @@ $wp_installer_instance = dirname( __FILE__ ) . '/installer.php';
51
  global $wp_installer_instances;
52
  $wp_installer_instances[ $wp_installer_instance ] = array(
53
  'bootfile' => $wp_installer_instance,
54
- 'version' => '2.2.3'
55
  );
56
 
57
 
51
  global $wp_installer_instances;
52
  $wp_installer_instances[ $wp_installer_instance ] = array(
53
  'bootfile' => $wp_installer_instance,
54
+ 'version' => '2.2.4'
55
  );
56
 
57
 
vendor/wpml-shared/wpml-lib-dependencies/src/dependencies/class-wpml-dependencies.php CHANGED
@@ -318,10 +318,16 @@ class WPML_Dependencies {
318
  }
319
 
320
  private function get_invalid_plugins_report_list() {
 
 
321
  $invalid_plugins_list = '<ul class="ul-disc">';
322
  foreach ( $this->invalid_plugins as $invalid_plugin ) {
323
- $plugin_name_html = '<li data-installed-version="' . $this->installed_plugins[ $invalid_plugin ] . '">';
324
- $plugin_name_html .= $invalid_plugin;
 
 
 
 
325
  $plugin_name_html .= '</li>';
326
 
327
  $invalid_plugins_list .= $plugin_name_html;
318
  }
319
 
320
  private function get_invalid_plugins_report_list() {
321
+ /* translators: %s: Version number */
322
+ $required_version = __( 'required version: %s', 'sitepress' );
323
  $invalid_plugins_list = '<ul class="ul-disc">';
324
  foreach ( $this->invalid_plugins as $invalid_plugin ) {
325
+ $plugin_name_html = '<li data-installed-version="' . $this->installed_plugins[ $invalid_plugin ] . '">';
326
+ $required_version_string = '';
327
+ if ( isset( $this->expected_versions[ $invalid_plugin ] ) ) {
328
+ $required_version_string = ' (' . sprintf( $required_version, $this->expected_versions[ $invalid_plugin ] ) . ')';
329
+ }
330
+ $plugin_name_html .= $invalid_plugin . $required_version_string;
331
  $plugin_name_html .= '</li>';
332
 
333
  $invalid_plugins_list .= $plugin_name_html;
wpml-woocommerce.php CHANGED
@@ -8,7 +8,7 @@
8
  * Text Domain: woocommerce-multilingual
9
  * Requires at least: 4.7
10
  * Tested up to: 5.3
11
- * Version: 4.7.6
12
  * Plugin Slug: woocommerce-multilingual
13
  * WC requires at least: 3.3.0
14
  * WC tested up to: 3.8.0
@@ -33,7 +33,7 @@ if ( ! $wpml_php_version_check->is_ok() ) {
33
  return;
34
  }
35
 
36
- define( 'WCML_VERSION', '4.7.6' );
37
  define( 'WCML_PLUGIN_PATH', dirname( __FILE__ ) );
38
  define( 'WCML_PLUGIN_FOLDER', basename( WCML_PLUGIN_PATH ) );
39
  define( 'WCML_LOCALE_PATH', WCML_PLUGIN_PATH . '/locale' );
@@ -81,7 +81,6 @@ function wcml_loader() {
81
  'WCML_ATE_Activate_Synchronization',
82
  \WCML\RewriteRules\Hooks::class,
83
  \WCML\Email\Settings\Hooks::class,
84
- \WCML\Email\OrderItems\Hooks::class,
85
  );
86
 
87
  if (
8
  * Text Domain: woocommerce-multilingual
9
  * Requires at least: 4.7
10
  * Tested up to: 5.3
11
+ * Version: 4.7.7
12
  * Plugin Slug: woocommerce-multilingual
13
  * WC requires at least: 3.3.0
14
  * WC tested up to: 3.8.0
33
  return;
34
  }
35
 
36
+ define( 'WCML_VERSION', '4.7.7' );
37
  define( 'WCML_PLUGIN_PATH', dirname( __FILE__ ) );
38
  define( 'WCML_PLUGIN_FOLDER', basename( WCML_PLUGIN_PATH ) );
39
  define( 'WCML_LOCALE_PATH', WCML_PLUGIN_PATH . '/locale' );
81
  'WCML_ATE_Activate_Synchronization',
82
  \WCML\RewriteRules\Hooks::class,
83
  \WCML\Email\Settings\Hooks::class,
 
84
  );
85
 
86
  if (