WooCommerce Multilingual – run WooCommerce with WPML - Version 4.7.8

Version Description

  • Make Additional content field translatable for Emails.
  • Fixed stock synchronization issue for some extra plugins.
  • Fixed cart item not deleted from cart page in some cases.
  • Fixed Average Rating Widget Filter in all languages.
  • Fixed a fatal error when applying a translation job on a product with tabs on PHP 7.1+.
  • Fixed admin order note language after order status change.
  • Fixed not showing products when shop page is a child page of the front/home page.
  • Fixed display glitch of displaying current currency while adding new one.
  • Fixed compatibility plugins additional content appears not translated when using ATE.
  • Fixed inability to edit 'before discount' field on edit order page.
  • Fixed products in all languages displayed on new booking admin page.
  • Fixed language icon not updated in real-time when using Advanced Translation Editor.
  • Fixed warning message displayed at the wrong moment.
  • Fixed wrong language of custom attributes on cart page with display as translated mode enabled for products.
  • Fixed multiple ajax calls on the front page if few tabs opened in different languages for non-logged users.
  • Fixed Subscriptions early renewal price if not subscription price selected in the shop.
  • Fixed Top Rated product widget displaying wrong products on the second language.
  • Fixed Variable subscription "From" from price display auto converted price instead of custom one.
  • Fixed the dynamic WooCommerce blocks which were not converted in the current language.
  • Fixed product in wrong language selected on new order admin page.
  • WP Super Cache enable cache for switching currency.
  • Lock attributes select on second language native edit screen.
  • Fixed price not shown issue with WooCommerce Bookings.
  • Removed limitation of decimals in multi-currency settings.
Download this release

Release Info

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

Code changes from version 4.7.7 to 4.7.8

Files changed (123) hide show
  1. changelog/4.7.7.md +0 -32
  2. changelog/4.7.8.md +31 -0
  3. classes/Block/Convert/Converter/ProductsByAttributes.php +22 -0
  4. classes/Block/Convert/ConverterProvider.php +141 -0
  5. classes/Block/Convert/Hooks.php +77 -0
  6. classes/Container/Config.php +1 -1
  7. classes/Email/Settings/Hooks.php +14 -13
  8. classes/Rest/Frontend/Language.php +35 -0
  9. classes/ate/class-wcml-ate-activate-synchronization.php +1 -1
  10. classes/class-wcml-admin-cookie.php +6 -9
  11. classes/class-wcml-tracking-link.php +3 -3
  12. classes/class-woocommerce-wpml.php +19 -20
  13. classes/currencies/class-wcml-admin-currency-selector.php +48 -42
  14. classes/currencies/class-wcml-currencies.php +9 -4
  15. classes/media/Wrapper/Translatable.php +40 -28
  16. classes/media/class-wcml-product-gallery-filter-factory.php +2 -2
  17. classes/media/class-wcml-product-gallery-filter.php +8 -9
  18. classes/media/class-wcml-product-image-filter-factory.php +2 -2
  19. classes/media/class-wcml-product-image-filter.php +16 -17
  20. classes/media/class-wcml-update-product-gallery-translation-factory.php +1 -1
  21. classes/media/class-wcml-update-product-gallery-translation.php +5 -5
  22. classes/multi-currency/class-wcml-exchange-rates.php +29 -32
  23. classes/multi-currency/exchange-rate-services/class-wcml-exchange-rate-service.php +12 -11
  24. classes/multi-currency/exchange-rate-services/class-wcml-exchange-rates-currencylayer.php +7 -7
  25. classes/multi-currency/exchange-rate-services/class-wcml-exchange-rates-fixerio.php +6 -6
  26. classes/multi-currency/payment-gateways/class-wcml-currencies-payment-gateways.php +1 -1
  27. classes/multi-currency/payment-gateways/class-wcml-payment-gateway-bacs.php +14 -14
  28. classes/multi-currency/payment-gateways/class-wcml-payment-gateway-paypal.php +27 -27
  29. classes/multi-currency/payment-gateways/class-wcml-payment-gateway-stripe.php +21 -21
  30. classes/multi-currency/payment-gateways/class-wcml-payment-gateway.php +14 -14
  31. classes/order-property-filter/class-wcml-payment-method-filter.php +11 -11
  32. classes/pointers/class-wcml-pointers.php +1 -1
  33. classes/privacy/class-wcml-privacy-content-factory.php +1 -1
  34. classes/privacy/class-wcml-privacy-content.php +3 -3
  35. classes/product/class-wcml-product-data-store-cpt.php +3 -3
  36. classes/shortcodes/class-wcml-wc-shortcode-product-category.php +19 -10
  37. classes/taxonomy-translation/class-wcml-taxonomy-translation-link-filters.php +19 -19
  38. classes/url-filters/class-wcml-url-filters-redirect-location.php +2 -2
  39. classes/urls/class-wcml-xdomain-data.php +6 -8
  40. classes/wcml-setup/class-wcml-setup-handlers.php +6 -6
  41. classes/wcml-setup/class-wcml-setup-ui.php +46 -28
  42. classes/wcml-setup/class-wcml-setup.php +55 -54
  43. compatibility/class-wcml-accommodation-bookings.php +1 -1
  44. compatibility/class-wcml-adventure-tours.php +272 -284
  45. compatibility/class-wcml-ajax-layered-nav-widget.php +23 -23
  46. compatibility/class-wcml-aurum.php +8 -8
  47. compatibility/class-wcml-bookings.php +733 -693
  48. compatibility/class-wcml-bulk-stock-management.php +23 -23
  49. compatibility/class-wcml-checkout-addons.php +3 -3
  50. compatibility/class-wcml-checkout-field-editor.php +156 -150
  51. compatibility/class-wcml-compatibility-helper.php +10 -10
  52. compatibility/class-wcml-composite-products.php +19 -19
  53. compatibility/class-wcml-dynamic-pricing.php +25 -26
  54. compatibility/class-wcml-etheme-blanco.php +0 -20
  55. compatibility/class-wcml-extra-product-options.php +20 -98
  56. compatibility/class-wcml-flatsome.php +9 -9
  57. compatibility/class-wcml-gravityforms.php +43 -43
  58. compatibility/class-wcml-jck-wssv.php +14 -14
  59. compatibility/class-wcml-klarna-gateway.php +1 -1
  60. compatibility/class-wcml-litespeed-cache.php +5 -5
  61. compatibility/class-wcml-maxstore.php +7 -7
  62. compatibility/class-wcml-mix-and-match-products.php +38 -51
  63. compatibility/class-wcml-order-status-manager.php +8 -8
  64. compatibility/class-wcml-per-product-shipping.php +25 -26
  65. compatibility/class-wcml-pip.php +57 -58
  66. compatibility/class-wcml-product-addons.php +180 -172
  67. compatibility/class-wcml-product-bundles.php +199 -162
  68. compatibility/class-wcml-relevanssi.php +2 -2
  69. compatibility/class-wcml-sensei.php +25 -32
  70. compatibility/class-wcml-tab-manager.php +149 -151
  71. compatibility/class-wcml-table-rate-shipping.php +68 -61
  72. compatibility/class-wcml-the-events-calendar.php +258 -281
  73. compatibility/class-wcml-variation-swatches-and-photos.php +8 -8
  74. compatibility/class-wcml-vpc.php +0 -20
  75. compatibility/class-wcml-wc-ajax-cart.php +0 -16
  76. compatibility/class-wcml-wc-memberships.php +9 -9
  77. compatibility/class-wcml-wc-name-your-price.php +15 -15
  78. compatibility/class-wcml-wc-product-type-column.php +1 -1
  79. compatibility/class-wcml-wc-subscriptions.php +207 -166
  80. compatibility/class-wcml-wcexporter.php +7 -7
  81. compatibility/class-wcml-woo-var-table.php +4 -4
  82. compatibility/class-wcml-woobe.php +8 -8
  83. compatibility/class-wcml-wpb-vc.php +3 -3
  84. compatibility/class-wcml-wpfastest-cache.php +7 -4
  85. compatibility/class-wcml-wpseo.php +35 -35
  86. compatibility/class-wcml-yikes-custom-product-tabs.php +37 -40
  87. compatibility/class-wcml-yith-wcqv.php +8 -8
  88. compatibility/includes/class-wcml-wc-product-bundles-items.php +11 -13
  89. inc/admin-menus/class-wcml-admin-menus.php +23 -23
  90. inc/class-wcml-ajax-setup.php +4 -4
  91. inc/class-wcml-attributes.php +147 -101
  92. inc/class-wcml-capabilities.php +1 -1
  93. inc/class-wcml-cart-switch-lang-functions.php +69 -68
  94. inc/class-wcml-cart-sync-warnings.php +33 -33
  95. inc/class-wcml-cart.php +130 -125
  96. inc/class-wcml-comments.php +88 -48
  97. inc/class-wcml-compatibility.php +3 -18
  98. inc/class-wcml-dependencies.php +91 -51
  99. inc/class-wcml-emails.php +212 -117
  100. inc/class-wcml-endpoints-legacy.php +15 -15
  101. inc/class-wcml-endpoints.php +1 -1
  102. inc/class-wcml-install.php +279 -263
  103. inc/class-wcml-languages-upgrader.php +178 -177
  104. inc/class-wcml-locale.php +46 -37
  105. inc/class-wcml-orders.php +100 -122
  106. inc/class-wcml-products-screen-options.php +2 -2
  107. inc/class-wcml-products.php +492 -485
  108. inc/class-wcml-reports.php +11 -11
  109. inc/class-wcml-requests.php +102 -102
  110. inc/class-wcml-resources.php +275 -253
  111. inc/class-wcml-store-pages.php +105 -89
  112. inc/class-wcml-terms.php +836 -745
  113. inc/class-wcml-tp-support.php +4 -2
  114. inc/class-wcml-troubleshooting.php +259 -251
  115. inc/class-wcml-upgrade.php +30 -0
  116. inc/class-wcml-url-translation.php +142 -132
  117. inc/class-wcml-wc-gateways.php +183 -179
  118. inc/class-wcml-wc-shipping.php +173 -167
  119. inc/class-wcml-wc-strings.php +111 -100
  120. inc/class-wcml-widgets.php +10 -11
  121. inc/constants.php +8 -8
  122. inc/currencies/class-wcml-custom-prices.php +365 -358
  123. inc/currencies/class-wcml-multi-currency-configuration.php +70 -75
changelog/4.7.7.md DELETED
@@ -1,32 +0,0 @@
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.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
changelog/4.7.8.md ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Features
2
+ * [wcml-2950] Make `Additional content` field translatable for Emails.
3
+
4
+ # Fixes
5
+ * [wcml-3103] Fixed stock synchronization issue for some extra plugins.
6
+ * [wcml-3100] Fixed cart item not deleted from cart page in some cases.
7
+ * [wcml-3098] Fixed Average Rating Widget Filter in all languages.
8
+ * [wcml-3096] Fixed a fatal error when applying a translation job on a product with tabs on PHP 7.1+.
9
+ * [wcml-3075] Fixed admin order note language after order status change.
10
+ * [wcml-3059] Fixed not showing products when shop page is a child page of the front/home page.
11
+ * [wcml-3051] Fixed display glitch of displaying current currency while adding new one.
12
+ * [wcml-3032] Fixed compatibility plugins additional content appears not translated when using ATE.
13
+ * [wcml-3007] Fixed inability to edit 'before discount' field on edit order page.
14
+ * [wcml-2962] Fixed products in all languages displayed on new booking admin page.
15
+ * [wcml-2956] Fixed language icon not updated in real-time when using Advanced Translation Editor.
16
+ * [wcml-2570] Fixed warning message displayed at the wrong moment.
17
+
18
+ # Compatibility
19
+ * [wcml-3091] Fixed wrong language of custom attributes on cart page with display as translated mode enabled for products.
20
+ * [wcml-3080] Fixed multiple ajax calls on the front page if few tabs opened in different languages for non-logged users.
21
+ * [wcml-2952] Fixed Subscriptions early renewal price if not subscription price selected in the shop.
22
+ * [wcml-2837] Fixed Top Rated product widget displaying wrong products on the second language.
23
+ * [wcml-2737] Fixed Variable subscription "From" from price display auto converted price instead of custom one.
24
+ * [wcml-2676] Fixed the dynamic WooCommerce blocks which were not converted in the current language.
25
+
26
+ # Usability
27
+ * [wcml-3019] Fixed product in wrong language selected on new order admin page.
28
+ * [wcml-3015] WP Super Cache enable cache for switching currency.
29
+ * [wcml-2925] Lock attributes select on second language native edit screen.
30
+ * [wcml-2808] Fixed price not shown issue with WooCommerce Bookings.
31
+ * [wcml-2535] Removed limitation of decimals in multi-currency settings.
classes/Block/Convert/Converter/ProductsByAttributes.php ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace WCML\Block\Convert\Converter;
4
+
5
+ class ProductsByAttributes extends \WPML\PB\Gutenberg\ConvertIdsInBlock\Base {
6
+
7
+ public function convert( array $block ) {
8
+ if ( ! isset( $block['attrs']['attributes'] ) ) {
9
+ return $block;
10
+ }
11
+
12
+ foreach ( $block['attrs']['attributes'] as $key => $attribute ) {
13
+ if ( ! isset( $attribute['id'], $attribute['attr_slug'] ) ) {
14
+ continue;
15
+ }
16
+
17
+ $block['attrs']['attributes'][ $key ]['id'] = self::convertIds( $attribute['id'], $attribute['attr_slug'], 'taxonomy' );
18
+ }
19
+
20
+ return $block;
21
+ }
22
+ }
classes/Block/Convert/ConverterProvider.php ADDED
@@ -0,0 +1,141 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace WCML\Block\Convert;
4
+
5
+ use WCML\Block\Convert\Converter\ProductsByAttributes;
6
+ use WPML\PB\Gutenberg\ConvertIdsInBlock\Base;
7
+ use WPML\PB\Gutenberg\ConvertIdsInBlock\Composite;
8
+ use WPML\PB\Gutenberg\ConvertIdsInBlock\NullConvert;
9
+ use WPML\PB\Gutenberg\ConvertIdsInBlock\BlockAttributes;
10
+ use WPML\PB\Gutenberg\ConvertIdsInBlock\TagAttributes;
11
+
12
+ class ConverterProvider {
13
+
14
+ /**
15
+ * @param string $blockName
16
+ *
17
+ * @return \WPML\PB\Gutenberg\ConvertIdsInBlock\Base
18
+ */
19
+ public static function get( $blockName ) {
20
+ switch ( $blockName ) {
21
+ case 'woocommerce/product-category':
22
+ $converter = new BlockAttributes(
23
+ [
24
+ [
25
+ 'name' => 'categories',
26
+ 'slug' => 'product_cat',
27
+ 'type' => 'taxonomy',
28
+ ],
29
+ ]
30
+ );
31
+ break;
32
+
33
+ case 'woocommerce/featured-category':
34
+ $converter = new BlockAttributes(
35
+ [
36
+ [
37
+ 'name' => 'categoryId',
38
+ 'slug' => 'product_cat',
39
+ 'type' => 'taxonomy',
40
+ ],
41
+ ]
42
+ );
43
+ break;
44
+
45
+ case 'woocommerce/featured-product':
46
+ $converter = new BlockAttributes(
47
+ [
48
+ [
49
+ 'name' => 'productId',
50
+ 'slug' => 'product',
51
+ 'type' => 'post'
52
+ ],
53
+ ]
54
+ );
55
+ break;
56
+
57
+ case 'woocommerce/handpicked-products':
58
+ $converter = new BlockAttributes(
59
+ [
60
+ [
61
+ 'name' => 'products',
62
+ 'slug' => 'product',
63
+ 'type' => 'post',
64
+ ],
65
+ ]
66
+ );
67
+ break;
68
+
69
+ case 'woocommerce/product-tag':
70
+ $converter = new BlockAttributes(
71
+ [
72
+ [
73
+ 'name' => 'tags',
74
+ 'slug' => 'product_tag',
75
+ 'type' => 'taxonomy',
76
+ ],
77
+ ]
78
+ );
79
+ break;
80
+
81
+ case 'woocommerce/reviews-by-product':
82
+ $converter = new Composite(
83
+ [
84
+ new BlockAttributes(
85
+ [
86
+ [
87
+ 'name' => 'productId',
88
+ 'slug' => 'product',
89
+ 'type' => 'post',
90
+ ],
91
+ ]
92
+ ),
93
+ new TagAttributes(
94
+ [
95
+ [
96
+ 'xpath' => '//*[contains(@class, "wp-block-woocommerce-reviews-by-product")]/@data-product-id',
97
+ 'slug' => 'product',
98
+ 'type' => 'post',
99
+ ],
100
+ ]
101
+ ),
102
+ ]
103
+ );
104
+ break;
105
+
106
+ case 'woocommerce/reviews-by-category':
107
+ $converter = new Composite(
108
+ [
109
+ new BlockAttributes(
110
+ [
111
+ [
112
+ 'name' => 'categoryIds',
113
+ 'slug' => 'product_cat',
114
+ 'type' => 'taxonomy',
115
+ ],
116
+ ]
117
+ ),
118
+ new TagAttributes(
119
+ [
120
+ [
121
+ 'xpath' => '//*[contains(@class, "wp-block-woocommerce-reviews-by-category")]/@data-category-ids',
122
+ 'slug' => 'product_cat',
123
+ 'type' => 'taxonomy',
124
+ ],
125
+ ]
126
+ ),
127
+ ]
128
+ );
129
+ break;
130
+
131
+ case 'woocommerce/products-by-attribute':
132
+ $converter = new ProductsByAttributes();
133
+ break;
134
+
135
+ default:
136
+ $converter = new Base();
137
+ }
138
+
139
+ return $converter;
140
+ }
141
+ }
classes/Block/Convert/Hooks.php ADDED
@@ -0,0 +1,77 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace WCML\Block\Convert;
4
+
5
+ use IWPML_DIC_Action;
6
+ use IWPML_Frontend_Action;
7
+ use SitePress;
8
+ use WCML\Rest\Frontend\Language;
9
+ use WPML_Cookie;
10
+
11
+ class Hooks implements IWPML_Frontend_Action, IWPML_DIC_Action {
12
+
13
+ /** @var SitePress $sitepress */
14
+ private $sitepress;
15
+
16
+ /** @var Language $frontendRestLang */
17
+ private $frontendRestLang;
18
+
19
+ public function __construct( SitePress $sitepress, Language $frontendRestLang ) {
20
+ $this->sitepress = $sitepress;
21
+ $this->frontendRestLang = $frontendRestLang;
22
+ }
23
+
24
+ public function add_hooks() {
25
+ add_filter( 'render_block_data', [ $this, 'filterIdsInBlock' ] );
26
+ add_action( 'parse_query', [ $this, 'addCurrentLangToQueryVars' ] );
27
+
28
+ if ( ! ( is_admin() || \WPML_URL_HTTP_Referer::is_post_edit_page() ) ) {
29
+ add_filter( 'rest_request_before_callbacks', [ $this, 'useLanguageFrontendRestLang' ], 10, 3 );
30
+ }
31
+ }
32
+
33
+ public function filterIdsInBlock( array $block ) {
34
+ return ConverterProvider::get( $block['blockName'] )->convert( $block );
35
+ }
36
+
37
+ /**
38
+ * WC is caching query results in transients which name
39
+ * is based on the query vars hash.
40
+ *
41
+ * @param \WP_Query $query
42
+ */
43
+ public function addCurrentLangToQueryVars( $query ) {
44
+ if ( $query instanceof \Automattic\WooCommerce\Blocks\Utils\BlocksWpQuery ) {
45
+ $query->query_vars['wpml_language'] = $this->sitepress->get_current_language();
46
+ }
47
+ }
48
+
49
+ /**
50
+ * @param \WP_HTTP_Response|\WP_Error $response
51
+ * @param array $handler
52
+ * @param \WP_REST_Request $request
53
+ *
54
+ * @return \WP_HTTP_Response|\WP_Error
55
+ */
56
+ public function useLanguageFrontendRestLang( $response, $handler, $request ) {
57
+ if ( $this->isWcRestRequest( $request ) ) {
58
+ $lang = $this->frontendRestLang->get();
59
+
60
+ if ( $lang ) {
61
+ $this->sitepress->switch_lang( $lang );
62
+ }
63
+ }
64
+
65
+ return $response;
66
+ }
67
+
68
+ /**
69
+ * @param \WP_REST_Request $request
70
+ *
71
+ * @return bool
72
+ */
73
+ private function isWcRestRequest( \WP_REST_Request $request ) {
74
+ return strpos( $request->get_route(), '/wc/blocks/' ) === 0
75
+ || strpos( $request->get_route(), '/wc/store/' ) === 0;
76
+ }
77
+ }
classes/Container/Config.php CHANGED
@@ -4,7 +4,7 @@ namespace WCML\Container;
4
 
5
  class Config {
6
 
7
- static public function getSharedInstances() {
8
  global $woocommerce_wpml;
9
 
10
  return [
4
 
5
  class Config {
6
 
7
+ public static function getSharedInstances() {
8
  global $woocommerce_wpml;
9
 
10
  return [
classes/Email/Settings/Hooks.php CHANGED
@@ -43,8 +43,8 @@ class Hooks implements IWPML_Backend_Action, IWPML_DIC_Action {
43
  && $_GET['tab'] === 'email';
44
  }
45
 
46
- function showLanguageLinksForWcEmails() {
47
- $emailOptions = array(
48
  'woocommerce_new_order_settings',
49
  'woocommerce_cancelled_order_settings',
50
  'woocommerce_failed_order_settings',
@@ -55,12 +55,12 @@ class Hooks implements IWPML_Backend_Action, IWPML_DIC_Action {
55
  'woocommerce_customer_invoice_settings',
56
  'woocommerce_customer_note_settings',
57
  'woocommerce_customer_reset_password_settings',
58
- 'woocommerce_customer_new_account_settings'
59
- );
60
 
61
  $emailOptions = apply_filters( 'wcml_emails_options_to_translate', $emailOptions );
62
 
63
- $textKeys = array(
64
  'subject',
65
  'heading',
66
  'subject_downloadable',
@@ -70,8 +70,9 @@ class Hooks implements IWPML_Backend_Action, IWPML_DIC_Action {
70
  'heading_full',
71
  'heading_partial',
72
  'subject_paid',
73
- 'heading_paid'
74
- );
 
75
 
76
  $textKeys = apply_filters( 'wcml_emails_text_keys_to_translate', $textKeys );
77
 
@@ -117,23 +118,23 @@ class Hooks implements IWPML_Backend_Action, IWPML_DIC_Action {
117
 
118
  ?>
119
  <script>
120
- var input = jQuery('input[name="<?php echo $emailInputKey ?>"]');
121
  if (input.length) {
122
  input.parent().append('<div class="translation_controls"></div>');
123
- input.parent().find('.translation_controls').append('<a href="<?php echo $stPage; ?>" style="margin-left: 10px"><?php _e( 'translations', 'woocommerce-multilingual' ); ?></a>');
124
- jQuery('#<?php echo $emailOption . '_' . $settingsKey . '_language_selector'; ?>').prependTo(input.parent().find('.translation_controls'));
125
  }
126
  </script>
127
- <?php }
 
128
  }
129
  }
130
  }
131
  }
132
  }
133
 
134
- function setEmailsStringLanguage() {
135
  foreach ( $_POST as $key => $language ) {
136
-
137
  if ( substr( $key, 0, 9 ) === self::KEY_PREFIX ) {
138
 
139
  $keyParts = explode( '-', $key );
43
  && $_GET['tab'] === 'email';
44
  }
45
 
46
+ public function showLanguageLinksForWcEmails() {
47
+ $emailOptions = [
48
  'woocommerce_new_order_settings',
49
  'woocommerce_cancelled_order_settings',
50
  'woocommerce_failed_order_settings',
55
  'woocommerce_customer_invoice_settings',
56
  'woocommerce_customer_note_settings',
57
  'woocommerce_customer_reset_password_settings',
58
+ 'woocommerce_customer_new_account_settings',
59
+ ];
60
 
61
  $emailOptions = apply_filters( 'wcml_emails_options_to_translate', $emailOptions );
62
 
63
+ $textKeys = [
64
  'subject',
65
  'heading',
66
  'subject_downloadable',
70
  'heading_full',
71
  'heading_partial',
72
  'subject_paid',
73
+ 'heading_paid',
74
+ 'additional_content',
75
+ ];
76
 
77
  $textKeys = apply_filters( 'wcml_emails_text_keys_to_translate', $textKeys );
78
 
118
 
119
  ?>
120
  <script>
121
+ var input = jQuery('#<?php echo $emailInputKey; ?>');
122
  if (input.length) {
123
  input.parent().append('<div class="translation_controls"></div>');
124
+ input.parent().find('.translation_controls').append('<a href="<?php echo esc_url( $stPage ); ?>" style="margin-left: 10px"><?php esc_html_e( 'translations', 'woocommerce-multilingual' ); ?></a>');
125
+ jQuery('#<?php echo esc_html( $emailOption . '_' . $settingsKey . '_language_selector' ); ?>').prependTo(input.parent().find('.translation_controls'));
126
  }
127
  </script>
128
+ <?php
129
+ }
130
  }
131
  }
132
  }
133
  }
134
  }
135
 
136
+ public function setEmailsStringLanguage() {
137
  foreach ( $_POST as $key => $language ) {
 
138
  if ( substr( $key, 0, 9 ) === self::KEY_PREFIX ) {
139
 
140
  $keyParts = explode( '-', $key );
classes/Rest/Frontend/Language.php ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace WCML\Rest\Frontend;
4
+
5
+ use WCML_Switch_Lang_Request;
6
+ use WPML_Cookie;
7
+ use WPML_URL_Converter;
8
+
9
+ class Language {
10
+
11
+ /** @var WPML_Cookie $cookie */
12
+ private $cookie;
13
+
14
+ /** @var WPML_URL_Converter $urlConverter */
15
+ private $urlConverter;
16
+
17
+ public function __construct(
18
+ WPML_Cookie $cookie,
19
+ WPML_URL_Converter $urlConverter
20
+ ) {
21
+ $this->cookie = $cookie;
22
+ $this->urlConverter = $urlConverter;
23
+ }
24
+
25
+ /** @return string */
26
+ public function get() {
27
+ $lang = $this->cookie->get_cookie( WCML_Switch_Lang_Request::COOKIE_NAME );
28
+
29
+ if ( ! $lang && isset( $_SERVER['HTTP_REFERER'] ) ) {
30
+ $lang = $this->urlConverter->get_language_from_url( $_SERVER['HTTP_REFERER'] );
31
+ }
32
+
33
+ return $lang;
34
+ }
35
+ }
classes/ate/class-wcml-ate-activate-synchronization.php CHANGED
@@ -13,4 +13,4 @@ class WCML_ATE_Activate_Synchronization implements IWPML_Action, IWPML_Backend_A
13
  public function create() {
14
  return $this;
15
  }
16
- }
13
  public function create() {
14
  return $this;
15
  }
16
+ }
classes/class-wcml-admin-cookie.php CHANGED
@@ -1,6 +1,6 @@
1
  <?php
2
 
3
- class WCML_Admin_Cookie{
4
 
5
  /** @var string */
6
  private $name;
@@ -16,10 +16,10 @@ class WCML_Admin_Cookie{
16
 
17
  /**
18
  * @param mixed $value
19
- * @param int $expiration
20
  */
21
- public function set_value( $value, $expiration = null ){
22
- if( null === $expiration ){
23
  $expiration = time() + DAY_IN_SECONDS;
24
  }
25
  $this->handle_cache_plugins();
@@ -31,17 +31,14 @@ class WCML_Admin_Cookie{
31
  */
32
  public function get_value() {
33
  $value = null;
34
- if ( isset( $_COOKIE [ $this->name ] ) ){
35
  $value = $_COOKIE[ $this->name ];
36
  }
37
  return $value;
38
  }
39
 
40
- /**
41
- * @param $name
42
- */
43
  private function handle_cache_plugins() {
44
  // @todo uncomment or delete when #wpmlcore-5796 is resolved
45
- //do_action( 'wpsc_add_cookie', $this->name );
46
  }
47
  }
1
  <?php
2
 
3
+ class WCML_Admin_Cookie {
4
 
5
  /** @var string */
6
  private $name;
16
 
17
  /**
18
  * @param mixed $value
19
+ * @param int $expiration
20
  */
21
+ public function set_value( $value, $expiration = null ) {
22
+ if ( null === $expiration ) {
23
  $expiration = time() + DAY_IN_SECONDS;
24
  }
25
  $this->handle_cache_plugins();
31
  */
32
  public function get_value() {
33
  $value = null;
34
+ if ( isset( $_COOKIE [ $this->name ] ) ) {
35
  $value = $_COOKIE[ $this->name ];
36
  }
37
  return $value;
38
  }
39
 
 
 
 
40
  private function handle_cache_plugins() {
41
  // @todo uncomment or delete when #wpmlcore-5796 is resolved
42
+ // do_action( 'wpsc_add_cookie', $this->name );
43
  }
44
  }
classes/class-wcml-tracking-link.php CHANGED
@@ -3,13 +3,13 @@
3
  class WCML_Tracking_Link {
4
 
5
  public function generate( $link, $term = false, $content = false, $id = false ) {
6
- $params = array(
7
  'utm_source' => 'wcml-admin',
8
  'utm_medium' => 'plugin',
9
  'utm_term' => $term ? $term : 'WPML',
10
  'utm_content' => $content ? $content : 'required-plugins',
11
  'utm_campaign' => 'WCML',
12
- );
13
 
14
  $link = add_query_arg( $params, $link );
15
 
@@ -19,4 +19,4 @@ class WCML_Tracking_Link {
19
 
20
  return $link;
21
  }
22
- }
3
  class WCML_Tracking_Link {
4
 
5
  public function generate( $link, $term = false, $content = false, $id = false ) {
6
+ $params = [
7
  'utm_source' => 'wcml-admin',
8
  'utm_medium' => 'plugin',
9
  'utm_term' => $term ? $term : 'WPML',
10
  'utm_content' => $content ? $content : 'required-plugins',
11
  'utm_campaign' => 'WCML',
12
+ ];
13
 
14
  $link = add_query_arg( $params, $link );
15
 
19
 
20
  return $link;
21
  }
22
+ }
classes/class-woocommerce-wpml.php CHANGED
@@ -87,11 +87,11 @@ class woocommerce_wpml {
87
 
88
  new WCML_Widgets( $this );
89
 
90
- add_action( 'init', array( $this, 'init' ), 2 );
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
 
@@ -125,8 +125,8 @@ class woocommerce_wpml {
125
  }
126
 
127
  public function add_hooks() {
128
- add_action( 'wpml_loaded', array( $this, 'load' ) );
129
- add_action( 'init', array( $this, 'init' ), 2 );
130
  }
131
 
132
  public function load() {
@@ -150,7 +150,7 @@ class woocommerce_wpml {
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 );
@@ -166,7 +166,7 @@ class woocommerce_wpml {
166
 
167
  $this->compatibility = new WCML_Compatibility( $sitepress, $this, $wpdb, new WPML_Element_Translation_Package(), $wpml_post_translations );
168
 
169
- $actions_that_need_mc = array(
170
  'save-mc-options',
171
  'wcml_new_currency',
172
  'wcml_save_currency',
@@ -178,7 +178,7 @@ class woocommerce_wpml {
178
  'wcml_currencies_switcher_save_settings',
179
  'wcml_delete_currency_switcher',
180
  'wcml_currencies_order',
181
- );
182
 
183
  $this->cart = new WCML_Cart( $this, $sitepress, $woocommerce );
184
 
@@ -223,7 +223,7 @@ class woocommerce_wpml {
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 );
@@ -240,8 +240,7 @@ class woocommerce_wpml {
240
  $this->endpoints = new WCML_Endpoints( $this, $sitepress, $wpdb );
241
  $this->endpoints->add_hooks();
242
  $this->requests = new WCML_Requests();
243
- $this->cart = new WCML_Cart( $this, $sitepress, $woocommerce );
244
- $this->cart->add_hooks();
245
  $this->coupons = new WCML_Coupons( $this, $sitepress );
246
  $this->coupons->add_hooks();
247
  $this->locale = new WCML_Locale( $this, $sitepress );
@@ -255,7 +254,7 @@ class woocommerce_wpml {
255
  $this->wcml_products_screen->init();
256
  $this->cart_sync_warnings = new WCML_Cart_Sync_Warnings( $this, $sitepress );
257
  $this->cart_sync_warnings->add_hooks();
258
- $this->comments = new WCML_Comments( $this, $sitepress, $wpml_post_translations );
259
  $this->comments->add_hooks();
260
 
261
  if ( is_admin() ) {
@@ -276,7 +275,7 @@ class woocommerce_wpml {
276
  $url_filters_redirect_location = new WCML_Url_Filters_Redirect_Location( $wpml_url_converter );
277
  $url_filters_redirect_location->add_hooks();
278
 
279
- add_action( 'wp_ajax_wcml_update_setting_ajx', array( $this, 'update_setting_ajx' ) );
280
 
281
  return true;
282
  }
@@ -287,21 +286,21 @@ class woocommerce_wpml {
287
  * @return mixed|void
288
  */
289
  public function get_settings() {
290
- $defaults = array(
291
  'file_path_sync' => 1,
292
  'is_term_order_synced' => 0,
293
  'enable_multi_currency' => WCML_MULTI_CURRENCIES_DISABLED,
294
  'dismiss_doc_main' => 0,
295
  'trnsl_interface' => 1,
296
- 'currency_options' => array(),
297
  'currency_switcher_product_visibility' => 1,
298
  'dismiss_tm_warning' => 0,
299
  'dismiss_cart_warning' => 0,
300
- 'cart_sync' => array(
301
  'lang_switch' => WCML_CART_SYNC,
302
  'currency_switch' => WCML_CART_SYNC,
303
- ),
304
- );
305
 
306
  if ( empty( $this->settings ) ) {
307
  $this->settings = get_option( '_wcml_settings' );
@@ -372,10 +371,10 @@ class woocommerce_wpml {
372
  $this->update_settings();
373
 
374
  echo wp_json_encode(
375
- array(
376
  'html' => $html,
377
  'error' => $error,
378
- )
379
  );
380
  exit;
381
  }
@@ -481,7 +480,7 @@ class woocommerce_wpml {
481
  global $sitepress;
482
 
483
  return $sitepress->get_wp_api()->version_compare( $this->get_constant( 'ICL_SITEPRESS_VERSION' ), '4.2.0', '<' ) ||
484
- $sitepress->get_wp_api()->version_compare( $this->get_constant( 'WPML_TM_VERSION' ), '2.8.0', '<' );
485
  }
486
 
487
  /**
87
 
88
  new WCML_Widgets( $this );
89
 
90
+ add_action( 'init', [ $this, 'init' ], 2 );
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
 
125
  }
126
 
127
  public function add_hooks() {
128
+ add_action( 'wpml_loaded', [ $this, 'load' ] );
129
+ add_action( 'init', [ $this, 'init' ], 2 );
130
  }
131
 
132
  public function load() {
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 );
166
 
167
  $this->compatibility = new WCML_Compatibility( $sitepress, $this, $wpdb, new WPML_Element_Translation_Package(), $wpml_post_translations );
168
 
169
+ $actions_that_need_mc = [
170
  'save-mc-options',
171
  'wcml_new_currency',
172
  'wcml_save_currency',
178
  'wcml_currencies_switcher_save_settings',
179
  'wcml_delete_currency_switcher',
180
  'wcml_currencies_order',
181
+ ];
182
 
183
  $this->cart = new WCML_Cart( $this, $sitepress, $woocommerce );
184
 
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 );
240
  $this->endpoints = new WCML_Endpoints( $this, $sitepress, $wpdb );
241
  $this->endpoints->add_hooks();
242
  $this->requests = new WCML_Requests();
243
+ $this->cart->add_hooks(); // object is instantiated before.
 
244
  $this->coupons = new WCML_Coupons( $this, $sitepress );
245
  $this->coupons->add_hooks();
246
  $this->locale = new WCML_Locale( $this, $sitepress );
254
  $this->wcml_products_screen->init();
255
  $this->cart_sync_warnings = new WCML_Cart_Sync_Warnings( $this, $sitepress );
256
  $this->cart_sync_warnings->add_hooks();
257
+ $this->comments = new WCML_Comments( $this, $sitepress, $wpml_post_translations, $wpdb );
258
  $this->comments->add_hooks();
259
 
260
  if ( is_admin() ) {
275
  $url_filters_redirect_location = new WCML_Url_Filters_Redirect_Location( $wpml_url_converter );
276
  $url_filters_redirect_location->add_hooks();
277
 
278
+ add_action( 'wp_ajax_wcml_update_setting_ajx', [ $this, 'update_setting_ajx' ] );
279
 
280
  return true;
281
  }
286
  * @return mixed|void
287
  */
288
  public function get_settings() {
289
+ $defaults = [
290
  'file_path_sync' => 1,
291
  'is_term_order_synced' => 0,
292
  'enable_multi_currency' => WCML_MULTI_CURRENCIES_DISABLED,
293
  'dismiss_doc_main' => 0,
294
  'trnsl_interface' => 1,
295
+ 'currency_options' => [],
296
  'currency_switcher_product_visibility' => 1,
297
  'dismiss_tm_warning' => 0,
298
  'dismiss_cart_warning' => 0,
299
+ 'cart_sync' => [
300
  'lang_switch' => WCML_CART_SYNC,
301
  'currency_switch' => WCML_CART_SYNC,
302
+ ],
303
+ ];
304
 
305
  if ( empty( $this->settings ) ) {
306
  $this->settings = get_option( '_wcml_settings' );
371
  $this->update_settings();
372
 
373
  echo wp_json_encode(
374
+ [
375
  'html' => $html,
376
  'error' => $error,
377
+ ]
378
  );
379
  exit;
380
  }
480
  global $sitepress;
481
 
482
  return $sitepress->get_wp_api()->version_compare( $this->get_constant( 'ICL_SITEPRESS_VERSION' ), '4.2.0', '<' ) ||
483
+ $sitepress->get_wp_api()->version_compare( $this->get_constant( 'WPML_TM_VERSION' ), '2.8.0', '<' );
484
  }
485
 
486
  /**
classes/currencies/class-wcml-admin-currency-selector.php CHANGED
@@ -14,58 +14,63 @@ class WCML_Admin_Currency_Selector {
14
  /**
15
  * WCML_Admin_Currency_Selector constructor.
16
  *
17
- * @param woocommerce_wpml $woocommerce_wpml
18
- * @param WCML_Admin_Cookie $currency_cookie
19
  */
20
  public function __construct( woocommerce_wpml $woocommerce_wpml, WCML_Admin_Cookie $currency_cookie ) {
21
- $this->woocommerce_wpml = $woocommerce_wpml;
22
- $this->currency_cookie = $currency_cookie;
23
  }
24
 
25
- public function add_hooks(){
26
- global $pagenow;
27
 
28
  if ( is_admin() ) {
29
 
30
- if( $this->user_can_manage_woocommerce() ){
31
- add_action( 'init', array( $this, 'set_dashboard_currency' ) );
32
- add_action( 'wp_ajax_wcml_dashboard_set_currency', array( $this, 'set_dashboard_currency_ajax' ) );
33
- add_filter( 'woocommerce_currency_symbol', array( $this, 'filter_dashboard_currency_symbol' ) );
34
- }
35
-
36
- add_action( 'woocommerce_after_dashboard_status_widget', array(
37
- $this,
38
- 'show_dashboard_currency_selector'
39
- ) );
40
- add_action( 'admin_enqueue_scripts', array( $this, 'load_js' ) );
 
 
 
41
  }
42
- }
43
 
44
  /**
45
  * @return bool
46
  */
47
  private function user_can_manage_woocommerce() {
48
  return current_user_can( 'view_woocommerce_reports' ) ||
49
- current_user_can( 'manage_woocommerce' ) ||
50
- current_user_can( 'publish_shop_orders' );
51
 
52
  }
53
 
54
- public function load_js(){
55
  wp_enqueue_script(
56
  'wcml-admin-currency-selector',
57
  $this->woocommerce_wpml->plugin_url() .
58
  '/res/js/admin-currency-selector' . $this->woocommerce_wpml->js_min_suffix() . '.js',
59
- array( 'jquery' ),
60
  $this->woocommerce_wpml->version(),
61
  true
62
  );
63
- wp_localize_script( 'wcml-admin-currency-selector', 'wcml_admin_currency_selector',
64
- array(
65
- 'nonce' => wp_create_nonce( self::NONCE_KEY )
66
- )
 
 
67
  );
68
- }
69
 
70
  /**
71
  * Add currency drop-down on dashboard page ( WooCommerce status block )
@@ -77,19 +82,19 @@ class WCML_Admin_Currency_Selector {
77
  $wc_currencies = get_woocommerce_currencies();
78
  $currency_codes = $this->woocommerce_wpml->multi_currency->get_currency_codes();
79
  ?>
80
- <select id="dropdown_dashboard_currency" style="display: none; margin : 10px; ">
81
- <?php if ( empty( $currency_codes ) ): ?>
82
- <option value=""><?php _e( 'Currency - no orders found', 'woocommerce-multilingual' ) ?></option>
83
- <?php else: ?>
84
- <?php foreach ( $currency_codes as $currency ): ?>
85
 
86
- <option value="<?php echo $currency ?>" <?php echo $current_dashboard_currency == $currency ? 'selected="selected"' : ''; ?>>
87
- <?php echo $wc_currencies[ $currency ]; ?>
88
- </option>
89
 
90
  <?php endforeach; ?>
91
  <?php endif; ?>
92
- </select>
93
  <?php
94
  }
95
 
@@ -128,16 +133,17 @@ class WCML_Admin_Currency_Selector {
128
  */
129
  public function get_cookie_dashboard_currency() {
130
 
131
- $currency = $this->currency_cookie->get_value();
132
- if( null === $currency ){
133
- $currency = wcml_get_woocommerce_currency_option();
134
- }
135
 
136
  return $currency;
137
  }
138
 
139
  /**
140
  * Filter currency symbol on dashboard page
 
141
  * @param string $currency Currency code
142
  *
143
  * @return string
@@ -145,11 +151,11 @@ class WCML_Admin_Currency_Selector {
145
  public function filter_dashboard_currency_symbol( $currency ) {
146
  global $pagenow;
147
 
148
- remove_filter( 'woocommerce_currency_symbol', array( $this, 'filter_dashboard_currency_symbol' ) );
149
  if ( 'index.php' === $pagenow && isset( $_COOKIE ['_wcml_dashboard_currency'] ) ) {
150
  $currency = get_woocommerce_currency_symbol( $_COOKIE ['_wcml_dashboard_currency'] );
151
  }
152
- add_filter( 'woocommerce_currency_symbol', array( $this, 'filter_dashboard_currency_symbol' ) );
153
 
154
  return $currency;
155
  }
14
  /**
15
  * WCML_Admin_Currency_Selector constructor.
16
  *
17
+ * @param woocommerce_wpml $woocommerce_wpml
18
+ * @param WCML_Admin_Cookie $currency_cookie
19
  */
20
  public function __construct( woocommerce_wpml $woocommerce_wpml, WCML_Admin_Cookie $currency_cookie ) {
21
+ $this->woocommerce_wpml = $woocommerce_wpml;
22
+ $this->currency_cookie = $currency_cookie;
23
  }
24
 
25
+ public function add_hooks() {
26
+ global $pagenow;
27
 
28
  if ( is_admin() ) {
29
 
30
+ if ( $this->user_can_manage_woocommerce() ) {
31
+ add_action( 'init', [ $this, 'set_dashboard_currency' ] );
32
+ add_action( 'wp_ajax_wcml_dashboard_set_currency', [ $this, 'set_dashboard_currency_ajax' ] );
33
+ add_filter( 'woocommerce_currency_symbol', [ $this, 'filter_dashboard_currency_symbol' ] );
34
+ }
35
+
36
+ add_action(
37
+ 'woocommerce_after_dashboard_status_widget',
38
+ [
39
+ $this,
40
+ 'show_dashboard_currency_selector',
41
+ ]
42
+ );
43
+ add_action( 'admin_enqueue_scripts', [ $this, 'load_js' ] );
44
  }
45
+ }
46
 
47
  /**
48
  * @return bool
49
  */
50
  private function user_can_manage_woocommerce() {
51
  return current_user_can( 'view_woocommerce_reports' ) ||
52
+ current_user_can( 'manage_woocommerce' ) ||
53
+ current_user_can( 'publish_shop_orders' );
54
 
55
  }
56
 
57
+ public function load_js() {
58
  wp_enqueue_script(
59
  'wcml-admin-currency-selector',
60
  $this->woocommerce_wpml->plugin_url() .
61
  '/res/js/admin-currency-selector' . $this->woocommerce_wpml->js_min_suffix() . '.js',
62
+ [ 'jquery' ],
63
  $this->woocommerce_wpml->version(),
64
  true
65
  );
66
+ wp_localize_script(
67
+ 'wcml-admin-currency-selector',
68
+ 'wcml_admin_currency_selector',
69
+ [
70
+ 'nonce' => wp_create_nonce( self::NONCE_KEY ),
71
+ ]
72
  );
73
+ }
74
 
75
  /**
76
  * Add currency drop-down on dashboard page ( WooCommerce status block )
82
  $wc_currencies = get_woocommerce_currencies();
83
  $currency_codes = $this->woocommerce_wpml->multi_currency->get_currency_codes();
84
  ?>
85
+ <select id="dropdown_dashboard_currency" style="display: none; margin : 10px; ">
86
+ <?php if ( empty( $currency_codes ) ) : ?>
87
+ <option value=""><?php _e( 'Currency - no orders found', 'woocommerce-multilingual' ); ?></option>
88
+ <?php else : ?>
89
+ <?php foreach ( $currency_codes as $currency ) : ?>
90
 
91
+ <option value="<?php echo esc_html( $currency ); ?>" <?php echo esc_html( $current_dashboard_currency === $currency ? 'selected="selected"' : '' ); ?>>
92
+ <?php echo esc_html( $wc_currencies[ $currency ] ); ?>
93
+ </option>
94
 
95
  <?php endforeach; ?>
96
  <?php endif; ?>
97
+ </select>
98
  <?php
99
  }
100
 
133
  */
134
  public function get_cookie_dashboard_currency() {
135
 
136
+ $currency = $this->currency_cookie->get_value();
137
+ if ( null === $currency ) {
138
+ $currency = wcml_get_woocommerce_currency_option();
139
+ }
140
 
141
  return $currency;
142
  }
143
 
144
  /**
145
  * Filter currency symbol on dashboard page
146
+ *
147
  * @param string $currency Currency code
148
  *
149
  * @return string
151
  public function filter_dashboard_currency_symbol( $currency ) {
152
  global $pagenow;
153
 
154
+ remove_filter( 'woocommerce_currency_symbol', [ $this, 'filter_dashboard_currency_symbol' ] );
155
  if ( 'index.php' === $pagenow && isset( $_COOKIE ['_wcml_dashboard_currency'] ) ) {
156
  $currency = get_woocommerce_currency_symbol( $_COOKIE ['_wcml_dashboard_currency'] );
157
  }
158
+ add_filter( 'woocommerce_currency_symbol', [ $this, 'filter_dashboard_currency_symbol' ] );
159
 
160
  return $currency;
161
  }
classes/currencies/class-wcml-currencies.php CHANGED
@@ -26,10 +26,15 @@ class WCML_Currencies {
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',
32
- ), 10, 2 );
 
 
 
 
 
33
  }
34
  }
35
 
26
  */
27
  public function add_hooks() {
28
  if ( is_admin() ) {
29
+ add_action(
30
+ 'update_option_woocommerce_currency',
31
+ [
32
+ $this,
33
+ 'setup_multi_currency_on_currency_update',
34
+ ],
35
+ 10,
36
+ 2
37
+ );
38
  }
39
  }
40
 
classes/media/Wrapper/Translatable.php CHANGED
@@ -27,20 +27,20 @@ class Translatable implements IMedia {
27
  }
28
 
29
  public function add_hooks() {
30
- //when save new attachment duplicate product gallery
31
  add_action( 'wpml_media_create_duplicate_attachment', [ $this, 'sync_product_gallery_duplicate_attachment' ], 11, 2 );
32
  }
33
 
34
  public function product_images_ids( $product_id ) {
35
  $product_images_ids = [];
36
 
37
- //thumbnail image
38
  $tmb = get_post_meta( $product_id, '_thumbnail_id', true );
39
  if ( $tmb ) {
40
  $product_images_ids[] = $tmb;
41
  }
42
 
43
- //product gallery
44
  $product_gallery = get_post_meta( $product_id, '_product_image_gallery', true );
45
  if ( $product_gallery ) {
46
  $product_gallery = explode( ',', $product_gallery );
@@ -51,19 +51,23 @@ class Translatable implements IMedia {
51
  }
52
  }
53
 
54
- foreach ( wp_get_post_terms( $product_id, 'product_type', [ "fields" => "names" ] ) as $type ) {
55
  $product_type = $type;
56
  }
57
 
58
- if ( isset( $product_type ) && $product_type == 'variable' ) {
59
- $get_post_variations_image = $this->wpdb->get_col( $this->wpdb->prepare( "SELECT pm.meta_value FROM {$this->wpdb->posts} AS p
 
 
60
  LEFT JOIN {$this->wpdb->postmeta} AS pm ON p.ID = pm.post_id
61
  WHERE pm.meta_key='_thumbnail_id'
62
  AND p.post_status IN ('publish','private')
63
  AND p.post_type = 'product_variation'
64
  AND p.post_parent = %d
65
  ORDER BY ID",
66
- $product_id ) );
 
 
67
  foreach ( $get_post_variations_image as $variation_image ) {
68
  if ( $variation_image && ! in_array( $variation_image, $product_images_ids ) ) {
69
  $product_images_ids[] = $variation_image;
@@ -104,7 +108,7 @@ class Translatable implements IMedia {
104
 
105
  /**
106
  * @param int|string $post_id
107
- * @param string $language
108
  *
109
  * @return int|null
110
  */
@@ -115,9 +119,11 @@ class Translatable implements IMedia {
115
  if ( is_null( $translated_thumbnail_id ) && $thumbnail_id ) {
116
  $factory = new WPML_Media_Attachments_Duplication_Factory();
117
  $media_duplicate = $factory->create();
118
- $translated_thumbnail_id = $media_duplicate->create_duplicate_attachment( $thumbnail_id,
 
119
  wp_get_post_parent_id( $thumbnail_id ),
120
- $language );
 
121
  }
122
 
123
  return $translated_thumbnail_id;
@@ -136,15 +142,19 @@ class Translatable implements IMedia {
136
  if ( ! $translation->original ) {
137
  foreach ( $gallery_ids as $image_id ) {
138
  if ( get_post( $image_id ) ) {
139
- $duplicated_id = apply_filters( 'translate_object_id',
140
- $image_id,
141
- 'attachment',
142
- false,
143
- $translation->language_code );
 
 
144
  if ( is_null( $duplicated_id ) && $image_id ) {
145
- $duplicated_id = $this->create_base_media_translation( $image_id,
146
- $translation->element_id,
147
- $translation->language_code );
 
 
148
  }
149
  $duplicated_ids .= $duplicated_id . ',';
150
  }
@@ -168,7 +178,7 @@ class Translatable implements IMedia {
168
  public function sync_product_gallery_duplicate_attachment( $att_id, $dup_att_id ) {
169
  $product_id = wp_get_post_parent_id( $att_id );
170
  $post_type = get_post_type( $product_id );
171
- if ( $post_type != 'product' || array_key_exists( $product_id, $this->products_being_synced ) ) {
172
  return;
173
  }
174
  $this->products_being_synced[ $product_id ] = 1;
@@ -176,27 +186,29 @@ class Translatable implements IMedia {
176
  unset( $this->products_being_synced[ $product_id ] );
177
  }
178
 
179
- private function is_thumbnail_image_duplication_enabled( $product_id ){
180
  return $this->is_duplication_enabled( $product_id, 'WPML_Admin_Post_Actions::DUPLICATE_FEATURED_META_KEY', 'WPML_Admin_Post_Actions::DUPLICATE_FEATURED_GLOBAL_KEY' );
181
  }
182
 
183
- private function is_media_duplication_enabled( $product_id ){
184
  return $this->is_duplication_enabled( $product_id, 'WPML_Admin_Post_Actions::DUPLICATE_MEDIA_META_KEY', 'WPML_Admin_Post_Actions::DUPLICATE_MEDIA_GLOBAL_KEY' );
185
  }
186
 
187
  private function is_duplication_enabled( $product_id, $meta_key, $global_key ) {
188
 
189
- $setting_value = get_post_meta( $product_id,
190
- $this->sitepress->get_wp_api()
191
- ->constant( $meta_key ),
192
- true );
 
 
193
 
194
  if ( '' === $setting_value ) {
195
- // fallback to global setting
196
  $media_options = get_option( '_wpml_media', [] );
197
 
198
  $global_setting_key = $this->sitepress->get_wp_api()
199
- ->constant( $global_key );
200
  if ( isset( $media_options['new_content_settings'][ $global_setting_key ] ) ) {
201
  $setting_value = $media_options['new_content_settings'][ $global_setting_key ];
202
  }
@@ -205,4 +217,4 @@ class Translatable implements IMedia {
205
  return (bool) $setting_value;
206
  }
207
 
208
- }
27
  }
28
 
29
  public function add_hooks() {
30
+ // when save new attachment duplicate product gallery.
31
  add_action( 'wpml_media_create_duplicate_attachment', [ $this, 'sync_product_gallery_duplicate_attachment' ], 11, 2 );
32
  }
33
 
34
  public function product_images_ids( $product_id ) {
35
  $product_images_ids = [];
36
 
37
+ // thumbnail image.
38
  $tmb = get_post_meta( $product_id, '_thumbnail_id', true );
39
  if ( $tmb ) {
40
  $product_images_ids[] = $tmb;
41
  }
42
 
43
+ // product gallery.
44
  $product_gallery = get_post_meta( $product_id, '_product_image_gallery', true );
45
  if ( $product_gallery ) {
46
  $product_gallery = explode( ',', $product_gallery );
51
  }
52
  }
53
 
54
+ foreach ( wp_get_post_terms( $product_id, 'product_type', [ 'fields' => 'names' ] ) as $type ) {
55
  $product_type = $type;
56
  }
57
 
58
+ if ( isset( $product_type ) && 'variable' === $product_type ) {
59
+ $get_post_variations_image = $this->wpdb->get_col(
60
+ $this->wpdb->prepare(
61
+ "SELECT pm.meta_value FROM {$this->wpdb->posts} AS p
62
  LEFT JOIN {$this->wpdb->postmeta} AS pm ON p.ID = pm.post_id
63
  WHERE pm.meta_key='_thumbnail_id'
64
  AND p.post_status IN ('publish','private')
65
  AND p.post_type = 'product_variation'
66
  AND p.post_parent = %d
67
  ORDER BY ID",
68
+ $product_id
69
+ )
70
+ );
71
  foreach ( $get_post_variations_image as $variation_image ) {
72
  if ( $variation_image && ! in_array( $variation_image, $product_images_ids ) ) {
73
  $product_images_ids[] = $variation_image;
108
 
109
  /**
110
  * @param int|string $post_id
111
+ * @param string $language
112
  *
113
  * @return int|null
114
  */
119
  if ( is_null( $translated_thumbnail_id ) && $thumbnail_id ) {
120
  $factory = new WPML_Media_Attachments_Duplication_Factory();
121
  $media_duplicate = $factory->create();
122
+ $translated_thumbnail_id = $media_duplicate->create_duplicate_attachment(
123
+ $thumbnail_id,
124
  wp_get_post_parent_id( $thumbnail_id ),
125
+ $language
126
+ );
127
  }
128
 
129
  return $translated_thumbnail_id;
142
  if ( ! $translation->original ) {
143
  foreach ( $gallery_ids as $image_id ) {
144
  if ( get_post( $image_id ) ) {
145
+ $duplicated_id = apply_filters(
146
+ 'translate_object_id',
147
+ $image_id,
148
+ 'attachment',
149
+ false,
150
+ $translation->language_code
151
+ );
152
  if ( is_null( $duplicated_id ) && $image_id ) {
153
+ $duplicated_id = $this->create_base_media_translation(
154
+ $image_id,
155
+ $translation->element_id,
156
+ $translation->language_code
157
+ );
158
  }
159
  $duplicated_ids .= $duplicated_id . ',';
160
  }
178
  public function sync_product_gallery_duplicate_attachment( $att_id, $dup_att_id ) {
179
  $product_id = wp_get_post_parent_id( $att_id );
180
  $post_type = get_post_type( $product_id );
181
+ if ( 'product' !== $post_type || array_key_exists( $product_id, $this->products_being_synced ) ) {
182
  return;
183
  }
184
  $this->products_being_synced[ $product_id ] = 1;
186
  unset( $this->products_being_synced[ $product_id ] );
187
  }
188
 
189
+ private function is_thumbnail_image_duplication_enabled( $product_id ) {
190
  return $this->is_duplication_enabled( $product_id, 'WPML_Admin_Post_Actions::DUPLICATE_FEATURED_META_KEY', 'WPML_Admin_Post_Actions::DUPLICATE_FEATURED_GLOBAL_KEY' );
191
  }
192
 
193
+ private function is_media_duplication_enabled( $product_id ) {
194
  return $this->is_duplication_enabled( $product_id, 'WPML_Admin_Post_Actions::DUPLICATE_MEDIA_META_KEY', 'WPML_Admin_Post_Actions::DUPLICATE_MEDIA_GLOBAL_KEY' );
195
  }
196
 
197
  private function is_duplication_enabled( $product_id, $meta_key, $global_key ) {
198
 
199
+ $setting_value = get_post_meta(
200
+ $product_id,
201
+ $this->sitepress->get_wp_api()
202
+ ->constant( $meta_key ),
203
+ true
204
+ );
205
 
206
  if ( '' === $setting_value ) {
207
+ // fallback to global setting.
208
  $media_options = get_option( '_wpml_media', [] );
209
 
210
  $global_setting_key = $this->sitepress->get_wp_api()
211
+ ->constant( $global_key );
212
  if ( isset( $media_options['new_content_settings'][ $global_setting_key ] ) ) {
213
  $setting_value = $media_options['new_content_settings'][ $global_setting_key ];
214
  }
217
  return (bool) $setting_value;
218
  }
219
 
220
+ }
classes/media/class-wcml-product-gallery-filter-factory.php CHANGED
@@ -5,9 +5,9 @@ class WCML_Product_Gallery_Filter_Factory implements IWPML_Frontend_Action_Loade
5
  public function create() {
6
  global $sitepress, $woocommerce_wpml;
7
 
8
- if( $woocommerce_wpml->get_setting( 'sync_media', true ) ){
9
  return new WCML_Product_Gallery_Filter( new WPML_Translation_Element_Factory( $sitepress ) );
10
  }
11
  }
12
 
13
- }
5
  public function create() {
6
  global $sitepress, $woocommerce_wpml;
7
 
8
+ if ( $woocommerce_wpml->get_setting( 'sync_media', true ) ) {
9
  return new WCML_Product_Gallery_Filter( new WPML_Translation_Element_Factory( $sitepress ) );
10
  }
11
  }
12
 
13
+ }
classes/media/class-wcml-product-gallery-filter.php CHANGED
@@ -20,24 +20,24 @@ class WCML_Product_Gallery_Filter implements IWPML_Action {
20
  }
21
 
22
  public function add_hooks() {
23
- add_filter( 'get_post_metadata', array( $this, 'localize_image_ids' ), 10, 3 );
24
  }
25
 
26
  public function localize_image_ids( $value, $object_id, $meta_key ) {
27
 
28
  $image_ids = false;
29
  if ( '_product_image_gallery' === $meta_key &&
30
- in_array( get_post_type( $object_id ), array( 'product', 'product_variation' ) ) ) {
31
 
32
- $cache_key = $object_id . '_image_gallery';
33
- $found = false;
34
  $image_ids = $this->wpml_cache->get( $cache_key, $found );
35
 
36
  if ( ! $image_ids ) {
37
 
38
- remove_filter( 'get_post_metadata', array( $this, 'localize_image_ids' ), 10 );
39
 
40
- $meta_value = array();
41
 
42
  $post_element = $this->translation_element_factory->create( $object_id, 'post' );
43
  $source_element = $post_element->get_source_element();
@@ -63,14 +63,13 @@ class WCML_Product_Gallery_Filter implements IWPML_Action {
63
  $image_ids = implode( ',', $meta_value );
64
  }
65
 
66
- add_filter( 'get_post_metadata', array( $this, 'localize_image_ids' ), 10, 3 );
67
 
68
  $this->wpml_cache->set( $cache_key, $image_ids );
69
  }
70
-
71
  }
72
 
73
  return $image_ids ? [ $image_ids ] : $value;
74
  }
75
 
76
- }
20
  }
21
 
22
  public function add_hooks() {
23
+ add_filter( 'get_post_metadata', [ $this, 'localize_image_ids' ], 10, 3 );
24
  }
25
 
26
  public function localize_image_ids( $value, $object_id, $meta_key ) {
27
 
28
  $image_ids = false;
29
  if ( '_product_image_gallery' === $meta_key &&
30
+ in_array( get_post_type( $object_id ), [ 'product', 'product_variation' ] ) ) {
31
 
32
+ $cache_key = $object_id . '_image_gallery';
33
+ $found = false;
34
  $image_ids = $this->wpml_cache->get( $cache_key, $found );
35
 
36
  if ( ! $image_ids ) {
37
 
38
+ remove_filter( 'get_post_metadata', [ $this, 'localize_image_ids' ], 10 );
39
 
40
+ $meta_value = [];
41
 
42
  $post_element = $this->translation_element_factory->create( $object_id, 'post' );
43
  $source_element = $post_element->get_source_element();
63
  $image_ids = implode( ',', $meta_value );
64
  }
65
 
66
+ add_filter( 'get_post_metadata', [ $this, 'localize_image_ids' ], 10, 3 );
67
 
68
  $this->wpml_cache->set( $cache_key, $image_ids );
69
  }
 
70
  }
71
 
72
  return $image_ids ? [ $image_ids ] : $value;
73
  }
74
 
75
+ }
classes/media/class-wcml-product-image-filter-factory.php CHANGED
@@ -5,9 +5,9 @@ class WCML_Product_Image_Filter_Factory implements IWPML_Frontend_Action_Loader
5
  public function create() {
6
  global $sitepress, $woocommerce_wpml;
7
 
8
- if( $woocommerce_wpml->get_setting( 'sync_media', true ) ) {
9
  return new WCML_Product_Image_Filter( new WPML_Translation_Element_Factory( $sitepress ) );
10
  }
11
  }
12
 
13
- }
5
  public function create() {
6
  global $sitepress, $woocommerce_wpml;
7
 
8
+ if ( $woocommerce_wpml->get_setting( 'sync_media', true ) ) {
9
  return new WCML_Product_Image_Filter( new WPML_Translation_Element_Factory( $sitepress ) );
10
  }
11
  }
12
 
13
+ }
classes/media/class-wcml-product-image-filter.php CHANGED
@@ -20,29 +20,29 @@ class WCML_Product_Image_Filter implements IWPML_Action {
20
  }
21
 
22
  public function add_hooks() {
23
- add_filter( 'get_post_metadata', array( $this, 'localize_image_id' ), 11, 3 );
24
  }
25
 
26
  public function localize_image_id( $value, $object_id, $meta_key ) {
27
 
28
  $image_id = false;
29
- if ( !$value && '_thumbnail_id' === $meta_key &&
30
- in_array( get_post_type( $object_id ), array( 'product', 'product_variation' ) ) &&
31
- (
32
- ! defined( 'WPML_Admin_Post_Actions::DISPLAY_FEATURED_IMAGE_AS_TRANSLATED_META_KEY' ) ||
33
- (
34
- ! get_post_meta( $object_id, WPML_Admin_Post_Actions::DISPLAY_FEATURED_IMAGE_AS_TRANSLATED_META_KEY, true ) ||
35
- get_post_meta( $object_id, WPML_Admin_Post_Actions::DISPLAY_FEATURED_IMAGE_AS_TRANSLATED_META_KEY, true ) === '0'
36
- )
37
- )
38
  ) {
39
 
40
- $cache_key = $object_id . '_thumbnail_id';
41
- $found = false;
42
- $image_id = $this->wpml_cache->get( $cache_key, $found );
43
 
44
  if ( ! $image_id ) {
45
- remove_filter( 'get_post_metadata', array( $this, 'localize_image_id' ), 11, 3 );
46
 
47
  $meta_value = get_post_meta( $object_id, '_thumbnail_id', true );
48
  if ( empty( $meta_value ) ) {
@@ -51,9 +51,8 @@ class WCML_Product_Image_Filter implements IWPML_Action {
51
  if ( null !== $source_element ) {
52
  $image_id = get_post_meta( $source_element->get_id(), '_thumbnail_id', true );
53
  }
54
-
55
  }
56
- add_filter( 'get_post_metadata', array( $this, 'localize_image_id' ), 11, 3 );
57
 
58
  $this->wpml_cache->set( $cache_key, $image_id );
59
  }
@@ -62,4 +61,4 @@ class WCML_Product_Image_Filter implements IWPML_Action {
62
  return $image_id ? [ $image_id ] : $value;
63
  }
64
 
65
- }
20
  }
21
 
22
  public function add_hooks() {
23
+ add_filter( 'get_post_metadata', [ $this, 'localize_image_id' ], 11, 3 );
24
  }
25
 
26
  public function localize_image_id( $value, $object_id, $meta_key ) {
27
 
28
  $image_id = false;
29
+ if ( ! $value && '_thumbnail_id' === $meta_key &&
30
+ in_array( get_post_type( $object_id ), [ 'product', 'product_variation' ] ) &&
31
+ (
32
+ ! defined( 'WPML_Admin_Post_Actions::DISPLAY_FEATURED_IMAGE_AS_TRANSLATED_META_KEY' ) ||
33
+ (
34
+ ! get_post_meta( $object_id, WPML_Admin_Post_Actions::DISPLAY_FEATURED_IMAGE_AS_TRANSLATED_META_KEY, true ) ||
35
+ get_post_meta( $object_id, WPML_Admin_Post_Actions::DISPLAY_FEATURED_IMAGE_AS_TRANSLATED_META_KEY, true ) === '0'
36
+ )
37
+ )
38
  ) {
39
 
40
+ $cache_key = $object_id . '_thumbnail_id';
41
+ $found = false;
42
+ $image_id = $this->wpml_cache->get( $cache_key, $found );
43
 
44
  if ( ! $image_id ) {
45
+ remove_filter( 'get_post_metadata', [ $this, 'localize_image_id' ], 11, 3 );
46
 
47
  $meta_value = get_post_meta( $object_id, '_thumbnail_id', true );
48
  if ( empty( $meta_value ) ) {
51
  if ( null !== $source_element ) {
52
  $image_id = get_post_meta( $source_element->get_id(), '_thumbnail_id', true );
53
  }
 
54
  }
55
+ add_filter( 'get_post_metadata', [ $this, 'localize_image_id' ], 11, 3 );
56
 
57
  $this->wpml_cache->set( $cache_key, $image_id );
58
  }
61
  return $image_id ? [ $image_id ] : $value;
62
  }
63
 
64
+ }
classes/media/class-wcml-update-product-gallery-translation-factory.php CHANGED
@@ -15,4 +15,4 @@ class WCML_Update_Product_Gallery_Translation_Factory implements IWPML_Backend_A
15
  return null;
16
  }
17
 
18
- }
15
  return null;
16
  }
17
 
18
+ }
classes/media/class-wcml-update-product-gallery-translation.php CHANGED
@@ -20,7 +20,7 @@ class WCML_Update_Product_Gallery_Translation implements IWPML_Action {
20
  }
21
 
22
  public function add_hooks() {
23
- add_action( 'wpml_added_media_file_translation', array( $this, 'update_meta' ), PHP_INT_MAX, 3 );
24
  }
25
 
26
  /**
@@ -40,14 +40,14 @@ class WCML_Update_Product_Gallery_Translation implements IWPML_Action {
40
  }
41
 
42
  /**
43
- * @param int $source_post_id
44
  * @param WPML_Post_Element $updated_attachment_element
45
  *
46
  * @return array
47
  * @throws \InvalidArgumentException
48
  */
49
  private function get_translated_gallery( $source_post_id, WPML_Post_Element $updated_attachment_element ) {
50
- $meta_value = array();
51
 
52
  $original_gallery_meta = get_post_meta( $source_post_id, '_product_image_gallery', true );
53
  if ( '' !== $original_gallery_meta ) {
@@ -68,7 +68,7 @@ class WCML_Update_Product_Gallery_Translation implements IWPML_Action {
68
  }
69
 
70
  /**
71
- * @param array $meta_value
72
  * @param WPML_Post_Element $source_post
73
  * @param WPML_Post_Element $updated_attachment_element
74
  *
@@ -89,4 +89,4 @@ class WCML_Update_Product_Gallery_Translation implements IWPML_Action {
89
  }
90
  }
91
 
92
- }
20
  }
21
 
22
  public function add_hooks() {
23
+ add_action( 'wpml_added_media_file_translation', [ $this, 'update_meta' ], PHP_INT_MAX, 3 );
24
  }
25
 
26
  /**
40
  }
41
 
42
  /**
43
+ * @param int $source_post_id
44
  * @param WPML_Post_Element $updated_attachment_element
45
  *
46
  * @return array
47
  * @throws \InvalidArgumentException
48
  */
49
  private function get_translated_gallery( $source_post_id, WPML_Post_Element $updated_attachment_element ) {
50
+ $meta_value = [];
51
 
52
  $original_gallery_meta = get_post_meta( $source_post_id, '_product_image_gallery', true );
53
  if ( '' !== $original_gallery_meta ) {
68
  }
69
 
70
  /**
71
+ * @param array $meta_value
72
  * @param WPML_Post_Element $source_post
73
  * @param WPML_Post_Element $updated_attachment_element
74
  *
89
  }
90
  }
91
 
92
+ }
classes/multi-currency/class-wcml-exchange-rates.php CHANGED
@@ -8,13 +8,13 @@ class WCML_Exchange_Rates {
8
  /** @var woocommerce_wpml */
9
  private $woocommerce_wpml;
10
  /** @var array */
11
- private $services = array();
12
  /** @var array */
13
  private $settings;
14
  /** @var WP_Locale */
15
  private $wp_locale;
16
 
17
- const CRONJOB_EVENT = 'wcml_exchange_rates_update';
18
  const DIGITS_AFTER_DECIMAL_POINT = 6;
19
 
20
  /**
@@ -25,36 +25,36 @@ class WCML_Exchange_Rates {
25
  */
26
  public function __construct( $woocommerce_wpml, $wp_locale ) {
27
  $this->woocommerce_wpml = $woocommerce_wpml;
28
- $this->wp_locale = $wp_locale;
29
  }
30
 
31
  public function add_actions() {
32
  if ( is_admin() ) {
33
- add_action( 'wcml_saved_mc_options', array( $this, 'update_exchange_rate_options' ) ); //before init
34
  }
35
- add_action( 'init', array( $this, 'init' ) );
36
  }
37
 
38
  public function init() {
39
  if ( $this->woocommerce_wpml->multi_currency->get_currencies() ) {
40
  if ( is_admin() ) {
41
- add_action( 'wp_ajax_wcml_update_exchange_rates', array( $this, 'update_exchange_rates_ajax' ) );
42
  }
43
- add_filter( 'cron_schedules', array( $this, 'cron_schedules' ) );
44
- add_action( self::CRONJOB_EVENT, array( $this, 'update_exchange_rates' ) );
45
  }
46
  }
47
 
48
  public function initialize_settings() {
49
  if ( ! isset( $this->woocommerce_wpml->settings['multi_currency']['exchange_rates'] ) ) {
50
- $this->settings = array(
51
  'automatic' => 0,
52
  'service' => 'fixerio',
53
  'lifting_charge' => 0,
54
  'schedule' => 'manual',
55
  'week_day' => 1,
56
- 'month_day' => 1
57
- );
58
  $this->save_settings();
59
  } else {
60
  $this->settings =& $this->woocommerce_wpml->settings['multi_currency']['exchange_rates'];
@@ -69,7 +69,7 @@ class WCML_Exchange_Rates {
69
  }
70
 
71
  /**
72
- * @param string $service_id
73
  * @param WCML_Exchange_Rate_Service $service
74
  */
75
  public function add_service( $service_id, $service ) {
@@ -99,7 +99,7 @@ class WCML_Exchange_Rates {
99
 
100
  /**
101
  * @param string $key
102
- * @param mixed $value
103
  */
104
  public function save_setting( $key, $value ) {
105
  $this->settings[ $key ] = $value;
@@ -107,7 +107,7 @@ class WCML_Exchange_Rates {
107
  }
108
 
109
  public function update_exchange_rates_ajax() {
110
- $response = array();
111
  if ( wp_create_nonce( 'update-exchange-rates' ) === $_POST['wcml_nonce'] ) {
112
  try {
113
  $rates = $this->update_exchange_rates();
@@ -133,13 +133,13 @@ class WCML_Exchange_Rates {
133
 
134
  $currencies = $this->woocommerce_wpml->multi_currency->get_currency_codes();
135
  $default_currency = wcml_get_woocommerce_currency_option();
136
- $secondary_currencies = array_diff( $currencies, array( $default_currency ) );
137
 
138
  try {
139
  $rates = $service->get_rates( $default_currency, $secondary_currencies );
140
  } catch ( Exception $e ) {
141
  if ( defined( 'WP_DEBUG_LOG' ) && WP_DEBUG_LOG ) {
142
- error_log( "Exchange rates update error (" . $this->settings['service'] . "): " . $e->getMessage() );
143
  }
144
  throw new Exception( $e->getMessage() );
145
  }
@@ -208,12 +208,10 @@ class WCML_Exchange_Rates {
208
  if ( isset( $post_data['services'] ) ) {
209
 
210
  foreach ( $post_data['services'] as $service_id => $service_data ) {
211
- if( isset( $service_data['api-key'] ) ){
212
  $this->services[ $service_id ]->save_setting( 'api-key', $service_data['api-key'] );
213
  }
214
-
215
  }
216
-
217
  }
218
 
219
  $this->settings['lifting_charge'] = is_numeric( $post_data['lifting_charge'] ) ? $post_data['lifting_charge'] : 0;
@@ -239,7 +237,6 @@ class WCML_Exchange_Rates {
239
  } else {
240
  $this->enable_update_cronjob();
241
  }
242
-
243
  } else {
244
  $this->settings['automatic'] = 0;
245
  $this->delete_update_cronjob();
@@ -277,7 +274,7 @@ class WCML_Exchange_Rates {
277
  /**
278
  * @return int
279
  */
280
- private function get_monthly_schedule_time_offset(){
281
  $current_day = date( 'j' );
282
  $days_in_current_month = cal_days_in_month( CAL_GREGORIAN, date( 'n' ), date( 'Y' ) );
283
 
@@ -295,7 +292,7 @@ class WCML_Exchange_Rates {
295
  /**
296
  * @return int
297
  */
298
- private function get_weekly_schedule_time_offset(){
299
  $current_day = date( 'w' );
300
  if ( $this->settings['week_day'] >= $current_day ) {
301
  $days = $this->settings['week_day'] - $current_day;
@@ -321,36 +318,36 @@ class WCML_Exchange_Rates {
321
 
322
  if ( 'monthly' === $this->settings['schedule'] ) {
323
 
324
- $month_day = $this->get_month_day_formatted();
325
  $current_month = date( 'n' );
326
  $days_in_current_month = cal_days_in_month( CAL_GREGORIAN, $current_month, date( 'Y' ) );
327
  if ( $this->settings['month_day'] <= $days_in_current_month && $this->settings['month_day'] >= date( 'j' ) ) {
328
  $interval = DAY_IN_SECONDS * $days_in_current_month;
329
  } else {
330
- $month_number = 12 === (int)$current_month ? 1 : $current_month + 1;
331
- $year_number = 12 === (int)$current_month? date( 'Y' ) + 1 : date( 'Y' );
332
  $interval = DAY_IN_SECONDS * cal_days_in_month( CAL_GREGORIAN, $month_number, $year_number );
333
  }
334
 
335
- $schedules[ 'wcml_monthly_on_' . $this->settings['month_day'] ] = array(
336
  'interval' => $interval,
337
  'display' => sprintf( __( 'Monthly on the %s', 'woocommerce-multilingual' ), $month_day ),
338
- );
339
 
340
  } elseif ( 'weekly' === $this->settings['schedule'] ) {
341
 
342
- $week_day = $this->wp_locale->get_weekday( $this->settings['week_day'] );
343
- $schedules[ 'wcml_weekly_on_' . $this->settings['week_day'] ] = array(
344
  'interval' => WEEK_IN_SECONDS,
345
  'display' => sprintf( __( 'Weekly on %s', 'woocommerce-multilingual' ), $week_day ),
346
- );
347
 
348
  }
349
 
350
  return $schedules;
351
  }
352
 
353
- private function get_month_day_formatted(){
354
  $month_day = $this->settings['month_day'];
355
  switch ( $month_day ) {
356
  case 1:
@@ -369,4 +366,4 @@ class WCML_Exchange_Rates {
369
  return $month_day;
370
  }
371
 
372
- }
8
  /** @var woocommerce_wpml */
9
  private $woocommerce_wpml;
10
  /** @var array */
11
+ private $services = [];
12
  /** @var array */
13
  private $settings;
14
  /** @var WP_Locale */
15
  private $wp_locale;
16
 
17
+ const CRONJOB_EVENT = 'wcml_exchange_rates_update';
18
  const DIGITS_AFTER_DECIMAL_POINT = 6;
19
 
20
  /**
25
  */
26
  public function __construct( $woocommerce_wpml, $wp_locale ) {
27
  $this->woocommerce_wpml = $woocommerce_wpml;
28
+ $this->wp_locale = $wp_locale;
29
  }
30
 
31
  public function add_actions() {
32
  if ( is_admin() ) {
33
+ add_action( 'wcml_saved_mc_options', [ $this, 'update_exchange_rate_options' ] ); // before init
34
  }
35
+ add_action( 'init', [ $this, 'init' ] );
36
  }
37
 
38
  public function init() {
39
  if ( $this->woocommerce_wpml->multi_currency->get_currencies() ) {
40
  if ( is_admin() ) {
41
+ add_action( 'wp_ajax_wcml_update_exchange_rates', [ $this, 'update_exchange_rates_ajax' ] );
42
  }
43
+ add_filter( 'cron_schedules', [ $this, 'cron_schedules' ] );
44
+ add_action( self::CRONJOB_EVENT, [ $this, 'update_exchange_rates' ] );
45
  }
46
  }
47
 
48
  public function initialize_settings() {
49
  if ( ! isset( $this->woocommerce_wpml->settings['multi_currency']['exchange_rates'] ) ) {
50
+ $this->settings = [
51
  'automatic' => 0,
52
  'service' => 'fixerio',
53
  'lifting_charge' => 0,
54
  'schedule' => 'manual',
55
  'week_day' => 1,
56
+ 'month_day' => 1,
57
+ ];
58
  $this->save_settings();
59
  } else {
60
  $this->settings =& $this->woocommerce_wpml->settings['multi_currency']['exchange_rates'];
69
  }
70
 
71
  /**
72
+ * @param string $service_id
73
  * @param WCML_Exchange_Rate_Service $service
74
  */
75
  public function add_service( $service_id, $service ) {
99
 
100
  /**
101
  * @param string $key
102
+ * @param mixed $value
103
  */
104
  public function save_setting( $key, $value ) {
105
  $this->settings[ $key ] = $value;
107
  }
108
 
109
  public function update_exchange_rates_ajax() {
110
+ $response = [];
111
  if ( wp_create_nonce( 'update-exchange-rates' ) === $_POST['wcml_nonce'] ) {
112
  try {
113
  $rates = $this->update_exchange_rates();
133
 
134
  $currencies = $this->woocommerce_wpml->multi_currency->get_currency_codes();
135
  $default_currency = wcml_get_woocommerce_currency_option();
136
+ $secondary_currencies = array_diff( $currencies, [ $default_currency ] );
137
 
138
  try {
139
  $rates = $service->get_rates( $default_currency, $secondary_currencies );
140
  } catch ( Exception $e ) {
141
  if ( defined( 'WP_DEBUG_LOG' ) && WP_DEBUG_LOG ) {
142
+ error_log( 'Exchange rates update error (' . $this->settings['service'] . '): ' . $e->getMessage() );
143
  }
144
  throw new Exception( $e->getMessage() );
145
  }
208
  if ( isset( $post_data['services'] ) ) {
209
 
210
  foreach ( $post_data['services'] as $service_id => $service_data ) {
211
+ if ( isset( $service_data['api-key'] ) ) {
212
  $this->services[ $service_id ]->save_setting( 'api-key', $service_data['api-key'] );
213
  }
 
214
  }
 
215
  }
216
 
217
  $this->settings['lifting_charge'] = is_numeric( $post_data['lifting_charge'] ) ? $post_data['lifting_charge'] : 0;
237
  } else {
238
  $this->enable_update_cronjob();
239
  }
 
240
  } else {
241
  $this->settings['automatic'] = 0;
242
  $this->delete_update_cronjob();
274
  /**
275
  * @return int
276
  */
277
+ private function get_monthly_schedule_time_offset() {
278
  $current_day = date( 'j' );
279
  $days_in_current_month = cal_days_in_month( CAL_GREGORIAN, date( 'n' ), date( 'Y' ) );
280
 
292
  /**
293
  * @return int
294
  */
295
+ private function get_weekly_schedule_time_offset() {
296
  $current_day = date( 'w' );
297
  if ( $this->settings['week_day'] >= $current_day ) {
298
  $days = $this->settings['week_day'] - $current_day;
318
 
319
  if ( 'monthly' === $this->settings['schedule'] ) {
320
 
321
+ $month_day = $this->get_month_day_formatted();
322
  $current_month = date( 'n' );
323
  $days_in_current_month = cal_days_in_month( CAL_GREGORIAN, $current_month, date( 'Y' ) );
324
  if ( $this->settings['month_day'] <= $days_in_current_month && $this->settings['month_day'] >= date( 'j' ) ) {
325
  $interval = DAY_IN_SECONDS * $days_in_current_month;
326
  } else {
327
+ $month_number = 12 === (int) $current_month ? 1 : $current_month + 1;
328
+ $year_number = 12 === (int) $current_month ? date( 'Y' ) + 1 : date( 'Y' );
329
  $interval = DAY_IN_SECONDS * cal_days_in_month( CAL_GREGORIAN, $month_number, $year_number );
330
  }
331
 
332
+ $schedules[ 'wcml_monthly_on_' . $this->settings['month_day'] ] = [
333
  'interval' => $interval,
334
  'display' => sprintf( __( 'Monthly on the %s', 'woocommerce-multilingual' ), $month_day ),
335
+ ];
336
 
337
  } elseif ( 'weekly' === $this->settings['schedule'] ) {
338
 
339
+ $week_day = $this->wp_locale->get_weekday( $this->settings['week_day'] );
340
+ $schedules[ 'wcml_weekly_on_' . $this->settings['week_day'] ] = [
341
  'interval' => WEEK_IN_SECONDS,
342
  'display' => sprintf( __( 'Weekly on %s', 'woocommerce-multilingual' ), $week_day ),
343
+ ];
344
 
345
  }
346
 
347
  return $schedules;
348
  }
349
 
350
+ private function get_month_day_formatted() {
351
  $month_day = $this->settings['month_day'];
352
  switch ( $month_day ) {
353
  case 1:
366
  return $month_day;
367
  }
368
 
369
+ }
classes/multi-currency/exchange-rate-services/class-wcml-exchange-rate-service.php CHANGED
@@ -14,9 +14,9 @@ abstract class WCML_Exchange_Rate_Service {
14
  /** @var string */
15
  private $api_url;
16
 
17
- private $settings = array();
18
 
19
- protected $api_key = '';
20
  protected $requires_key = false;
21
 
22
  /**
@@ -34,7 +34,7 @@ abstract class WCML_Exchange_Rate_Service {
34
  $this->api_url = $api_url;
35
  $this->url = $url;
36
 
37
- $this->settings = get_option( 'wcml_exchange_rate_service_' . $this->id, array() );
38
 
39
  $this->api_key = $this->get_setting( 'api-key' );
40
  }
@@ -55,11 +55,11 @@ abstract class WCML_Exchange_Rate_Service {
55
 
56
  /**
57
  * @param string $from
58
- * @param array $to
59
  *
60
  * @return mixed
61
  */
62
- public abstract function get_rates( $from, $to );
63
 
64
  /**
65
  * @return bool
@@ -90,7 +90,7 @@ abstract class WCML_Exchange_Rate_Service {
90
 
91
  /**
92
  * @param string $key
93
- * @param mixed $value
94
  */
95
  public function save_setting( $key, $value ) {
96
  $this->settings[ $key ] = $value;
@@ -101,11 +101,12 @@ abstract class WCML_Exchange_Rate_Service {
101
  * @param string $error_message
102
  */
103
  public function save_last_error( $error_message ) {
104
- $this->save_setting( 'last_error',
105
- array(
 
106
  'text' => $error_message,
107
- 'time' => date_i18n( 'F j, Y g:i a', current_time( 'timestamp' ) )
108
- )
109
  );
110
  }
111
 
@@ -120,4 +121,4 @@ abstract class WCML_Exchange_Rate_Service {
120
  return isset( $this->settings['last_error'] ) ? $this->settings['last_error'] : false;
121
  }
122
 
123
- }
14
  /** @var string */
15
  private $api_url;
16
 
17
+ private $settings = [];
18
 
19
+ protected $api_key = '';
20
  protected $requires_key = false;
21
 
22
  /**
34
  $this->api_url = $api_url;
35
  $this->url = $url;
36
 
37
+ $this->settings = get_option( 'wcml_exchange_rate_service_' . $this->id, [] );
38
 
39
  $this->api_key = $this->get_setting( 'api-key' );
40
  }
55
 
56
  /**
57
  * @param string $from
58
+ * @param array $to
59
  *
60
  * @return mixed
61
  */
62
+ abstract public function get_rates( $from, $to );
63
 
64
  /**
65
  * @return bool
90
 
91
  /**
92
  * @param string $key
93
+ * @param mixed $value
94
  */
95
  public function save_setting( $key, $value ) {
96
  $this->settings[ $key ] = $value;
101
  * @param string $error_message
102
  */
103
  public function save_last_error( $error_message ) {
104
+ $this->save_setting(
105
+ 'last_error',
106
+ [
107
  'text' => $error_message,
108
+ 'time' => date_i18n( 'F j, Y g:i a', current_time( 'timestamp' ) ),
109
+ ]
110
  );
111
  }
112
 
121
  return isset( $this->settings['last_error'] ) ? $this->settings['last_error'] : false;
122
  }
123
 
124
+ }
classes/multi-currency/exchange-rate-services/class-wcml-exchange-rates-currencylayer.php CHANGED
@@ -5,9 +5,9 @@
5
  */
6
  class WCML_Exchange_Rates_Currencylayer extends WCML_Exchange_Rate_Service {
7
 
8
- private $id = 'currencylayer';
9
- private $name = 'currencylayer';
10
- private $url = 'https://currencylayer.com/';
11
  private $api_url = 'http://apilayer.net/api/live?access_key=%s&source=%s&currencies=%s&amount=1';
12
 
13
  public function __construct() {
@@ -17,7 +17,7 @@ class WCML_Exchange_Rates_Currencylayer extends WCML_Exchange_Rate_Service {
17
 
18
  /**
19
  * @param string $from
20
- * @param array $tos
21
  *
22
  * @return array
23
  * @throws Exception
@@ -25,7 +25,7 @@ class WCML_Exchange_Rates_Currencylayer extends WCML_Exchange_Rate_Service {
25
  public function get_rates( $from, $tos ) {
26
 
27
  parent::clear_last_error();
28
- $rates = array();
29
 
30
  $url = sprintf( $this->api_url, $this->api_key, $from, implode( ',', $tos ) );
31
 
@@ -62,9 +62,9 @@ class WCML_Exchange_Rates_Currencylayer extends WCML_Exchange_Rate_Service {
62
  }
63
  }
64
  }
65
-
66
  return $rates;
67
 
68
  }
69
 
70
- }
5
  */
6
  class WCML_Exchange_Rates_Currencylayer extends WCML_Exchange_Rate_Service {
7
 
8
+ private $id = 'currencylayer';
9
+ private $name = 'currencylayer';
10
+ private $url = 'https://currencylayer.com/';
11
  private $api_url = 'http://apilayer.net/api/live?access_key=%s&source=%s&currencies=%s&amount=1';
12
 
13
  public function __construct() {
17
 
18
  /**
19
  * @param string $from
20
+ * @param array $tos
21
  *
22
  * @return array
23
  * @throws Exception
25
  public function get_rates( $from, $tos ) {
26
 
27
  parent::clear_last_error();
28
+ $rates = [];
29
 
30
  $url = sprintf( $this->api_url, $this->api_key, $from, implode( ',', $tos ) );
31
 
62
  }
63
  }
64
  }
65
+
66
  return $rates;
67
 
68
  }
69
 
70
+ }
classes/multi-currency/exchange-rate-services/class-wcml-exchange-rates-fixerio.php CHANGED
@@ -5,9 +5,9 @@
5
  */
6
  class WCML_Exchange_Rates_Fixerio extends WCML_Exchange_Rate_Service {
7
 
8
- private $id = 'fixerio';
9
- private $name = 'Fixer.io';
10
- private $url = 'http://fixer.io/';
11
  private $api_url = 'http://data.fixer.io/api/latest?access_key=%1$s&base=%2$s&symbols=%3$s';
12
 
13
  public function __construct() {
@@ -17,7 +17,7 @@ class WCML_Exchange_Rates_Fixerio extends WCML_Exchange_Rate_Service {
17
 
18
  /**
19
  * @param string $from
20
- * @param array $tos
21
  *
22
  * @return array
23
  * @throws Exception
@@ -25,7 +25,7 @@ class WCML_Exchange_Rates_Fixerio extends WCML_Exchange_Rate_Service {
25
  public function get_rates( $from, $tos ) {
26
 
27
  parent::clear_last_error();
28
- $rates = array();
29
 
30
  $url = sprintf( $this->api_url, $this->api_key, $from, implode( ',', $tos ) );
31
 
@@ -59,4 +59,4 @@ class WCML_Exchange_Rates_Fixerio extends WCML_Exchange_Rate_Service {
59
 
60
  }
61
 
62
- }
5
  */
6
  class WCML_Exchange_Rates_Fixerio extends WCML_Exchange_Rate_Service {
7
 
8
+ private $id = 'fixerio';
9
+ private $name = 'Fixer.io';
10
+ private $url = 'http://fixer.io/';
11
  private $api_url = 'http://data.fixer.io/api/latest?access_key=%1$s&base=%2$s&symbols=%3$s';
12
 
13
  public function __construct() {
17
 
18
  /**
19
  * @param string $from
20
+ * @param array $tos
21
  *
22
  * @return array
23
  * @throws Exception
25
  public function get_rates( $from, $tos ) {
26
 
27
  parent::clear_last_error();
28
+ $rates = [];
29
 
30
  $url = sprintf( $this->api_url, $this->api_key, $from, implode( ',', $tos ) );
31
 
59
 
60
  }
61
 
62
+ }
classes/multi-currency/payment-gateways/class-wcml-currencies-payment-gateways.php CHANGED
@@ -33,7 +33,7 @@ class WCML_Currencies_Payment_Gateways {
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' ] );
33
  }
34
 
35
  public function add_hooks() {
36
+ add_action( 'init', [ $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' ] );
classes/multi-currency/payment-gateways/class-wcml-payment-gateway-bacs.php CHANGED
@@ -8,14 +8,14 @@ class WCML_Payment_Gateway_Bacs extends WCML_Payment_Gateway {
8
  const TEMPLATE = 'bacs.twig';
9
 
10
  protected function get_output_model() {
11
- return array(
12
- 'strings' => array(
13
  'currency_label' => __( 'Currency', 'woocommerce-multilingual' ),
14
  'setting_label' => __( 'Bank Account', 'woocommerce-multilingual' ),
15
  'all_label' => __( 'All Accounts', 'woocommerce-multilingual' ),
16
  'all_in_label' => __( 'All in selected currency', 'woocommerce-multilingual' ),
17
- 'tooltip' => __( 'Set the currency in which your customer will see the final price when they checkout. Choose which accounts they will see in their payment message.', 'woocommerce-multilingual' )
18
- ),
19
  'gateway_id' => $this->get_id(),
20
  'gateway_title' => $this->get_title(),
21
  'current_currency' => $this->current_currency,
@@ -23,15 +23,15 @@ class WCML_Payment_Gateway_Bacs extends WCML_Payment_Gateway {
23
  'gateway_settings' => $this->get_setting( $this->current_currency ),
24
  'active_currencies' => $this->get_active_currencies(),
25
  'account_details' => $this->get_gateway()->account_details,
26
- );
27
  }
28
 
29
  protected function get_output_template() {
30
  return self::TEMPLATE;
31
  }
32
 
33
- public function add_hooks(){
34
- add_filter( 'woocommerce_bacs_accounts', array( $this, 'filter_bacs_accounts' ) );
35
  }
36
 
37
  public function filter_bacs_accounts( $accounts ) {
@@ -39,18 +39,18 @@ class WCML_Payment_Gateway_Bacs extends WCML_Payment_Gateway {
39
  $client_currency = $this->woocommerce_wpml->multi_currency->get_client_currency();
40
  $gateway_setting = $this->get_setting( $client_currency );
41
 
42
- $allowed_accounts = array();
43
 
44
  if ( $gateway_setting && 'all' !== $gateway_setting['value'] ) {
45
 
46
- if( 'all_in' === $gateway_setting['value'] ){
47
- $bacs_accounts_currencies = get_option( WCML_WC_Gateways::WCML_BACS_ACCOUNTS_CURRENCIES_OPTION, array() );
48
- foreach ( $bacs_accounts_currencies as $account_key => $currency ){
49
- if( $gateway_setting['currency'] === $currency ){
50
  $allowed_accounts[] = $accounts[ $account_key ];
51
  }
52
  }
53
- }else{
54
  $allowed_accounts[] = $accounts[ $gateway_setting['value'] ];
55
  }
56
  }
@@ -58,4 +58,4 @@ class WCML_Payment_Gateway_Bacs extends WCML_Payment_Gateway {
58
  return $allowed_accounts ? $allowed_accounts : $accounts;
59
  }
60
 
61
- }
8
  const TEMPLATE = 'bacs.twig';
9
 
10
  protected function get_output_model() {
11
+ return [
12
+ 'strings' => [
13
  'currency_label' => __( 'Currency', 'woocommerce-multilingual' ),
14
  'setting_label' => __( 'Bank Account', 'woocommerce-multilingual' ),
15
  'all_label' => __( 'All Accounts', 'woocommerce-multilingual' ),
16
  'all_in_label' => __( 'All in selected currency', 'woocommerce-multilingual' ),
17
+ 'tooltip' => __( 'Set the currency in which your customer will see the final price when they checkout. Choose which accounts they will see in their payment message.', 'woocommerce-multilingual' ),
18
+ ],
19
  'gateway_id' => $this->get_id(),
20
  'gateway_title' => $this->get_title(),
21
  'current_currency' => $this->current_currency,
23
  'gateway_settings' => $this->get_setting( $this->current_currency ),
24
  'active_currencies' => $this->get_active_currencies(),
25
  'account_details' => $this->get_gateway()->account_details,
26
+ ];
27
  }
28
 
29
  protected function get_output_template() {
30
  return self::TEMPLATE;
31
  }
32
 
33
+ public function add_hooks() {
34
+ add_filter( 'woocommerce_bacs_accounts', [ $this, 'filter_bacs_accounts' ] );
35
  }
36
 
37
  public function filter_bacs_accounts( $accounts ) {
39
  $client_currency = $this->woocommerce_wpml->multi_currency->get_client_currency();
40
  $gateway_setting = $this->get_setting( $client_currency );
41
 
42
+ $allowed_accounts = [];
43
 
44
  if ( $gateway_setting && 'all' !== $gateway_setting['value'] ) {
45
 
46
+ if ( 'all_in' === $gateway_setting['value'] ) {
47
+ $bacs_accounts_currencies = get_option( WCML_WC_Gateways::WCML_BACS_ACCOUNTS_CURRENCIES_OPTION, [] );
48
+ foreach ( $bacs_accounts_currencies as $account_key => $currency ) {
49
+ if ( $gateway_setting['currency'] === $currency ) {
50
  $allowed_accounts[] = $accounts[ $account_key ];
51
  }
52
  }
53
+ } else {
54
  $allowed_accounts[] = $accounts[ $gateway_setting['value'] ];
55
  }
56
  }
58
  return $allowed_accounts ? $allowed_accounts : $accounts;
59
  }
60
 
61
+ }
classes/multi-currency/payment-gateways/class-wcml-payment-gateway-paypal.php CHANGED
@@ -5,9 +5,9 @@
5
  */
6
  class WCML_Payment_Gateway_PayPal extends WCML_Payment_Gateway {
7
 
8
- const TEMPLATE = 'paypal.twig';
9
- const ID = 'paypal';
10
- const SUPPORTED_CURRENCIES = array(
11
  'AUD',
12
  'BRL',
13
  'CAD',
@@ -34,31 +34,31 @@ class WCML_Payment_Gateway_PayPal extends WCML_Payment_Gateway {
34
  'GBP',
35
  'RMB',
36
  'RUB',
37
- 'INR'
38
- );
39
 
40
  protected function get_output_model() {
41
 
42
- if( $this->is_current_currency_default() ){
43
- return array();
44
  }
45
 
46
  $currencies_details = $this->get_currencies_details();
47
 
48
- return array(
49
- 'strings' => array(
50
  'currency_label' => __( 'Currency', 'woocommerce-multilingual' ),
51
  'setting_label' => __( 'PayPal Email', 'woocommerce-multilingual' ),
52
- 'not_supported' => sprintf( __( 'This gateway does not support %s. To show this gateway please select another currency.', 'woocommerce-multilingual' ), $this->current_currency )
53
- ),
54
  'gateway_id' => $this->get_id(),
55
  'gateway_title' => $this->get_title(),
56
  'current_currency' => $this->current_currency,
57
  'gateway_settings' => $this->get_setting( $this->current_currency ),
58
  'currencies_details' => array_intersect_key( $currencies_details, $this->get_active_currencies() ),
59
  'selected_currency_valid' => $this->is_valid_for_use( $currencies_details[ $this->current_currency ]['currency'] ),
60
- 'current_currency_valid' => $currencies_details[ $this->current_currency ]['is_valid']
61
- );
62
  }
63
 
64
  protected function get_output_template() {
@@ -72,7 +72,7 @@ class WCML_Payment_Gateway_PayPal extends WCML_Payment_Gateway {
72
  */
73
  public function is_valid_for_use( $currency ) {
74
 
75
- $filter_removed = remove_filter( 'woocommerce_paypal_supported_currencies', array( 'WCML_Payment_Gateway_PayPal', 'filter_supported_currencies' ) );
76
 
77
  $is_valid = in_array(
78
  $currency,
@@ -83,8 +83,8 @@ class WCML_Payment_Gateway_PayPal extends WCML_Payment_Gateway {
83
  true
84
  );
85
 
86
- if( $filter_removed ){
87
- add_filter( 'woocommerce_paypal_supported_currencies', array( 'WCML_Payment_Gateway_PayPal', 'filter_supported_currencies' ) );
88
  }
89
 
90
  return $is_valid;
@@ -95,21 +95,21 @@ class WCML_Payment_Gateway_PayPal extends WCML_Payment_Gateway {
95
  *
96
  * @return array
97
  */
98
- public function get_currencies_details(){
99
 
100
- $currencies_details = array();
101
- $default_currency = wcml_get_woocommerce_currency_option();
102
  $woocommerce_currencies = get_woocommerce_currencies();
103
 
104
  foreach ( $woocommerce_currencies as $code => $currency ) {
105
 
106
  if ( $default_currency === $code ) {
107
- $currencies_details[ $code ]['value'] = $this->get_gateway()->settings['email'];
108
  $currencies_details[ $code ]['currency'] = $code;
109
  $currencies_details[ $code ]['is_valid'] = $this->is_valid_for_use( $default_currency );
110
  } else {
111
- $currency_gateway_setting = $this->get_setting( $code );
112
- $currencies_details[ $code ]['value'] = $currency_gateway_setting ? $currency_gateway_setting['value'] : '';
113
  $currencies_details[ $code ]['currency'] = $currency_gateway_setting ? $currency_gateway_setting['currency'] : $code;
114
  $currencies_details[ $code ]['is_valid'] = $this->is_valid_for_use( $code );
115
  }
@@ -119,12 +119,12 @@ class WCML_Payment_Gateway_PayPal extends WCML_Payment_Gateway {
119
 
120
  }
121
 
122
- public function add_hooks(){
123
- add_filter( 'woocommerce_paypal_args', array( $this, 'filter_paypal_args' ), 10, 2 );
124
  }
125
 
126
  /**
127
- * @param array $args
128
  * @param WC_Order $order
129
  *
130
  * @return array
@@ -172,7 +172,7 @@ class WCML_Payment_Gateway_PayPal extends WCML_Payment_Gateway {
172
  $client_currency = $woocommerce_wpml->multi_currency->get_client_currency();
173
 
174
  if ( ! in_array( $client_currency, self::SUPPORTED_CURRENCIES, true ) ) {
175
- $gateway_settings = get_option( self::OPTION_KEY . self::ID, array() );
176
 
177
  if ( $gateway_settings && isset( $gateway_settings[ $client_currency ] ) ) {
178
 
@@ -185,4 +185,4 @@ class WCML_Payment_Gateway_PayPal extends WCML_Payment_Gateway {
185
  return $supported_currencies;
186
  }
187
 
188
- }
5
  */
6
  class WCML_Payment_Gateway_PayPal extends WCML_Payment_Gateway {
7
 
8
+ const TEMPLATE = 'paypal.twig';
9
+ const ID = 'paypal';
10
+ const SUPPORTED_CURRENCIES = [
11
  'AUD',
12
  'BRL',
13
  'CAD',
34
  'GBP',
35
  'RMB',
36
  'RUB',
37
+ 'INR',
38
+ ];
39
 
40
  protected function get_output_model() {
41
 
42
+ if ( $this->is_current_currency_default() ) {
43
+ return [];
44
  }
45
 
46
  $currencies_details = $this->get_currencies_details();
47
 
48
+ return [
49
+ 'strings' => [
50
  'currency_label' => __( 'Currency', 'woocommerce-multilingual' ),
51
  'setting_label' => __( 'PayPal Email', 'woocommerce-multilingual' ),
52
+ 'not_supported' => sprintf( __( 'This gateway does not support %s. To show this gateway please select another currency.', 'woocommerce-multilingual' ), $this->current_currency ),
53
+ ],
54
  'gateway_id' => $this->get_id(),
55
  'gateway_title' => $this->get_title(),
56
  'current_currency' => $this->current_currency,
57
  'gateway_settings' => $this->get_setting( $this->current_currency ),
58
  'currencies_details' => array_intersect_key( $currencies_details, $this->get_active_currencies() ),
59
  'selected_currency_valid' => $this->is_valid_for_use( $currencies_details[ $this->current_currency ]['currency'] ),
60
+ 'current_currency_valid' => $currencies_details[ $this->current_currency ]['is_valid'],
61
+ ];
62
  }
63
 
64
  protected function get_output_template() {
72
  */
73
  public function is_valid_for_use( $currency ) {
74
 
75
+ $filter_removed = remove_filter( 'woocommerce_paypal_supported_currencies', [ 'WCML_Payment_Gateway_PayPal', 'filter_supported_currencies' ] );
76
 
77
  $is_valid = in_array(
78
  $currency,
83
  true
84
  );
85
 
86
+ if ( $filter_removed ) {
87
+ add_filter( 'woocommerce_paypal_supported_currencies', [ 'WCML_Payment_Gateway_PayPal', 'filter_supported_currencies' ] );
88
  }
89
 
90
  return $is_valid;
95
  *
96
  * @return array
97
  */
98
+ public function get_currencies_details() {
99
 
100
+ $currencies_details = [];
101
+ $default_currency = wcml_get_woocommerce_currency_option();
102
  $woocommerce_currencies = get_woocommerce_currencies();
103
 
104
  foreach ( $woocommerce_currencies as $code => $currency ) {
105
 
106
  if ( $default_currency === $code ) {
107
+ $currencies_details[ $code ]['value'] = $this->get_gateway()->settings['email'];
108
  $currencies_details[ $code ]['currency'] = $code;
109
  $currencies_details[ $code ]['is_valid'] = $this->is_valid_for_use( $default_currency );
110
  } else {
111
+ $currency_gateway_setting = $this->get_setting( $code );
112
+ $currencies_details[ $code ]['value'] = $currency_gateway_setting ? $currency_gateway_setting['value'] : '';
113
  $currencies_details[ $code ]['currency'] = $currency_gateway_setting ? $currency_gateway_setting['currency'] : $code;
114
  $currencies_details[ $code ]['is_valid'] = $this->is_valid_for_use( $code );
115
  }
119
 
120
  }
121
 
122
+ public function add_hooks() {
123
+ add_filter( 'woocommerce_paypal_args', [ $this, 'filter_paypal_args' ], 10, 2 );
124
  }
125
 
126
  /**
127
+ * @param array $args
128
  * @param WC_Order $order
129
  *
130
  * @return array
172
  $client_currency = $woocommerce_wpml->multi_currency->get_client_currency();
173
 
174
  if ( ! in_array( $client_currency, self::SUPPORTED_CURRENCIES, true ) ) {
175
+ $gateway_settings = get_option( self::OPTION_KEY . self::ID, [] );
176
 
177
  if ( $gateway_settings && isset( $gateway_settings[ $client_currency ] ) ) {
178
 
185
  return $supported_currencies;
186
  }
187
 
188
+ }
classes/multi-currency/payment-gateways/class-wcml-payment-gateway-stripe.php CHANGED
@@ -6,33 +6,33 @@
6
  class WCML_Payment_Gateway_Stripe extends WCML_Payment_Gateway {
7
 
8
  const TEMPLATE = 'stripe.twig';
9
- const ID = 'stripe';
10
 
11
  protected function get_output_model() {
12
- if( $this->is_current_currency_default() ){
13
- return array();
14
  }
15
 
16
- return array(
17
- 'strings' => array(
18
  'currency_label' => __( 'Currency', 'woocommerce-multilingual' ),
19
  'publishable_label' => __( 'Live Publishable Key', 'woocommerce-multilingual' ),
20
  'secret_label' => __( 'Live Secret Key', 'woocommerce-multilingual' ),
21
- ),
22
  'gateway_id' => $this->get_id(),
23
  'gateway_title' => $this->get_title(),
24
  'current_currency' => $this->current_currency,
25
  'gateway_settings' => $this->get_setting( $this->current_currency ),
26
- 'currencies_details' => $this->get_currencies_details( $this->get_active_currencies() )
27
- );
28
  }
29
 
30
  protected function get_output_template() {
31
  return self::TEMPLATE;
32
  }
33
 
34
- public function add_hooks(){
35
- add_filter( 'woocommerce_stripe_request_body', array( $this, 'filter_request_body' ) );
36
  }
37
 
38
  public function filter_request_body( $request ) {
@@ -56,20 +56,20 @@ class WCML_Payment_Gateway_Stripe extends WCML_Payment_Gateway {
56
  *
57
  * @return array
58
  */
59
- public function get_currencies_details( $active_currencies ){
60
 
61
- $currencies_details = array();
62
  $default_currency = wcml_get_woocommerce_currency_option();
63
 
64
  foreach ( $active_currencies as $code => $currency ) {
65
 
66
  if ( $default_currency === $code ) {
67
  $currencies_details[ $code ]['publishable_key'] = $this->get_gateway()->settings['publishable_key'];
68
- $currencies_details[ $code ]['secret_key'] = $this->get_gateway()->settings['secret_key'];
69
  } else {
70
- $currency_gateway_setting = $this->get_setting( $code );
71
  $currencies_details[ $code ]['publishable_key'] = $currency_gateway_setting ? $currency_gateway_setting['publishable_key'] : '';
72
- $currencies_details[ $code ]['secret_key'] = $currency_gateway_setting ? $currency_gateway_setting['secret_key'] : '';
73
  }
74
  }
75
 
@@ -85,18 +85,18 @@ class WCML_Payment_Gateway_Stripe extends WCML_Payment_Gateway {
85
  * @return array
86
  */
87
  public static function filter_stripe_settings( $settings ) {
88
- if ( is_admin() ){
89
  return $settings;
90
  }
91
 
92
  global $woocommerce_wpml;
93
 
94
  $client_currency = $woocommerce_wpml->multi_currency->get_client_currency();
95
- $gateway_settings = get_option( self::OPTION_KEY . self::ID, array() );
96
 
97
- if( $gateway_settings && isset( $gateway_settings[ $client_currency ] ) ){
98
- $gateway_setting = $gateway_settings[ $client_currency ];
99
- if( $gateway_setting['publishable_key'] && $gateway_setting['secret_key'] ){
100
  if ( 'yes' === $settings['testmode'] ) {
101
  $settings['test_publishable_key'] = $gateway_setting['publishable_key'];
102
  $settings['test_secret_key'] = $gateway_setting['secret_key'];
@@ -110,4 +110,4 @@ class WCML_Payment_Gateway_Stripe extends WCML_Payment_Gateway {
110
  return $settings;
111
  }
112
 
113
- }
6
  class WCML_Payment_Gateway_Stripe extends WCML_Payment_Gateway {
7
 
8
  const TEMPLATE = 'stripe.twig';
9
+ const ID = 'stripe';
10
 
11
  protected function get_output_model() {
12
+ if ( $this->is_current_currency_default() ) {
13
+ return [];
14
  }
15
 
16
+ return [
17
+ 'strings' => [
18
  'currency_label' => __( 'Currency', 'woocommerce-multilingual' ),
19
  'publishable_label' => __( 'Live Publishable Key', 'woocommerce-multilingual' ),
20
  'secret_label' => __( 'Live Secret Key', 'woocommerce-multilingual' ),
21
+ ],
22
  'gateway_id' => $this->get_id(),
23
  'gateway_title' => $this->get_title(),
24
  'current_currency' => $this->current_currency,
25
  'gateway_settings' => $this->get_setting( $this->current_currency ),
26
+ 'currencies_details' => $this->get_currencies_details( $this->get_active_currencies() ),
27
+ ];
28
  }
29
 
30
  protected function get_output_template() {
31
  return self::TEMPLATE;
32
  }
33
 
34
+ public function add_hooks() {
35
+ add_filter( 'woocommerce_stripe_request_body', [ $this, 'filter_request_body' ] );
36
  }
37
 
38
  public function filter_request_body( $request ) {
56
  *
57
  * @return array
58
  */
59
+ public function get_currencies_details( $active_currencies ) {
60
 
61
+ $currencies_details = [];
62
  $default_currency = wcml_get_woocommerce_currency_option();
63
 
64
  foreach ( $active_currencies as $code => $currency ) {
65
 
66
  if ( $default_currency === $code ) {
67
  $currencies_details[ $code ]['publishable_key'] = $this->get_gateway()->settings['publishable_key'];
68
+ $currencies_details[ $code ]['secret_key'] = $this->get_gateway()->settings['secret_key'];
69
  } else {
70
+ $currency_gateway_setting = $this->get_setting( $code );
71
  $currencies_details[ $code ]['publishable_key'] = $currency_gateway_setting ? $currency_gateway_setting['publishable_key'] : '';
72
+ $currencies_details[ $code ]['secret_key'] = $currency_gateway_setting ? $currency_gateway_setting['secret_key'] : '';
73
  }
74
  }
75
 
85
  * @return array
86
  */
87
  public static function filter_stripe_settings( $settings ) {
88
+ if ( is_admin() ) {
89
  return $settings;
90
  }
91
 
92
  global $woocommerce_wpml;
93
 
94
  $client_currency = $woocommerce_wpml->multi_currency->get_client_currency();
95
+ $gateway_settings = get_option( self::OPTION_KEY . self::ID, [] );
96
 
97
+ if ( $gateway_settings && isset( $gateway_settings[ $client_currency ] ) ) {
98
+ $gateway_setting = $gateway_settings[ $client_currency ];
99
+ if ( $gateway_setting['publishable_key'] && $gateway_setting['secret_key'] ) {
100
  if ( 'yes' === $settings['testmode'] ) {
101
  $settings['test_publishable_key'] = $gateway_setting['publishable_key'];
102
  $settings['test_secret_key'] = $gateway_setting['secret_key'];
110
  return $settings;
111
  }
112
 
113
+ }
classes/multi-currency/payment-gateways/class-wcml-payment-gateway.php CHANGED
@@ -24,7 +24,7 @@ abstract class WCML_Payment_Gateway {
24
  */
25
  protected $gateway;
26
 
27
- private $settings = array();
28
 
29
  /**
30
  * @var \IWPML_Template_Service
@@ -36,15 +36,15 @@ abstract class WCML_Payment_Gateway {
36
  protected $woocommerce_wpml;
37
 
38
  /**
39
- * @param WC_Payment_Gateway $gateway
40
  * @param \IWPML_Template_Service $template_service
41
- * @param woocommerce_wpml $woocommerce_wpml
42
  */
43
  public function __construct( WC_Payment_Gateway $gateway, IWPML_Template_Service $template_service, woocommerce_wpml $woocommerce_wpml ) {
44
  $this->gateway = $gateway;
45
  $this->template_service = $template_service;
46
  $this->woocommerce_wpml = $woocommerce_wpml;
47
- $this->settings = get_option( self::OPTION_KEY . $this->get_id(), array() );
48
  }
49
 
50
  public function get_settings_output( $current_currency, $active_currencies ) {
@@ -63,8 +63,8 @@ abstract class WCML_Payment_Gateway {
63
 
64
  abstract protected function get_output_template();
65
 
66
- protected function is_current_currency_default(){
67
- if( $this->current_currency === $this->default_currency ){
68
  return true;
69
  }
70
  return false;
@@ -72,21 +72,21 @@ abstract class WCML_Payment_Gateway {
72
  /**
73
  * @return WC_Payment_Gateway
74
  */
75
- public function get_gateway(){
76
  return $this->gateway;
77
  }
78
 
79
  /**
80
  * @return string
81
  */
82
- public function get_id(){
83
  return $this->gateway->id;
84
  }
85
 
86
  /**
87
  * @return string
88
  */
89
- public function get_title(){
90
  return $this->gateway->title;
91
  }
92
 
@@ -112,22 +112,22 @@ abstract class WCML_Payment_Gateway {
112
 
113
  /**
114
  * @param string $key
115
- * @param mixed $value
116
  */
117
  public function save_setting( $key, $value ) {
118
  $this->settings[ $key ] = $value;
119
  $this->save_settings();
120
  }
121
 
122
- public function get_active_currencies(){
123
 
124
  $active_currencies = $this->active_currencies;
125
 
126
- if( !in_array( $this->current_currency, array_keys( $active_currencies ) ) ){
127
- $active_currencies[ $this->current_currency ] = array();
128
  }
129
 
130
  return $active_currencies;
131
  }
132
 
133
- }
24
  */
25
  protected $gateway;
26
 
27
+ private $settings = [];
28
 
29
  /**
30
  * @var \IWPML_Template_Service
36
  protected $woocommerce_wpml;
37
 
38
  /**
39
+ * @param WC_Payment_Gateway $gateway
40
  * @param \IWPML_Template_Service $template_service
41
+ * @param woocommerce_wpml $woocommerce_wpml
42
  */
43
  public function __construct( WC_Payment_Gateway $gateway, IWPML_Template_Service $template_service, woocommerce_wpml $woocommerce_wpml ) {
44
  $this->gateway = $gateway;
45
  $this->template_service = $template_service;
46
  $this->woocommerce_wpml = $woocommerce_wpml;
47
+ $this->settings = get_option( self::OPTION_KEY . $this->get_id(), [] );
48
  }
49
 
50
  public function get_settings_output( $current_currency, $active_currencies ) {
63
 
64
  abstract protected function get_output_template();
65
 
66
+ protected function is_current_currency_default() {
67
+ if ( $this->current_currency === $this->default_currency ) {
68
  return true;
69
  }
70
  return false;
72
  /**
73
  * @return WC_Payment_Gateway
74
  */
75
+ public function get_gateway() {
76
  return $this->gateway;
77
  }
78
 
79
  /**
80
  * @return string
81
  */
82
+ public function get_id() {
83
  return $this->gateway->id;
84
  }
85
 
86
  /**
87
  * @return string
88
  */
89
+ public function get_title() {
90
  return $this->gateway->title;
91
  }
92
 
112
 
113
  /**
114
  * @param string $key
115
+ * @param mixed $value
116
  */
117
  public function save_setting( $key, $value ) {
118
  $this->settings[ $key ] = $value;
119
  $this->save_settings();
120
  }
121
 
122
+ public function get_active_currencies() {
123
 
124
  $active_currencies = $this->active_currencies;
125
 
126
+ if ( ! in_array( $this->current_currency, array_keys( $active_currencies ) ) ) {
127
+ $active_currencies[ $this->current_currency ] = [];
128
  }
129
 
130
  return $active_currencies;
131
  }
132
 
133
+ }
classes/order-property-filter/class-wcml-payment-method-filter.php CHANGED
@@ -2,31 +2,31 @@
2
 
3
  class WCML_Payment_Method_Filter {
4
  /** @var array */
5
- private $payment_gateway_cache = array();
6
 
7
  /** @var array */
8
- private $post_type_cache = array();
9
 
10
  public function add_hooks() {
11
- add_filter( 'get_post_metadata', array( $this, 'payment_method_string' ), 10, 3 );
12
  }
13
 
14
  public function payment_method_string( $title, $object_id, $meta_key ) {
15
 
16
- if ( '_payment_method_title' === $meta_key && !empty( $title ) && $object_id && 'shop_order' === $this->get_post_type( $object_id ) ) {
17
  $payment_gateway = $this->get_payment_gateway( $object_id );
18
 
19
- if( isset( $_POST['payment_method'] ) && $payment_gateway->id !== $_POST['payment_method'] && WC()->payment_gateways() ){
20
  $payment_gateways = WC()->payment_gateways->payment_gateways();
21
- if( isset( $payment_gateways[ $_POST['payment_method'] ] ) ){
22
  $payment_gateway = $payment_gateways[ $_POST['payment_method'] ];
23
  }
24
  }
25
 
26
- if( $payment_gateway ){
27
  $title = icl_translate( 'admin_texts_woocommerce_gateways', $payment_gateway->id . '_gateway_title', $payment_gateway->title );
28
 
29
- if( $title === $payment_gateway->title ){
30
  $title = __( $payment_gateway->title, 'woocommerce' );
31
 
32
  if ( 'cheque' === $payment_gateway->id && $title === $payment_gateway->title ) {
@@ -59,12 +59,12 @@ class WCML_Payment_Method_Filter {
59
  */
60
  private function get_payment_gateway( $object_id ) {
61
  if ( ! array_key_exists( $object_id, $this->payment_gateway_cache ) ) {
62
- remove_filter( 'get_post_metadata', array( $this, 'payment_method_string' ), 10, 3 );
63
  $payment_gateway = wc_get_payment_gateway_by_order( $object_id );
64
- add_filter( 'get_post_metadata', array( $this, 'payment_method_string' ), 10, 3 );
65
  $this->payment_gateway_cache[ $object_id ] = $payment_gateway;
66
  }
67
 
68
  return $this->payment_gateway_cache[ $object_id ];
69
  }
70
- }
2
 
3
  class WCML_Payment_Method_Filter {
4
  /** @var array */
5
+ private $payment_gateway_cache = [];
6
 
7
  /** @var array */
8
+ private $post_type_cache = [];
9
 
10
  public function add_hooks() {
11
+ add_filter( 'get_post_metadata', [ $this, 'payment_method_string' ], 10, 3 );
12
  }
13
 
14
  public function payment_method_string( $title, $object_id, $meta_key ) {
15
 
16
+ if ( '_payment_method_title' === $meta_key && ! empty( $title ) && $object_id && 'shop_order' === $this->get_post_type( $object_id ) ) {
17
  $payment_gateway = $this->get_payment_gateway( $object_id );
18
 
19
+ if ( isset( $_POST['payment_method'] ) && $payment_gateway->id !== $_POST['payment_method'] && WC()->payment_gateways() ) {
20
  $payment_gateways = WC()->payment_gateways->payment_gateways();
21
+ if ( isset( $payment_gateways[ $_POST['payment_method'] ] ) ) {
22
  $payment_gateway = $payment_gateways[ $_POST['payment_method'] ];
23
  }
24
  }
25
 
26
+ if ( $payment_gateway ) {
27
  $title = icl_translate( 'admin_texts_woocommerce_gateways', $payment_gateway->id . '_gateway_title', $payment_gateway->title );
28
 
29
+ if ( $title === $payment_gateway->title ) {
30
  $title = __( $payment_gateway->title, 'woocommerce' );
31
 
32
  if ( 'cheque' === $payment_gateway->id && $title === $payment_gateway->title ) {
59
  */
60
  private function get_payment_gateway( $object_id ) {
61
  if ( ! array_key_exists( $object_id, $this->payment_gateway_cache ) ) {
62
+ remove_filter( 'get_post_metadata', [ $this, 'payment_method_string' ], 10, 3 );
63
  $payment_gateway = wc_get_payment_gateway_by_order( $object_id );
64
+ add_filter( 'get_post_metadata', [ $this, 'payment_method_string' ], 10, 3 );
65
  $this->payment_gateway_cache[ $object_id ] = $payment_gateway;
66
  }
67
 
68
  return $this->payment_gateway_cache[ $object_id ];
69
  }
70
+ }
classes/pointers/class-wcml-pointers.php CHANGED
@@ -85,7 +85,7 @@ class WCML_Pointers{
85
  wp_enqueue_style( 'wcml-pointers' );
86
 
87
  $method = $before ? 'before' : 'append';
88
- // @todo move to an enqueued script?
89
  ?>
90
  <script type="text/javascript">
91
  jQuery('<?php echo $jquery_selector; ?>').<?php echo $method; ?>('<?php echo $this->get_anchor( $link, $name, $anchor_template ); ?>');
85
  wp_enqueue_style( 'wcml-pointers' );
86
 
87
  $method = $before ? 'before' : 'append';
88
+ // @todo move to an enqueued script?.
89
  ?>
90
  <script type="text/javascript">
91
  jQuery('<?php echo $jquery_selector; ?>').<?php echo $method; ?>('<?php echo $this->get_anchor( $link, $name, $anchor_template ); ?>');
classes/privacy/class-wcml-privacy-content-factory.php CHANGED
@@ -15,4 +15,4 @@ class WCML_Privacy_Content_Factory implements IWPML_Backend_Action_Loader {
15
 
16
  return null;
17
  }
18
- }
15
 
16
  return null;
17
  }
18
+ }
classes/privacy/class-wcml-privacy-content.php CHANGED
@@ -16,10 +16,10 @@ class WCML_Privacy_Content extends WPML_Privacy_Content {
16
  * @return string|array
17
  */
18
  protected function get_privacy_policy() {
19
- return array(
20
  __( 'WooCommerce Multilingual will use cookies to understand the basket info when using languages in domains and to transfer data between the domains.', 'woocommerce-multilingual' ),
21
  __( 'WooCommerce Multilingual will also use cookies to identify the language and currency of each customer’s order as well as the currency of the reports created by WooCommerce. WooCommerce Multilingual extends these reports by adding the currency’s information.', 'woocommerce-multilingual' ),
22
- );
23
  }
24
 
25
- }
16
  * @return string|array
17
  */
18
  protected function get_privacy_policy() {
19
+ return [
20
  __( 'WooCommerce Multilingual will use cookies to understand the basket info when using languages in domains and to transfer data between the domains.', 'woocommerce-multilingual' ),
21
  __( 'WooCommerce Multilingual will also use cookies to identify the language and currency of each customer’s order as well as the currency of the reports created by WooCommerce. WooCommerce Multilingual extends these reports by adding the currency’s information.', 'woocommerce-multilingual' ),
22
+ ];
23
  }
24
 
25
+ }
classes/product/class-wcml-product-data-store-cpt.php CHANGED
@@ -2,13 +2,13 @@
2
  /**
3
  * Class WCML_Product_Data_Store_CPT
4
  */
5
- class WCML_Product_Data_Store_CPT extends WC_Product_Data_Store_CPT{
6
 
7
  /**
8
  * @param int $product_id
9
  */
10
- public function update_lookup_table_data( $product_id ){
11
- if( method_exists( $this, 'update_lookup_table' ) ){
12
  $this->update_lookup_table( $product_id, 'wc_product_meta_lookup' );
13
  }
14
  }
2
  /**
3
  * Class WCML_Product_Data_Store_CPT
4
  */
5
+ class WCML_Product_Data_Store_CPT extends WC_Product_Data_Store_CPT {
6
 
7
  /**
8
  * @param int $product_id
9
  */
10
+ public function update_lookup_table_data( $product_id ) {
11
+ if ( method_exists( $this, 'update_lookup_table' ) ) {
12
  $this->update_lookup_table( $product_id, 'wc_product_meta_lookup' );
13
  }
14
  }
classes/shortcodes/class-wcml-wc-shortcode-product-category.php CHANGED
@@ -4,6 +4,7 @@ use WPML\Collect\Support\Collection;
4
 
5
  /**
6
  * Class WCML_WC_Shortcode_Product_Category
 
7
  * @since 4.2.2
8
  */
9
  class WCML_WC_Shortcode_Product_Category {
@@ -23,7 +24,7 @@ class WCML_WC_Shortcode_Product_Category {
23
  }
24
 
25
  public function add_hooks() {
26
- add_filter( 'woocommerce_shortcode_products_query', array( $this, 'translate_category' ), 10, 2 );
27
  }
28
 
29
 
@@ -35,7 +36,7 @@ class WCML_WC_Shortcode_Product_Category {
35
  */
36
  public function translate_category( $args, $atts = null ) {
37
 
38
- if( $this->sitepress->get_default_language() !== $this->sitepress->get_current_language() ) {
39
 
40
  if ( isset( $args['product_cat'] ) ) {
41
  $args = $this->translate_categories_using_simple_tax_query( $args );
@@ -49,7 +50,10 @@ class WCML_WC_Shortcode_Product_Category {
49
  };
50
 
51
  $categories = wpml_collect( explode( ',', $atts['category'] ) )
52
- ->map( function( $slugOrId ) { return trim( $slugOrId ); } )
 
 
 
53
  ->filter()
54
  ->map( $getProductCategoryObject );
55
 
@@ -66,12 +70,12 @@ class WCML_WC_Shortcode_Product_Category {
66
  *
67
  * @return array
68
  */
69
- private function replace_category_in_query_arguments( array $args, Collection $terms ){
70
 
71
  foreach ( $args['tax_query'] as $i => $tax_query ) {
72
- $args['tax_query'][ $i ] = array();
73
  if ( ! is_int( key( $tax_query ) ) ) {
74
- $tax_query = array( $tax_query );
75
  }
76
  foreach ( $tax_query as $j => $condition ) {
77
  if ( 'product_cat' === $condition['taxonomy'] ) {
@@ -93,13 +97,18 @@ class WCML_WC_Shortcode_Product_Category {
93
 
94
  $category_slugs = array_map( 'trim', explode( ',', $args['product_cat'] ) );
95
 
96
- $filter_exists = remove_filter( 'terms_clauses', array( $this->sitepress, 'terms_clauses' ), 10 );
97
- $categories_translated = get_terms( array( 'slug' => $category_slugs, 'taxonomy' => 'product_cat' ) );
 
 
 
 
 
98
  if ( $filter_exists ) {
99
- add_filter( 'terms_clauses', array( $this->sitepress, 'terms_clauses' ), 10, 3 );
100
  }
101
 
102
- $category_slugs_translated = array();
103
  foreach ( $categories_translated as $category_translated ) {
104
  $category_slugs_translated[] = $category_translated->slug;
105
  }
4
 
5
  /**
6
  * Class WCML_WC_Shortcode_Product_Category
7
+ *
8
  * @since 4.2.2
9
  */
10
  class WCML_WC_Shortcode_Product_Category {
24
  }
25
 
26
  public function add_hooks() {
27
+ add_filter( 'woocommerce_shortcode_products_query', [ $this, 'translate_category' ], 10, 2 );
28
  }
29
 
30
 
36
  */
37
  public function translate_category( $args, $atts = null ) {
38
 
39
+ if ( $this->sitepress->get_default_language() !== $this->sitepress->get_current_language() ) {
40
 
41
  if ( isset( $args['product_cat'] ) ) {
42
  $args = $this->translate_categories_using_simple_tax_query( $args );
50
  };
51
 
52
  $categories = wpml_collect( explode( ',', $atts['category'] ) )
53
+ ->map(
54
+ function( $slugOrId ) {
55
+ return trim( $slugOrId ); }
56
+ )
57
  ->filter()
58
  ->map( $getProductCategoryObject );
59
 
70
  *
71
  * @return array
72
  */
73
+ private function replace_category_in_query_arguments( array $args, Collection $terms ) {
74
 
75
  foreach ( $args['tax_query'] as $i => $tax_query ) {
76
+ $args['tax_query'][ $i ] = [];
77
  if ( ! is_int( key( $tax_query ) ) ) {
78
+ $tax_query = [ $tax_query ];
79
  }
80
  foreach ( $tax_query as $j => $condition ) {
81
  if ( 'product_cat' === $condition['taxonomy'] ) {
97
 
98
  $category_slugs = array_map( 'trim', explode( ',', $args['product_cat'] ) );
99
 
100
+ $filter_exists = remove_filter( 'terms_clauses', [ $this->sitepress, 'terms_clauses' ], 10 );
101
+ $categories_translated = get_terms(
102
+ [
103
+ 'slug' => $category_slugs,
104
+ 'taxonomy' => 'product_cat',
105
+ ]
106
+ );
107
  if ( $filter_exists ) {
108
+ add_filter( 'terms_clauses', [ $this->sitepress, 'terms_clauses' ], 10, 3 );
109
  }
110
 
111
+ $category_slugs_translated = [];
112
  foreach ( $categories_translated as $category_translated ) {
113
  $category_slugs_translated[] = $category_translated->slug;
114
  }
classes/taxonomy-translation/class-wcml-taxonomy-translation-link-filters.php CHANGED
@@ -1,6 +1,6 @@
1
  <?php
2
 
3
- class WCML_Taxonomy_Translation_Link_Filters{
4
 
5
  /**
6
  * @var WCML_Attributes
@@ -11,30 +11,30 @@ class WCML_Taxonomy_Translation_Link_Filters{
11
  $this->wcml_attributes = $wcml_attributes;
12
  }
13
 
14
- public function add_filters(){
15
- add_filter( 'wpml_notice_text', array( $this, 'override_translation_notice_text' ), 10, 2 );
16
- add_filter( 'wpml_taxonomy_slug_translation_ui', array( $this, 'slug_translation_ui_class' ), 10, 2 );
17
  }
18
 
19
  /**
20
  * @param string text
21
- * @param array $notice
22
  *
23
  * @return string
24
  */
25
  public function override_translation_notice_text( $text, $notice ) {
26
- if( 'taxonomy-term-help-notices' === $notice['group'] ) {
27
  $taxonomy = get_taxonomy( $notice['id'] );
28
  if ( false !== $taxonomy ) {
29
 
30
- $link = sprintf(
31
- '<a href="%s">%s</a>',
32
- $this->get_screen_url( $taxonomy->name ),
33
- sprintf( esc_html__( '%s translation', 'woocommerce-multilingual' ), $taxonomy->labels->singular_name )
34
- );
35
 
36
  $text = sprintf(
37
- esc_html__( 'Translating %s? Use the %s table for easier translation.', 'woocommerce-multilingual' ),
38
  $taxonomy->labels->name,
39
  $link
40
  );
@@ -53,9 +53,9 @@ class WCML_Taxonomy_Translation_Link_Filters{
53
  $url = false;
54
 
55
  $base_url = admin_url( 'admin.php' );
56
- $args = array( 'page' => 'wpml-wcml' );
57
 
58
- $built_in_taxonomies = array( 'product_cat', 'product_tag', 'product_shipping_class' );
59
  if ( in_array( $taxonomy, $built_in_taxonomies, true ) ) {
60
  $args['tab'] = $taxonomy;
61
  } else {
@@ -68,7 +68,7 @@ class WCML_Taxonomy_Translation_Link_Filters{
68
  } else {
69
  $custom_taxonomies = get_object_taxonomies( 'product', 'objects' );
70
 
71
- $translatable_taxonomies = array();
72
  foreach ( $custom_taxonomies as $product_taxonomy_name => $product_taxonomy_object ) {
73
  if ( is_taxonomy_translated( $product_taxonomy_name ) ) {
74
  $translatable_taxonomies[] = $product_taxonomy_name;
@@ -90,9 +90,9 @@ class WCML_Taxonomy_Translation_Link_Filters{
90
  }
91
 
92
 
93
- private function get_translatable_attributes(){
94
 
95
- $translatable_attributes = array();
96
  foreach ( $this->wcml_attributes->get_translatable_attributes() as $attribute ) {
97
  $translatable_attributes[] = 'pa_' . $attribute->attribute_name;
98
  }
@@ -100,9 +100,9 @@ class WCML_Taxonomy_Translation_Link_Filters{
100
  return $translatable_attributes;
101
  }
102
 
103
- public function slug_translation_ui_class( $ui_class, $taxonomy ){
104
 
105
- if( in_array( $taxonomy, $this->get_translatable_attributes() ) ){
106
 
107
  $ui_class = new WCML_St_Taxonomy_UI( get_taxonomy( $taxonomy ) );
108
  }
1
  <?php
2
 
3
+ class WCML_Taxonomy_Translation_Link_Filters {
4
 
5
  /**
6
  * @var WCML_Attributes
11
  $this->wcml_attributes = $wcml_attributes;
12
  }
13
 
14
+ public function add_filters() {
15
+ add_filter( 'wpml_notice_text', [ $this, 'override_translation_notice_text' ], 10, 2 );
16
+ add_filter( 'wpml_taxonomy_slug_translation_ui', [ $this, 'slug_translation_ui_class' ], 10, 2 );
17
  }
18
 
19
  /**
20
  * @param string text
21
+ * @param array $notice
22
  *
23
  * @return string
24
  */
25
  public function override_translation_notice_text( $text, $notice ) {
26
+ if ( 'taxonomy-term-help-notices' === $notice['group'] ) {
27
  $taxonomy = get_taxonomy( $notice['id'] );
28
  if ( false !== $taxonomy ) {
29
 
30
+ $link = sprintf(
31
+ '<a href="%s">%s</a>',
32
+ $this->get_screen_url( $taxonomy->name ),
33
+ sprintf( esc_html__( '%s translation', 'woocommerce-multilingual' ), $taxonomy->labels->singular_name )
34
+ );
35
 
36
  $text = sprintf(
37
+ esc_html__( 'Translating %1$s? Use the %2$s table for easier translation.', 'woocommerce-multilingual' ),
38
  $taxonomy->labels->name,
39
  $link
40
  );
53
  $url = false;
54
 
55
  $base_url = admin_url( 'admin.php' );
56
+ $args = [ 'page' => 'wpml-wcml' ];
57
 
58
+ $built_in_taxonomies = [ 'product_cat', 'product_tag', 'product_shipping_class' ];
59
  if ( in_array( $taxonomy, $built_in_taxonomies, true ) ) {
60
  $args['tab'] = $taxonomy;
61
  } else {
68
  } else {
69
  $custom_taxonomies = get_object_taxonomies( 'product', 'objects' );
70
 
71
+ $translatable_taxonomies = [];
72
  foreach ( $custom_taxonomies as $product_taxonomy_name => $product_taxonomy_object ) {
73
  if ( is_taxonomy_translated( $product_taxonomy_name ) ) {
74
  $translatable_taxonomies[] = $product_taxonomy_name;
90
  }
91
 
92
 
93
+ private function get_translatable_attributes() {
94
 
95
+ $translatable_attributes = [];
96
  foreach ( $this->wcml_attributes->get_translatable_attributes() as $attribute ) {
97
  $translatable_attributes[] = 'pa_' . $attribute->attribute_name;
98
  }
100
  return $translatable_attributes;
101
  }
102
 
103
+ public function slug_translation_ui_class( $ui_class, $taxonomy ) {
104
 
105
+ if ( in_array( $taxonomy, $this->get_translatable_attributes() ) ) {
106
 
107
  $ui_class = new WCML_St_Taxonomy_UI( get_taxonomy( $taxonomy ) );
108
  }
classes/url-filters/class-wcml-url-filters-redirect-location.php CHANGED
@@ -12,10 +12,10 @@ class WCML_Url_Filters_Redirect_Location {
12
  }
13
 
14
  public function add_hooks() {
15
- $hooks = array( 'woocommerce_get_checkout_payment_url', 'woocommerce_get_cancel_order_url', 'woocommerce_get_return_url' );
16
 
17
  foreach ( $hooks as $hook ) {
18
- add_filter( $hook, array( $this, 'filter' ), 10, 1 );
19
  }
20
  }
21
 
12
  }
13
 
14
  public function add_hooks() {
15
+ $hooks = [ 'woocommerce_get_checkout_payment_url', 'woocommerce_get_cancel_order_url', 'woocommerce_get_return_url' ];
16
 
17
  foreach ( $hooks as $hook ) {
18
+ add_filter( $hook, [ $this, 'filter' ], 10, 1 );
19
  }
20
  }
21
 
classes/urls/class-wcml-xdomain-data.php CHANGED
@@ -3,7 +3,6 @@
3
  /**
4
  * Handles data being passed between different domains using WPML xDomain logic
5
  * https://wpml.org/?page_id=693147
6
- *
7
  */
8
  class WCML_xDomain_Data {
9
 
@@ -22,8 +21,8 @@ class WCML_xDomain_Data {
22
  }
23
 
24
  public function add_hooks() {
25
- add_filter( 'wpml_cross_domain_language_data', array( $this, 'pass_data_to_domain' ) );
26
- add_action( 'before_woocommerce_init', array( $this, 'check_request' ) );
27
  }
28
 
29
  /**
@@ -35,7 +34,7 @@ class WCML_xDomain_Data {
35
 
36
  $wcml_session_id = md5( microtime() . uniqid( mt_rand(), true ) );
37
  $data['wcsid'] = $wcml_session_id;
38
- $session_data = array();
39
 
40
  if ( isset( $_COOKIE[ 'wp_woocommerce_session_' . COOKIEHASH ] ) ) {
41
  $session_data['session'] = $_COOKIE[ 'wp_woocommerce_session_' . COOKIEHASH ];
@@ -55,8 +54,8 @@ class WCML_xDomain_Data {
55
 
56
  public function check_request() {
57
 
58
- if ( has_filter( 'wpml_get_cross_domain_language_data' ) ) { // After WPML 3.2.7
59
- $xdomain_data = apply_filters( 'wpml_get_cross_domain_language_data', array() );
60
  } elseif ( isset( $_GET['xdomain_data'] ) ) {
61
  $xdomain_data = json_decode( base64_decode( $_GET['xdomain_data'] ), true );
62
  }
@@ -76,7 +75,7 @@ class WCML_xDomain_Data {
76
 
77
  if ( ! empty( $data ) ) {
78
 
79
- $session_expiration = time() + (int) apply_filters( 'wc_session_expiration', 60 * 60 * 48 ); // 48 Hours
80
  $secure = apply_filters( 'wc_session_use_secure_cookie', false );
81
 
82
  if ( isset( $data['session'] ) ) {
@@ -90,7 +89,6 @@ class WCML_xDomain_Data {
90
  $_COOKIE['woocommerce_cart_hash'] = $data['hash'];
91
  $_COOKIE['woocommerce_items_in_cart'] = $data['items'];
92
  }
93
-
94
  }
95
 
96
  delete_option( 'wcml_session_data_' . $wcml_session_id );
3
  /**
4
  * Handles data being passed between different domains using WPML xDomain logic
5
  * https://wpml.org/?page_id=693147
 
6
  */
7
  class WCML_xDomain_Data {
8
 
21
  }
22
 
23
  public function add_hooks() {
24
+ add_filter( 'wpml_cross_domain_language_data', [ $this, 'pass_data_to_domain' ] );
25
+ add_action( 'before_woocommerce_init', [ $this, 'check_request' ] );
26
  }
27
 
28
  /**
34
 
35
  $wcml_session_id = md5( microtime() . uniqid( mt_rand(), true ) );
36
  $data['wcsid'] = $wcml_session_id;
37
+ $session_data = [];
38
 
39
  if ( isset( $_COOKIE[ 'wp_woocommerce_session_' . COOKIEHASH ] ) ) {
40
  $session_data['session'] = $_COOKIE[ 'wp_woocommerce_session_' . COOKIEHASH ];
54
 
55
  public function check_request() {
56
 
57
+ if ( has_filter( 'wpml_get_cross_domain_language_data' ) ) { // After WPML 3.2.7.
58
+ $xdomain_data = apply_filters( 'wpml_get_cross_domain_language_data', [] );
59
  } elseif ( isset( $_GET['xdomain_data'] ) ) {
60
  $xdomain_data = json_decode( base64_decode( $_GET['xdomain_data'] ), true );
61
  }
75
 
76
  if ( ! empty( $data ) ) {
77
 
78
+ $session_expiration = time() + (int) apply_filters( 'wc_session_expiration', 60 * 60 * 48 ); // 48 Hours.
79
  $secure = apply_filters( 'wc_session_use_secure_cookie', false );
80
 
81
  if ( isset( $data['session'] ) ) {
89
  $_COOKIE['woocommerce_cart_hash'] = $data['hash'];
90
  $_COOKIE['woocommerce_items_in_cart'] = $data['items'];
91
  }
 
92
  }
93
 
94
  delete_option( 'wcml_session_data_' . $wcml_session_id );
classes/wcml-setup/class-wcml-setup-handlers.php CHANGED
@@ -41,25 +41,25 @@ class WCML_Setup_Handlers {
41
 
42
  }
43
 
44
- public function save_translation_options( $data ){
45
 
46
  if ( isset( $data['translation-option'] ) ) {
47
 
48
  $settings_helper = wpml_load_settings_helper();
49
 
50
- if( 1 === (int) $data['translation-option'] ){
51
  $settings_helper->set_post_type_display_as_translated( 'product' );
52
  $settings_helper->set_post_type_translation_unlocked_option( 'product' );
53
- $settings_helper->set_taxonomy_display_as_translated('product_cat' );
54
  $settings_helper->set_taxonomy_translation_unlocked_option( 'product_cat' );
55
- }else{
56
  $settings_helper->set_post_type_translatable( 'product' );
57
  $settings_helper->set_post_type_translation_unlocked_option( 'product', false );
58
- $settings_helper->set_taxonomy_translatable('product_cat' );
59
  $settings_helper->set_taxonomy_translation_unlocked_option( 'product_cat', false );
60
  }
61
  }
62
  }
63
 
64
 
65
- }
41
 
42
  }
43
 
44
+ public function save_translation_options( $data ) {
45
 
46
  if ( isset( $data['translation-option'] ) ) {
47
 
48
  $settings_helper = wpml_load_settings_helper();
49
 
50
+ if ( 1 === (int) $data['translation-option'] ) {
51
  $settings_helper->set_post_type_display_as_translated( 'product' );
52
  $settings_helper->set_post_type_translation_unlocked_option( 'product' );
53
+ $settings_helper->set_taxonomy_display_as_translated( 'product_cat' );
54
  $settings_helper->set_taxonomy_translation_unlocked_option( 'product_cat' );
55
+ } else {
56
  $settings_helper->set_post_type_translatable( 'product' );
57
  $settings_helper->set_post_type_translation_unlocked_option( 'product', false );
58
+ $settings_helper->set_taxonomy_translatable( 'product_cat' );
59
  $settings_helper->set_taxonomy_translation_unlocked_option( 'product_cat', false );
60
  }
61
  }
62
  }
63
 
64
 
65
+ }
classes/wcml-setup/class-wcml-setup-ui.php CHANGED
@@ -14,32 +14,32 @@ class WCML_Setup_UI {
14
  $this->woocommerce_wpml = $woocommerce_wpml;
15
  }
16
 
17
- public function add_hooks(){
18
  if ( current_user_can( 'manage_options' ) && $this->is_wcml_setup_page() ) {
19
- add_action( 'admin_menu', array( $this, 'admin_menus' ) );
20
  }
21
- }
22
 
23
  public function add_wizard_notice_hook() {
24
-
25
  if ( $this->must_display_the_wizard() ) {
26
- add_filter( 'admin_notices', array( $this, 'wizard_notice' ) );
27
  }
28
  }
29
-
30
  /**
31
  * @return bool
32
  */
33
  private function must_display_the_wizard() {
34
  global $pagenow;
35
-
36
- $allowed_pages = array('index.php', 'plugins.php');
37
-
38
  return in_array( $pagenow, $allowed_pages, true )
39
- || ( isset( $_GET['page'] ) && 'wpml-wcml' === $_GET['page'] );
40
  }
41
-
42
-
43
  /**
44
  * @return bool
45
  */
@@ -52,60 +52,78 @@ class WCML_Setup_UI {
52
  }
53
 
54
  /**
55
- * @param array $steps
56
  * @param string $step
 
 
 
 
57
  */
58
  public function setup_header( $steps, $step ) {
59
  set_current_screen( 'wcml-setup' );
60
  $header = new WCML_Setup_Header_UI( $steps, $step );
 
61
  echo $header->get_view();
62
  }
63
 
64
  /**
65
- * @param array $steps
66
  * @param string $current_step
67
  */
68
  public function setup_steps( array $steps, $current_step ) {
69
  $step_keys = array_keys( $steps );
70
  array_shift( $steps );
71
  ?>
72
- <ol class="wcml-setup-steps">
73
  <?php foreach ( $steps as $step_key => $step ) : ?>
74
- <li class="<?php
 
75
  if ( $step_key === $current_step ) {
76
  echo 'active';
77
  } elseif ( array_search( $current_step, $step_keys ) > array_search( $step_key, $step_keys ) ) {
78
  echo 'done';
79
  }
80
- ?>"><?php echo esc_html( $step['name'] ); ?></li>
 
81
  <?php endforeach; ?>
82
- </ol>
83
  <?php
84
  }
85
 
86
- /**
87
- * @param mixed $view
88
- */
89
- public function setup_content( $view ){
90
 
91
- echo '<div class="wcml-setup-content">';
92
- echo $view->get_view();
93
- echo '</div>';
 
94
 
95
- }
96
 
97
  /**
98
  * @param bool $has_handler
 
 
 
 
99
  */
100
  public function setup_footer( $has_handler = false ) {
101
  $footer = new WCML_Setup_Footer_UI( $has_handler );
 
102
  echo $footer->get_view();
103
  }
104
 
 
 
 
 
 
105
  public function wizard_notice() {
106
  wp_enqueue_style( 'wcml-setup-wizard-notice', WCML_PLUGIN_URL . '/res/css/wcml-setup-wizard-notice.css' );
107
  $notice = new WCML_Setup_Notice_UI();
 
108
  echo $notice->get_view();
109
  }
110
-
111
- }
14
  $this->woocommerce_wpml = $woocommerce_wpml;
15
  }
16
 
17
+ public function add_hooks() {
18
  if ( current_user_can( 'manage_options' ) && $this->is_wcml_setup_page() ) {
19
+ add_action( 'admin_menu', [ $this, 'admin_menus' ] );
20
  }
21
+ }
22
 
23
  public function add_wizard_notice_hook() {
24
+
25
  if ( $this->must_display_the_wizard() ) {
26
+ add_filter( 'admin_notices', [ $this, 'wizard_notice' ] );
27
  }
28
  }
29
+
30
  /**
31
  * @return bool
32
  */
33
  private function must_display_the_wizard() {
34
  global $pagenow;
35
+
36
+ $allowed_pages = [ 'index.php', 'plugins.php' ];
37
+
38
  return in_array( $pagenow, $allowed_pages, true )
39
+ || ( isset( $_GET['page'] ) && 'wpml-wcml' === $_GET['page'] );
40
  }
41
+
42
+
43
  /**
44
  * @return bool
45
  */
52
  }
53
 
54
  /**
55
+ * @param array $steps
56
  * @param string $step
57
+ *
58
+ * @throws \WPML\Core\Twig_Error_Loader Exception.
59
+ * @throws \WPML\Core\Twig_Error_Runtime Exception.
60
+ * @throws \WPML\Core\Twig_Error_Syntax Exception.
61
  */
62
  public function setup_header( $steps, $step ) {
63
  set_current_screen( 'wcml-setup' );
64
  $header = new WCML_Setup_Header_UI( $steps, $step );
65
+ // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
66
  echo $header->get_view();
67
  }
68
 
69
  /**
70
+ * @param array $steps
71
  * @param string $current_step
72
  */
73
  public function setup_steps( array $steps, $current_step ) {
74
  $step_keys = array_keys( $steps );
75
  array_shift( $steps );
76
  ?>
77
+ <ol class="wcml-setup-steps">
78
  <?php foreach ( $steps as $step_key => $step ) : ?>
79
+ <li class="
80
+ <?php
81
  if ( $step_key === $current_step ) {
82
  echo 'active';
83
  } elseif ( array_search( $current_step, $step_keys ) > array_search( $step_key, $step_keys ) ) {
84
  echo 'done';
85
  }
86
+ ?>
87
+ "><?php echo esc_html( $step['name'] ); ?></li>
88
  <?php endforeach; ?>
89
+ </ol>
90
  <?php
91
  }
92
 
93
+ /**
94
+ * @param mixed $view
95
+ */
96
+ public function setup_content( $view ) {
97
 
98
+ echo '<div class="wcml-setup-content">';
99
+ // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
100
+ echo $view->get_view();
101
+ echo '</div>';
102
 
103
+ }
104
 
105
  /**
106
  * @param bool $has_handler
107
+ *
108
+ * @throws \WPML\Core\Twig_Error_Loader Exception.
109
+ * @throws \WPML\Core\Twig_Error_Runtime Exception.
110
+ * @throws \WPML\Core\Twig_Error_Syntax Exception.
111
  */
112
  public function setup_footer( $has_handler = false ) {
113
  $footer = new WCML_Setup_Footer_UI( $has_handler );
114
+ // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
115
  echo $footer->get_view();
116
  }
117
 
118
+ /**
119
+ * @throws \WPML\Core\Twig_Error_Loader Exception.
120
+ * @throws \WPML\Core\Twig_Error_Runtime Exception.
121
+ * @throws \WPML\Core\Twig_Error_Syntax Exception.
122
+ */
123
  public function wizard_notice() {
124
  wp_enqueue_style( 'wcml-setup-wizard-notice', WCML_PLUGIN_URL . '/res/css/wcml-setup-wizard-notice.css' );
125
  $notice = new WCML_Setup_Notice_UI();
126
+ // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
127
  echo $notice->get_view();
128
  }
129
+ }
 
classes/wcml-setup/class-wcml-setup.php CHANGED
@@ -23,10 +23,10 @@ class WCML_Setup {
23
  /**
24
  * WCML_Setup constructor.
25
  *
26
- * @param WCML_Setup_UI $ui
27
  * @param WCML_Setup_Handlers $handlers
28
- * @param woocommerce_wpml $woocommerce_wpml
29
- * @param SitePress $sitepress
30
  */
31
  public function __construct( WCML_Setup_UI $ui, WCML_Setup_Handlers $handlers, woocommerce_wpml $woocommerce_wpml, SitePress $sitepress ) {
32
 
@@ -35,76 +35,73 @@ class WCML_Setup {
35
  $this->woocommerce_wpml = $woocommerce_wpml;
36
  $this->sitepress = $sitepress;
37
 
38
- $this->steps = array(
39
- 'introduction' => array(
40
  'name' => __( 'Introduction', 'woocommerce-multilingual' ),
41
  'view' => new WCML_Setup_Introduction_UI(
42
  $this->woocommerce_wpml,
43
  $this->step_url( 'store-pages' )
44
  ),
45
- 'handler' => ''
46
- ),
47
- 'store-pages' => array(
48
  'name' => __( 'Store Pages', 'woocommerce-multilingual' ),
49
  'view' => new WCML_Setup_Store_Pages_UI(
50
  $this->woocommerce_wpml,
51
  $this->sitepress,
52
  $this->step_url( 'attributes' )
53
  ),
54
- 'handler' => array( $this->handlers, 'install_store_pages' ),
55
- ),
56
- 'attributes' => array(
57
  'name' => __( 'Global Attributes', 'woocommerce-multilingual' ),
58
  'view' => new WCML_Setup_Attributes_UI(
59
  $this->woocommerce_wpml,
60
  $this->step_url( 'multi-currency' )
61
  ),
62
- 'handler' => array( $this->handlers, 'save_attributes' )
63
- ),
64
- 'multi-currency' => array(
65
  'name' => __( 'Multiple Currencies', 'woocommerce-multilingual' ),
66
  'view' => new WCML_Setup_Multi_Currency_UI(
67
  $this->woocommerce_wpml,
68
  $this->step_url( 'translation-options' )
69
  ),
70
- 'handler' => array( $this->handlers, 'save_multi_currency' )
71
- )
72
- );
73
-
74
 
75
- $this->steps['translation-options'] = array(
76
- 'name' => __( 'Translation Options', 'woocommerce-multilingual' ),
77
  'view' => new WCML_Setup_Translation_Options_UI(
78
  $this->woocommerce_wpml,
79
  $this->step_url( 'ready' )
80
  ),
81
- 'handler' => array( $this->handlers, 'save_translation_options' )
82
- );
83
 
84
-
85
- $this->steps['ready'] = array(
86
  'name' => __( 'Ready!', 'woocommerce-multilingual' ),
87
  'view' => new WCML_Setup_Ready_UI( $this->woocommerce_wpml ),
88
- 'handler' => ''
89
- );
90
-
91
 
92
  }
93
 
94
  public function add_hooks() {
95
  if ( current_user_can( 'manage_options' ) ) {
96
- add_action( 'admin_init', array( $this, 'wizard' ) );
97
- add_action( 'admin_init', array( $this, 'handle_steps' ), 0 );
98
- add_filter( 'wp_redirect', array( $this, 'redirect_filters' ) );
99
  }
100
 
101
  if ( ! $this->has_completed() ) {
102
  $this->ui->add_wizard_notice_hook();
103
- add_action( 'admin_init', array( $this, 'skip_setup' ), 1 );
104
  }
105
  }
106
 
107
- public function exit_wrapper(){
108
  exit;
109
  }
110
 
@@ -114,7 +111,7 @@ class WCML_Setup {
114
 
115
  if ( ! $this->do_not_redirect_to_setup() && ! $this->has_completed() ) {
116
  wp_safe_redirect( admin_url( 'index.php?page=wcml-setup' ) );
117
- add_filter( 'wp_die_handler', array( $this, 'exit_wrapper' ) );
118
  wp_die();
119
  }
120
  }
@@ -122,14 +119,14 @@ class WCML_Setup {
122
 
123
  private function do_not_redirect_to_setup() {
124
 
125
- $woocommerce_notices = get_option( 'woocommerce_admin_notices', array() );
126
  $woocommerce_setup_not_run = in_array( 'install', $woocommerce_notices, true );
127
 
128
  return $this->is_wcml_setup_page() ||
129
- is_network_admin() ||
130
- isset( $_GET['activate-multi'] ) ||
131
- ! current_user_can( 'manage_options' ) ||
132
- $woocommerce_setup_not_run;
133
 
134
  }
135
 
@@ -151,24 +148,28 @@ class WCML_Setup {
151
 
152
  $this->splash_wizard_on_wcml_pages();
153
 
154
- if ( ! $this->is_wcml_setup_page() ){
155
  return;
156
  }
157
 
158
  $this->step = isset( $_GET['step'] ) ? sanitize_key( $_GET['step'] ) : current( array_keys( $this->steps ) );
159
 
160
  wp_enqueue_style( 'otgs-ico', ICL_PLUGIN_URL . '/res/css/otgs-ico.css', null, ICL_SITEPRESS_VERSION );
161
- wp_enqueue_style( 'wcml-setup', WCML_PLUGIN_URL . '/res/css/wcml-setup.css', array(
162
- 'dashicons',
163
- 'install'
164
- ), WCML_VERSION );
165
-
166
- wp_enqueue_script( 'wcml-setup', WCML_PLUGIN_URL . '/res/js/wcml-setup.js', array( 'jquery' ), WCML_VERSION, true );
 
 
 
167
 
 
168
 
169
  $this->ui->setup_header( $this->steps, $this->step );
170
 
171
- $steps_keys = array_keys( $this->steps );
172
  $step_index = array_search( $this->step, $steps_keys );
173
  $this->next_step = isset( $steps_keys[ $step_index + 1 ] ) ? $steps_keys[ $step_index + 1 ] : '';
174
 
@@ -176,7 +177,7 @@ class WCML_Setup {
176
  $this->ui->setup_content( $this->steps[ $this->step ]['view'] );
177
  $this->ui->setup_footer( ! empty( $this->steps[ $this->step ]['handler'] ) );
178
 
179
- if ( $this->step == 'ready' ) {
180
  $this->complete_setup();
181
  }
182
 
@@ -185,14 +186,14 @@ class WCML_Setup {
185
 
186
  private function splash_wizard_on_wcml_pages() {
187
 
188
- if ( isset( $_GET['src'] ) && $_GET['src'] == 'setup_later' ) {
189
  $this->woocommerce_wpml->settings['set_up_wizard_splash'] = 1;
190
  $this->woocommerce_wpml->update_settings();
191
  }
192
 
193
  if ( $this->is_wcml_admin_page() && ! $this->has_completed() && empty( $this->woocommerce_wpml->settings['set_up_wizard_splash'] ) ) {
194
  wp_redirect( 'admin.php?page=wcml-setup' );
195
- add_filter( 'wp_die_handler', array( $this, 'exit_wrapper' ) );
196
  wp_die();
197
  }
198
  }
@@ -201,7 +202,7 @@ class WCML_Setup {
201
 
202
  if ( isset( $_GET['wcml-setup-skip'] ) && isset( $_GET['_wcml_setup_nonce'] ) ) {
203
  if ( ! wp_verify_nonce( $_GET['_wcml_setup_nonce'], 'wcml_setup_skip_nonce' ) ) {
204
- wp_die( __( 'Action failed. Please refresh the page and retry.', 'woocommerce-multilingual' ) );
205
  }
206
 
207
  if ( ! current_user_can( 'manage_options' ) ) {
@@ -209,7 +210,7 @@ class WCML_Setup {
209
  }
210
 
211
  $this->complete_setup();
212
- remove_filter( 'admin_notices', array( $this->ui, 'wizard_notice' ) );
213
 
214
  delete_transient( '_wcml_activation_redirect' );
215
  }
@@ -243,7 +244,7 @@ class WCML_Setup {
243
  *
244
  * @return string
245
  */
246
- private function step_url( $step ){
247
  $url = admin_url( 'admin.php?page=wcml-setup&step=' . $step );
248
  return $url;
249
  }
@@ -267,10 +268,10 @@ class WCML_Setup {
267
  }
268
 
269
  public function handle_steps() {
270
- if ( isset( $_POST['handle_step'] ) && $_POST['nonce'] == wp_create_nonce( $_POST['handle_step'] ) ) {
271
  $step_name = sanitize_text_field( $_POST['handle_step'] );
272
  if ( $handler = $this->get_handler( $step_name ) ) {
273
- if( is_callable( $handler, true ) ){
274
  call_user_func( $handler, $_POST );
275
  }
276
  }
23
  /**
24
  * WCML_Setup constructor.
25
  *
26
+ * @param WCML_Setup_UI $ui
27
  * @param WCML_Setup_Handlers $handlers
28
+ * @param woocommerce_wpml $woocommerce_wpml
29
+ * @param SitePress $sitepress
30
  */
31
  public function __construct( WCML_Setup_UI $ui, WCML_Setup_Handlers $handlers, woocommerce_wpml $woocommerce_wpml, SitePress $sitepress ) {
32
 
35
  $this->woocommerce_wpml = $woocommerce_wpml;
36
  $this->sitepress = $sitepress;
37
 
38
+ $this->steps = [
39
+ 'introduction' => [
40
  'name' => __( 'Introduction', 'woocommerce-multilingual' ),
41
  'view' => new WCML_Setup_Introduction_UI(
42
  $this->woocommerce_wpml,
43
  $this->step_url( 'store-pages' )
44
  ),
45
+ 'handler' => '',
46
+ ],
47
+ 'store-pages' => [
48
  'name' => __( 'Store Pages', 'woocommerce-multilingual' ),
49
  'view' => new WCML_Setup_Store_Pages_UI(
50
  $this->woocommerce_wpml,
51
  $this->sitepress,
52
  $this->step_url( 'attributes' )
53
  ),
54
+ 'handler' => [ $this->handlers, 'install_store_pages' ],
55
+ ],
56
+ 'attributes' => [
57
  'name' => __( 'Global Attributes', 'woocommerce-multilingual' ),
58
  'view' => new WCML_Setup_Attributes_UI(
59
  $this->woocommerce_wpml,
60
  $this->step_url( 'multi-currency' )
61
  ),
62
+ 'handler' => [ $this->handlers, 'save_attributes' ],
63
+ ],
64
+ 'multi-currency' => [
65
  'name' => __( 'Multiple Currencies', 'woocommerce-multilingual' ),
66
  'view' => new WCML_Setup_Multi_Currency_UI(
67
  $this->woocommerce_wpml,
68
  $this->step_url( 'translation-options' )
69
  ),
70
+ 'handler' => [ $this->handlers, 'save_multi_currency' ],
71
+ ],
72
+ ];
 
73
 
74
+ $this->steps['translation-options'] = [
75
+ 'name' => __( 'Translation Options', 'woocommerce-multilingual' ),
76
  'view' => new WCML_Setup_Translation_Options_UI(
77
  $this->woocommerce_wpml,
78
  $this->step_url( 'ready' )
79
  ),
80
+ 'handler' => [ $this->handlers, 'save_translation_options' ],
81
+ ];
82
 
83
+ $this->steps['ready'] = [
 
84
  'name' => __( 'Ready!', 'woocommerce-multilingual' ),
85
  'view' => new WCML_Setup_Ready_UI( $this->woocommerce_wpml ),
86
+ 'handler' => '',
87
+ ];
 
88
 
89
  }
90
 
91
  public function add_hooks() {
92
  if ( current_user_can( 'manage_options' ) ) {
93
+ add_action( 'admin_init', [ $this, 'wizard' ] );
94
+ add_action( 'admin_init', [ $this, 'handle_steps' ], 0 );
95
+ add_filter( 'wp_redirect', [ $this, 'redirect_filters' ] );
96
  }
97
 
98
  if ( ! $this->has_completed() ) {
99
  $this->ui->add_wizard_notice_hook();
100
+ add_action( 'admin_init', [ $this, 'skip_setup' ], 1 );
101
  }
102
  }
103
 
104
+ public function exit_wrapper() {
105
  exit;
106
  }
107
 
111
 
112
  if ( ! $this->do_not_redirect_to_setup() && ! $this->has_completed() ) {
113
  wp_safe_redirect( admin_url( 'index.php?page=wcml-setup' ) );
114
+ add_filter( 'wp_die_handler', [ $this, 'exit_wrapper' ] );
115
  wp_die();
116
  }
117
  }
119
 
120
  private function do_not_redirect_to_setup() {
121
 
122
+ $woocommerce_notices = get_option( 'woocommerce_admin_notices', [] );
123
  $woocommerce_setup_not_run = in_array( 'install', $woocommerce_notices, true );
124
 
125
  return $this->is_wcml_setup_page() ||
126
+ is_network_admin() ||
127
+ isset( $_GET['activate-multi'] ) ||
128
+ ! current_user_can( 'manage_options' ) ||
129
+ $woocommerce_setup_not_run;
130
 
131
  }
132
 
148
 
149
  $this->splash_wizard_on_wcml_pages();
150
 
151
+ if ( ! $this->is_wcml_setup_page() ) {
152
  return;
153
  }
154
 
155
  $this->step = isset( $_GET['step'] ) ? sanitize_key( $_GET['step'] ) : current( array_keys( $this->steps ) );
156
 
157
  wp_enqueue_style( 'otgs-ico', ICL_PLUGIN_URL . '/res/css/otgs-ico.css', null, ICL_SITEPRESS_VERSION );
158
+ wp_enqueue_style(
159
+ 'wcml-setup',
160
+ WCML_PLUGIN_URL . '/res/css/wcml-setup.css',
161
+ [
162
+ 'dashicons',
163
+ 'install',
164
+ ],
165
+ WCML_VERSION
166
+ );
167
 
168
+ wp_enqueue_script( 'wcml-setup', WCML_PLUGIN_URL . '/res/js/wcml-setup.js', [ 'jquery' ], WCML_VERSION, true );
169
 
170
  $this->ui->setup_header( $this->steps, $this->step );
171
 
172
+ $steps_keys = array_keys( $this->steps );
173
  $step_index = array_search( $this->step, $steps_keys );
174
  $this->next_step = isset( $steps_keys[ $step_index + 1 ] ) ? $steps_keys[ $step_index + 1 ] : '';
175
 
177
  $this->ui->setup_content( $this->steps[ $this->step ]['view'] );
178
  $this->ui->setup_footer( ! empty( $this->steps[ $this->step ]['handler'] ) );
179
 
180
+ if ( 'ready' === $this->step ) {
181
  $this->complete_setup();
182
  }
183
 
186
 
187
  private function splash_wizard_on_wcml_pages() {
188
 
189
+ if ( isset( $_GET['src'] ) && 'setup_later' === $_GET['src'] ) {
190
  $this->woocommerce_wpml->settings['set_up_wizard_splash'] = 1;
191
  $this->woocommerce_wpml->update_settings();
192
  }
193
 
194
  if ( $this->is_wcml_admin_page() && ! $this->has_completed() && empty( $this->woocommerce_wpml->settings['set_up_wizard_splash'] ) ) {
195
  wp_redirect( 'admin.php?page=wcml-setup' );
196
+ add_filter( 'wp_die_handler', [ $this, 'exit_wrapper' ] );
197
  wp_die();
198
  }
199
  }
202
 
203
  if ( isset( $_GET['wcml-setup-skip'] ) && isset( $_GET['_wcml_setup_nonce'] ) ) {
204
  if ( ! wp_verify_nonce( $_GET['_wcml_setup_nonce'], 'wcml_setup_skip_nonce' ) ) {
205
+ wp_die( esc_html__( 'Action failed. Please refresh the page and retry.', 'woocommerce-multilingual' ) );
206
  }
207
 
208
  if ( ! current_user_can( 'manage_options' ) ) {
210
  }
211
 
212
  $this->complete_setup();
213
+ remove_filter( 'admin_notices', [ $this->ui, 'wizard_notice' ] );
214
 
215
  delete_transient( '_wcml_activation_redirect' );
216
  }
244
  *
245
  * @return string
246
  */
247
+ private function step_url( $step ) {
248
  $url = admin_url( 'admin.php?page=wcml-setup&step=' . $step );
249
  return $url;
250
  }
268
  }
269
 
270
  public function handle_steps() {
271
+ if ( isset( $_POST['handle_step'] ) && wp_create_nonce( $_POST['handle_step'] ) === $_POST['nonce'] ) {
272
  $step_name = sanitize_text_field( $_POST['handle_step'] );
273
  if ( $handler = $this->get_handler( $step_name ) ) {
274
+ if ( is_callable( $handler, true ) ) {
275
  call_user_func( $handler, $_POST );
276
  }
277
  }
compatibility/class-wcml-accommodation-bookings.php CHANGED
@@ -27,7 +27,7 @@ class WCML_Accommodation_Bookings{
27
  add_action( 'init', [ $this, 'load_assets' ], 100 );
28
  }
29
 
30
- function wcml_price_field_after_booking_base_cost( $post_id ){
31
 
32
  $this->echo_wcml_price_field( $post_id, 'wcml_wc_booking_base_cost' );
33
 
27
  add_action( 'init', [ $this, 'load_assets' ], 100 );
28
  }
29
 
30
+ public function wcml_price_field_after_booking_base_cost( $post_id ){
31
 
32
  $this->echo_wcml_price_field( $post_id, 'wcml_wc_booking_base_cost' );
33
 
compatibility/class-wcml-adventure-tours.php CHANGED
@@ -1,395 +1,383 @@
1
  <?php
2
 
3
- class WCML_Adventure_tours{
4
 
5
- /**
6
- * @var woocommerce_wpml
7
- */
8
- private $woocommerce_wpml;
9
- /**
10
- * @var SitePress
11
- */
12
- private $sitepress;
13
 
14
- /**
15
- * @var WPML_Element_Translation_Package
16
- */
17
- private $tp;
18
 
19
- /**
20
- * WCML_Adventure_tours constructor.
21
- * @param woocommerce_wpml $woocommerce_wpml
22
- * @param SitePress $sitepress
23
- * @param WPML_Element_Translation_Package $tp
24
- */
25
- function __construct( woocommerce_wpml $woocommerce_wpml, SitePress $sitepress, WPML_Element_Translation_Package $tp ) {
26
- $this->woocommerce_wpml = $woocommerce_wpml;
27
- $this->sitepress = $sitepress;
28
- $this->tp = $tp;
29
- }
 
30
 
31
- public function add_hooks(){
32
- add_action( 'updated_post_meta', array( $this, 'sync_tour_data_across_translations' ), 10, 4 );
33
- add_filter( 'get_post_metadata', array( $this, 'product_price_filter'), 9, 4 );
 
34
 
35
- if ( is_admin() ) {
36
 
37
- add_action( 'wcml_gui_additional_box_html', array( $this, 'custom_box_html' ), 10, 3 );
38
- add_filter( 'wcml_gui_additional_box_data', array( $this, 'custom_box_html_data' ), 10, 4 );
39
- add_action( 'wcml_update_extra_fields', array( $this, 'tour_data_update' ), 10, 3 );
40
 
41
- add_filter( 'wpml_tm_translation_job_data', array( $this, 'append_tour_data_translation_package' ), 10, 2 );
42
- add_action( 'wpml_translation_job_saved', array( $this, 'save_tour_data_translation' ), 10, 3 );
43
 
44
- add_action( 'admin_footer', array( $this, 'load_assets' ) );
45
- add_action( 'wcml_after_custom_prices_block', array( $this, 'add_custom_prices_block' ) );
46
- add_action( 'wcml_after_save_custom_prices', array( $this, 'save_custom_costs' ) );
47
 
48
- add_filter( 'wcml_is_variable_product', array( $this, 'is_variable_tour' ), 10, 2 );
49
- add_filter( 'wcml_variation_term_taxonomy_ids', array( $this, 'add_tour_tax_id' ) );
50
- add_filter( 'wcml_is_attributes_page', array( $this, 'is_attributes_page' ) );
51
- add_filter( 'wcml_is_attributes_page', array( $this, 'is_attributes_page' ) );
52
 
53
- add_filter( 'wcml_do_not_display_custom_fields_for_product', array(
54
- $this,
55
- 'replace_tm_editor_custom_fields_with_own_sections'
56
- ) );
57
- }
58
- }
 
 
 
59
 
60
 
61
- function sync_tour_data_across_translations($meta_id, $post_id, $meta_key, $tour_tabs_meta)
62
- {
63
- if ($meta_key != 'tour_tabs_meta')
64
- return false;
65
 
 
66
 
67
- $post = get_post($post_id);
 
 
 
68
 
69
- // skip auto-drafts // skip autosave
70
- if ( $post->post_status == 'auto-draft' || isset( $_POST['autosave'] ) ) {
71
- return false;
72
- }
73
 
74
- if ($post->post_type == 'product') {
75
 
76
- remove_action('updated_post_meta', array($this, 'sync_tour_data_across_translations'), 10, 4);
 
 
 
 
77
 
78
- $original_product_id = $post_id;
79
- if ( ! $this->woocommerce_wpml->products->is_original_product( $post_id ) ) {
80
- $original_product_language = $this->woocommerce_wpml->products->get_original_product_language( $post_id );
81
- $original_product_id = apply_filters( 'translate_object_id', $post_id, 'product', true, $original_product_language );
82
- }
83
 
84
- $product_trid = $this->sitepress->get_element_trid( $original_product_id, 'post_product' );
85
- $product_translations = $this->sitepress->get_element_translations( $product_trid, 'post_product' );
86
 
87
- foreach ($product_translations as $product_translation) {
88
 
89
- if ( empty( $product_translation->original ) ) {
90
 
91
- $trnsl_tour_tabs_meta = get_post_meta( $product_translation->element_id, 'tour_tabs_meta', true );
92
 
93
- $trnsl_tour_tabs_meta['tour_badge'] = $tour_tabs_meta['tour_badge'];
94
 
95
- update_post_meta( $product_translation->element_id, 'tour_tabs_meta', $trnsl_tour_tabs_meta);
 
96
 
97
- }
98
 
99
- }
100
 
101
- add_action('updated_post_meta', array($this, 'sync_tour_data_across_translations'), 10, 4);
102
 
103
- }
104
 
105
- }
106
 
107
- function custom_box_html($obj, $product_id, $data)
108
- {
109
 
110
- if ( $tour_tabs_meta = get_post_meta( $product_id, 'tour_tabs_meta', true ) ) {
111
 
112
- $tour_section = new WPML_Editor_UI_Field_Section( __('Tour Data', 'woocommerce-multilingual'));
113
 
114
- $divider = true;
 
 
 
 
 
115
 
116
- foreach( $tour_tabs_meta['tabs'] as $tour_tab_id => $tour_tab_meta) {
117
 
118
- $group = new WPML_Editor_UI_Field_Group('', $divider);
119
- $composite_field = new WPML_Editor_UI_Single_Line_Field('adventure_tour_' . $tour_tab_id . '_title', __('Title', 'woocommerce-multilingual'), $data, false);
120
- $group->add_field($composite_field);
121
- $composite_field = new WPML_Editor_UI_Single_Line_Field('adventure_tour_' . $tour_tab_id . '_content', __('Content', 'woocommerce-multilingual'), $data, false);
122
- $group->add_field($composite_field);
123
- $tour_section->add_field($group);
124
 
125
- }
126
 
127
- if ( !empty( $tour_tabs_meta['tabs'] ) ) {
128
- $obj->add_field( $tour_section );
129
- }
130
 
131
- }
132
 
133
- }
 
 
 
134
 
135
- function custom_box_html_data($data, $product_id, $translation, $lang){
 
136
 
137
- if ( $tour_tabs_meta = get_post_meta( $product_id, 'tour_tabs_meta', true ) ) {
 
 
 
 
 
 
 
138
 
139
- foreach ( $tour_tabs_meta['tabs'] as $tour_tab_id => $tour_tab_meta ) {
140
- $data['adventure_tour_' . $tour_tab_id . '_title'] = array('original' => $tour_tab_meta['title'] );
141
- $data['adventure_tour_' . $tour_tab_id . '_content'] = array('original' => $tour_tab_meta['content'] );
142
- }
143
 
144
- if ($translation) {
145
- $translated_tour_tabs_meta = get_post_meta( $translation->ID, 'tour_tabs_meta', true );
146
 
147
- if( $translated_tour_tabs_meta ){
148
- foreach ( $translated_tour_tabs_meta['tabs'] as $tour_tab_id => $tour_tab_meta) {
149
- $data['adventure_tour_' . $tour_tab_id . '_title']['translation'] = $tour_tab_meta['title'];
150
- $data['adventure_tour_' . $tour_tab_id . '_content']['translation'] = $tour_tab_meta['content'];
151
- }
152
- }
153
- }
154
 
155
- }
 
156
 
157
- return $data;
158
- }
 
159
 
160
- function tour_data_update( $original_product_id, $product_id, $data)
161
- {
 
 
 
162
 
163
- $tour_tabs_meta = get_post_meta( $original_product_id, 'tour_tabs_meta', true );
164
 
165
- if( isset( $tour_tabs_meta['tabs'] ) && is_array( $tour_tabs_meta['tabs'] ) ){
166
- foreach ( $tour_tabs_meta['tabs'] as $tour_tab_id => $tour_tab_meta ) {
167
 
168
- if (!empty($data[md5('adventure_tour_' . $tour_tab_id . '_title')])) {
169
- $tour_tabs_meta['tabs'][$tour_tab_id]['title'] = $data[md5('adventure_tour_' . $tour_tab_id . '_title')];
170
- }
171
 
172
- if (!empty($data[md5('adventure_tour_' . $tour_tab_id . '_content')])) {
173
- $tour_tabs_meta['tabs'][$tour_tab_id]['content'] = $data[md5('adventure_tour_' . $tour_tab_id . '_content')];
174
- }
175
- }
176
- remove_action('updated_post_meta', array($this, 'sync_tour_data_across_translations'), 10, 4);
177
 
178
- update_post_meta($product_id, 'tour_tabs_meta', $tour_tabs_meta);
179
 
180
- add_action('updated_post_meta', array($this, 'sync_tour_data_across_translations'), 10, 4);
181
- }
182
 
183
- }
184
 
185
- function append_tour_data_translation_package($package, $post)
186
- {
187
 
188
- if ($post->post_type == 'product') {
189
 
190
- $tour_tabs_meta = get_post_meta( $post->ID, 'tour_tabs_meta', true );
 
191
 
192
- if ($tour_tabs_meta) {
 
 
 
 
193
 
194
- $fields = array('title', 'content');
 
 
 
 
195
 
196
- foreach ( $tour_tabs_meta['tabs'] as $tour_tab_id => $tour_tab_meta) {
197
 
198
- foreach ($fields as $field) {
199
- if (!empty($tour_tab_meta[$field])) {
200
 
201
- $package['contents']['wc_adventure_tour:' . $tour_tab_id . ':' . $field] = array(
202
- 'translate' => 1,
203
- 'data' => $this->tp->encode_field_data($tour_tab_meta[$field], 'base64'),
204
- 'format' => 'base64'
205
- );
206
 
207
- }
208
- }
209
 
210
- }
211
 
212
- }
 
213
 
214
- }
215
 
216
- return $package;
 
217
 
218
- }
219
 
220
- function save_tour_data_translation($post_id, $data, $job)
221
- {
222
 
 
223
 
224
- $translated_tour_data = array();
225
- foreach ($data as $value) {
 
226
 
227
- if (preg_match('/wc_adventure_tour:([0-9]+):(.+)/', $value['field_type'], $matches)) {
 
 
 
 
 
 
 
228
 
229
- $tour_tab_id = $matches[1];
230
- $field = $matches[2];
231
 
232
- $translated_tour_data[$tour_tab_id][$field] = $value['data'];
 
233
 
234
- }
 
 
 
 
235
 
236
- }
237
 
238
- if ($translated_tour_data) {
 
 
 
 
 
 
239
 
240
- $tour_tabs_meta = get_post_meta( $job->original_doc_id, 'tour_tabs_meta', true );
241
 
 
 
 
 
 
 
 
242
 
243
- foreach ( $tour_tabs_meta['tabs'] as $tour_tab_id => $tour_tab_meta) {
 
 
 
 
 
244
 
245
- if (isset($translated_tour_data[$tour_tab_id]['title'])) {
246
- $tour_tabs_meta['tabs'][$tour_tab_id]['title'] = $translated_tour_data[$tour_tab_id]['title'];
247
- }
248
 
249
- if (isset($translated_tour_data[$tour_tab_id]['content'])) {
250
- $tour_tabs_meta['tabs'][$tour_tab_id]['content'] = $translated_tour_data[$tour_tab_id]['content'];
251
- }
252
- }
253
 
254
- }
255
- remove_action('updated_post_meta', array($this, 'sync_tour_data_across_translations'), 10, 4);
256
- update_post_meta($post_id, 'tour_tabs_meta', $tour_tabs_meta);
257
- add_action('updated_post_meta', array($this, 'sync_tour_data_across_translations'), 10, 4);
258
 
259
- }
260
 
261
- function load_assets(){
262
- global $pagenow;
263
 
264
- if( $pagenow == 'post.php' || $pagenow == 'post-new.php' ){
265
- wp_register_script( 'wcml-adventure-tours', WCML_PLUGIN_URL . '/compatibility/res/js/wcml-adventure-tours.js', array( 'jquery' ), WCML_VERSION, true );
266
- wp_enqueue_script( 'wcml-adventure-tours' );
267
- }
268
- }
269
 
270
- function add_custom_prices_block( $product_id ){
 
271
 
272
- if( $product_id != 'new' ){
273
- $currencies = $this->woocommerce_wpml->multi_currency->get_currencies();
274
- $tour_booking_periods = get_post_meta( $product_id, 'tour_booking_periods', true );
275
- $custom_periods_prices = get_post_meta( $product_id, 'custom_booking_periods_prices', true );
276
- if( $tour_booking_periods ){
277
- foreach( $tour_booking_periods as $per_key => $tour_booking_period ){
278
- foreach( $currencies as $key => $currency ){
279
 
280
- $value = isset($custom_periods_prices[ $per_key ][ $key ]) ? $custom_periods_prices[ $per_key ][ $key ]: '';
281
 
282
- echo '<div class="wcml_custom_cost_field" data-tour="'.$per_key.'" style="display: none;">';
283
- echo '<div>'.get_woocommerce_currency_symbol($key).'</div>';
284
- echo '<input type="text" class="wc_input_price" style="width: 60px;" name="tour_spec_price['.$per_key.']['.$key.']" value="'.$value.'" />';
285
- echo '</div>';
286
- }
287
- }
288
- }
289
 
290
- echo '<div class="wcml_custom_cost_field_empty" style="display: none;">';
291
- echo '<div></div>';
292
- echo '<input type="text" class="wc_input_price" style="width: 60px;" name="tour_spec_price" value="" />';
293
- echo '</div>';
294
- }
295
- }
296
 
297
- function save_custom_costs( $post_id ){
 
298
 
299
- $tour_spec_price = array();
300
- $currencies = $this->woocommerce_wpml->multi_currency->get_currencies();
 
 
 
 
 
 
 
301
 
302
- if( isset( $_POST[ 'tour_spec_price' ] ) && is_array( $_POST[ 'tour_spec_price' ] ) ) {
 
 
 
 
 
 
 
 
303
 
304
- foreach( $_POST[ 'tour_spec_price' ] as $per_key => $costs ) {
 
305
 
306
- foreach( $currencies as $code => $currency ) {
 
 
307
 
308
- $tour_spec_price[ $per_key ][ $code ] = $costs[ $code ];
 
 
309
 
310
- }
311
- }
312
 
313
- update_post_meta( $post_id, 'custom_booking_periods_prices', $tour_spec_price );
314
- }
315
- }
316
 
317
- function product_price_filter( $value, $object_id, $meta_key, $single ){
 
318
 
319
- if(
320
- $meta_key === 'tour_booking_periods' &&
321
- $this->woocommerce_wpml->settings[ 'enable_multi_currency' ] === WCML_MULTI_CURRENCIES_INDEPENDENT &&
322
- !is_admin() &&
323
- get_post_type( $object_id ) === 'product' &&
324
- ( $currency = $this->woocommerce_wpml->multi_currency->get_client_currency() ) !== wcml_get_woocommerce_currency_option()
325
- ) {
326
 
327
- remove_filter( 'get_post_metadata', array( $this, 'product_price_filter' ), 9, 4 );
 
328
 
329
- $original_language = $this->woocommerce_wpml->products->get_original_product_language( $object_id );
330
- $original_product = apply_filters( 'translate_object_id', $object_id, 'product', true, $original_language );
331
 
332
- if ( get_post_meta( $original_product, '_wcml_custom_prices_status' ) ) {
333
- $custom_periods_prices = get_post_meta( $object_id, 'custom_booking_periods_prices', true );
334
- $tours_data = get_post_meta( $object_id, 'tour_booking_periods', true );
335
- if( $tours_data ){
336
- foreach( $tours_data as $key => $periods ){
337
- if( isset( $custom_periods_prices[ $key ][ $currency ] ) ){
338
- $tours_data[ $key ][ 'spec_price' ] = $custom_periods_prices[ $key ][ $currency ];
339
- }
340
- }
341
 
342
- if( $single ){
343
- $value[0] = $tours_data;
344
- }else{
345
- $value = $tours_data;
346
- }
347
 
348
- }
349
- }
350
- add_filter( 'get_post_metadata', array( $this, 'product_price_filter' ), 9, 4 );
351
- }
352
 
353
- return $value;
354
- }
355
-
356
- function add_tour_tax_id( $variation_term_taxonomy_ids ){
357
- global $wpdb;
358
- $tour_taxonomy_id = $wpdb->get_var( "SELECT tt.term_taxonomy_id FROM {$wpdb->terms} AS t LEFT JOIN {$wpdb->term_taxonomy} AS tt ON t.term_id = tt.term_id WHERE t.name = 'tour' AND tt.taxonomy = 'product_type'" );
359
-
360
- if( $tour_taxonomy_id ){
361
- $variation_term_taxonomy_ids[] = $tour_taxonomy_id;
362
- }
363
-
364
- return $variation_term_taxonomy_ids;
365
-
366
- }
367
-
368
- function is_variable_tour( $is_variable, $product_id ){
369
- $var_tour_meta = get_post_meta( $product_id, '_variable_tour', true );
370
-
371
- if( $is_variable && $var_tour_meta == 'yes' ){
372
- $is_variable = true;
373
- }elseif( $var_tour_meta == 'no' ){
374
- $is_variable = false;
375
- }
376
-
377
- return $is_variable;
378
- }
379
-
380
- function is_attributes_page( $is_attributes_page ){
381
-
382
- if( isset( $_GET[ 'page' ] ) && $_GET[ 'page' ] == 'product_attributes_extended' && isset( $_GET[ 'post_type' ] ) && $_GET[ 'post_type' ] == 'product' ){
383
- $is_attributes_page = true;
384
- }
385
-
386
- return $is_attributes_page;
387
- }
388
-
389
- function replace_tm_editor_custom_fields_with_own_sections( $fields ){
390
- $fields[] = 'tour_tabs_meta';
391
-
392
- return $fields;
393
- }
394
 
395
  }
1
  <?php
2
 
3
+ class WCML_Adventure_tours {
4
 
5
+ /**
6
+ * @var woocommerce_wpml
7
+ */
8
+ private $woocommerce_wpml;
9
+ /**
10
+ * @var SitePress
11
+ */
12
+ private $sitepress;
13
 
14
+ /**
15
+ * @var WPML_Element_Translation_Package
16
+ */
17
+ private $tp;
18
 
19
+ /**
20
+ * WCML_Adventure_tours constructor.
21
+ *
22
+ * @param woocommerce_wpml $woocommerce_wpml
23
+ * @param SitePress $sitepress
24
+ * @param WPML_Element_Translation_Package $tp
25
+ */
26
+ public function __construct( woocommerce_wpml $woocommerce_wpml, SitePress $sitepress, WPML_Element_Translation_Package $tp ) {
27
+ $this->woocommerce_wpml = $woocommerce_wpml;
28
+ $this->sitepress = $sitepress;
29
+ $this->tp = $tp;
30
+ }
31
 
32
+ public function add_hooks() {
33
+ add_action( 'updated_post_meta', [ $this, 'sync_tour_data_across_translations' ], 10, 4 );
34
+ add_filter( 'get_post_metadata', [ $this, 'product_price_filter' ], 9, 4 );
35
+ add_action( 'wpml_translation_job_saved', [ $this, 'save_tour_data_translation' ], 10, 3 );
36
 
37
+ if ( is_admin() ) {
38
 
39
+ add_action( 'wcml_gui_additional_box_html', [ $this, 'custom_box_html' ], 10, 3 );
40
+ add_filter( 'wcml_gui_additional_box_data', [ $this, 'custom_box_html_data' ], 10, 4 );
41
+ add_action( 'wcml_update_extra_fields', [ $this, 'tour_data_update' ], 10, 3 );
42
 
43
+ add_filter( 'wpml_tm_translation_job_data', [ $this, 'append_tour_data_translation_package' ], 10, 2 );
 
44
 
45
+ add_action( 'admin_footer', [ $this, 'load_assets' ] );
46
+ add_action( 'wcml_after_custom_prices_block', [ $this, 'add_custom_prices_block' ] );
47
+ add_action( 'wcml_after_save_custom_prices', [ $this, 'save_custom_costs' ] );
48
 
49
+ add_filter( 'wcml_is_variable_product', [ $this, 'is_variable_tour' ], 10, 2 );
50
+ add_filter( 'wcml_variation_term_taxonomy_ids', [ $this, 'add_tour_tax_id' ] );
51
+ add_filter( 'wcml_is_attributes_page', [ $this, 'is_attributes_page' ] );
52
+ add_filter( 'wcml_is_attributes_page', [ $this, 'is_attributes_page' ] );
53
 
54
+ add_filter(
55
+ 'wcml_do_not_display_custom_fields_for_product',
56
+ [
57
+ $this,
58
+ 'replace_tm_editor_custom_fields_with_own_sections',
59
+ ]
60
+ );
61
+ }
62
+ }
63
 
64
 
65
+ public function sync_tour_data_across_translations( $meta_id, $post_id, $meta_key, $tour_tabs_meta ) {
66
+ if ( 'tour_tabs_meta' !== $meta_key ) {
67
+ return false;
68
+ }
69
 
70
+ $post = get_post( $post_id );
71
 
72
+ // Skip auto-drafts // skip autosave.
73
+ if ( 'auto-draft' === $post->post_status || isset( $_POST['autosave'] ) ) {
74
+ return false;
75
+ }
76
 
77
+ if ( 'product' === $post->post_type ) {
 
 
 
78
 
79
+ remove_action( 'updated_post_meta', [ $this, 'sync_tour_data_across_translations' ], 10, 4 );
80
 
81
+ $original_product_id = $post_id;
82
+ if ( ! $this->woocommerce_wpml->products->is_original_product( $post_id ) ) {
83
+ $original_product_language = $this->woocommerce_wpml->products->get_original_product_language( $post_id );
84
+ $original_product_id = apply_filters( 'translate_object_id', $post_id, 'product', true, $original_product_language );
85
+ }
86
 
87
+ $product_trid = $this->sitepress->get_element_trid( $original_product_id, 'post_product' );
88
+ $product_translations = $this->sitepress->get_element_translations( $product_trid, 'post_product' );
 
 
 
89
 
90
+ foreach ( $product_translations as $product_translation ) {
 
91
 
92
+ if ( empty( $product_translation->original ) ) {
93
 
94
+ $trnsl_tour_tabs_meta = get_post_meta( $product_translation->element_id, 'tour_tabs_meta', true );
95
 
96
+ $trnsl_tour_tabs_meta['tour_badge'] = $tour_tabs_meta['tour_badge'];
97
 
98
+ update_post_meta( $product_translation->element_id, 'tour_tabs_meta', $trnsl_tour_tabs_meta );
99
 
100
+ }
101
+ }
102
 
103
+ add_action( 'updated_post_meta', [ $this, 'sync_tour_data_across_translations' ], 10, 4 );
104
 
105
+ }
106
 
107
+ }
108
 
109
+ public function custom_box_html( $obj, $product_id, $data ) {
110
 
111
+ if ( $tour_tabs_meta = get_post_meta( $product_id, 'tour_tabs_meta', true ) ) {
112
 
113
+ $tour_section = new WPML_Editor_UI_Field_Section( __( 'Tour Data', 'woocommerce-multilingual' ) );
 
114
 
115
+ $divider = true;
116
 
117
+ foreach ( $tour_tabs_meta['tabs'] as $tour_tab_id => $tour_tab_meta ) {
118
 
119
+ $group = new WPML_Editor_UI_Field_Group( '', $divider );
120
+ $composite_field = new WPML_Editor_UI_Single_Line_Field( 'adventure_tour_' . $tour_tab_id . '_title', __( 'Title', 'woocommerce-multilingual' ), $data, false );
121
+ $group->add_field( $composite_field );
122
+ $composite_field = new WPML_Editor_UI_Single_Line_Field( 'adventure_tour_' . $tour_tab_id . '_content', __( 'Content', 'woocommerce-multilingual' ), $data, false );
123
+ $group->add_field( $composite_field );
124
+ $tour_section->add_field( $group );
125
 
126
+ }
127
 
128
+ if ( ! empty( $tour_tabs_meta['tabs'] ) ) {
129
+ $obj->add_field( $tour_section );
130
+ }
131
+ }
 
 
132
 
133
+ }
134
 
135
+ public function custom_box_html_data( $data, $product_id, $translation, $lang ) {
 
 
136
 
137
+ if ( $tour_tabs_meta = get_post_meta( $product_id, 'tour_tabs_meta', true ) ) {
138
 
139
+ foreach ( $tour_tabs_meta['tabs'] as $tour_tab_id => $tour_tab_meta ) {
140
+ $data[ 'adventure_tour_' . $tour_tab_id . '_title' ] = [ 'original' => $tour_tab_meta['title'] ];
141
+ $data[ 'adventure_tour_' . $tour_tab_id . '_content' ] = [ 'original' => $tour_tab_meta['content'] ];
142
+ }
143
 
144
+ if ( $translation ) {
145
+ $translated_tour_tabs_meta = get_post_meta( $translation->ID, 'tour_tabs_meta', true );
146
 
147
+ if ( $translated_tour_tabs_meta ) {
148
+ foreach ( $translated_tour_tabs_meta['tabs'] as $tour_tab_id => $tour_tab_meta ) {
149
+ $data[ 'adventure_tour_' . $tour_tab_id . '_title' ]['translation'] = $tour_tab_meta['title'];
150
+ $data[ 'adventure_tour_' . $tour_tab_id . '_content' ]['translation'] = $tour_tab_meta['content'];
151
+ }
152
+ }
153
+ }
154
+ }
155
 
156
+ return $data;
157
+ }
 
 
158
 
159
+ public function tour_data_update( $original_product_id, $product_id, $data ) {
 
160
 
161
+ $tour_tabs_meta = get_post_meta( $original_product_id, 'tour_tabs_meta', true );
 
 
 
 
 
 
162
 
163
+ if ( isset( $tour_tabs_meta['tabs'] ) && is_array( $tour_tabs_meta['tabs'] ) ) {
164
+ foreach ( $tour_tabs_meta['tabs'] as $tour_tab_id => $tour_tab_meta ) {
165
 
166
+ if ( ! empty( $data[ md5( 'adventure_tour_' . $tour_tab_id . '_title' ) ] ) ) {
167
+ $tour_tabs_meta['tabs'][ $tour_tab_id ]['title'] = $data[ md5( 'adventure_tour_' . $tour_tab_id . '_title' ) ];
168
+ }
169
 
170
+ if ( ! empty( $data[ md5( 'adventure_tour_' . $tour_tab_id . '_content' ) ] ) ) {
171
+ $tour_tabs_meta['tabs'][ $tour_tab_id ]['content'] = $data[ md5( 'adventure_tour_' . $tour_tab_id . '_content' ) ];
172
+ }
173
+ }
174
+ remove_action( 'updated_post_meta', [ $this, 'sync_tour_data_across_translations' ], 10, 4 );
175
 
176
+ update_post_meta( $product_id, 'tour_tabs_meta', $tour_tabs_meta );
177
 
178
+ add_action( 'updated_post_meta', [ $this, 'sync_tour_data_across_translations' ], 10, 4 );
179
+ }
180
 
181
+ }
 
 
182
 
183
+ public function append_tour_data_translation_package( $package, $post ) {
 
 
 
 
184
 
185
+ if ( 'product' === $post->post_type ) {
186
 
187
+ $tour_tabs_meta = get_post_meta( $post->ID, 'tour_tabs_meta', true );
 
188
 
189
+ if ( $tour_tabs_meta ) {
190
 
191
+ $fields = [ 'title', 'content' ];
 
192
 
193
+ foreach ( $tour_tabs_meta['tabs'] as $tour_tab_id => $tour_tab_meta ) {
194
 
195
+ foreach ( $fields as $field ) {
196
+ if ( ! empty( $tour_tab_meta[ $field ] ) ) {
197
 
198
+ $package['contents'][ 'wc_adventure_tour:' . $tour_tab_id . ':' . $field ] = [
199
+ 'translate' => 1,
200
+ 'data' => $this->tp->encode_field_data( $tour_tab_meta[ $field ], 'base64' ),
201
+ 'format' => 'base64',
202
+ ];
203
 
204
+ }
205
+ }
206
+ }
207
+ }
208
+ }
209
 
210
+ return $package;
211
 
212
+ }
 
213
 
214
+ public function save_tour_data_translation( $post_id, $data, $job ) {
 
 
 
 
215
 
216
+ $translated_tour_data = [];
217
+ foreach ( $data as $value ) {
218
 
219
+ if ( preg_match( '/wc_adventure_tour:([0-9]+):(.+)/', $value['field_type'], $matches ) ) {
220
 
221
+ $tour_tab_id = $matches[1];
222
+ $field = $matches[2];
223
 
224
+ $translated_tour_data[ $tour_tab_id ][ $field ] = $value['data'];
225
 
226
+ }
227
+ }
228
 
229
+ if ( $translated_tour_data ) {
230
 
231
+ $tour_tabs_meta = get_post_meta( $job->original_doc_id, 'tour_tabs_meta', true );
 
232
 
233
+ foreach ( $tour_tabs_meta['tabs'] as $tour_tab_id => $tour_tab_meta ) {
234
 
235
+ if ( isset( $translated_tour_data[ $tour_tab_id ]['title'] ) ) {
236
+ $tour_tabs_meta['tabs'][ $tour_tab_id ]['title'] = $translated_tour_data[ $tour_tab_id ]['title'];
237
+ }
238
 
239
+ if ( isset( $translated_tour_data[ $tour_tab_id ]['content'] ) ) {
240
+ $tour_tabs_meta['tabs'][ $tour_tab_id ]['content'] = $translated_tour_data[ $tour_tab_id ]['content'];
241
+ }
242
+ }
243
+ }
244
+ remove_action( 'updated_post_meta', [ $this, 'sync_tour_data_across_translations' ], 10, 4 );
245
+ update_post_meta( $post_id, 'tour_tabs_meta', $tour_tabs_meta );
246
+ add_action( 'updated_post_meta', [ $this, 'sync_tour_data_across_translations' ], 10, 4 );
247
 
248
+ }
 
249
 
250
+ public function load_assets() {
251
+ global $pagenow;
252
 
253
+ if ( 'post.php' === $pagenow || 'post-new.php' === $pagenow ) {
254
+ wp_register_script( 'wcml-adventure-tours', WCML_PLUGIN_URL . '/compatibility/res/js/wcml-adventure-tours.js', [ 'jquery' ], WCML_VERSION, true );
255
+ wp_enqueue_script( 'wcml-adventure-tours' );
256
+ }
257
+ }
258
 
259
+ public function add_custom_prices_block( $product_id ) {
260
 
261
+ if ( 'new' !== $product_id ) {
262
+ $currencies = $this->woocommerce_wpml->multi_currency->get_currencies();
263
+ $tour_booking_periods = get_post_meta( $product_id, 'tour_booking_periods', true );
264
+ $custom_periods_prices = get_post_meta( $product_id, 'custom_booking_periods_prices', true );
265
+ if ( $tour_booking_periods ) {
266
+ foreach ( $tour_booking_periods as $per_key => $tour_booking_period ) {
267
+ foreach ( $currencies as $key => $currency ) {
268
 
269
+ $value = isset( $custom_periods_prices[ $per_key ][ $key ] ) ? $custom_periods_prices[ $per_key ][ $key ] : '';
270
 
271
+ echo '<div class="wcml_custom_cost_field" data-tour="' . esc_html( $per_key ) . '" style="display: none;">';
272
+ echo '<div>' . wp_kses_post( get_woocommerce_currency_symbol( $key ) ) . '</div>';
273
+ echo '<input type="text" class="wc_input_price" style="width: 60px;" name="tour_spec_price[' . esc_html( $per_key ) . '][' . esc_html( $key ) . ']" value="' . esc_html( $value ) . '" />';
274
+ echo '</div>';
275
+ }
276
+ }
277
+ }
278
 
279
+ echo '<div class="wcml_custom_cost_field_empty" style="display: none;">';
280
+ echo '<div></div>';
281
+ echo '<input type="text" class="wc_input_price" style="width: 60px;" name="tour_spec_price" value="" />';
282
+ echo '</div>';
283
+ }
284
+ }
285
 
286
+ public function save_custom_costs( $post_id ) {
 
 
287
 
288
+ $tour_spec_price = [];
289
+ $currencies = $this->woocommerce_wpml->multi_currency->get_currencies();
 
 
290
 
291
+ if ( isset( $_POST['tour_spec_price'] ) && is_array( $_POST['tour_spec_price'] ) ) {
 
 
 
292
 
293
+ foreach ( $_POST['tour_spec_price'] as $per_key => $costs ) {
294
 
295
+ foreach ( $currencies as $code => $currency ) {
 
296
 
297
+ $tour_spec_price[ $per_key ][ $code ] = $costs[ $code ];
 
 
 
 
298
 
299
+ }
300
+ }
301
 
302
+ update_post_meta( $post_id, 'custom_booking_periods_prices', $tour_spec_price );
303
+ }
304
+ }
 
 
 
 
305
 
306
+ public function product_price_filter( $value, $object_id, $meta_key, $single ) {
307
 
308
+ if (
309
+ $meta_key === 'tour_booking_periods' &&
310
+ $this->woocommerce_wpml->settings['enable_multi_currency'] === WCML_MULTI_CURRENCIES_INDEPENDENT &&
311
+ ! is_admin() &&
312
+ get_post_type( $object_id ) === 'product' &&
313
+ ( $currency = $this->woocommerce_wpml->multi_currency->get_client_currency() ) !== wcml_get_woocommerce_currency_option()
314
+ ) {
315
 
316
+ remove_filter( 'get_post_metadata', [ $this, 'product_price_filter' ], 9, 4 );
 
 
 
 
 
317
 
318
+ $original_language = $this->woocommerce_wpml->products->get_original_product_language( $object_id );
319
+ $original_product = apply_filters( 'translate_object_id', $object_id, 'product', true, $original_language );
320
 
321
+ if ( get_post_meta( $original_product, '_wcml_custom_prices_status' ) ) {
322
+ $custom_periods_prices = get_post_meta( $object_id, 'custom_booking_periods_prices', true );
323
+ $tours_data = get_post_meta( $object_id, 'tour_booking_periods', true );
324
+ if ( $tours_data ) {
325
+ foreach ( $tours_data as $key => $periods ) {
326
+ if ( isset( $custom_periods_prices[ $key ][ $currency ] ) ) {
327
+ $tours_data[ $key ]['spec_price'] = $custom_periods_prices[ $key ][ $currency ];
328
+ }
329
+ }
330
 
331
+ if ( $single ) {
332
+ $value[0] = $tours_data;
333
+ } else {
334
+ $value = $tours_data;
335
+ }
336
+ }
337
+ }
338
+ add_filter( 'get_post_metadata', [ $this, 'product_price_filter' ], 9, 4 );
339
+ }
340
 
341
+ return $value;
342
+ }
343
 
344
+ public function add_tour_tax_id( $variation_term_taxonomy_ids ) {
345
+ global $wpdb;
346
+ $tour_taxonomy_id = $wpdb->get_var( "SELECT tt.term_taxonomy_id FROM {$wpdb->terms} AS t LEFT JOIN {$wpdb->term_taxonomy} AS tt ON t.term_id = tt.term_id WHERE t.name = 'tour' AND tt.taxonomy = 'product_type'" );
347
 
348
+ if ( $tour_taxonomy_id ) {
349
+ $variation_term_taxonomy_ids[] = $tour_taxonomy_id;
350
+ }
351
 
352
+ return $variation_term_taxonomy_ids;
 
353
 
354
+ }
 
 
355
 
356
+ public function is_variable_tour( $is_variable, $product_id ) {
357
+ $var_tour_meta = get_post_meta( $product_id, '_variable_tour', true );
358
 
359
+ if ( $is_variable && 'yes' === $var_tour_meta ) {
360
+ $is_variable = true;
361
+ } elseif ( 'no' === $var_tour_meta ) {
362
+ $is_variable = false;
363
+ }
 
 
364
 
365
+ return $is_variable;
366
+ }
367
 
368
+ public function is_attributes_page( $is_attributes_page ) {
 
369
 
370
+ if ( isset( $_GET['page'] ) && 'product_attributes_extended' === $_GET['page'] && isset( $_GET['post_type'] ) && 'product' === $_GET['post_type'] ) {
371
+ $is_attributes_page = true;
372
+ }
 
 
 
 
 
 
373
 
374
+ return $is_attributes_page;
375
+ }
 
 
 
376
 
377
+ public function replace_tm_editor_custom_fields_with_own_sections( $fields ) {
378
+ $fields[] = 'tour_tabs_meta';
 
 
379
 
380
+ return $fields;
381
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
382
 
383
  }
compatibility/class-wcml-ajax-layered-nav-widget.php CHANGED
@@ -5,34 +5,34 @@
5
  */
6
 
7
  class WCML_Ajax_Layered_Nav_Widget {
8
- function __construct() {
9
- add_filter('wc_ajax_layered_nav_sizeselector_term_id', array($this, 'wc_ajax_layered_nav_sizeselector_term_id'));
10
- add_filter('wc_ajax_layered_nav_query_editor', array($this, 'wc_ajax_layered_nav_query_editor'),10,3);
11
  }
12
 
13
- function wc_ajax_layered_nav_sizeselector_term_id($term_id) {
14
  $ulanguage_code = apply_filters( 'wpml_default_language', null );
15
- $term_id = apply_filters( 'wpml_object_id', $term_id, 'category', true, $ulanguage_code );
16
  return $term_id;
17
  }
18
 
19
- function wc_ajax_layered_nav_query_editor($posts, $attribute, $value){
20
- $posts = get_posts(
21
- array(
22
- 'post_type' => 'product',
23
- 'numberposts' => -1,
24
- 'post_status' => 'publish',
25
- 'fields' => 'ids',
26
- 'no_found_rows' => true,
27
- 'tax_query' => array(
28
- array(
29
- 'taxonomy' => $attribute,
30
- 'terms' => $value,
31
- 'field' => 'term_id'
32
- )
33
- )
34
- )
35
- );
36
- return $posts;
37
  }
38
  }
5
  */
6
 
7
  class WCML_Ajax_Layered_Nav_Widget {
8
+ public function __construct() {
9
+ add_filter( 'wc_ajax_layered_nav_sizeselector_term_id', [ $this, 'wc_ajax_layered_nav_sizeselector_term_id' ] );
10
+ add_filter( 'wc_ajax_layered_nav_query_editor', [ $this, 'wc_ajax_layered_nav_query_editor' ], 10, 3 );
11
  }
12
 
13
+ public function wc_ajax_layered_nav_sizeselector_term_id( $term_id ) {
14
  $ulanguage_code = apply_filters( 'wpml_default_language', null );
15
+ $term_id = apply_filters( 'wpml_object_id', $term_id, 'category', true, $ulanguage_code );
16
  return $term_id;
17
  }
18
 
19
+ public function wc_ajax_layered_nav_query_editor( $posts, $attribute, $value ) {
20
+ $posts = get_posts(
21
+ [
22
+ 'post_type' => 'product',
23
+ 'numberposts' => -1,
24
+ 'post_status' => 'publish',
25
+ 'fields' => 'ids',
26
+ 'no_found_rows' => true,
27
+ 'tax_query' => [
28
+ [
29
+ 'taxonomy' => $attribute,
30
+ 'terms' => $value,
31
+ 'field' => 'term_id',
32
+ ],
33
+ ],
34
+ ]
35
+ );
36
+ return $posts;
37
  }
38
  }
compatibility/class-wcml-aurum.php CHANGED
@@ -1,17 +1,17 @@
1
  <?php
2
 
3
- class WCML_Aurum{
4
 
5
- function __construct(){
6
 
7
- add_filter( 'wcml_multi_currency_ajax_actions', array( $this,'add_ajax_action' ) );
8
- }
9
 
10
- function add_ajax_action( $actions ){
11
 
12
- $actions[] = 'lab_wc_add_to_cart';
13
 
14
- return $actions;
15
- }
16
 
17
  }
1
  <?php
2
 
3
+ class WCML_Aurum {
4
 
5
+ public function __construct() {
6
 
7
+ add_filter( 'wcml_multi_currency_ajax_actions', [ $this, 'add_ajax_action' ] );
8
+ }
9
 
10
+ public function add_ajax_action( $actions ) {
11
 
12
+ $actions[] = 'lab_wc_add_to_cart';
13
 
14
+ return $actions;
15
+ }
16
 
17
  }
compatibility/class-wcml-bookings.php CHANGED
@@ -37,14 +37,15 @@ class WCML_Bookings {
37
 
38
  /**
39
  * WCML_Bookings constructor.
40
- * @param SitePress $sitepress
41
- * @param woocommerce_wpml $woocommerce_wpml
42
- * @param woocommerce $woocommerce
43
- * @param wpdb $wpdb
 
44
  * @param WPML_Element_Translation_Package $tp
45
- * @param WPML_Post_Translation $wpml_post_translations
46
  */
47
- function __construct( SitePress $sitepress, woocommerce_wpml $woocommerce_wpml, woocommerce $woocommerce, wpdb $wpdb, WPML_Element_Translation_Package $tp, WPML_Post_Translation $wpml_post_translations ) {
48
  $this->sitepress = $sitepress;
49
  $this->woocommerce_wpml = $woocommerce_wpml;
50
  $this->woocommerce = $woocommerce;
@@ -56,101 +57,156 @@ class WCML_Bookings {
56
  /**
57
  * Adds hooks.
58
  */
59
- public function add_hooks(){
60
 
61
  // Translate emails.
62
- add_filter( 'get_post_metadata', array( $this, 'get_order_language' ), 10, 4 );
63
- add_filter( 'woocommerce_booking_reminder_notification', array( $this, 'translate_notification' ), 9 );
64
- add_filter( 'woocommerce_booking_confirmed_notification', array( $this, 'translate_notification' ), 9 );
65
- add_filter( 'woocommerce_booking_cancelled_notification', array( $this, 'translate_notification' ), 9 );
66
-
67
- add_action( 'woocommerce_bookings_after_booking_base_cost', array(
68
- $this,
69
- 'wcml_price_field_after_booking_base_cost'
70
- ) );
71
- add_action( 'woocommerce_bookings_after_booking_block_cost', array(
72
- $this,
73
- 'wcml_price_field_after_booking_block_cost'
74
- ) );
75
- add_action( 'woocommerce_bookings_after_display_cost', array( $this, 'wcml_price_field_after_display_cost' ) );
76
- add_action( 'woocommerce_bookings_after_booking_pricing_base_cost', array(
77
- $this,
78
- 'wcml_price_field_after_booking_pricing_base_cost'
79
- ), 10, 2 );
80
- add_action( 'woocommerce_bookings_after_booking_pricing_cost', array(
81
- $this,
82
- 'wcml_price_field_after_booking_pricing_cost'
83
- ), 10, 2 );
84
- add_action( 'woocommerce_bookings_after_person_cost', array( $this, 'wcml_price_field_after_person_cost' ) );
85
- add_action( 'woocommerce_bookings_after_person_block_cost', array(
86
- $this,
87
- 'wcml_price_field_after_person_block_cost'
88
- ) );
89
- add_action( 'woocommerce_bookings_after_resource_cost', array(
90
- $this,
91
- 'wcml_price_field_after_resource_cost'
92
- ), 10, 2 );
93
- add_action( 'woocommerce_bookings_after_resource_block_cost', array(
94
- $this,
95
- 'wcml_price_field_after_resource_block_cost'
96
- ), 10, 2 );
97
- add_action( 'woocommerce_bookings_after_bookings_pricing', array( $this, 'after_bookings_pricing' ) );
98
-
99
- add_action( 'init', array( $this, 'load_assets' ) );
100
-
101
- add_action( 'save_post', array( $this, 'save_booking_action_handler' ), 110 );
102
-
103
- add_action( 'wcml_before_sync_product_data', array( $this, 'sync_bookings' ), 10, 3 );
104
- add_action( 'wcml_before_sync_product', array( $this, 'sync_booking_data' ), 10, 2 );
105
-
106
- add_filter( 'woocommerce_bookings_process_cost_rules_cost', array(
107
- $this,
108
- 'wc_bookings_process_cost_rules_cost'
109
- ), 10, 3 );
110
- add_filter( 'woocommerce_bookings_process_cost_rules_base_cost', array(
111
- $this,
112
- 'wc_bookings_process_cost_rules_base_cost'
113
- ), 10, 3 );
114
- add_filter( 'woocommerce_bookings_process_cost_rules_override_block', array(
115
- $this,
116
- 'wc_bookings_process_cost_rules_override_block_cost'
117
- ), 10, 3 );
118
-
119
- add_filter( 'wcml_multi_currency_ajax_actions', array( $this, 'wcml_multi_currency_is_ajax' ) );
120
-
121
- add_filter( 'wcml_cart_contents_not_changed', array(
122
- $this,
123
- 'filter_bundled_product_in_cart_contents'
124
- ), 10, 3 );
125
-
126
- add_action( 'woocommerce_bookings_after_create_booking_page', array( $this, 'booking_currency_dropdown' ) );
127
- add_action( 'init', array( $this, 'set_booking_currency' ) );
128
-
129
- add_action( 'wp_ajax_wcml_booking_set_currency', array( $this, 'set_booking_currency_ajax' ) );
130
- add_action( 'woocommerce_bookings_create_booking_page_add_order_item', array(
131
- $this,
132
- 'set_order_currency_on_create_booking_page'
133
- ) );
134
- add_filter( 'woocommerce_currency_symbol', array( $this, 'filter_booking_currency_symbol' ) );
135
- add_filter( 'get_booking_products_args', array( $this, 'filter_get_booking_products_args' ) );
136
- add_filter( 'wcml_filter_currency_position', array( $this, 'create_booking_page_client_currency' ) );
137
-
138
- add_filter( 'wcml_client_currency', array( $this, 'create_booking_page_client_currency' ) );
139
-
140
- add_action( 'wcml_gui_additional_box_html', array( $this, 'custom_box_html' ), 10, 3 );
141
- add_filter( 'wcml_gui_additional_box_data', array( $this, 'custom_box_html_data' ), 10, 4 );
142
- add_filter( 'wcml_check_is_single', array( $this, 'show_custom_blocks_for_resources_and_persons' ), 10, 3 );
143
- add_filter( 'wcml_do_not_display_custom_fields_for_product', array( $this, 'replace_tm_editor_custom_fields_with_own_sections' ) );
144
- add_filter( 'wcml_not_display_single_fields_to_translate', array(
145
- $this,
146
- 'remove_single_custom_fields_to_translate'
147
- ) );
148
- add_filter( 'wcml_product_content_label', array( $this, 'product_content_resource_label' ), 10, 2 );
149
- add_action( 'wcml_update_extra_fields', array( $this, 'wcml_products_tab_sync_resources_and_persons' ), 10, 4 );
150
-
151
- add_action( 'woocommerce_new_booking', array( $this, 'duplicate_booking_for_translations' ) );
152
-
153
- $bookings_statuses = array(
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
154
  'unpaid',
155
  'pending-confirmation',
156
  'confirmed',
@@ -158,89 +214,97 @@ class WCML_Bookings {
158
  'cancelled',
159
  'complete',
160
  'in-cart',
161
- 'was-in-cart'
162
- );
163
  foreach ( $bookings_statuses as $status ) {
164
- add_action( 'woocommerce_booking_' . $status, array( $this, 'update_status_for_translations' ) );
165
  }
166
 
167
- add_filter( 'parse_query', array( $this, 'booking_filters_query' ) );
168
- add_filter( 'woocommerce_bookings_in_date_range_query', array( $this, 'bookings_in_date_range_query' ) );
169
- add_action( 'before_delete_post', array( $this, 'delete_bookings' ) );
170
- add_action( 'wp_trash_post', array( $this, 'trash_bookings' ) );
 
171
 
172
  if ( is_admin() ) {
173
 
174
- add_filter( 'wpml_tm_translation_job_data', array(
175
- $this,
176
- 'append_persons_to_translation_package'
177
- ), 10, 2 );
178
- add_action( 'wpml_translation_job_saved', array( $this, 'save_person_translation' ), 10, 3 );
179
-
180
- add_filter( 'wpml_tm_translation_job_data', array(
181
- $this,
182
- 'append_resources_to_translation_package'
183
- ), 10, 2 );
184
- add_action( 'wpml_translation_job_saved', array( $this, 'save_resource_translation' ), 10, 3 );
185
 
186
- //lock fields on translations pages
187
- add_filter( 'wcml_js_lock_fields_ids', array( $this, 'wcml_js_lock_fields_ids' ) );
188
- add_filter( 'wcml_after_load_lock_fields_js', array( $this, 'localize_lock_fields_js' ) );
 
 
 
 
 
 
189
 
190
- //allow filtering resources by language
191
- add_filter( 'get_booking_resources_args', array( $this, 'filter_get_booking_resources_args' ) );
 
192
 
193
- add_filter( 'get_translatable_documents_all', array( $this, 'filter_translatable_documents' ) );
 
194
 
195
- add_filter( 'pre_wpml_is_translated_post_type', array( $this, 'filter_is_translated_post_type' ) );
196
 
197
- add_action( 'woocommerce_product_data_panels', array( $this, 'show_pointer_info' ) );
198
 
199
- add_action( 'save_post', array( $this, 'sync_booking_status' ), 10, 3 );
200
 
201
- add_filter( 'wcml_emails_options_to_translate', array( $this, 'emails_options_to_translate' ) );
202
 
203
- add_filter( 'wcml_emails_text_keys_to_translate', array( $this, 'emails_text_keys_to_translate' ) );
204
 
205
- add_filter( 'woocommerce_email_get_option', array( $this, 'translate_emails_text_strings' ), 10, 4 );
206
 
 
207
 
208
- add_action( 'woocommerce_booking_confirmed_notification', array( $this, 'translate_booking_confirmed_email_texts' ), 9 );
209
 
210
- add_action( 'woocommerce_booking_pending-confirmation_to_cancelled_notification', array( $this, 'translate_booking_cancelled_email_texts' ), 9 );
211
- add_action( 'woocommerce_booking_confirmed_to_cancelled_notification', array( $this, 'translate_booking_cancelled_email_texts' ), 9 );
212
- add_action( 'woocommerce_booking_paid_to_cancelled_notification', array( $this, 'translate_booking_cancelled_email_texts' ), 9 );
213
 
214
- add_action( 'wc-booking-reminder', array( $this, 'translate_booking_confirmed_email_texts' ), 9 );
215
- add_action( 'woocommerce_admin_new_booking_notification', array( $this, 'translate_new_booking_email_texts' ), 9 );
216
 
217
 
218
- add_action( 'woocommerce_booking_pending-confirmation_to_cancelled_notification', array( $this, 'translate_booking_cancelled_admin_email_texts' ), 9 );
219
- add_action( 'woocommerce_booking_confirmed_to_cancelled_notification', array( $this, 'translate_booking_cancelled_admin_email_texts' ), 9 );
220
- add_action( 'woocommerce_booking_paid_to_cancelled_notification', array( $this, 'translate_booking_cancelled_admin_email_texts' ), 9 );
221
 
222
- add_filter( 'wcml_email_language', array( $this, 'booking_email_language' ) );
223
 
224
- if( $this->is_bookings_listing_page() ) {
225
  $this->remove_language_switcher();
226
- add_filter( 'wp_count_posts', array( $this, 'count_bookings_by_current_language' ), 10, 2 );
227
- add_filter( 'views_edit-wc_booking', array( $this, 'unset_mine_from_bookings_views' ) );
228
  }
229
  }
230
 
231
- if ( ! is_admin() || isset( $_POST['action'] ) && $_POST['action'] == 'wc_bookings_calculate_costs' ) {
232
- add_filter( 'get_post_metadata', array( $this, 'filter_wc_booking_cost' ), 10, 4 );
233
  }
234
 
235
- add_filter( 'wpml_language_filter_extra_conditions_snippet', array( $this, 'extra_conditions_to_filter_bookings' ) );
236
 
237
  $this->clear_transient_fields();
238
 
239
- add_filter( 'wpml_tm_dashboard_translatable_types', array( $this, 'hide_bookings_type_on_tm_dashboard' ) );
240
 
241
- add_filter( 'wcml_add_to_cart_sold_individually', array( $this, 'add_to_cart_sold_individually' ), 10, 4 );
242
 
243
- add_filter( 'woocommerce_bookings_account_tables', array( $this, 'filter_my_account_bookings_tables_by_current_language' ) );
244
 
245
  }
246
 
@@ -264,13 +328,15 @@ class WCML_Bookings {
264
  }
265
 
266
  // From here we can grab the order_id and return its language.
267
- $order_id = $this->wpdb->get_var( $this->wpdb->prepare(
268
- "SELECT order_id FROM {$this->wpdb->prefix}woocommerce_order_items WHERE order_item_id = %d",
269
- $order_item_id
270
- ) ); // WPCS: unprepared SQL OK.
271
- remove_filter( 'get_post_metadata', array( $this, 'get_order_language' ), 10 );
 
 
272
  $check = get_post_meta( $order_id, 'wpml_language', $single );
273
- add_filter( 'get_post_metadata', array( $this, 'get_order_language' ), 10, 4 );
274
  }
275
 
276
  return $check;
@@ -292,64 +358,63 @@ class WCML_Bookings {
292
  $this->save_custom_costs( $booking_id );
293
  }
294
 
295
- function wcml_price_field_after_booking_base_cost( $post_id ) {
296
 
297
  $this->echo_wcml_price_field( $post_id, 'wcml_wc_booking_cost' );
298
 
299
  }
300
 
301
- function wcml_price_field_after_booking_block_cost( $post_id ) {
302
  if ( $this->sitepress->get_wp_api()->version_compare( $this->sitepress->get_wp_api()->constant( 'WC_BOOKINGS_VERSION' ), '1.10.9', '<' ) ) {
303
  $this->echo_wcml_price_field( $post_id, 'wcml_wc_booking_base_cost' );
304
- }else{
305
  $this->echo_wcml_price_field( $post_id, 'wcml_wc_booking_block_cost' );
306
- }
307
  }
308
 
309
- function wcml_price_field_after_display_cost( $post_id ) {
310
 
311
  $this->echo_wcml_price_field( $post_id, 'wcml_wc_display_cost' );
312
 
313
  }
314
 
315
- function wcml_price_field_after_booking_pricing_base_cost( $pricing, $post_id ) {
316
 
317
  $this->echo_wcml_price_field( $post_id, 'wcml_wc_booking_pricing_base_cost', $pricing );
318
 
319
  }
320
 
321
- function wcml_price_field_after_booking_pricing_cost( $pricing, $post_id ) {
322
 
323
  $this->echo_wcml_price_field( $post_id, 'wcml_wc_booking_pricing_cost', $pricing );
324
 
325
  }
326
 
327
- function wcml_price_field_after_person_cost( $person_type_id ) {
328
 
329
  $this->echo_wcml_price_field( $person_type_id, 'wcml_wc_booking_person_cost', false, false );
330
 
331
  }
332
 
333
- function wcml_price_field_after_person_block_cost( $person_type_id ) {
334
 
335
  $this->echo_wcml_price_field( $person_type_id, 'wcml_wc_booking_person_block_cost', false, false );
336
 
337
  }
338
 
339
- function wcml_price_field_after_resource_cost( $resource_id, $post_id ) {
340
 
341
  $this->echo_wcml_price_field( $post_id, 'wcml_wc_booking_resource_cost', false, true, $resource_id );
342
 
343
  }
344
 
345
- function wcml_price_field_after_resource_block_cost( $resource_id, $post_id ) {
346
 
347
  $this->echo_wcml_price_field( $post_id, 'wcml_wc_booking_resource_block_cost', false, true, $resource_id );
348
 
349
  }
350
 
351
- function echo_wcml_price_field( $post_id, $field, $pricing = false, $check = true, $resource_id = false ) {
352
-
353
 
354
  if ( ( ! $check || $this->woocommerce_wpml->products->is_original_product( $post_id ) ) && $this->woocommerce_wpml->settings['enable_multi_currency'] == WCML_MULTI_CURRENCIES_INDEPENDENT ) {
355
 
@@ -367,62 +432,67 @@ class WCML_Bookings {
367
 
368
  switch ( $field ) {
369
  case 'wcml_wc_booking_cost':
370
- woocommerce_wp_text_input( array(
371
- 'id' => 'wcml_wc_booking_cost',
372
- 'class' => 'wcml_bookings_custom_price',
373
- 'name' => 'wcml_wc_booking_cost[' . $currency_code . ']',
374
- 'label' => get_woocommerce_currency_symbol( $currency_code ),
375
- 'description' => __( 'One-off cost for the booking as a whole.', 'woocommerce-bookings' ),
376
- 'value' => get_post_meta( $post_id, '_wc_booking_cost_' . $currency_code, true ),
377
- 'type' => 'number',
378
- 'desc_tip' => true,
379
- 'custom_attributes' => array(
380
- 'min' => '',
381
- 'step' => '0.01'
382
- )
383
- ) );
 
 
384
  break;
385
  case 'wcml_wc_booking_block_cost':
386
  case 'wcml_wc_booking_base_cost':
387
- $block_cost_key = '_wc_booking_base_cost_';
388
- if ($field === 'wcml_wc_booking_block_cost' ){
389
- $block_cost_key = '_wc_booking_block_cost_';
390
- }
391
- $block_cost_key .= $currency_code;
392
- woocommerce_wp_text_input( array(
393
- 'id' => $field,
394
- 'class' => 'wcml_bookings_custom_price',
395
- 'name' => $field . '[' . $currency_code . ']',
396
- 'label' => get_woocommerce_currency_symbol( $currency_code ),
397
- 'description' => __( 'This is the cost per block booked. All other costs (for resources and persons) are added to this.', 'woocommerce-bookings' ),
398
- 'value' => get_post_meta( $post_id, $block_cost_key, true ),
399
- 'type' => 'number',
400
- 'desc_tip' => true,
401
- 'custom_attributes' => array(
402
- 'min' => '',
403
- 'step' => '0.01'
404
- )
405
- ) );
 
 
406
  break;
407
  case 'wcml_wc_display_cost':
408
- woocommerce_wp_text_input( array(
409
- 'id' => 'wcml_wc_display_cost',
410
- 'class' => 'wcml_bookings_custom_price',
411
- 'name' => 'wcml_wc_display_cost[' . $currency_code . ']',
412
- 'label' => get_woocommerce_currency_symbol( $currency_code ),
413
- 'description' => __( 'The cost is displayed to the user on the frontend. Leave blank to have it calculated for you. If a booking has varying costs, this will be prefixed with the word "from:".', 'woocommerce-bookings' ),
414
- 'value' => get_post_meta( $post_id, '_wc_display_cost_' . $currency_code, true ),
415
- 'type' => 'number',
416
- 'desc_tip' => true,
417
- 'custom_attributes' => array(
418
- 'min' => '',
419
- 'step' => '0.01'
420
- )
421
- ) );
 
 
422
  break;
423
 
424
  case 'wcml_wc_booking_pricing_base_cost':
425
-
426
  if ( isset( $pricing[ 'base_cost_' . $currency_code ] ) ) {
427
  $value = $pricing[ 'base_cost_' . $currency_code ];
428
  } else {
@@ -430,13 +500,12 @@ class WCML_Bookings {
430
  }
431
 
432
  echo '<div class="wcml_bookings_range_block" >';
433
- echo '<label>' . get_woocommerce_currency_symbol( $currency_code ) . '</label>';
434
- echo '<input type="number" step="0.01" name="wcml_wc_booking_pricing_base_cost[' . $currency_code . '][]" class="wcml_bookings_custom_price" value="' . $value . '" placeholder="0" />';
435
  echo '</div>';
436
  break;
437
 
438
  case 'wcml_wc_booking_pricing_cost':
439
-
440
  if ( isset( $pricing[ 'cost_' . $currency_code ] ) ) {
441
  $value = $pricing[ 'cost_' . $currency_code ];
442
  } else {
@@ -444,33 +513,30 @@ class WCML_Bookings {
444
  }
445
 
446
  echo '<div class="wcml_bookings_range_block" >';
447
- echo '<label>' . get_woocommerce_currency_symbol( $currency_code ) . '</label>';
448
- echo '<input type="number" step="0.01" name="wcml_wc_booking_pricing_cost[' . $currency_code . '][]" class="wcml_bookings_custom_price" value="' . $value . '" placeholder="0" />';
449
  echo '</div>';
450
  break;
451
 
452
  case 'wcml_wc_booking_person_cost':
453
-
454
  $value = get_post_meta( $post_id, 'cost_' . $currency_code, true );
455
 
456
  echo '<div class="wcml_bookings_person_block" >';
457
- echo '<label>' . get_woocommerce_currency_symbol( $currency_code ) . '</label>';
458
- echo '<input type="number" step="0.01" name="wcml_wc_booking_person_cost[' . $post_id . '][' . $currency_code . ']" class="wcml_bookings_custom_price" value="' . $value . '" placeholder="0" />';
459
  echo '</div>';
460
  break;
461
 
462
  case 'wcml_wc_booking_person_block_cost':
463
-
464
  $value = get_post_meta( $post_id, 'block_cost_' . $currency_code, true );
465
 
466
  echo '<div class="wcml_bookings_person_block" >';
467
- echo '<label>' . get_woocommerce_currency_symbol( $currency_code ) . '</label>';
468
- echo '<input type="number" step="0.01" name="wcml_wc_booking_person_block_cost[' . $post_id . '][' . $currency_code . ']" class="wcml_bookings_custom_price" value="' . $value . '" placeholder="0" />';
469
  echo '</div>';
470
  break;
471
 
472
  case 'wcml_wc_booking_resource_cost':
473
-
474
  $resource_base_costs = maybe_unserialize( get_post_meta( $post_id, '_resource_base_costs', true ) );
475
 
476
  if ( isset( $resource_base_costs['custom_costs'][ $currency_code ][ $resource_id ] ) ) {
@@ -480,13 +546,12 @@ class WCML_Bookings {
480
  }
481
 
482
  echo '<div class="wcml_bookings_resource_block" >';
483
- echo '<label>' . get_woocommerce_currency_symbol( $currency_code ) . '</label>';
484
- echo '<input type="number" step="0.01" name="wcml_wc_booking_resource_cost[' . $resource_id . '][' . $currency_code . ']" class="wcml_bookings_custom_price" value="' . $value . '" placeholder="0" />';
485
  echo '</div>';
486
  break;
487
 
488
  case 'wcml_wc_booking_resource_block_cost':
489
-
490
  $resource_block_costs = maybe_unserialize( get_post_meta( $post_id, '_resource_block_costs', true ) );
491
 
492
  if ( isset( $resource_block_costs['custom_costs'][ $currency_code ][ $resource_id ] ) ) {
@@ -496,8 +561,8 @@ class WCML_Bookings {
496
  }
497
 
498
  echo '<div class="wcml_bookings_resource_block" >';
499
- echo '<label>' . get_woocommerce_currency_symbol( $currency_code ) . '</label>';
500
- echo '<input type="number" step="0.01" name="wcml_wc_booking_resource_block_cost[' . $resource_id . '][' . $currency_code . ']" class="wcml_bookings_custom_price" value="' . $value . '" placeholder="0" />';
501
  echo '</div>';
502
  break;
503
 
@@ -505,7 +570,6 @@ class WCML_Bookings {
505
  break;
506
 
507
  }
508
-
509
  }
510
 
511
  echo '</div>';
@@ -513,10 +577,9 @@ class WCML_Bookings {
513
  }
514
  }
515
 
516
- function after_bookings_pricing( $post_id ) {
517
 
518
-
519
- if ( in_array( 'booking', wp_get_post_terms( $post_id, 'product_type', array( "fields" => "names" ) ) ) && $this->woocommerce_wpml->products->is_original_product( $post_id ) && $this->woocommerce_wpml->settings['enable_multi_currency'] == WCML_MULTI_CURRENCIES_INDEPENDENT ) {
520
 
521
  $custom_costs_status = get_post_meta( $post_id, '_wcml_custom_costs_status', true );
522
 
@@ -524,13 +587,13 @@ class WCML_Bookings {
524
 
525
  echo '<div class="wcml_custom_costs">';
526
 
527
- echo '<input type="radio" name="_wcml_custom_costs" id="wcml_custom_costs_auto" value="0" class="wcml_custom_costs_input" ' . $checked . ' />';
528
- echo '<label for="wcml_custom_costs_auto">' . __( 'Calculate costs in other currencies automatically', 'woocommerce-multilingual' ) . '</label>';
529
 
530
- $checked = $custom_costs_status == 1 ? 'checked="checked"' : ' ';
531
 
532
- echo '<input type="radio" name="_wcml_custom_costs" value="1" id="wcml_custom_costs_manually" class="wcml_custom_costs_input" ' . $checked . ' />';
533
- echo '<label for="wcml_custom_costs_manually">' . __( 'Set costs in other currencies manually', 'woocommerce-multilingual' ) . '</label>';
534
 
535
  wp_nonce_field( 'wcml_save_custom_costs', '_wcml_custom_costs_nonce' );
536
 
@@ -539,7 +602,7 @@ class WCML_Bookings {
539
 
540
  }
541
 
542
- function save_custom_costs( $post_id ) {
543
  $nonce = filter_var( isset( $_POST['_wcml_custom_costs_nonce'] ) ? $_POST['_wcml_custom_costs_nonce'] : '', FILTER_SANITIZE_FULL_SPECIAL_CHARS );
544
 
545
  if ( isset( $_POST['_wcml_custom_costs'] ) && isset( $nonce ) && wp_verify_nonce( $nonce, 'wcml_save_custom_costs' ) ) {
@@ -556,7 +619,6 @@ class WCML_Bookings {
556
  $this->update_booking_costs( $currencies, $post_id );
557
  $this->update_booking_pricing( $currencies, $post_id );
558
 
559
-
560
  if ( isset( $_POST['wcml_wc_booking_person_cost'] ) && is_array( $_POST['wcml_wc_booking_person_cost'] ) ) {
561
  $this->update_booking_person_cost( $currencies, $_POST['wcml_wc_booking_person_cost'] );
562
  }
@@ -581,64 +643,70 @@ class WCML_Bookings {
581
 
582
  }
583
 
584
- // sync existing product bookings for translations
585
- function sync_bookings( $original_product_id, $product_id, $language ) {
586
  $all_bookings_for_product = $this->wpdb->get_results( $this->wpdb->prepare( "SELECT post_id as id FROM {$this->wpdb->postmeta} WHERE meta_key = '_booking_product_id' AND meta_value = %d", $original_product_id ) );
587
 
588
  foreach ( $all_bookings_for_product as $booking ) {
589
 
590
- if( $language === $this->wpml_post_translations->get_source_lang_code( $booking->id ) ){
591
- continue;
592
- }
593
 
594
  $booking_translations = $this->get_translated_bookings( $booking->id );
595
 
596
- if ( !isset( $booking_translations[ $language ] ) ) {
597
  $this->duplicate_booking_for_translations( $booking->id, $language );
598
- } elseif ( !get_post_meta( $booking_translations[ $language ], '_booking_product_id', true ) ) {
599
- $this->update_translated_booking_meta( $booking_translations[ $language ], $booking->id, $language );
600
  }
601
  }
602
  }
603
 
604
  /**
605
- * @param int $translated_booking_id
606
- * @param int $original_booking_id
607
  * @param string $language
608
  */
609
- private function update_translated_booking_meta( $translated_booking_id, $original_booking_id, $language ){
610
  update_post_meta( $translated_booking_id, '_booking_product_id', $this->get_translated_booking_product_id( $original_booking_id, $language ) );
611
  update_post_meta( $translated_booking_id, '_booking_resource_id', $this->get_translated_booking_resource_id( $original_booking_id, $language ) );
612
  update_post_meta( $translated_booking_id, '_booking_persons', $this->get_translated_booking_persons_ids( $original_booking_id, $language ) );
613
- }
614
 
615
- function sync_booking_data( $original_product_id, $current_product_id ) {
616
 
617
  if ( has_term( 'booking', 'product_type', $original_product_id ) ) {
618
  $translations = $this->wpml_post_translations->get_element_translations( $original_product_id, false, true );
619
  foreach ( $translations as $translation ) {
620
- $language = $this->wpml_post_translations->get_element_lang_code( $translation );
621
 
622
- //sync_resources
623
- $this->sync_resources( $original_product_id, $translation, $language );
624
 
625
- //sync_persons
626
- $this->sync_persons( $original_product_id, $translation, $language );
627
  }
628
  }
629
  }
630
 
631
- function sync_resources( $original_product_id, $translated_product_id, $lang_code, $duplicate = true ) {
632
 
633
- $original_resources = $this->wpdb->get_results( $this->wpdb->prepare(
634
- "SELECT resource_id, sort_order FROM {$this->wpdb->prefix}wc_booking_relationships WHERE product_id = %d",
635
- $original_product_id ) );
 
 
 
636
 
637
- $translated_resources = $this->wpdb->get_col( $this->wpdb->prepare(
638
- "SELECT resource_id FROM {$this->wpdb->prefix}wc_booking_relationships WHERE product_id = %d",
639
- $translated_product_id ) );
 
 
 
640
 
641
- $used_translated_resources = array();
642
 
643
  foreach ( $original_resources as $resource ) {
644
 
@@ -656,7 +724,6 @@ class WCML_Bookings {
656
  $this->duplicate_resource( $translated_product_id, $resource, $lang_code );
657
  }
658
  }
659
-
660
  }
661
 
662
  $removed_translated_resources_id = array_diff( $translated_resources, $used_translated_resources );
@@ -669,7 +736,7 @@ class WCML_Bookings {
669
 
670
  }
671
 
672
- function duplicate_resource( $tr_product_id, $resource, $lang_code ) {
673
  global $iclTranslationManagement;
674
 
675
  if ( method_exists( $this->sitepress, 'make_duplicate' ) ) {
@@ -679,7 +746,7 @@ class WCML_Bookings {
679
  } else {
680
 
681
  if ( ! isset( $iclTranslationManagement ) ) {
682
- $iclTranslationManagement = new TranslationManagement;
683
  }
684
 
685
  $trns_resource_id = $iclTranslationManagement->make_duplicate( $resource->resource_id, $lang_code );
@@ -688,11 +755,11 @@ class WCML_Bookings {
688
 
689
  $this->wpdb->insert(
690
  $this->wpdb->prefix . 'wc_booking_relationships',
691
- array(
692
  'product_id' => $tr_product_id,
693
  'resource_id' => $trns_resource_id,
694
- 'sort_order' => $resource->sort_order
695
- )
696
  );
697
 
698
  delete_post_meta( $trns_resource_id, '_icl_lang_duplicate_of' );
@@ -704,11 +771,11 @@ class WCML_Bookings {
704
 
705
  $this->wpdb->insert(
706
  $this->wpdb->prefix . 'wc_booking_relationships',
707
- array(
708
  'sort_order' => $resource_data->sort_order,
709
  'product_id' => $product_id,
710
- 'resource_id' => $resource_id
711
- )
712
  );
713
 
714
  update_post_meta( $resource_id, 'qty', get_post_meta( $resource_data->resource_id, 'qty', true ) );
@@ -720,10 +787,10 @@ class WCML_Bookings {
720
 
721
  $this->wpdb->delete(
722
  $this->wpdb->prefix . 'wc_booking_relationships',
723
- array(
724
  'product_id' => $product_id,
725
- 'resource_id' => $resource_id
726
- )
727
  );
728
 
729
  }
@@ -732,27 +799,25 @@ class WCML_Bookings {
732
 
733
  $this->wpdb->update(
734
  $this->wpdb->prefix . 'wc_booking_relationships',
735
- array(
736
- 'sort_order' => $resource_data->sort_order
737
- ),
738
- array(
739
  'product_id' => $product_id,
740
- 'resource_id' => $resource_id
741
- )
742
  );
743
 
744
  update_post_meta( $resource_id, 'qty', get_post_meta( $resource_data->resource_id, 'qty', true ) );
745
  update_post_meta( $resource_id, '_wc_booking_availability', get_post_meta( $resource_data->resource_id, '_wc_booking_availability', true ) );
746
 
747
-
748
  }
749
 
750
- function sync_persons( $original_product_id, $tr_product_id, $lang_code, $duplicate = true ) {
751
  $orig_persons = $this->wpdb->get_col( $this->wpdb->prepare( "SELECT ID FROM {$this->wpdb->posts} WHERE post_parent = %d AND post_type = 'bookable_person'", $original_product_id ) );
752
 
753
  $trnsl_persons = $this->wpdb->get_col( $this->wpdb->prepare( "SELECT ID FROM {$this->wpdb->posts} WHERE post_parent = %d AND post_type = 'bookable_person'", $tr_product_id ) );
754
 
755
-
756
  foreach ( $orig_persons as $person ) {
757
 
758
  $trnsl_person_id = apply_filters( 'translate_object_id', $person, 'bookable_person', false, $lang_code );
@@ -768,7 +833,6 @@ class WCML_Bookings {
768
  update_post_meta( $trnsl_person_id, 'max', get_post_meta( $person, 'max', true ) );
769
  update_post_meta( $trnsl_person_id, 'min', get_post_meta( $person, 'min', true ) );
770
 
771
-
772
  if ( get_post_meta( $person, '_wcml_custom_costs_status', true ) && $this->woocommerce_wpml->settings['enable_multi_currency'] == WCML_MULTI_CURRENCIES_INDEPENDENT ) {
773
  $currencies = $this->woocommerce_wpml->multi_currency->get_currencies();
774
 
@@ -779,9 +843,7 @@ class WCML_Bookings {
779
 
780
  }
781
  }
782
-
783
  }
784
-
785
  } else {
786
 
787
  if ( $duplicate ) {
@@ -793,9 +855,7 @@ class WCML_Bookings {
793
  continue;
794
 
795
  }
796
-
797
  }
798
-
799
  }
800
 
801
  foreach ( $trnsl_persons as $trnsl_person ) {
@@ -806,7 +866,7 @@ class WCML_Bookings {
806
 
807
  }
808
 
809
- function duplicate_person( $tr_product_id, $person_id, $lang_code ) {
810
  global $iclTranslationManagement;
811
 
812
  if ( method_exists( $this->sitepress, 'make_duplicate' ) ) {
@@ -816,7 +876,7 @@ class WCML_Bookings {
816
  } else {
817
 
818
  if ( ! isset( $iclTranslationManagement ) ) {
819
- $iclTranslationManagement = new TranslationManagement;
820
  }
821
 
822
  $new_person_id = $iclTranslationManagement->make_duplicate( $person_id, $lang_code );
@@ -825,12 +885,12 @@ class WCML_Bookings {
825
 
826
  $this->wpdb->update(
827
  $this->wpdb->posts,
828
- array(
829
- 'post_parent' => $tr_product_id
830
- ),
831
- array(
832
- 'ID' => $new_person_id
833
- )
834
  );
835
 
836
  delete_post_meta( $new_person_id, '_icl_lang_duplicate_of' );
@@ -838,19 +898,22 @@ class WCML_Bookings {
838
  return $new_person_id;
839
  }
840
 
841
- function filter_wc_booking_cost( $check, $object_id, $meta_key, $single ) {
842
 
843
- if ( in_array( $meta_key, array(
844
- '_wc_booking_cost',
845
- '_wc_booking_base_cost',
846
- '_wc_display_cost',
847
- '_wc_booking_pricing',
848
- 'cost',
849
- '_wc_booking_block_cost',
850
- 'block_cost',
851
- '_resource_base_costs',
852
- '_resource_block_costs'
853
- ) ) ) {
 
 
 
854
 
855
  if ( WCML_MULTI_CURRENCIES_INDEPENDENT === $this->woocommerce_wpml->settings['enable_multi_currency'] ) {
856
 
@@ -864,7 +927,7 @@ class WCML_Bookings {
864
  return $check;
865
  }
866
 
867
- if ( in_array( $meta_key, array( 'cost', 'block_cost' ) ) ) {
868
 
869
  if ( get_post_type( $object_id ) == 'bookable_person' ) {
870
 
@@ -879,30 +942,31 @@ class WCML_Bookings {
879
 
880
  } else {
881
 
882
- remove_filter( 'get_post_metadata', array( $this, 'filter_wc_booking_cost' ), 10, 4 );
883
 
884
  $cost = get_post_meta( $object_id, $meta_key, true );
885
 
886
- add_filter( 'get_post_metadata', array( $this, 'filter_wc_booking_cost' ), 10, 4 );
887
 
888
  return $this->woocommerce_wpml->multi_currency->prices->convert_price_amount( $cost, $currency );
889
  }
890
-
891
  } else {
892
 
893
  return $check;
894
 
895
  }
896
-
897
  }
898
 
899
- if ( in_array( $meta_key, array(
900
- '_wc_booking_pricing',
901
- '_resource_base_costs',
902
- '_resource_block_costs'
903
- ) ) ) {
 
 
 
904
 
905
- remove_filter( 'get_post_metadata', array( $this, 'filter_wc_booking_cost' ), 10, 4 );
906
 
907
  if ( $meta_key == '_wc_booking_pricing' ) {
908
 
@@ -911,7 +975,6 @@ class WCML_Bookings {
911
  } else {
912
  $value = $check;
913
  }
914
-
915
  } else {
916
 
917
  $costs = maybe_unserialize( get_post_meta( $object_id, $meta_key, true ) );
@@ -920,17 +983,17 @@ class WCML_Bookings {
920
  $value = $check;
921
  } elseif ( $cost_status && isset( $costs['custom_costs'][ $currency ] ) ) {
922
 
923
- $res_costs = array();
924
  foreach ( $costs['custom_costs'][ $currency ] as $resource_id => $cost ) {
925
  $trns_resource_id = apply_filters( 'translate_object_id', $resource_id, 'bookable_resource', true, $this->sitepress->get_current_language() );
926
  $res_costs[ $trns_resource_id ] = $cost;
927
  }
928
- $value = array( 0 => $res_costs );
929
  } elseif ( $cost_status && isset( $costs[0]['custom_costs'][ $currency ] ) ) {
930
- $value = array( 0 => $costs[0]['custom_costs'][ $currency ] );
931
  } else {
932
 
933
- $converted_values = array();
934
 
935
  foreach ( $costs as $resource_id => $cost ) {
936
  $converted_values[0][ $resource_id ] = $this->woocommerce_wpml->multi_currency->prices->convert_price_amount( $cost, $currency );
@@ -938,10 +1001,9 @@ class WCML_Bookings {
938
 
939
  $value = $converted_values;
940
  }
941
-
942
  }
943
 
944
- add_filter( 'get_post_metadata', array( $this, 'filter_wc_booking_cost' ), 10, 4 );
945
 
946
  return $value;
947
 
@@ -955,61 +1017,58 @@ class WCML_Bookings {
955
 
956
  } else {
957
 
958
- remove_filter( 'get_post_metadata', array( $this, 'filter_wc_booking_cost' ), 10, 4 );
959
 
960
  $value = get_post_meta( $original_id, $meta_key, true );
961
 
962
  $value = $this->woocommerce_wpml->multi_currency->prices->convert_price_amount( $value, $currency );
963
 
964
- add_filter( 'get_post_metadata', array( $this, 'filter_wc_booking_cost' ), 10, 4 );
965
 
966
  return $value;
967
 
968
  }
969
-
970
  }
971
-
972
  }
973
 
974
  return $check;
975
  }
976
 
977
- function sync_resource_costs_with_translations( $object_id, $meta_key, $check = false ) {
978
-
979
 
980
  $original_product_id = $this->woocommerce_wpml->products->get_original_product_id( $object_id );
981
 
982
  if ( $object_id == $original_product_id ) {
983
 
984
- $translations = $this->wpml_post_translations->get_element_translations( $object_id, false, true );
985
 
986
  foreach ( $translations as $translation ) {
987
  $this->sync_resource_costs(
988
  $original_product_id,
989
- $translation,
990
- $meta_key,
991
- $this->wpml_post_translations->get_element_lang_code( $translation )
992
- );
993
  }
994
 
995
  return $check;
996
  } else {
997
  $this->sync_resource_costs(
998
- $original_product_id,
999
- $object_id,
1000
- $meta_key,
1001
- $this->wpml_post_translations->get_element_lang_code( $object_id )
1002
- );
1003
  return true;
1004
  }
1005
 
1006
  }
1007
 
1008
- function sync_resource_costs( $original_product_id, $object_id, $meta_key, $language_code ) {
1009
 
1010
  $original_costs = maybe_unserialize( get_post_meta( $original_product_id, $meta_key, true ) );
1011
 
1012
- $wc_booking_resource_costs = array();
1013
  if ( ! empty( $original_costs ) ) {
1014
  foreach ( $original_costs as $resource_id => $costs ) {
1015
 
@@ -1024,9 +1083,7 @@ class WCML_Bookings {
1024
  $wc_booking_resource_costs['custom_costs'][ $code ][ $trns_resource_id ] = $custom_cost;
1025
 
1026
  }
1027
-
1028
  }
1029
-
1030
  } else {
1031
 
1032
  $trns_resource_id = apply_filters( 'translate_object_id', $resource_id, 'bookable_resource', true, $language_code );
@@ -1034,7 +1091,6 @@ class WCML_Bookings {
1034
  $wc_booking_resource_costs[ $trns_resource_id ] = $costs;
1035
 
1036
  }
1037
-
1038
  }
1039
  }
1040
 
@@ -1042,19 +1098,19 @@ class WCML_Bookings {
1042
 
1043
  }
1044
 
1045
- function wc_bookings_process_cost_rules_cost( $cost, $fields, $key ) {
1046
  return $this->filter_pricing_cost( $cost, $fields, 'cost_', $key );
1047
  }
1048
 
1049
- function wc_bookings_process_cost_rules_base_cost( $base_cost, $fields, $key ) {
1050
  return $this->filter_pricing_cost( $base_cost, $fields, 'base_cost_', $key );
1051
  }
1052
 
1053
- function wc_bookings_process_cost_rules_override_block_cost( $override_cost, $fields, $key ) {
1054
  return $this->filter_pricing_cost( $override_cost, $fields, 'override_block_', $key );
1055
  }
1056
 
1057
- function filter_pricing_cost( $cost, $fields, $name, $key ) {
1058
  global $product;
1059
 
1060
  if ( $this->woocommerce_wpml->settings['enable_multi_currency'] == WCML_MULTI_CURRENCIES_INDEPENDENT ) {
@@ -1087,50 +1143,49 @@ class WCML_Bookings {
1087
 
1088
  $needs_filter_pricing_cost = $this->needs_filter_pricing_cost( $name, $fields );
1089
 
1090
- if( $needs_filter_pricing_cost ){
1091
  if ( isset( $fields[ $name . $currency ] ) ) {
1092
  return $fields[ $name . $currency ];
1093
  } else {
1094
  return $this->woocommerce_wpml->multi_currency->prices->convert_price_amount( $cost, $currency );
1095
  }
1096
  }
1097
-
1098
  }
1099
 
1100
  return $cost;
1101
 
1102
  }
1103
 
1104
- function needs_filter_pricing_cost( $name, $fields ){
1105
 
1106
- $modifier_skip_values = array( 'divide', 'times' );
1107
 
1108
- if(
1109
  'override_block_' === $name ||
1110
- ( 'cost_' === $name && !in_array( $fields[ 'modifier' ], $modifier_skip_values ) ) ||
1111
- ( 'base_cost_' === $name && !in_array( $fields[ 'base_modifier' ], $modifier_skip_values ) )
1112
- ){
1113
  return true;
1114
- }else{
1115
  return false;
1116
  }
1117
  }
1118
 
1119
- function load_assets( $external_product_type = false ) {
1120
  global $pagenow;
1121
 
1122
- $product_id = $pagenow == 'post.php' && isset( $_GET['post'] ) ? (int)$_GET['post'] : false;
1123
 
1124
- if( $product_id && get_post_type( $product_id ) === 'product' ){
1125
- $product = wc_get_product( $product_id );
1126
- $product_type = $product->get_type();
1127
 
1128
  if ( ( $this->is_booking( $product ) || $product_type === $external_product_type ) || $pagenow == 'post-new.php' ) {
1129
 
1130
- wp_register_style( 'wcml-bookings-css', WCML_PLUGIN_URL . '/compatibility/res/css/wcml-bookings.css', array(), WCML_VERSION );
1131
  wp_enqueue_style( 'wcml-bookings-css' );
1132
 
1133
- wp_register_script( 'wcml-bookings-js', WCML_PLUGIN_URL . '/compatibility/res/js/wcml-bookings.js', array( 'jquery' ), WCML_VERSION, true );
1134
  wp_enqueue_script( 'wcml-bookings-js' );
1135
 
1136
  }
@@ -1138,11 +1193,11 @@ class WCML_Bookings {
1138
 
1139
  }
1140
 
1141
- function localize_lock_fields_js() {
1142
- wp_localize_script( 'wcml-bookings-js', 'lock_settings', array( 'lock_fields' => 1 ) );
1143
  }
1144
 
1145
- function wcml_multi_currency_is_ajax( $actions ) {
1146
 
1147
  $actions[] = 'wc_bookings_calculate_costs';
1148
 
@@ -1153,7 +1208,6 @@ class WCML_Bookings {
1153
 
1154
  if ( $cart_item['data'] instanceof WC_Product_Booking && isset( $cart_item['booking'] ) ) {
1155
 
1156
-
1157
  $current_id = apply_filters( 'translate_object_id', $cart_item['product_id'], 'product', true, $current_language );
1158
  $cart_product_id = $cart_item['product_id'];
1159
 
@@ -1165,12 +1219,12 @@ class WCML_Bookings {
1165
 
1166
  if ( $this->woocommerce_wpml->settings['enable_multi_currency'] == WCML_MULTI_CURRENCIES_INDEPENDENT || $current_id != $cart_product_id ) {
1167
 
1168
- $booking_info = array(
1169
  'wc_bookings_field_start_date_year' => $cart_item['booking']['_year'],
1170
  'wc_bookings_field_start_date_month' => $cart_item['booking']['_month'],
1171
  'wc_bookings_field_start_date_day' => $cart_item['booking']['_day'],
1172
- 'add-to-cart' => $current_id
1173
- );
1174
 
1175
  if ( isset( $cart_item['booking']['_persons'] ) ) {
1176
  foreach ( $cart_item['booking']['_persons'] as $person_id => $value ) {
@@ -1198,7 +1252,6 @@ class WCML_Bookings {
1198
  $cart_item['data']->set_price( $cost );
1199
  }
1200
  }
1201
-
1202
  }
1203
 
1204
  return $cart_item;
@@ -1215,8 +1268,7 @@ class WCML_Bookings {
1215
  return $cost;
1216
  }
1217
 
1218
- function booking_currency_dropdown() {
1219
-
1220
 
1221
  if ( $this->woocommerce_wpml->settings['enable_multi_currency'] == WCML_MULTI_CURRENCIES_INDEPENDENT ) {
1222
  $current_booking_currency = $this->get_cookie_booking_currency();
@@ -1224,27 +1276,24 @@ class WCML_Bookings {
1224
  $wc_currencies = get_woocommerce_currencies();
1225
  $currencies = $this->woocommerce_wpml->multi_currency->get_currencies( $include_default = true );
1226
  ?>
1227
- <tr valign="top">
1228
- <th scope="row"><?php _e( 'Booking currency', 'woocommerce-multilingual' ); ?></th>
1229
- <td>
1230
- <select id="dropdown_booking_currency">
1231
-
1232
- <?php foreach ( $currencies as $currency => $count ): ?>
1233
-
1234
- <option
1235
- value="<?php echo $currency ?>" <?php echo $current_booking_currency == $currency ? 'selected="selected"' : ''; ?>><?php echo $wc_currencies[ $currency ]; ?></option>
1236
-
1237
  <?php endforeach; ?>
1238
-
1239
- </select>
1240
- </td>
1241
- </tr>
1242
 
1243
  <?php
1244
 
1245
  $wcml_booking_set_currency_nonce = wp_create_nonce( 'booking_set_currency' );
1246
 
1247
- wc_enqueue_js( "
 
1248
 
1249
  jQuery(document).on('change', '#dropdown_booking_currency', function(){
1250
  jQuery.ajax({
@@ -1264,17 +1313,18 @@ class WCML_Bookings {
1264
  }
1265
  })
1266
  });
1267
- " );
 
1268
 
1269
  }
1270
 
1271
  }
1272
 
1273
- function set_booking_currency_ajax() {
1274
 
1275
  $nonce = filter_input( INPUT_POST, 'wcml_nonce', FILTER_SANITIZE_FULL_SPECIAL_CHARS );
1276
  if ( ! $nonce || ! wp_verify_nonce( $nonce, 'booking_set_currency' ) ) {
1277
- echo json_encode( array( 'error' => __( 'Invalid nonce', 'woocommerce-multilingual' ) ) );
1278
  die();
1279
  }
1280
 
@@ -1301,7 +1351,7 @@ class WCML_Bookings {
1301
  }
1302
  }
1303
 
1304
- function get_cookie_booking_currency() {
1305
 
1306
  if ( isset( $_COOKIE ['_wcml_booking_currency'] ) ) {
1307
  $currency = $_COOKIE['_wcml_booking_currency'];
@@ -1312,19 +1362,19 @@ class WCML_Bookings {
1312
  return $currency;
1313
  }
1314
 
1315
- function filter_booking_currency_symbol( $currency ) {
1316
  global $pagenow;
1317
 
1318
- remove_filter( 'woocommerce_currency_symbol', array( $this, 'filter_booking_currency_symbol' ) );
1319
  if ( isset( $_COOKIE ['_wcml_booking_currency'] ) && $pagenow == 'edit.php' && isset( $_GET['page'] ) && $_GET['page'] == 'create_booking' ) {
1320
  $currency = get_woocommerce_currency_symbol( $_COOKIE ['_wcml_booking_currency'] );
1321
  }
1322
- add_filter( 'woocommerce_currency_symbol', array( $this, 'filter_booking_currency_symbol' ) );
1323
 
1324
  return $currency;
1325
  }
1326
 
1327
- function create_booking_page_client_currency( $currency ) {
1328
  global $pagenow;
1329
 
1330
  if ( wpml_is_ajax() && isset( $_POST['form'] ) ) {
@@ -1338,14 +1388,14 @@ class WCML_Bookings {
1338
  return $currency;
1339
  }
1340
 
1341
- function set_order_currency_on_create_booking_page( $order_id ) {
1342
  update_post_meta( $order_id, '_order_currency', $this->get_cookie_booking_currency() );
1343
 
1344
  update_post_meta( $order_id, 'wpml_language', $this->sitepress->get_current_language() );
1345
 
1346
  }
1347
 
1348
- function filter_get_booking_products_args( $args ) {
1349
  if ( isset( $args['suppress_filters'] ) ) {
1350
  $args['suppress_filters'] = false;
1351
  }
@@ -1353,9 +1403,9 @@ class WCML_Bookings {
1353
  return $args;
1354
  }
1355
 
1356
- function custom_box_html( $obj, $product_id, $data ) {
1357
 
1358
- if ( !$this->is_booking( $product_id ) ) {
1359
  return;
1360
  }
1361
 
@@ -1386,7 +1436,6 @@ class WCML_Bookings {
1386
  $group->add_field( $resource_field );
1387
  $bookings_section->add_field( $group );
1388
  }
1389
-
1390
  }
1391
 
1392
  $original_persons = $this->get_original_persons( $product_id );
@@ -1416,15 +1465,15 @@ class WCML_Bookings {
1416
  }
1417
 
1418
 
1419
- function custom_box_html_data( $data, $product_id, $translation, $lang ) {
1420
 
1421
- if ( !$this->is_booking( $product_id ) ) {
1422
  return $data;
1423
  }
1424
 
1425
  if ( get_post_meta( $product_id, '_wc_booking_has_resources', true ) == 'yes' ) {
1426
 
1427
- $data['_wc_booking_resouce_label'] = array( 'original' => get_post_meta( $product_id, '_wc_booking_resouce_label', true ) );
1428
  $data['_wc_booking_resouce_label']['translation'] = $translation ? get_post_meta( $translation->ID, '_wc_booking_resouce_label', true ) : '';
1429
  }
1430
 
@@ -1437,9 +1486,9 @@ class WCML_Bookings {
1437
  if ( 'custom_costs' === $resource_id ) {
1438
  continue;
1439
  }
1440
- $data[ 'bookings-resource_' . $resource_id . '_title' ] = array( 'original' => get_the_title( $resource_id ) );
1441
  global $sitepress;
1442
- $trns_resource_id = apply_filters( 'translate_object_id', $resource_id, 'bookable_resource', false, $lang );
1443
  $data[ 'bookings-resource_' . $resource_id . '_title' ]['translation'] = $trns_resource_id ? get_the_title( $trns_resource_id ) : '';
1444
  }
1445
  }
@@ -1448,10 +1497,10 @@ class WCML_Bookings {
1448
 
1449
  foreach ( $original_persons as $person_id ) {
1450
 
1451
- $data[ 'bookings-person_' . $person_id . '_title' ] = array( 'original' => get_the_title( $person_id ) );
1452
- $data[ 'bookings-person_' . $person_id . '_description' ] = array( 'original' => get_post( $person_id )->post_excerpt );
1453
 
1454
- $trnsl_person_id = apply_filters( 'translate_object_id', $person_id, 'bookable_person', false, $lang );
1455
  $data[ 'bookings-person_' . $person_id . '_title' ]['translation'] = $trnsl_person_id ? get_the_title( $trnsl_person_id ) : '';
1456
  $data[ 'bookings-person_' . $person_id . '_description' ]['translation'] = $trnsl_person_id ? get_post( $trnsl_person_id )->post_excerpt : '';
1457
 
@@ -1461,40 +1510,40 @@ class WCML_Bookings {
1461
  }
1462
 
1463
 
1464
- function get_original_resources( $product_id ) {
1465
  $orig_resources = maybe_unserialize( get_post_meta( $product_id, '_resource_base_costs', true ) );
1466
 
1467
  return $orig_resources;
1468
  }
1469
 
1470
- function get_original_persons( $product_id ) {
1471
  $original_persons = $this->wpdb->get_col( $this->wpdb->prepare( "SELECT ID FROM {$this->wpdb->posts} WHERE post_parent = %d AND post_type = 'bookable_person' AND post_status = 'publish'", $product_id ) );
1472
 
1473
  return $original_persons;
1474
  }
1475
 
1476
- function show_custom_blocks_for_resources_and_persons( $check, $product_id, $product_content ) {
1477
- if ( in_array( $product_content, array( 'wc_booking_resources', 'wc_booking_persons' ) ) ) {
1478
  return false;
1479
  }
1480
 
1481
  return $check;
1482
  }
1483
 
1484
- function replace_tm_editor_custom_fields_with_own_sections( $fields ) {
1485
  $fields[] = '_resource_base_costs';
1486
  $fields[] = '_resource_block_costs';
1487
 
1488
  return $fields;
1489
  }
1490
 
1491
- function remove_single_custom_fields_to_translate( $fields ) {
1492
  $fields[] = '_wc_booking_resouce_label';
1493
 
1494
  return $fields;
1495
  }
1496
 
1497
- function product_content_resource_label( $meta_key, $product_id ) {
1498
  if ( $meta_key == '_wc_booking_resouce_label' ) {
1499
  return __( 'Resources label', 'woocommerce-multilingual' );
1500
  }
@@ -1502,12 +1551,12 @@ class WCML_Bookings {
1502
  return $meta_key;
1503
  }
1504
 
1505
- function wcml_products_tab_sync_resources_and_persons( $original_product_id, $tr_product_id, $data, $language ) {
1506
  global $wpml_post_translations;
1507
 
1508
- remove_action( 'save_post', array( $wpml_post_translations, 'save_post_actions' ), 100, 2 );
1509
 
1510
- $orig_resources = $orig_resources = $this->get_original_resources( $original_product_id );;
1511
 
1512
  if ( $orig_resources ) {
1513
 
@@ -1523,50 +1572,46 @@ class WCML_Bookings {
1523
  } else {
1524
  continue;
1525
  }
1526
-
1527
  } else {
1528
- //update_relationship
1529
-
1530
  $exist = $this->wpdb->get_var( $this->wpdb->prepare( "SELECT ID FROM {$this->wpdb->prefix}wc_booking_relationships WHERE resource_id = %d AND product_id = %d", $resource_id, $tr_product_id ) );
1531
 
1532
  if ( ! $exist ) {
1533
 
1534
  $this->wpdb->insert(
1535
  $this->wpdb->prefix . 'wc_booking_relationships',
1536
- array(
1537
  'product_id' => $tr_product_id,
1538
  'resource_id' => $resource_id,
1539
- 'sort_order' => $orig_resource->sort_order
1540
- )
1541
  );
1542
 
1543
  }
1544
-
1545
  }
1546
 
1547
-
1548
  $this->wpdb->update(
1549
  $this->wpdb->posts,
1550
- array(
1551
- 'post_title' => $data[ md5( 'bookings-resource_' . $orig_resource_id . '_title' ) ]
1552
- ),
1553
- array(
1554
- 'ID' => $resource_id
1555
- )
1556
  );
1557
 
1558
  update_post_meta( $resource_id, 'wcml_is_translated', true );
1559
 
1560
  }
1561
 
1562
- //sync resources data
1563
  $this->sync_resources( $original_product_id, $tr_product_id, $language, false );
1564
 
1565
  }
1566
 
1567
  $original_persons = $this->get_original_persons( $original_product_id );
1568
 
1569
- //sync persons
1570
  if ( $original_persons ) {
1571
 
1572
  foreach ( $original_persons as $original_person_id ) {
@@ -1581,53 +1626,55 @@ class WCML_Bookings {
1581
 
1582
  $this->wpdb->update(
1583
  $this->wpdb->posts,
1584
- array(
1585
- 'post_parent' => $tr_product_id
1586
- ),
1587
- array(
1588
- 'ID' => $person_id
1589
- )
1590
  );
1591
 
1592
  }
1593
 
1594
  $this->wpdb->update(
1595
  $this->wpdb->posts,
1596
- array(
1597
  'post_title' => $data[ md5( 'bookings-person_' . $original_person_id . '_title' ) ],
1598
  'post_excerpt' => $data[ md5( 'bookings-person_' . $original_person_id . '_description' ) ],
1599
- ),
1600
- array(
1601
- 'ID' => $person_id
1602
- )
1603
  );
1604
 
1605
  update_post_meta( $person_id, 'wcml_is_translated', true );
1606
 
1607
  }
1608
 
1609
- //sync persons data
1610
  $this->sync_persons( $original_product_id, $tr_product_id, $language, false );
1611
 
1612
  }
1613
 
1614
- add_action( 'save_post', array( $wpml_post_translations, 'save_post_actions' ), 100, 2 );
1615
 
1616
  }
1617
 
1618
- function duplicate_booking_for_translations( $booking_id, $lang = false ) {
1619
  $booking_object = get_post( $booking_id );
1620
 
1621
- $booking_data = array(
1622
  'post_type' => 'wc_booking',
1623
  'post_title' => $booking_object->post_title,
1624
  'post_status' => $booking_object->post_status,
1625
- 'ping_status' => 'closed'
1626
- );
1627
 
1628
- if( $booking_object->post_parent && $lang ){
1629
  $translated_parent = apply_filters( 'translate_object_id', $booking_object->post_parent, get_post_type( $booking_object->post_parent ), false, $lang );
1630
- if( $translated_parent ) $booking_data[ 'post_parent' ] = $translated_parent;
 
 
1631
  }
1632
 
1633
  $active_languages = $this->sitepress->get_active_languages();
@@ -1646,7 +1693,7 @@ class WCML_Bookings {
1646
  }
1647
 
1648
  $booking_persons = maybe_unserialize( get_post_meta( $booking_id, '_booking_persons', true ) );
1649
- $trnsl_booking_persons = array();
1650
 
1651
  if ( is_array( $booking_persons ) && ! empty( $booking_persons ) ) {
1652
  foreach ( $booking_persons as $person_id => $person_count ) {
@@ -1658,7 +1705,6 @@ class WCML_Bookings {
1658
  } else {
1659
  $trnsl_booking_persons[ $trnsl_person_id ] = $person_count;
1660
  }
1661
-
1662
  }
1663
  }
1664
 
@@ -1666,7 +1712,7 @@ class WCML_Bookings {
1666
  $trid = $this->sitepress->get_element_trid( $booking_id );
1667
  $this->sitepress->set_element_language_details( $trnsl_booking_id, 'post_wc_booking', $trid, $language['code'] );
1668
 
1669
- $meta_args = array(
1670
  '_booking_order_item_id' => 0,
1671
  '_booking_product_id' => $this->get_translated_booking_product_id( $booking_id, $language['code'] ),
1672
  '_booking_resource_id' => $this->get_translated_booking_resource_id( $booking_id, $language['code'] ),
@@ -1679,7 +1725,7 @@ class WCML_Bookings {
1679
  '_booking_customer_id' => get_post_meta( $booking_id, '_booking_customer_id', true ),
1680
  '_booking_duplicate_of' => $booking_id,
1681
  '_language_code' => $language['code'],
1682
- );
1683
 
1684
  foreach ( $meta_args as $key => $value ) {
1685
  update_post_meta( $trnsl_booking_id, $key, $value );
@@ -1689,10 +1735,9 @@ class WCML_Bookings {
1689
 
1690
  }
1691
 
1692
-
1693
  }
1694
 
1695
- function get_translated_booking_product_id( $booking_id, $language ) {
1696
 
1697
  $booking_product_id = get_post_meta( $booking_id, '_booking_product_id', true );
1698
  $trnsl_booking_product_id = '';
@@ -1708,7 +1753,7 @@ class WCML_Bookings {
1708
 
1709
  }
1710
 
1711
- function get_translated_booking_resource_id( $booking_id, $language ) {
1712
 
1713
  $booking_resource_id = get_post_meta( $booking_id, '_booking_resource_id', true );
1714
  $trnsl_booking_resource_id = '';
@@ -1724,10 +1769,10 @@ class WCML_Bookings {
1724
  return $trnsl_booking_resource_id;
1725
  }
1726
 
1727
- function get_translated_booking_persons_ids( $booking_id, $language ) {
1728
 
1729
  $booking_persons = maybe_unserialize( get_post_meta( $booking_id, '_booking_persons', true ) );
1730
- $trnsl_booking_persons = array();
1731
 
1732
  if ( is_array( $booking_persons ) && ! empty( $booking_persons ) ) {
1733
  foreach ( $booking_persons as $person_id => $person_count ) {
@@ -1739,7 +1784,6 @@ class WCML_Bookings {
1739
  } else {
1740
  $trnsl_booking_persons[ $trnsl_person_id ] = $person_count;
1741
  }
1742
-
1743
  }
1744
  }
1745
 
@@ -1747,22 +1791,22 @@ class WCML_Bookings {
1747
 
1748
  }
1749
 
1750
- function update_status_for_translations( $booking_id ) {
1751
 
1752
  foreach ( $this->get_translated_bookings( $booking_id ) as $translated_booking_id ) {
1753
 
1754
- $status = $this->wpdb->get_var( $this->wpdb->prepare( "SELECT post_status FROM {$this->wpdb->posts} WHERE ID = %d", $booking_id ) ); //get_post_status( $booking_id );
1755
  $language = get_post_meta( $translated_booking_id, '_language_code', true );
1756
 
1757
  $this->wpdb->update(
1758
  $this->wpdb->posts,
1759
- array(
1760
  'post_status' => $status,
1761
  'post_parent' => wp_get_post_parent_id( $booking_id ),
1762
- ),
1763
- array(
1764
- 'ID' => $translated_booking_id
1765
- )
1766
  );
1767
 
1768
  $this->update_translated_booking_meta( $translated_booking_id, $booking_id, $language );
@@ -1770,7 +1814,7 @@ class WCML_Bookings {
1770
 
1771
  }
1772
 
1773
- function get_translated_bookings( $booking_id ) {
1774
 
1775
  return $this->wpml_post_translations->get_element_translations( $booking_id, false, true );
1776
  }
@@ -1782,34 +1826,38 @@ class WCML_Bookings {
1782
 
1783
  $current_lang = $this->sitepress->get_current_language();
1784
 
1785
- $product_ids = $this->wpdb->get_col( $this->wpdb->prepare(
1786
- "SELECT element_id
 
1787
  FROM {$this->wpdb->prefix}icl_translations
1788
- WHERE language_code = %s AND element_type = 'post_product'", $current_lang ) );
 
 
 
1789
 
1790
- $product_ids = array_diff( $product_ids, array( null ) );
1791
 
1792
  if ( ( ! isset( $_GET['lang'] ) || ( isset( $_GET['lang'] ) && $_GET['lang'] != 'all' ) ) ) {
1793
- $query->query_vars['meta_query'][] = array(
1794
  'relation' => 'OR',
1795
- array(
1796
  'key' => '_language_code',
1797
  'value' => $current_lang,
1798
- 'compare ' => '='
1799
- ),
1800
- array(
1801
  'key' => '_booking_product_id',
1802
  'value' => $product_ids,
1803
- 'compare ' => 'IN'
1804
- )
1805
- );
1806
  }
1807
  }
1808
 
1809
  return $query;
1810
  }
1811
 
1812
- function bookings_in_date_range_query( $booking_ids ) {
1813
  foreach ( $booking_ids as $key => $booking_id ) {
1814
 
1815
  $language_code = $this->sitepress->get_language_for_element( get_post_meta( $booking_id, '_booking_product_id', true ), 'post_product' );
@@ -1818,52 +1866,53 @@ class WCML_Bookings {
1818
  if ( $language_code != $current_language ) {
1819
  unset( $booking_ids[ $key ] );
1820
  }
1821
-
1822
  }
1823
 
1824
  return $booking_ids;
1825
 
1826
  }
1827
 
1828
- function clear_transient_fields() {
1829
 
1830
  if ( isset( $_GET['post_type'] ) && $_GET['post_type'] == 'wc_booking' && isset( $_GET['page'] ) && $_GET['page'] == 'booking_calendar' ) {
1831
 
1832
- //delete transient fields
1833
- $this->wpdb->query( "
 
1834
  DELETE FROM {$this->wpdb->options}
1835
  WHERE option_name LIKE '%book_dr_%'
1836
- " );
 
1837
 
1838
  }
1839
 
1840
  }
1841
 
1842
- function delete_bookings( $booking_id ) {
1843
 
1844
  if (
1845
  ! $this->is_delete_all_action()
1846
  && $booking_id
1847
  && get_post_type( $booking_id ) == 'wc_booking'
1848
  ) {
1849
- remove_action( 'before_delete_post', array( $this, 'delete_bookings' ) );
1850
 
1851
  foreach ( $this->get_translated_bookings( $booking_id ) as $translated_booking_id ) {
1852
  $this->wpdb->update(
1853
  $this->wpdb->posts,
1854
- array(
1855
- 'post_parent' => 0
1856
- ),
1857
- array(
1858
- 'ID' => $translated_booking_id
1859
- )
1860
  );
1861
 
1862
  wp_delete_post( $translated_booking_id );
1863
 
1864
  }
1865
 
1866
- add_action( 'before_delete_post', array( $this, 'delete_bookings' ) );
1867
  }
1868
  }
1869
 
@@ -1871,7 +1920,7 @@ class WCML_Bookings {
1871
  return array_key_exists( 'delete_all', $_GET ) && $_GET['delete_all'];
1872
  }
1873
 
1874
- function trash_bookings( $booking_id ) {
1875
 
1876
  if ( $booking_id > 0 && get_post_type( $booking_id ) == 'wc_booking' ) {
1877
 
@@ -1879,16 +1928,15 @@ class WCML_Bookings {
1879
 
1880
  $this->wpdb->update(
1881
  $this->wpdb->posts,
1882
- array(
1883
- 'post_status' => 'trash'
1884
- ),
1885
- array(
1886
- 'ID' => $translated_booking_id
1887
- )
1888
  );
1889
 
1890
  }
1891
-
1892
  }
1893
 
1894
  }
@@ -1905,29 +1953,27 @@ class WCML_Bookings {
1905
 
1906
  $bookable_person = get_post( $person_type->ID );
1907
 
1908
- $package['contents'][ 'wc_bookings:person:' . $bookable_person->ID . ':name' ] = array(
1909
  'translate' => 1,
1910
  'data' => $this->tp->encode_field_data( $bookable_person->post_title, 'base64' ),
1911
- 'format' => 'base64'
1912
- );
1913
 
1914
- $package['contents'][ 'wc_bookings:person:' . $bookable_person->ID . ':description' ] = array(
1915
  'translate' => 1,
1916
  'data' => $this->tp->encode_field_data( $bookable_person->post_excerpt, 'base64' ),
1917
- 'format' => 'base64'
1918
- );
1919
 
1920
  }
1921
-
1922
  }
1923
-
1924
  }
1925
 
1926
  return $package;
1927
  }
1928
 
1929
- function save_person_translation( $post_id, $data, $job ) {
1930
- $person_translations = array();
1931
 
1932
  if ( $this->is_booking( $post_id ) ) {
1933
 
@@ -1943,7 +1989,6 @@ class WCML_Bookings {
1943
  $person_translations[ $person_id ][ $field ] = $value['data'];
1944
 
1945
  }
1946
-
1947
  }
1948
 
1949
  if ( $person_translations ) {
@@ -1952,20 +1997,19 @@ class WCML_Bookings {
1952
 
1953
  $person_trid = $this->sitepress->get_element_trid( $person_id, 'post_bookable_person' );
1954
 
1955
-
1956
  $person_id_translated = apply_filters( 'translate_object_id', $person_id, 'bookable_person', false, $job->language_code );
1957
 
1958
  if ( empty( $person_id_translated ) ) {
1959
 
1960
- $person_post = array(
1961
 
1962
  'post_type' => 'bookable_person',
1963
  'post_status' => 'publish',
1964
  'post_title' => $pt['name'],
1965
  'post_parent' => $post_id,
1966
- 'post_excerpt' => isset( $pt['description'] ) ? $pt['description'] : ''
1967
 
1968
- );
1969
 
1970
  $person_id_translated = wp_insert_post( $person_post );
1971
 
@@ -1973,25 +2017,22 @@ class WCML_Bookings {
1973
 
1974
  } else {
1975
 
1976
- $person_post = array(
1977
  'ID' => $person_id_translated,
1978
  'post_title' => $pt['name'],
1979
- 'post_excerpt' => isset( $pt['description'] ) ? $pt['description'] : ''
1980
- );
1981
 
1982
  wp_update_post( $person_post );
1983
 
1984
  }
1985
-
1986
  }
1987
-
1988
  }
1989
-
1990
  }
1991
 
1992
  }
1993
 
1994
- function append_resources_to_translation_package( $package, $post ) {
1995
 
1996
  if ( $post->post_type == 'product' ) {
1997
  $product = wc_get_product( $post->ID );
@@ -2001,24 +2042,22 @@ class WCML_Bookings {
2001
 
2002
  foreach ( $resources as $resource ) {
2003
 
2004
- $package['contents'][ 'wc_bookings:resource:' . $resource->ID . ':name' ] = array(
2005
  'translate' => 1,
2006
  'data' => $this->tp->encode_field_data( $resource->post_title, 'base64' ),
2007
- 'format' => 'base64'
2008
- );
2009
 
2010
  }
2011
-
2012
  }
2013
-
2014
  }
2015
 
2016
  return $package;
2017
 
2018
  }
2019
 
2020
- function save_resource_translation( $post_id, $data, $job ) {
2021
- $resource_translations = array();
2022
 
2023
  if ( $this->is_booking( $post_id ) ) {
2024
 
@@ -2034,7 +2073,6 @@ class WCML_Bookings {
2034
  $resource_translations[ $resource_id ][ $field ] = $value['data'];
2035
 
2036
  }
2037
-
2038
  }
2039
 
2040
  if ( $resource_translations ) {
@@ -2047,80 +2085,83 @@ class WCML_Bookings {
2047
 
2048
  if ( empty( $resource_id_translated ) ) {
2049
 
2050
- $resource_post = array(
2051
 
2052
  'post_type' => 'bookable_resource',
2053
  'post_status' => 'publish',
2054
  'post_title' => $rt['name'],
2055
- 'post_parent' => $post_id
2056
- );
2057
 
2058
  $resource_id_translated = wp_insert_post( $resource_post );
2059
 
2060
  $this->sitepress->set_element_language_details( $resource_id_translated, 'post_bookable_resource', $resource_trid, $job->language_code );
2061
 
2062
  $sort_order = $this->wpdb->get_var( $this->wpdb->prepare( "SELECT sort_order FROM {$this->wpdb->prefix}wc_booking_relationships WHERE resource_id=%d", $resource_id ) );
2063
- $relationship = array(
2064
  'product_id' => $post_id,
2065
  'resource_id' => $resource_id_translated,
2066
- 'sort_order' => $sort_order
2067
- );
2068
  $this->wpdb->insert( $this->wpdb->prefix . 'wc_booking_relationships', $relationship );
2069
 
2070
  } else {
2071
 
2072
- $resource_post = array(
2073
  'ID' => $resource_id_translated,
2074
- 'post_title' => $rt['name']
2075
- );
2076
 
2077
  wp_update_post( $resource_post );
2078
 
2079
  $sort_order = $this->wpdb->get_var( $this->wpdb->prepare( "SELECT sort_order FROM {$this->wpdb->prefix}wc_booking_relationships WHERE resource_id=%d", $resource_id ) );
2080
- $this->wpdb->update( $this->wpdb->prefix . 'wc_booking_relationships', array( 'sort_order' => $sort_order ),
2081
- array( 'product_id' => $post_id, 'resource_id' => $resource_id_translated ) );
2082
-
 
 
 
 
 
2083
 
2084
  }
2085
-
2086
-
2087
  }
2088
-
2089
  }
2090
-
2091
  }
2092
 
2093
  }
2094
 
2095
- function wcml_js_lock_fields_ids( $ids ) {
2096
-
2097
- $ids = array_merge( $ids, array(
2098
- '_wc_booking_has_resources',
2099
- '_wc_booking_has_persons',
2100
- '_wc_booking_duration_type',
2101
- '_wc_booking_duration',
2102
- '_wc_booking_duration_unit',
2103
- '_wc_booking_calendar_display_mode',
2104
- '_wc_booking_requires_confirmation',
2105
- '_wc_booking_user_can_cancel',
2106
- '_wc_accommodation_booking_min_duration',
2107
- '_wc_accommodation_booking_max_duration',
2108
- '_wc_accommodation_booking_max_duration',
2109
- '_wc_accommodation_booking_calendar_display_mode',
2110
- '_wc_accommodation_booking_requires_confirmation',
2111
- '_wc_accommodation_booking_user_can_cancel',
2112
- '_wc_accommodation_booking_cancel_limit',
2113
- '_wc_accommodation_booking_cancel_limit_unit',
2114
- '_wc_accommodation_booking_qty',
2115
- '_wc_accommodation_booking_min_date',
2116
- '_wc_accommodation_booking_min_date_unit',
2117
- '_wc_accommodation_booking_max_date',
2118
- '_wc_accommodation_booking_max_date_unit',
2119
- 'bookings_pricing select',
2120
- 'bookings_resources select',
2121
- 'bookings_availability select',
2122
- 'bookings_persons input[type="checkbox"]'
2123
- ) );
 
 
2124
 
2125
  return $ids;
2126
  }
@@ -2143,23 +2184,22 @@ class WCML_Bookings {
2143
 
2144
  /**
2145
  * @param array $currencies
2146
- * @param int $post_id
2147
  *
2148
  * @return bool
2149
  */
2150
- private function update_booking_costs( $currencies = array(), $post_id = 0 ) {
2151
- $booking_options = array(
2152
- 'wcml_wc_booking_cost' => '_wc_booking_cost_',
2153
  'wcml_wc_booking_block_cost' => '_wc_booking_block_cost_',
2154
- 'wcml_wc_display_cost' => '_wc_display_cost_',
2155
- );
2156
 
2157
  if ( $this->sitepress->get_wp_api()->version_compare( $this->sitepress->get_wp_api()->constant( 'WC_BOOKINGS_VERSION' ), '1.10.9', '<' ) ) {
2158
- unset( $booking_options['wcml_wc_booking_block_cost']);
2159
  $booking_options['wcml_wc_booking_base_cost'] = '_wc_booking_base_cost_';
2160
  }
2161
 
2162
-
2163
  foreach ( $currencies as $code => $currency ) {
2164
  foreach ( $booking_options as $booking_options_post_key => $booking_options_meta_key_prefix ) {
2165
  if ( isset( $_POST[ $booking_options_post_key ][ $code ] ) ) {
@@ -2173,12 +2213,12 @@ class WCML_Bookings {
2173
 
2174
  /**
2175
  * @param array $currencies
2176
- * @param int $post_id
2177
  *
2178
  * @return bool
2179
  */
2180
- private function update_booking_pricing( $currencies = array(), $post_id = 0 ) {
2181
- $updated_meta = array();
2182
  $booking_pricing = get_post_meta( $post_id, '_wc_booking_pricing', true );
2183
  if ( empty( $booking_pricing ) ) {
2184
  return false;
@@ -2194,7 +2234,6 @@ class WCML_Bookings {
2194
  $updated_meta[ $key ][ 'cost_' . $code ] = sanitize_text_field( $_POST['wcml_wc_booking_pricing_cost'][ $code ][ $key ] );
2195
  }
2196
  }
2197
-
2198
  }
2199
 
2200
  update_post_meta( $post_id, '_wc_booking_pricing', $updated_meta );
@@ -2208,7 +2247,7 @@ class WCML_Bookings {
2208
  *
2209
  * @return bool
2210
  */
2211
- private function update_booking_person_cost( $currencies = array(), $person_costs = array() ) {
2212
  if ( empty( $person_costs ) ) {
2213
  return false;
2214
  }
@@ -2230,7 +2269,7 @@ class WCML_Bookings {
2230
  *
2231
  * @return bool
2232
  */
2233
- private function update_booking_person_block_cost( $currencies = array(), $block_costs = array() ) {
2234
  if ( empty( $block_costs ) ) {
2235
  return false;
2236
  }
@@ -2248,22 +2287,22 @@ class WCML_Bookings {
2248
 
2249
  /**
2250
  * @param array $currencies
2251
- * @param int $post_id
2252
  * @param array $resource_cost
2253
  *
2254
  * @return bool
2255
  */
2256
- private function update_booking_resource_cost( $currencies = array(), $post_id = 0, $resource_cost = array() ) {
2257
  if ( empty( $resource_cost ) ) {
2258
  return false;
2259
  }
2260
 
2261
  $updated_meta = get_post_meta( $post_id, '_resource_base_costs', true );
2262
  if ( ! is_array( $updated_meta ) ) {
2263
- $updated_meta = array();
2264
  }
2265
 
2266
- $wc_booking_resource_costs = array();
2267
 
2268
  foreach ( $resource_cost as $resource_id => $costs ) {
2269
 
@@ -2272,9 +2311,7 @@ class WCML_Bookings {
2272
  if ( isset( $costs[ $code ] ) ) {
2273
  $wc_booking_resource_costs[ $code ][ $resource_id ] = sanitize_text_field( $costs[ $code ] );
2274
  }
2275
-
2276
  }
2277
-
2278
  }
2279
 
2280
  $updated_meta['custom_costs'] = $wc_booking_resource_costs;
@@ -2288,18 +2325,18 @@ class WCML_Bookings {
2288
 
2289
  /**
2290
  * @param array $currencies
2291
- * @param int $post_id
2292
  *
2293
  * @return bool
2294
  */
2295
- private function update_booking_resource_block_cost( $currencies = array(), $post_id = 0, $resource_block_cost = array() ) {
2296
  if ( empty( $resource_block_cost ) ) {
2297
  return false;
2298
  }
2299
 
2300
  $updated_meta = get_post_meta( $post_id, '_resource_block_costs', true );
2301
 
2302
- $wc_booking_resource_block_costs = array();
2303
 
2304
  foreach ( $resource_block_cost as $resource_id => $costs ) {
2305
 
@@ -2308,9 +2345,7 @@ class WCML_Bookings {
2308
  if ( isset( $costs[ $code ] ) ) {
2309
  $wc_booking_resource_block_costs[ $code ][ $resource_id ] = sanitize_text_field( $costs[ $code ] );
2310
  }
2311
-
2312
  }
2313
-
2314
  }
2315
 
2316
  $updated_meta['custom_costs'] = $wc_booking_resource_block_costs;
@@ -2322,24 +2357,24 @@ class WCML_Bookings {
2322
  return true;
2323
  }
2324
 
2325
- public function extra_conditions_to_filter_bookings( $extra_conditions ){
2326
 
2327
- if( isset( $_GET[ 'post_type' ] ) && $_GET[ 'post_type' ] == 'wc_booking' && !isset( $_GET[ 'post_status' ] ) ){
2328
- $extra_conditions = str_replace( "GROUP BY", " AND post_status = 'confirmed' GROUP BY", $extra_conditions );
2329
  }
2330
 
2331
  return $extra_conditions;
2332
  }
2333
 
2334
- public function hide_bookings_type_on_tm_dashboard( $types ){
2335
- unset( $types[ 'wc_booking' ] );
2336
  return $types;
2337
  }
2338
 
2339
- public function show_pointer_info(){
2340
 
2341
  $pointer_ui = new WCML_Pointer_UI(
2342
- sprintf( __( 'You can translate the titles of your custom Resources on the %sWooCommerce product translation page%s', 'woocommerce-multilingual' ), '<a href="'.admin_url('admin.php?page=wpml-wcml').'">', '</a>' ),
2343
  'https://wpml.org/documentation/woocommerce-extensions-compatibility/translating-woocommerce-bookings-woocommerce-multilingual/',
2344
  'bookings_resources .woocommerce_bookable_resources #message'
2345
  );
@@ -2347,7 +2382,7 @@ class WCML_Bookings {
2347
  $pointer_ui->show();
2348
 
2349
  $pointer_ui = new WCML_Pointer_UI(
2350
- sprintf( __( 'You can translate the Person Type Name and Description on the %sWooCommerce product translation page%s', 'woocommerce-multilingual' ), '<a href="'.admin_url('admin.php?page=wpml-wcml').'">', '</a>' ),
2351
  'https://wpml.org/documentation/woocommerce-extensions-compatibility/translating-woocommerce-bookings-woocommerce-multilingual/',
2352
  'bookings_persons #persons-types>div.toolbar'
2353
  );
@@ -2356,17 +2391,17 @@ class WCML_Bookings {
2356
 
2357
  }
2358
 
2359
- public function add_to_cart_sold_individually( $sold_indiv, $cart_item_data, $product_id, $quantity ){
2360
 
2361
- if( isset( $cart_item_data[ 'booking' ] ) ){
2362
  $sold_indiv = false;
2363
- foreach( WC()->cart->cart_contents as $cart_item ){
2364
- if(
2365
- isset( $cart_item[ 'booking' ] ) && isset( $cart_item[ 'booking' ][ '_booking_id' ] ) &&
2366
- $cart_item[ 'booking' ][ '_start_date' ] == $cart_item_data[ 'booking' ][ '_start_date' ] &&
2367
- $cart_item[ 'booking' ][ '_end_date' ] == $cart_item_data[ 'booking' ][ '_end_date' ] &&
2368
- $cart_item[ 'booking' ][ '_booking_id' ] == $cart_item_data[ 'booking' ][ '_booking_id' ]
2369
- ){
2370
  $sold_indiv = true;
2371
  }
2372
  }
@@ -2376,22 +2411,24 @@ class WCML_Bookings {
2376
  }
2377
 
2378
  // unset "bookings" from translatable documents to hide WPML languages section from booking edit page
2379
- public function filter_translatable_documents( $icl_post_types ){
2380
 
2381
- if(
2382
- ( isset( $_GET[ 'post_type' ] ) && 'wc_booking' === $_GET[ 'post_type' ] ) ||
2383
- ( isset( $_GET[ 'post' ] ) && 'wc_booking' === get_post_type( $_GET[ 'post' ] ) )
2384
- ){
2385
- unset( $icl_post_types[ 'wc_booking' ] );
2386
  }
2387
 
2388
  return $icl_post_types;
2389
  }
2390
 
2391
  // hide WPML languages links section from bookings list page
2392
- public function filter_is_translated_post_type( $type ){
 
 
2393
 
2394
- if( isset( $_GET[ 'post_type' ] ) && $_GET[ 'post_type' ] == 'wc_booking' ){
2395
  return false;
2396
  }
2397
 
@@ -2399,23 +2436,21 @@ class WCML_Bookings {
2399
  }
2400
 
2401
  /**
2402
- * @param int $post_id
2403
  * @param WP_Post $post
2404
- * @param bool $update
2405
- *
2406
  */
2407
- public function sync_booking_status( $post_id, $post, $update ){
2408
 
2409
- if( $post->post_type === 'wc_booking' && $update ){
2410
 
2411
- foreach( $this->get_translated_bookings( $post_id ) as $translated_booking_id ){
2412
- $this->wpdb->update(
2413
- $this->wpdb->posts,
2414
- array( 'post_status' => $post->post_status ),
2415
- array( 'ID' => $translated_booking_id )
2416
- );
2417
  }
2418
-
2419
  }
2420
 
2421
  }
@@ -2429,11 +2464,11 @@ class WCML_Bookings {
2429
  if ( isset( $table['bookings'] ) ) {
2430
 
2431
  foreach ( $table['bookings'] as $key => $booking ) {
2432
- $language_code = get_post_meta( $booking->get_id(), '_language_code', true );
2433
 
2434
- if( !$language_code ){
2435
- $language_code = $this->sitepress->get_language_for_element( $booking->get_product_id(), 'post_product' );
2436
- }
2437
 
2438
  if ( $language_code !== $current_language ) {
2439
  unset( $tables[ $table_key ]['bookings'][ $key ] );
@@ -2447,7 +2482,7 @@ class WCML_Bookings {
2447
  return $tables;
2448
  }
2449
 
2450
- public function emails_options_to_translate( $emails_options ){
2451
  $emails_options[] = 'woocommerce_new_booking_settings';
2452
  $emails_options[] = 'woocommerce_booking_reminder_settings';
2453
  $emails_options[] = 'woocommerce_booking_confirmed_settings';
@@ -2457,45 +2492,45 @@ class WCML_Bookings {
2457
  return $emails_options;
2458
  }
2459
 
2460
- public function emails_text_keys_to_translate( $text_keys ){
2461
  $text_keys[] = 'subject_confirmation';
2462
  $text_keys[] = 'heading_confirmation';
2463
 
2464
  return $text_keys;
2465
  }
2466
 
2467
- public function translate_emails_text_strings( $value, $object , $old_value, $key ){
2468
 
2469
- $emails_ids = array( 'admin_booking_cancelled', 'new_booking', 'booking_cancelled', 'booking_confirmed', 'booking_reminder' );
2470
- $keys = array( 'subject', 'subject_confirmation', 'heading', 'heading_confirmation' );
2471
 
2472
- if( in_array( $key, $keys ) && in_array( $object->id, $emails_ids ) ){
2473
  $translated_value = $object->$key;
2474
  }
2475
 
2476
- return !empty( $translated_value ) ? $translated_value : $value;
2477
  }
2478
 
2479
- public function translate_booking_confirmed_email_texts( $booking_id ){
2480
- if( $this->email_class_exists( 'WC_Email_Booking_Confirmed' ) ){
2481
  $this->translate_email_strings( 'WC_Email_Booking_Confirmed', 'woocommerce_booking_confirmed_settings', $booking_id );
2482
  }
2483
  }
2484
 
2485
- public function translate_booking_cancelled_email_texts( $booking_id ){
2486
- if( $this->email_class_exists( 'WC_Email_Booking_Cancelled' ) ){
2487
  $this->translate_email_strings( 'WC_Email_Booking_Cancelled', 'woocommerce_booking_cancelled_settings', $booking_id );
2488
  }
2489
  }
2490
 
2491
- public function translate_booking_reminder_email_texts( $booking_id ){
2492
- if( $this->email_class_exists( 'WC_Email_Booking_Reminder' ) ){
2493
  $this->translate_email_strings( 'WC_Email_Booking_Reminder', 'woocommerce_booking_reminder_settings', $booking_id );
2494
  }
2495
  }
2496
 
2497
- public function translate_new_booking_email_texts( $booking_id ){
2498
- if( $this->email_class_exists( 'WC_Email_New_Booking' ) ){
2499
  $user_lang = $this->get_admin_user_email_language( 'WC_Email_New_Booking' );
2500
  $this->translate_email_strings( 'WC_Email_New_Booking', 'woocommerce_new_booking_settings', $booking_id, $user_lang );
2501
  $this->woocommerce->mailer()->emails['WC_Email_New_Booking']->heading_confirmation = $this->woocommerce_wpml->emails->wcml_get_translated_email_string( 'admin_texts_woocommerce_new_booking_settings', '[woocommerce_new_booking_settings]heading_confirmation', $user_lang );
@@ -2503,8 +2538,8 @@ class WCML_Bookings {
2503
  }
2504
  }
2505
 
2506
- public function translate_booking_cancelled_admin_email_texts( $booking_id ){
2507
- if( $this->email_class_exists( 'WC_Email_Admin_Booking_Cancelled' ) ){
2508
  $this->translate_email_strings( 'WC_Email_Admin_Booking_Cancelled', 'woocommerce_admin_booking_cancelled_settings', $booking_id, $this->get_admin_user_email_language( 'WC_Email_Admin_Booking_Cancelled' ) );
2509
  }
2510
  }
@@ -2523,24 +2558,24 @@ class WCML_Bookings {
2523
  *
2524
  * @return bool|mixed|null|string
2525
  */
2526
- private function get_admin_user_email_language( $email_class ){
2527
 
2528
- $user = get_user_by('email', $this->woocommerce->mailer()->emails[$email_class]->recipient );
2529
  if ( $user ) {
2530
  return $this->sitepress->get_user_admin_language( $user->ID, true );
2531
  }
2532
 
2533
  return null;
2534
- }
2535
 
2536
  /**
2537
  * @param $booking_id
2538
  *
2539
  * @return bool|WC_Order
2540
  */
2541
- private function get_booking_order( $booking_id ){
2542
  return get_wc_booking( $booking_id )->get_order();
2543
- }
2544
 
2545
 
2546
  /**
@@ -2561,26 +2596,26 @@ class WCML_Bookings {
2561
  }
2562
 
2563
  /**
2564
- * @param string $email_class
2565
- * @param string $setting_slug
2566
- * @param int $booking_id
2567
  * @param string|null $user_lang
2568
  */
2569
- private function translate_email_strings( $email_class, $setting_slug, $booking_id, $user_lang = null ){
2570
 
2571
  $order_id = false;
2572
- if ( !$user_lang ){
2573
  $booking_order = $this->get_booking_order( $booking_id );
2574
- if( $booking_order ){
2575
  $order_id = $booking_order->get_id();
2576
  }
2577
  }
2578
 
2579
- if( $order_id || $user_lang ){
2580
- $this->woocommerce->mailer()->emails[$email_class]->heading = $this->woocommerce_wpml->emails->wcml_get_translated_email_string( 'admin_texts_'.$setting_slug, '['.$setting_slug.']heading', $order_id, $user_lang );
2581
- $this->woocommerce->mailer()->emails[$email_class]->subject = $this->woocommerce_wpml->emails->wcml_get_translated_email_string( 'admin_texts_'.$setting_slug, '['.$setting_slug.']subject', $order_id, $user_lang );
2582
- }
2583
- }
2584
 
2585
  public function maybe_set_booking_language( $booking_id ) {
2586
 
@@ -2643,7 +2678,7 @@ class WCML_Bookings {
2643
  }
2644
 
2645
  public function remove_language_switcher() {
2646
- remove_action( 'wp_before_admin_bar_render', array( $this->sitepress, 'admin_language_switcher' ) );
2647
  }
2648
 
2649
  /**
@@ -2652,4 +2687,9 @@ class WCML_Bookings {
2652
  private function is_bookings_listing_page() {
2653
  return isset( $_GET['post_type'] ) && 'wc_booking' === $_GET['post_type'];
2654
  }
 
 
 
 
 
2655
  }
37
 
38
  /**
39
  * WCML_Bookings constructor.
40
+ *
41
+ * @param SitePress $sitepress
42
+ * @param woocommerce_wpml $woocommerce_wpml
43
+ * @param woocommerce $woocommerce
44
+ * @param wpdb $wpdb
45
  * @param WPML_Element_Translation_Package $tp
46
+ * @param WPML_Post_Translation $wpml_post_translations
47
  */
48
+ public function __construct( SitePress $sitepress, woocommerce_wpml $woocommerce_wpml, woocommerce $woocommerce, wpdb $wpdb, WPML_Element_Translation_Package $tp, WPML_Post_Translation $wpml_post_translations ) {
49
  $this->sitepress = $sitepress;
50
  $this->woocommerce_wpml = $woocommerce_wpml;
51
  $this->woocommerce = $woocommerce;
57
  /**
58
  * Adds hooks.
59
  */
60
+ public function add_hooks() {
61
 
62
  // Translate emails.
63
+ add_filter( 'get_post_metadata', [ $this, 'get_order_language' ], 10, 4 );
64
+ add_filter( 'woocommerce_booking_reminder_notification', [ $this, 'translate_notification' ], 9 );
65
+ add_filter( 'woocommerce_booking_confirmed_notification', [ $this, 'translate_notification' ], 9 );
66
+ add_filter( 'woocommerce_booking_cancelled_notification', [ $this, 'translate_notification' ], 9 );
67
+
68
+ add_action(
69
+ 'woocommerce_bookings_after_booking_base_cost',
70
+ [
71
+ $this,
72
+ 'wcml_price_field_after_booking_base_cost',
73
+ ]
74
+ );
75
+ add_action(
76
+ 'woocommerce_bookings_after_booking_block_cost',
77
+ [
78
+ $this,
79
+ 'wcml_price_field_after_booking_block_cost',
80
+ ]
81
+ );
82
+ add_action( 'woocommerce_bookings_after_display_cost', [ $this, 'wcml_price_field_after_display_cost' ] );
83
+ add_action(
84
+ 'woocommerce_bookings_after_booking_pricing_base_cost',
85
+ [
86
+ $this,
87
+ 'wcml_price_field_after_booking_pricing_base_cost',
88
+ ],
89
+ 10,
90
+ 2
91
+ );
92
+ add_action(
93
+ 'woocommerce_bookings_after_booking_pricing_cost',
94
+ [
95
+ $this,
96
+ 'wcml_price_field_after_booking_pricing_cost',
97
+ ],
98
+ 10,
99
+ 2
100
+ );
101
+ add_action( 'woocommerce_bookings_after_person_cost', [ $this, 'wcml_price_field_after_person_cost' ] );
102
+ add_action(
103
+ 'woocommerce_bookings_after_person_block_cost',
104
+ [
105
+ $this,
106
+ 'wcml_price_field_after_person_block_cost',
107
+ ]
108
+ );
109
+ add_action(
110
+ 'woocommerce_bookings_after_resource_cost',
111
+ [
112
+ $this,
113
+ 'wcml_price_field_after_resource_cost',
114
+ ],
115
+ 10,
116
+ 2
117
+ );
118
+ add_action(
119
+ 'woocommerce_bookings_after_resource_block_cost',
120
+ [
121
+ $this,
122
+ 'wcml_price_field_after_resource_block_cost',
123
+ ],
124
+ 10,
125
+ 2
126
+ );
127
+ add_action( 'woocommerce_bookings_after_bookings_pricing', [ $this, 'after_bookings_pricing' ] );
128
+
129
+ add_action( 'init', [ $this, 'load_assets' ] );
130
+
131
+ add_action( 'save_post', [ $this, 'save_booking_action_handler' ], 110 );
132
+
133
+ add_action( 'wcml_before_sync_product_data', [ $this, 'sync_bookings' ], 10, 3 );
134
+ add_action( 'wcml_before_sync_product', [ $this, 'sync_booking_data' ], 10, 2 );
135
+
136
+ add_filter(
137
+ 'woocommerce_bookings_process_cost_rules_cost',
138
+ [
139
+ $this,
140
+ 'wc_bookings_process_cost_rules_cost',
141
+ ],
142
+ 10,
143
+ 3
144
+ );
145
+ add_filter(
146
+ 'woocommerce_bookings_process_cost_rules_base_cost',
147
+ [
148
+ $this,
149
+ 'wc_bookings_process_cost_rules_base_cost',
150
+ ],
151
+ 10,
152
+ 3
153
+ );
154
+ add_filter(
155
+ 'woocommerce_bookings_process_cost_rules_override_block',
156
+ [
157
+ $this,
158
+ 'wc_bookings_process_cost_rules_override_block_cost',
159
+ ],
160
+ 10,
161
+ 3
162
+ );
163
+
164
+ add_filter( 'wcml_multi_currency_ajax_actions', [ $this, 'wcml_multi_currency_is_ajax' ] );
165
+
166
+ add_filter(
167
+ 'wcml_cart_contents_not_changed',
168
+ [
169
+ $this,
170
+ 'filter_bundled_product_in_cart_contents',
171
+ ],
172
+ 10,
173
+ 3
174
+ );
175
+
176
+ add_action( 'woocommerce_bookings_after_create_booking_page', [ $this, 'booking_currency_dropdown' ] );
177
+ add_action( 'init', [ $this, 'set_booking_currency' ] );
178
+
179
+ add_action( 'wp_ajax_wcml_booking_set_currency', [ $this, 'set_booking_currency_ajax' ] );
180
+ add_action(
181
+ 'woocommerce_bookings_create_booking_page_add_order_item',
182
+ [
183
+ $this,
184
+ 'set_order_currency_on_create_booking_page',
185
+ ]
186
+ );
187
+ add_filter( 'woocommerce_currency_symbol', [ $this, 'filter_booking_currency_symbol' ] );
188
+ add_filter( 'get_booking_products_args', [ $this, 'filter_get_booking_products_args' ] );
189
+ add_filter( 'wcml_filter_currency_position', [ $this, 'create_booking_page_client_currency' ] );
190
+
191
+ add_filter( 'wcml_client_currency', [ $this, 'create_booking_page_client_currency' ] );
192
+
193
+ add_action( 'wcml_gui_additional_box_html', [ $this, 'custom_box_html' ], 10, 3 );
194
+ add_filter( 'wcml_gui_additional_box_data', [ $this, 'custom_box_html_data' ], 10, 4 );
195
+ add_filter( 'wcml_check_is_single', [ $this, 'show_custom_blocks_for_resources_and_persons' ], 10, 3 );
196
+ add_filter( 'wcml_do_not_display_custom_fields_for_product', [ $this, 'replace_tm_editor_custom_fields_with_own_sections' ] );
197
+ add_filter(
198
+ 'wcml_not_display_single_fields_to_translate',
199
+ [
200
+ $this,
201
+ 'remove_single_custom_fields_to_translate',
202
+ ]
203
+ );
204
+ add_filter( 'wcml_product_content_label', [ $this, 'product_content_resource_label' ], 10, 2 );
205
+ add_action( 'wcml_update_extra_fields', [ $this, 'wcml_products_tab_sync_resources_and_persons' ], 10, 4 );
206
+
207
+ add_action( 'woocommerce_new_booking', [ $this, 'duplicate_booking_for_translations' ] );
208
+
209
+ $bookings_statuses = [
210
  'unpaid',
211
  'pending-confirmation',
212
  'confirmed',
214
  'cancelled',
215
  'complete',
216
  'in-cart',
217
+ 'was-in-cart',
218
+ ];
219
  foreach ( $bookings_statuses as $status ) {
220
+ add_action( 'woocommerce_booking_' . $status, [ $this, 'update_status_for_translations' ] );
221
  }
222
 
223
+ add_filter( 'parse_query', [ $this, 'booking_filters_query' ] );
224
+ add_filter( 'woocommerce_bookings_in_date_range_query', [ $this, 'bookings_in_date_range_query' ] );
225
+ add_action( 'before_delete_post', [ $this, 'delete_bookings' ] );
226
+ add_action( 'wp_trash_post', [ $this, 'trash_bookings' ] );
227
+ add_action( 'wpml_translation_job_saved', [ $this, 'save_booking_data_to_translation' ], 10, 3 );
228
 
229
  if ( is_admin() ) {
230
 
231
+ add_filter(
232
+ 'wpml_tm_translation_job_data',
233
+ [
234
+ $this,
235
+ 'append_persons_to_translation_package',
236
+ ],
237
+ 10,
238
+ 2
239
+ );
 
 
240
 
241
+ add_filter(
242
+ 'wpml_tm_translation_job_data',
243
+ [
244
+ $this,
245
+ 'append_resources_to_translation_package',
246
+ ],
247
+ 10,
248
+ 2
249
+ );
250
 
251
+ // lock fields on translations pages.
252
+ add_filter( 'wcml_js_lock_fields_ids', [ $this, 'wcml_js_lock_fields_ids' ] );
253
+ add_filter( 'wcml_after_load_lock_fields_js', [ $this, 'localize_lock_fields_js' ] );
254
 
255
+ // allow filtering resources by language.
256
+ add_filter( 'get_booking_resources_args', [ $this, 'filter_get_booking_resources_args' ] );
257
 
258
+ add_filter( 'get_translatable_documents_all', [ $this, 'filter_translatable_documents' ] );
259
 
260
+ add_filter( 'pre_wpml_is_translated_post_type', [ $this, 'filter_is_translated_post_type' ] );
261
 
262
+ add_action( 'woocommerce_product_data_panels', [ $this, 'show_pointer_info' ] );
263
 
264
+ add_action( 'save_post', [ $this, 'sync_booking_status' ], 10, 3 );
265
 
266
+ add_filter( 'wcml_emails_options_to_translate', [ $this, 'emails_options_to_translate' ] );
267
 
268
+ add_filter( 'wcml_emails_text_keys_to_translate', [ $this, 'emails_text_keys_to_translate' ] );
269
 
270
+ add_filter( 'woocommerce_email_get_option', [ $this, 'translate_emails_text_strings' ], 10, 4 );
271
 
272
+ add_action( 'woocommerce_booking_confirmed_notification', [ $this, 'translate_booking_confirmed_email_texts' ], 9 );
273
 
274
+ add_action( 'woocommerce_booking_pending-confirmation_to_cancelled_notification', [ $this, 'translate_booking_cancelled_email_texts' ], 9 );
275
+ add_action( 'woocommerce_booking_confirmed_to_cancelled_notification', [ $this, 'translate_booking_cancelled_email_texts' ], 9 );
276
+ add_action( 'woocommerce_booking_paid_to_cancelled_notification', [ $this, 'translate_booking_cancelled_email_texts' ], 9 );
277
 
278
+ add_action( 'wc-booking-reminder', [ $this, 'translate_booking_confirmed_email_texts' ], 9 );
279
+ add_action( 'woocommerce_admin_new_booking_notification', [ $this, 'translate_new_booking_email_texts' ], 9 );
280
 
281
 
282
+ add_action( 'woocommerce_booking_pending-confirmation_to_cancelled_notification', [ $this, 'translate_booking_cancelled_admin_email_texts' ], 9 );
283
+ add_action( 'woocommerce_booking_confirmed_to_cancelled_notification', [ $this, 'translate_booking_cancelled_admin_email_texts' ], 9 );
284
+ add_action( 'woocommerce_booking_paid_to_cancelled_notification', [ $this, 'translate_booking_cancelled_admin_email_texts' ], 9 );
285
 
286
+ add_filter( 'wcml_email_language', [ $this, 'booking_email_language' ] );
287
 
288
+ if ( $this->is_bookings_listing_page() ) {
289
  $this->remove_language_switcher();
290
+ add_filter( 'wp_count_posts', [ $this, 'count_bookings_by_current_language' ], 10, 2 );
291
+ add_filter( 'views_edit-wc_booking', [ $this, 'unset_mine_from_bookings_views' ] );
292
  }
293
  }
294
 
295
+ if ( ! is_admin() || isset( $_POST['action'] ) && 'wc_bookings_calculate_costs' === $_POST['action'] ) {
296
+ add_filter( 'get_post_metadata', [ $this, 'filter_wc_booking_cost' ], 10, 4 );
297
  }
298
 
299
+ add_filter( 'wpml_language_filter_extra_conditions_snippet', [ $this, 'extra_conditions_to_filter_bookings' ] );
300
 
301
  $this->clear_transient_fields();
302
 
303
+ add_filter( 'wpml_tm_dashboard_translatable_types', [ $this, 'hide_bookings_type_on_tm_dashboard' ] );
304
 
305
+ add_filter( 'wcml_add_to_cart_sold_individually', [ $this, 'add_to_cart_sold_individually' ], 10, 4 );
306
 
307
+ add_filter( 'woocommerce_bookings_account_tables', [ $this, 'filter_my_account_bookings_tables_by_current_language' ] );
308
 
309
  }
310
 
328
  }
329
 
330
  // From here we can grab the order_id and return its language.
331
+ $order_id = $this->wpdb->get_var(
332
+ $this->wpdb->prepare(
333
+ "SELECT order_id FROM {$this->wpdb->prefix}woocommerce_order_items WHERE order_item_id = %d",
334
+ $order_item_id
335
+ )
336
+ ); // WPCS: unprepared SQL OK.
337
+ remove_filter( 'get_post_metadata', [ $this, 'get_order_language' ], 10 );
338
  $check = get_post_meta( $order_id, 'wpml_language', $single );
339
+ add_filter( 'get_post_metadata', [ $this, 'get_order_language' ], 10, 4 );
340
  }
341
 
342
  return $check;
358
  $this->save_custom_costs( $booking_id );
359
  }
360
 
361
+ public function wcml_price_field_after_booking_base_cost( $post_id ) {
362
 
363
  $this->echo_wcml_price_field( $post_id, 'wcml_wc_booking_cost' );
364
 
365
  }
366
 
367
+ public function wcml_price_field_after_booking_block_cost( $post_id ) {
368
  if ( $this->sitepress->get_wp_api()->version_compare( $this->sitepress->get_wp_api()->constant( 'WC_BOOKINGS_VERSION' ), '1.10.9', '<' ) ) {
369
  $this->echo_wcml_price_field( $post_id, 'wcml_wc_booking_base_cost' );
370
+ } else {
371
  $this->echo_wcml_price_field( $post_id, 'wcml_wc_booking_block_cost' );
372
+ }
373
  }
374
 
375
+ public function wcml_price_field_after_display_cost( $post_id ) {
376
 
377
  $this->echo_wcml_price_field( $post_id, 'wcml_wc_display_cost' );
378
 
379
  }
380
 
381
+ public function wcml_price_field_after_booking_pricing_base_cost( $pricing, $post_id ) {
382
 
383
  $this->echo_wcml_price_field( $post_id, 'wcml_wc_booking_pricing_base_cost', $pricing );
384
 
385
  }
386
 
387
+ public function wcml_price_field_after_booking_pricing_cost( $pricing, $post_id ) {
388
 
389
  $this->echo_wcml_price_field( $post_id, 'wcml_wc_booking_pricing_cost', $pricing );
390
 
391
  }
392
 
393
+ public function wcml_price_field_after_person_cost( $person_type_id ) {
394
 
395
  $this->echo_wcml_price_field( $person_type_id, 'wcml_wc_booking_person_cost', false, false );
396
 
397
  }
398
 
399
+ public function wcml_price_field_after_person_block_cost( $person_type_id ) {
400
 
401
  $this->echo_wcml_price_field( $person_type_id, 'wcml_wc_booking_person_block_cost', false, false );
402
 
403
  }
404
 
405
+ public function wcml_price_field_after_resource_cost( $resource_id, $post_id ) {
406
 
407
  $this->echo_wcml_price_field( $post_id, 'wcml_wc_booking_resource_cost', false, true, $resource_id );
408
 
409
  }
410
 
411
+ public function wcml_price_field_after_resource_block_cost( $resource_id, $post_id ) {
412
 
413
  $this->echo_wcml_price_field( $post_id, 'wcml_wc_booking_resource_block_cost', false, true, $resource_id );
414
 
415
  }
416
 
417
+ public function echo_wcml_price_field( $post_id, $field, $pricing = false, $check = true, $resource_id = false ) {
 
418
 
419
  if ( ( ! $check || $this->woocommerce_wpml->products->is_original_product( $post_id ) ) && $this->woocommerce_wpml->settings['enable_multi_currency'] == WCML_MULTI_CURRENCIES_INDEPENDENT ) {
420
 
432
 
433
  switch ( $field ) {
434
  case 'wcml_wc_booking_cost':
435
+ woocommerce_wp_text_input(
436
+ [
437
+ 'id' => 'wcml_wc_booking_cost',
438
+ 'class' => 'wcml_bookings_custom_price',
439
+ 'name' => 'wcml_wc_booking_cost[' . $currency_code . ']',
440
+ 'label' => get_woocommerce_currency_symbol( $currency_code ),
441
+ 'description' => __( 'One-off cost for the booking as a whole.', 'woocommerce-bookings' ),
442
+ 'value' => get_post_meta( $post_id, '_wc_booking_cost_' . $currency_code, true ),
443
+ 'type' => 'number',
444
+ 'desc_tip' => true,
445
+ 'custom_attributes' => [
446
+ 'min' => '',
447
+ 'step' => '0.01',
448
+ ],
449
+ ]
450
+ );
451
  break;
452
  case 'wcml_wc_booking_block_cost':
453
  case 'wcml_wc_booking_base_cost':
454
+ $block_cost_key = '_wc_booking_base_cost_';
455
+ if ( $field === 'wcml_wc_booking_block_cost' ) {
456
+ $block_cost_key = '_wc_booking_block_cost_';
457
+ }
458
+ $block_cost_key .= $currency_code;
459
+ woocommerce_wp_text_input(
460
+ [
461
+ 'id' => $field,
462
+ 'class' => 'wcml_bookings_custom_price',
463
+ 'name' => $field . '[' . $currency_code . ']',
464
+ 'label' => get_woocommerce_currency_symbol( $currency_code ),
465
+ 'description' => __( 'This is the cost per block booked. All other costs (for resources and persons) are added to this.', 'woocommerce-bookings' ),
466
+ 'value' => get_post_meta( $post_id, $block_cost_key, true ),
467
+ 'type' => 'number',
468
+ 'desc_tip' => true,
469
+ 'custom_attributes' => [
470
+ 'min' => '',
471
+ 'step' => '0.01',
472
+ ],
473
+ ]
474
+ );
475
  break;
476
  case 'wcml_wc_display_cost':
477
+ woocommerce_wp_text_input(
478
+ [
479
+ 'id' => 'wcml_wc_display_cost',
480
+ 'class' => 'wcml_bookings_custom_price',
481
+ 'name' => 'wcml_wc_display_cost[' . $currency_code . ']',
482
+ 'label' => get_woocommerce_currency_symbol( $currency_code ),
483
+ 'description' => __( 'The cost is displayed to the user on the frontend. Leave blank to have it calculated for you. If a booking has varying costs, this will be prefixed with the word "from:".', 'woocommerce-bookings' ),
484
+ 'value' => get_post_meta( $post_id, '_wc_display_cost_' . $currency_code, true ),
485
+ 'type' => 'number',
486
+ 'desc_tip' => true,
487
+ 'custom_attributes' => [
488
+ 'min' => '',
489
+ 'step' => '0.01',
490
+ ],
491
+ ]
492
+ );
493
  break;
494
 
495
  case 'wcml_wc_booking_pricing_base_cost':
 
496
  if ( isset( $pricing[ 'base_cost_' . $currency_code ] ) ) {
497
  $value = $pricing[ 'base_cost_' . $currency_code ];
498
  } else {
500
  }
501
 
502
  echo '<div class="wcml_bookings_range_block" >';
503
+ echo '<label>' . wp_kses_post( get_woocommerce_currency_symbol( $currency_code ) ) . '</label>';
504
+ echo '<input type="number" step="0.01" name="wcml_wc_booking_pricing_base_cost[' . esc_html( $currency_code ) . '][]" class="wcml_bookings_custom_price" value="' . esc_html( $value ) . '" placeholder="0" />';
505
  echo '</div>';
506
  break;
507
 
508
  case 'wcml_wc_booking_pricing_cost':
 
509
  if ( isset( $pricing[ 'cost_' . $currency_code ] ) ) {
510
  $value = $pricing[ 'cost_' . $currency_code ];
511
  } else {
513
  }
514
 
515
  echo '<div class="wcml_bookings_range_block" >';
516
+ echo '<label>' . wp_kses_post( get_woocommerce_currency_symbol( $currency_code ) ) . '</label>';
517
+ echo '<input type="number" step="0.01" name="wcml_wc_booking_pricing_cost[' . esc_html( $currency_code ) . '][]" class="wcml_bookings_custom_price" value="' . esc_html( $value ) . '" placeholder="0" />';
518
  echo '</div>';
519
  break;
520
 
521
  case 'wcml_wc_booking_person_cost':
 
522
  $value = get_post_meta( $post_id, 'cost_' . $currency_code, true );
523
 
524
  echo '<div class="wcml_bookings_person_block" >';
525
+ echo '<label>' . wp_kses_post( get_woocommerce_currency_symbol( $currency_code ) ) . '</label>';
526
+ echo '<input type="number" step="0.01" name="wcml_wc_booking_person_cost[' . intval( $post_id ) . '][' . esc_html( $currency_code ) . ']" class="wcml_bookings_custom_price" value="' . esc_html( $value ) . '" placeholder="0" />';
527
  echo '</div>';
528
  break;
529
 
530
  case 'wcml_wc_booking_person_block_cost':
 
531
  $value = get_post_meta( $post_id, 'block_cost_' . $currency_code, true );
532
 
533
  echo '<div class="wcml_bookings_person_block" >';
534
+ echo '<label>' . wp_kses_post( get_woocommerce_currency_symbol( $currency_code ) ) . '</label>';
535
+ echo '<input type="number" step="0.01" name="wcml_wc_booking_person_block_cost[' . intval( $post_id ) . '][' . esc_html( $currency_code ) . ']" class="wcml_bookings_custom_price" value="' . esc_html( $value ) . '" placeholder="0" />';
536
  echo '</div>';
537
  break;
538
 
539
  case 'wcml_wc_booking_resource_cost':
 
540
  $resource_base_costs = maybe_unserialize( get_post_meta( $post_id, '_resource_base_costs', true ) );
541
 
542
  if ( isset( $resource_base_costs['custom_costs'][ $currency_code ][ $resource_id ] ) ) {
546
  }
547
 
548
  echo '<div class="wcml_bookings_resource_block" >';
549
+ echo '<label>' . wp_kses_post( get_woocommerce_currency_symbol( $currency_code ) ) . '</label>';
550
+ echo '<input type="number" step="0.01" name="wcml_wc_booking_resource_cost[' . esc_html( $resource_id ) . '][' . esc_html( $currency_code ) . ']" class="wcml_bookings_custom_price" value="' . esc_html( $value ) . '" placeholder="0" />';
551
  echo '</div>';
552
  break;
553
 
554
  case 'wcml_wc_booking_resource_block_cost':
 
555
  $resource_block_costs = maybe_unserialize( get_post_meta( $post_id, '_resource_block_costs', true ) );
556
 
557
  if ( isset( $resource_block_costs['custom_costs'][ $currency_code ][ $resource_id ] ) ) {
561
  }
562
 
563
  echo '<div class="wcml_bookings_resource_block" >';
564
+ echo '<label>' . wp_kses_post( get_woocommerce_currency_symbol( $currency_code ) ) . '</label>';
565
+ echo '<input type="number" step="0.01" name="wcml_wc_booking_resource_block_cost[' . esc_html( $resource_id ) . '][' . esc_html( $currency_code ) . ']" class="wcml_bookings_custom_price" value="' . esc_html( $value ) . '" placeholder="0" />';
566
  echo '</div>';
567
  break;
568
 
570
  break;
571
 
572
  }
 
573
  }
574
 
575
  echo '</div>';
577
  }
578
  }
579
 
580
+ public function after_bookings_pricing( $post_id ) {
581
 
582
+ if ( in_array( 'booking', wp_get_post_terms( $post_id, 'product_type', [ 'fields' => 'names' ] ) ) && $this->woocommerce_wpml->products->is_original_product( $post_id ) && $this->woocommerce_wpml->settings['enable_multi_currency'] == WCML_MULTI_CURRENCIES_INDEPENDENT ) {
 
583
 
584
  $custom_costs_status = get_post_meta( $post_id, '_wcml_custom_costs_status', true );
585
 
587
 
588
  echo '<div class="wcml_custom_costs">';
589
 
590
+ echo '<input type="radio" name="_wcml_custom_costs" id="wcml_custom_costs_auto" value="0" class="wcml_custom_costs_input" ' . esc_html( $checked ) . ' />';
591
+ echo '<label for="wcml_custom_costs_auto">' . esc_html__( 'Calculate costs in other currencies automatically', 'woocommerce-multilingual' ) . '</label>';
592
 
593
+ $checked = 1 === (int) $custom_costs_status ? 'checked="checked"' : ' ';
594
 
595
+ echo '<input type="radio" name="_wcml_custom_costs" value="1" id="wcml_custom_costs_manually" class="wcml_custom_costs_input" ' . esc_html( $checked ) . ' />';
596
+ echo '<label for="wcml_custom_costs_manually">' . esc_html__( 'Set costs in other currencies manually', 'woocommerce-multilingual' ) . '</label>';
597
 
598
  wp_nonce_field( 'wcml_save_custom_costs', '_wcml_custom_costs_nonce' );
599
 
602
 
603
  }
604
 
605
+ public function save_custom_costs( $post_id ) {
606
  $nonce = filter_var( isset( $_POST['_wcml_custom_costs_nonce'] ) ? $_POST['_wcml_custom_costs_nonce'] : '', FILTER_SANITIZE_FULL_SPECIAL_CHARS );
607
 
608
  if ( isset( $_POST['_wcml_custom_costs'] ) && isset( $nonce ) && wp_verify_nonce( $nonce, 'wcml_save_custom_costs' ) ) {
619
  $this->update_booking_costs( $currencies, $post_id );
620
  $this->update_booking_pricing( $currencies, $post_id );
621
 
 
622
  if ( isset( $_POST['wcml_wc_booking_person_cost'] ) && is_array( $_POST['wcml_wc_booking_person_cost'] ) ) {
623
  $this->update_booking_person_cost( $currencies, $_POST['wcml_wc_booking_person_cost'] );
624
  }
643
 
644
  }
645
 
646
+ // sync existing product bookings for translations.
647
+ public function sync_bookings( $original_product_id, $product_id, $language ) {
648
  $all_bookings_for_product = $this->wpdb->get_results( $this->wpdb->prepare( "SELECT post_id as id FROM {$this->wpdb->postmeta} WHERE meta_key = '_booking_product_id' AND meta_value = %d", $original_product_id ) );
649
 
650
  foreach ( $all_bookings_for_product as $booking ) {
651
 
652
+ if ( $language === $this->wpml_post_translations->get_source_lang_code( $booking->id ) ) {
653
+ continue;
654
+ }
655
 
656
  $booking_translations = $this->get_translated_bookings( $booking->id );
657
 
658
+ if ( ! isset( $booking_translations[ $language ] ) ) {
659
  $this->duplicate_booking_for_translations( $booking->id, $language );
660
+ } elseif ( ! get_post_meta( $booking_translations[ $language ], '_booking_product_id', true ) ) {
661
+ $this->update_translated_booking_meta( $booking_translations[ $language ], $booking->id, $language );
662
  }
663
  }
664
  }
665
 
666
  /**
667
+ * @param int $translated_booking_id
668
+ * @param int $original_booking_id
669
  * @param string $language
670
  */
671
+ private function update_translated_booking_meta( $translated_booking_id, $original_booking_id, $language ) {
672
  update_post_meta( $translated_booking_id, '_booking_product_id', $this->get_translated_booking_product_id( $original_booking_id, $language ) );
673
  update_post_meta( $translated_booking_id, '_booking_resource_id', $this->get_translated_booking_resource_id( $original_booking_id, $language ) );
674
  update_post_meta( $translated_booking_id, '_booking_persons', $this->get_translated_booking_persons_ids( $original_booking_id, $language ) );
675
+ }
676
 
677
+ public function sync_booking_data( $original_product_id, $current_product_id ) {
678
 
679
  if ( has_term( 'booking', 'product_type', $original_product_id ) ) {
680
  $translations = $this->wpml_post_translations->get_element_translations( $original_product_id, false, true );
681
  foreach ( $translations as $translation ) {
682
+ $language = $this->wpml_post_translations->get_element_lang_code( $translation );
683
 
684
+ // sync_resources.
685
+ $this->sync_resources( $original_product_id, $translation, $language );
686
 
687
+ // sync_persons.
688
+ $this->sync_persons( $original_product_id, $translation, $language );
689
  }
690
  }
691
  }
692
 
693
+ public function sync_resources( $original_product_id, $translated_product_id, $lang_code, $duplicate = true ) {
694
 
695
+ $original_resources = $this->wpdb->get_results(
696
+ $this->wpdb->prepare(
697
+ "SELECT resource_id, sort_order FROM {$this->wpdb->prefix}wc_booking_relationships WHERE product_id = %d",
698
+ $original_product_id
699
+ )
700
+ );
701
 
702
+ $translated_resources = $this->wpdb->get_col(
703
+ $this->wpdb->prepare(
704
+ "SELECT resource_id FROM {$this->wpdb->prefix}wc_booking_relationships WHERE product_id = %d",
705
+ $translated_product_id
706
+ )
707
+ );
708
 
709
+ $used_translated_resources = [];
710
 
711
  foreach ( $original_resources as $resource ) {
712
 
724
  $this->duplicate_resource( $translated_product_id, $resource, $lang_code );
725
  }
726
  }
 
727
  }
728
 
729
  $removed_translated_resources_id = array_diff( $translated_resources, $used_translated_resources );
736
 
737
  }
738
 
739
+ public function duplicate_resource( $tr_product_id, $resource, $lang_code ) {
740
  global $iclTranslationManagement;
741
 
742
  if ( method_exists( $this->sitepress, 'make_duplicate' ) ) {
746
  } else {
747
 
748
  if ( ! isset( $iclTranslationManagement ) ) {
749
+ $iclTranslationManagement = new TranslationManagement();
750
  }
751
 
752
  $trns_resource_id = $iclTranslationManagement->make_duplicate( $resource->resource_id, $lang_code );
755
 
756
  $this->wpdb->insert(
757
  $this->wpdb->prefix . 'wc_booking_relationships',
758
+ [
759
  'product_id' => $tr_product_id,
760
  'resource_id' => $trns_resource_id,
761
+ 'sort_order' => $resource->sort_order,
762
+ ]
763
  );
764
 
765
  delete_post_meta( $trns_resource_id, '_icl_lang_duplicate_of' );
771
 
772
  $this->wpdb->insert(
773
  $this->wpdb->prefix . 'wc_booking_relationships',
774
+ [
775
  'sort_order' => $resource_data->sort_order,
776
  'product_id' => $product_id,
777
+ 'resource_id' => $resource_id,
778
+ ]
779
  );
780
 
781
  update_post_meta( $resource_id, 'qty', get_post_meta( $resource_data->resource_id, 'qty', true ) );
787
 
788
  $this->wpdb->delete(
789
  $this->wpdb->prefix . 'wc_booking_relationships',
790
+ [
791
  'product_id' => $product_id,
792
+ 'resource_id' => $resource_id,
793
+ ]
794
  );
795
 
796
  }
799
 
800
  $this->wpdb->update(
801
  $this->wpdb->prefix . 'wc_booking_relationships',
802
+ [
803
+ 'sort_order' => $resource_data->sort_order,
804
+ ],
805
+ [
806
  'product_id' => $product_id,
807
+ 'resource_id' => $resource_id,
808
+ ]
809
  );
810
 
811
  update_post_meta( $resource_id, 'qty', get_post_meta( $resource_data->resource_id, 'qty', true ) );
812
  update_post_meta( $resource_id, '_wc_booking_availability', get_post_meta( $resource_data->resource_id, '_wc_booking_availability', true ) );
813
 
 
814
  }
815
 
816
+ public function sync_persons( $original_product_id, $tr_product_id, $lang_code, $duplicate = true ) {
817
  $orig_persons = $this->wpdb->get_col( $this->wpdb->prepare( "SELECT ID FROM {$this->wpdb->posts} WHERE post_parent = %d AND post_type = 'bookable_person'", $original_product_id ) );
818
 
819
  $trnsl_persons = $this->wpdb->get_col( $this->wpdb->prepare( "SELECT ID FROM {$this->wpdb->posts} WHERE post_parent = %d AND post_type = 'bookable_person'", $tr_product_id ) );
820
 
 
821
  foreach ( $orig_persons as $person ) {
822
 
823
  $trnsl_person_id = apply_filters( 'translate_object_id', $person, 'bookable_person', false, $lang_code );
833
  update_post_meta( $trnsl_person_id, 'max', get_post_meta( $person, 'max', true ) );
834
  update_post_meta( $trnsl_person_id, 'min', get_post_meta( $person, 'min', true ) );
835
 
 
836
  if ( get_post_meta( $person, '_wcml_custom_costs_status', true ) && $this->woocommerce_wpml->settings['enable_multi_currency'] == WCML_MULTI_CURRENCIES_INDEPENDENT ) {
837
  $currencies = $this->woocommerce_wpml->multi_currency->get_currencies();
838
 
843
 
844
  }
845
  }
 
846
  }
 
847
  } else {
848
 
849
  if ( $duplicate ) {
855
  continue;
856
 
857
  }
 
858
  }
 
859
  }
860
 
861
  foreach ( $trnsl_persons as $trnsl_person ) {
866
 
867
  }
868
 
869
+ public function duplicate_person( $tr_product_id, $person_id, $lang_code ) {
870
  global $iclTranslationManagement;
871
 
872
  if ( method_exists( $this->sitepress, 'make_duplicate' ) ) {
876
  } else {
877
 
878
  if ( ! isset( $iclTranslationManagement ) ) {
879
+ $iclTranslationManagement = new TranslationManagement();
880
  }
881
 
882
  $new_person_id = $iclTranslationManagement->make_duplicate( $person_id, $lang_code );
885
 
886
  $this->wpdb->update(
887
  $this->wpdb->posts,
888
+ [
889
+ 'post_parent' => $tr_product_id,
890
+ ],
891
+ [
892
+ 'ID' => $new_person_id,
893
+ ]
894
  );
895
 
896
  delete_post_meta( $new_person_id, '_icl_lang_duplicate_of' );
898
  return $new_person_id;
899
  }
900
 
901
+ public function filter_wc_booking_cost( $check, $object_id, $meta_key, $single ) {
902
 
903
+ if ( in_array(
904
+ $meta_key,
905
+ [
906
+ '_wc_booking_cost',
907
+ '_wc_booking_base_cost',
908
+ '_wc_display_cost',
909
+ '_wc_booking_pricing',
910
+ 'cost',
911
+ '_wc_booking_block_cost',
912
+ 'block_cost',
913
+ '_resource_base_costs',
914
+ '_resource_block_costs',
915
+ ]
916
+ ) ) {
917
 
918
  if ( WCML_MULTI_CURRENCIES_INDEPENDENT === $this->woocommerce_wpml->settings['enable_multi_currency'] ) {
919
 
927
  return $check;
928
  }
929
 
930
+ if ( in_array( $meta_key, [ 'cost', 'block_cost' ] ) ) {
931
 
932
  if ( get_post_type( $object_id ) == 'bookable_person' ) {
933
 
942
 
943
  } else {
944
 
945
+ remove_filter( 'get_post_metadata', [ $this, 'filter_wc_booking_cost' ], 10, 4 );
946
 
947
  $cost = get_post_meta( $object_id, $meta_key, true );
948
 
949
+ add_filter( 'get_post_metadata', [ $this, 'filter_wc_booking_cost' ], 10, 4 );
950
 
951
  return $this->woocommerce_wpml->multi_currency->prices->convert_price_amount( $cost, $currency );
952
  }
 
953
  } else {
954
 
955
  return $check;
956
 
957
  }
 
958
  }
959
 
960
+ if ( in_array(
961
+ $meta_key,
962
+ [
963
+ '_wc_booking_pricing',
964
+ '_resource_base_costs',
965
+ '_resource_block_costs',
966
+ ]
967
+ ) ) {
968
 
969
+ remove_filter( 'get_post_metadata', [ $this, 'filter_wc_booking_cost' ], 10, 4 );
970
 
971
  if ( $meta_key == '_wc_booking_pricing' ) {
972
 
975
  } else {
976
  $value = $check;
977
  }
 
978
  } else {
979
 
980
  $costs = maybe_unserialize( get_post_meta( $object_id, $meta_key, true ) );
983
  $value = $check;
984
  } elseif ( $cost_status && isset( $costs['custom_costs'][ $currency ] ) ) {
985
 
986
+ $res_costs = [];
987
  foreach ( $costs['custom_costs'][ $currency ] as $resource_id => $cost ) {
988
  $trns_resource_id = apply_filters( 'translate_object_id', $resource_id, 'bookable_resource', true, $this->sitepress->get_current_language() );
989
  $res_costs[ $trns_resource_id ] = $cost;
990
  }
991
+ $value = [ 0 => $res_costs ];
992
  } elseif ( $cost_status && isset( $costs[0]['custom_costs'][ $currency ] ) ) {
993
+ $value = [ 0 => $costs[0]['custom_costs'][ $currency ] ];
994
  } else {
995
 
996
+ $converted_values = [];
997
 
998
  foreach ( $costs as $resource_id => $cost ) {
999
  $converted_values[0][ $resource_id ] = $this->woocommerce_wpml->multi_currency->prices->convert_price_amount( $cost, $currency );
1001
 
1002
  $value = $converted_values;
1003
  }
 
1004
  }
1005
 
1006
+ add_filter( 'get_post_metadata', [ $this, 'filter_wc_booking_cost' ], 10, 4 );
1007
 
1008
  return $value;
1009
 
1017
 
1018
  } else {
1019
 
1020
+ remove_filter( 'get_post_metadata', [ $this, 'filter_wc_booking_cost' ], 10, 4 );
1021
 
1022
  $value = get_post_meta( $original_id, $meta_key, true );
1023
 
1024
  $value = $this->woocommerce_wpml->multi_currency->prices->convert_price_amount( $value, $currency );
1025
 
1026
+ add_filter( 'get_post_metadata', [ $this, 'filter_wc_booking_cost' ], 10, 4 );
1027
 
1028
  return $value;
1029
 
1030
  }
 
1031
  }
 
1032
  }
1033
 
1034
  return $check;
1035
  }
1036
 
1037
+ public function sync_resource_costs_with_translations( $object_id, $meta_key, $check = false ) {
 
1038
 
1039
  $original_product_id = $this->woocommerce_wpml->products->get_original_product_id( $object_id );
1040
 
1041
  if ( $object_id == $original_product_id ) {
1042
 
1043
+ $translations = $this->wpml_post_translations->get_element_translations( $object_id, false, true );
1044
 
1045
  foreach ( $translations as $translation ) {
1046
  $this->sync_resource_costs(
1047
  $original_product_id,
1048
+ $translation,
1049
+ $meta_key,
1050
+ $this->wpml_post_translations->get_element_lang_code( $translation )
1051
+ );
1052
  }
1053
 
1054
  return $check;
1055
  } else {
1056
  $this->sync_resource_costs(
1057
+ $original_product_id,
1058
+ $object_id,
1059
+ $meta_key,
1060
+ $this->wpml_post_translations->get_element_lang_code( $object_id )
1061
+ );
1062
  return true;
1063
  }
1064
 
1065
  }
1066
 
1067
+ public function sync_resource_costs( $original_product_id, $object_id, $meta_key, $language_code ) {
1068
 
1069
  $original_costs = maybe_unserialize( get_post_meta( $original_product_id, $meta_key, true ) );
1070
 
1071
+ $wc_booking_resource_costs = [];
1072
  if ( ! empty( $original_costs ) ) {
1073
  foreach ( $original_costs as $resource_id => $costs ) {
1074
 
1083
  $wc_booking_resource_costs['custom_costs'][ $code ][ $trns_resource_id ] = $custom_cost;
1084
 
1085
  }
 
1086
  }
 
1087
  } else {
1088
 
1089
  $trns_resource_id = apply_filters( 'translate_object_id', $resource_id, 'bookable_resource', true, $language_code );
1091
  $wc_booking_resource_costs[ $trns_resource_id ] = $costs;
1092
 
1093
  }
 
1094
  }
1095
  }
1096
 
1098
 
1099
  }
1100
 
1101
+ public function wc_bookings_process_cost_rules_cost( $cost, $fields, $key ) {
1102
  return $this->filter_pricing_cost( $cost, $fields, 'cost_', $key );
1103
  }
1104
 
1105
+ public function wc_bookings_process_cost_rules_base_cost( $base_cost, $fields, $key ) {
1106
  return $this->filter_pricing_cost( $base_cost, $fields, 'base_cost_', $key );
1107
  }
1108
 
1109
+ public function wc_bookings_process_cost_rules_override_block_cost( $override_cost, $fields, $key ) {
1110
  return $this->filter_pricing_cost( $override_cost, $fields, 'override_block_', $key );
1111
  }
1112
 
1113
+ public function filter_pricing_cost( $cost, $fields, $name, $key ) {
1114
  global $product;
1115
 
1116
  if ( $this->woocommerce_wpml->settings['enable_multi_currency'] == WCML_MULTI_CURRENCIES_INDEPENDENT ) {
1143
 
1144
  $needs_filter_pricing_cost = $this->needs_filter_pricing_cost( $name, $fields );
1145
 
1146
+ if ( $needs_filter_pricing_cost ) {
1147
  if ( isset( $fields[ $name . $currency ] ) ) {
1148
  return $fields[ $name . $currency ];
1149
  } else {
1150
  return $this->woocommerce_wpml->multi_currency->prices->convert_price_amount( $cost, $currency );
1151
  }
1152
  }
 
1153
  }
1154
 
1155
  return $cost;
1156
 
1157
  }
1158
 
1159
+ public function needs_filter_pricing_cost( $name, $fields ) {
1160
 
1161
+ $modifier_skip_values = [ 'divide', 'times' ];
1162
 
1163
+ if (
1164
  'override_block_' === $name ||
1165
+ ( 'cost_' === $name && ! in_array( $fields['modifier'], $modifier_skip_values ) ) ||
1166
+ ( 'base_cost_' === $name && ! in_array( $fields['base_modifier'], $modifier_skip_values ) )
1167
+ ) {
1168
  return true;
1169
+ } else {
1170
  return false;
1171
  }
1172
  }
1173
 
1174
+ public function load_assets( $external_product_type = false ) {
1175
  global $pagenow;
1176
 
1177
+ $product_id = $pagenow == 'post.php' && isset( $_GET['post'] ) ? (int) $_GET['post'] : false;
1178
 
1179
+ if ( $product_id && get_post_type( $product_id ) === 'product' ) {
1180
+ $product = wc_get_product( $product_id );
1181
+ $product_type = $product->get_type();
1182
 
1183
  if ( ( $this->is_booking( $product ) || $product_type === $external_product_type ) || $pagenow == 'post-new.php' ) {
1184
 
1185
+ wp_register_style( 'wcml-bookings-css', WCML_PLUGIN_URL . '/compatibility/res/css/wcml-bookings.css', [], WCML_VERSION );
1186
  wp_enqueue_style( 'wcml-bookings-css' );
1187
 
1188
+ wp_register_script( 'wcml-bookings-js', WCML_PLUGIN_URL . '/compatibility/res/js/wcml-bookings.js', [ 'jquery' ], WCML_VERSION, true );
1189
  wp_enqueue_script( 'wcml-bookings-js' );
1190
 
1191
  }
1193
 
1194
  }
1195
 
1196
+ public function localize_lock_fields_js() {
1197
+ wp_localize_script( 'wcml-bookings-js', 'lock_settings', [ 'lock_fields' => 1 ] );
1198
  }
1199
 
1200
+ public function wcml_multi_currency_is_ajax( $actions ) {
1201
 
1202
  $actions[] = 'wc_bookings_calculate_costs';
1203
 
1208
 
1209
  if ( $cart_item['data'] instanceof WC_Product_Booking && isset( $cart_item['booking'] ) ) {
1210
 
 
1211
  $current_id = apply_filters( 'translate_object_id', $cart_item['product_id'], 'product', true, $current_language );
1212
  $cart_product_id = $cart_item['product_id'];
1213
 
1219
 
1220
  if ( $this->woocommerce_wpml->settings['enable_multi_currency'] == WCML_MULTI_CURRENCIES_INDEPENDENT || $current_id != $cart_product_id ) {
1221
 
1222
+ $booking_info = [
1223
  'wc_bookings_field_start_date_year' => $cart_item['booking']['_year'],
1224
  'wc_bookings_field_start_date_month' => $cart_item['booking']['_month'],
1225
  'wc_bookings_field_start_date_day' => $cart_item['booking']['_day'],
1226
+ 'add-to-cart' => $current_id,
1227
+ ];
1228
 
1229
  if ( isset( $cart_item['booking']['_persons'] ) ) {
1230
  foreach ( $cart_item['booking']['_persons'] as $person_id => $value ) {
1252
  $cart_item['data']->set_price( $cost );
1253
  }
1254
  }
 
1255
  }
1256
 
1257
  return $cart_item;
1268
  return $cost;
1269
  }
1270
 
1271
+ public function booking_currency_dropdown() {
 
1272
 
1273
  if ( $this->woocommerce_wpml->settings['enable_multi_currency'] == WCML_MULTI_CURRENCIES_INDEPENDENT ) {
1274
  $current_booking_currency = $this->get_cookie_booking_currency();
1276
  $wc_currencies = get_woocommerce_currencies();
1277
  $currencies = $this->woocommerce_wpml->multi_currency->get_currencies( $include_default = true );
1278
  ?>
1279
+ <tr valign="top">
1280
+ <th scope="row"><?php _e( 'Booking currency', 'woocommerce-multilingual' ); ?></th>
1281
+ <td>
1282
+ <select id="dropdown_booking_currency">
1283
+ <?php foreach ( $currencies as $currency => $count ) : ?>
1284
+ <option
1285
+ value="<?php echo esc_html( $currency ); ?>" <?php echo $current_booking_currency == $currency ? 'selected="selected"' : ''; ?>><?php echo esc_html( $wc_currencies[ $currency ] ); ?></option>
 
 
 
1286
  <?php endforeach; ?>
1287
+ </select>
1288
+ </td>
1289
+ </tr>
 
1290
 
1291
  <?php
1292
 
1293
  $wcml_booking_set_currency_nonce = wp_create_nonce( 'booking_set_currency' );
1294
 
1295
+ wc_enqueue_js(
1296
+ "
1297
 
1298
  jQuery(document).on('change', '#dropdown_booking_currency', function(){
1299
  jQuery.ajax({
1313
  }
1314
  })
1315
  });
1316
+ "
1317
+ );
1318
 
1319
  }
1320
 
1321
  }
1322
 
1323
+ public function set_booking_currency_ajax() {
1324
 
1325
  $nonce = filter_input( INPUT_POST, 'wcml_nonce', FILTER_SANITIZE_FULL_SPECIAL_CHARS );
1326
  if ( ! $nonce || ! wp_verify_nonce( $nonce, 'booking_set_currency' ) ) {
1327
+ echo json_encode( [ 'error' => __( 'Invalid nonce', 'woocommerce-multilingual' ) ] );
1328
  die();
1329
  }
1330
 
1351
  }
1352
  }
1353
 
1354
+ public function get_cookie_booking_currency() {
1355
 
1356
  if ( isset( $_COOKIE ['_wcml_booking_currency'] ) ) {
1357
  $currency = $_COOKIE['_wcml_booking_currency'];
1362
  return $currency;
1363
  }
1364
 
1365
+ public function filter_booking_currency_symbol( $currency ) {
1366
  global $pagenow;
1367
 
1368
+ remove_filter( 'woocommerce_currency_symbol', [ $this, 'filter_booking_currency_symbol' ] );
1369
  if ( isset( $_COOKIE ['_wcml_booking_currency'] ) && $pagenow == 'edit.php' && isset( $_GET['page'] ) && $_GET['page'] == 'create_booking' ) {
1370
  $currency = get_woocommerce_currency_symbol( $_COOKIE ['_wcml_booking_currency'] );
1371
  }
1372
+ add_filter( 'woocommerce_currency_symbol', [ $this, 'filter_booking_currency_symbol' ] );
1373
 
1374
  return $currency;
1375
  }
1376
 
1377
+ public function create_booking_page_client_currency( $currency ) {
1378
  global $pagenow;
1379
 
1380
  if ( wpml_is_ajax() && isset( $_POST['form'] ) ) {
1388
  return $currency;
1389
  }
1390
 
1391
+ public function set_order_currency_on_create_booking_page( $order_id ) {
1392
  update_post_meta( $order_id, '_order_currency', $this->get_cookie_booking_currency() );
1393
 
1394
  update_post_meta( $order_id, 'wpml_language', $this->sitepress->get_current_language() );
1395
 
1396
  }
1397
 
1398
+ public function filter_get_booking_products_args( $args ) {
1399
  if ( isset( $args['suppress_filters'] ) ) {
1400
  $args['suppress_filters'] = false;
1401
  }
1403
  return $args;
1404
  }
1405
 
1406
+ public function custom_box_html( $obj, $product_id, $data ) {
1407
 
1408
+ if ( ! $this->is_booking( $product_id ) ) {
1409
  return;
1410
  }
1411
 
1436
  $group->add_field( $resource_field );
1437
  $bookings_section->add_field( $group );
1438
  }
 
1439
  }
1440
 
1441
  $original_persons = $this->get_original_persons( $product_id );
1465
  }
1466
 
1467
 
1468
+ public function custom_box_html_data( $data, $product_id, $translation, $lang ) {
1469
 
1470
+ if ( ! $this->is_booking( $product_id ) ) {
1471
  return $data;
1472
  }
1473
 
1474
  if ( get_post_meta( $product_id, '_wc_booking_has_resources', true ) == 'yes' ) {
1475
 
1476
+ $data['_wc_booking_resouce_label'] = [ 'original' => get_post_meta( $product_id, '_wc_booking_resouce_label', true ) ];
1477
  $data['_wc_booking_resouce_label']['translation'] = $translation ? get_post_meta( $translation->ID, '_wc_booking_resouce_label', true ) : '';
1478
  }
1479
 
1486
  if ( 'custom_costs' === $resource_id ) {
1487
  continue;
1488
  }
1489
+ $data[ 'bookings-resource_' . $resource_id . '_title' ] = [ 'original' => get_the_title( $resource_id ) ];
1490
  global $sitepress;
1491
+ $trns_resource_id = apply_filters( 'translate_object_id', $resource_id, 'bookable_resource', false, $lang );
1492
  $data[ 'bookings-resource_' . $resource_id . '_title' ]['translation'] = $trns_resource_id ? get_the_title( $trns_resource_id ) : '';
1493
  }
1494
  }
1497
 
1498
  foreach ( $original_persons as $person_id ) {
1499
 
1500
+ $data[ 'bookings-person_' . $person_id . '_title' ] = [ 'original' => get_the_title( $person_id ) ];
1501
+ $data[ 'bookings-person_' . $person_id . '_description' ] = [ 'original' => get_post( $person_id )->post_excerpt ];
1502
 
1503
+ $trnsl_person_id = apply_filters( 'translate_object_id', $person_id, 'bookable_person', false, $lang );
1504
  $data[ 'bookings-person_' . $person_id . '_title' ]['translation'] = $trnsl_person_id ? get_the_title( $trnsl_person_id ) : '';
1505
  $data[ 'bookings-person_' . $person_id . '_description' ]['translation'] = $trnsl_person_id ? get_post( $trnsl_person_id )->post_excerpt : '';
1506
 
1510
  }
1511
 
1512
 
1513
+ public function get_original_resources( $product_id ) {
1514
  $orig_resources = maybe_unserialize( get_post_meta( $product_id, '_resource_base_costs', true ) );
1515
 
1516
  return $orig_resources;
1517
  }
1518
 
1519
+ public function get_original_persons( $product_id ) {
1520
  $original_persons = $this->wpdb->get_col( $this->wpdb->prepare( "SELECT ID FROM {$this->wpdb->posts} WHERE post_parent = %d AND post_type = 'bookable_person' AND post_status = 'publish'", $product_id ) );
1521
 
1522
  return $original_persons;
1523
  }
1524
 
1525
+ public function show_custom_blocks_for_resources_and_persons( $check, $product_id, $product_content ) {
1526
+ if ( in_array( $product_content, [ 'wc_booking_resources', 'wc_booking_persons' ] ) ) {
1527
  return false;
1528
  }
1529
 
1530
  return $check;
1531
  }
1532
 
1533
+ public function replace_tm_editor_custom_fields_with_own_sections( $fields ) {
1534
  $fields[] = '_resource_base_costs';
1535
  $fields[] = '_resource_block_costs';
1536
 
1537
  return $fields;
1538
  }
1539
 
1540
+ public function remove_single_custom_fields_to_translate( $fields ) {
1541
  $fields[] = '_wc_booking_resouce_label';
1542
 
1543
  return $fields;
1544
  }
1545
 
1546
+ public function product_content_resource_label( $meta_key, $product_id ) {
1547
  if ( $meta_key == '_wc_booking_resouce_label' ) {
1548
  return __( 'Resources label', 'woocommerce-multilingual' );
1549
  }
1551
  return $meta_key;
1552
  }
1553
 
1554
+ public function wcml_products_tab_sync_resources_and_persons( $original_product_id, $tr_product_id, $data, $language ) {
1555
  global $wpml_post_translations;
1556
 
1557
+ remove_action( 'save_post', [ $wpml_post_translations, 'save_post_actions' ], 100, 2 );
1558
 
1559
+ $orig_resources = $orig_resources = $this->get_original_resources( $original_product_id );
1560
 
1561
  if ( $orig_resources ) {
1562
 
1572
  } else {
1573
  continue;
1574
  }
 
1575
  } else {
1576
+ // update_relationship
 
1577
  $exist = $this->wpdb->get_var( $this->wpdb->prepare( "SELECT ID FROM {$this->wpdb->prefix}wc_booking_relationships WHERE resource_id = %d AND product_id = %d", $resource_id, $tr_product_id ) );
1578
 
1579
  if ( ! $exist ) {
1580
 
1581
  $this->wpdb->insert(
1582
  $this->wpdb->prefix . 'wc_booking_relationships',
1583
+ [
1584
  'product_id' => $tr_product_id,
1585
  'resource_id' => $resource_id,
1586
+ 'sort_order' => $orig_resource->sort_order,
1587
+ ]
1588
  );
1589
 
1590
  }
 
1591
  }
1592
 
 
1593
  $this->wpdb->update(
1594
  $this->wpdb->posts,
1595
+ [
1596
+ 'post_title' => $data[ md5( 'bookings-resource_' . $orig_resource_id . '_title' ) ],
1597
+ ],
1598
+ [
1599
+ 'ID' => $resource_id,
1600
+ ]
1601
  );
1602
 
1603
  update_post_meta( $resource_id, 'wcml_is_translated', true );
1604
 
1605
  }
1606
 
1607
+ // sync resources data
1608
  $this->sync_resources( $original_product_id, $tr_product_id, $language, false );
1609
 
1610
  }
1611
 
1612
  $original_persons = $this->get_original_persons( $original_product_id );
1613
 
1614
+ // sync persons
1615
  if ( $original_persons ) {
1616
 
1617
  foreach ( $original_persons as $original_person_id ) {
1626
 
1627
  $this->wpdb->update(
1628
  $this->wpdb->posts,
1629
+ [
1630
+ 'post_parent' => $tr_product_id,
1631
+ ],
1632
+ [
1633
+ 'ID' => $person_id,
1634
+ ]
1635
  );
1636
 
1637
  }
1638
 
1639
  $this->wpdb->update(
1640
  $this->wpdb->posts,
1641
+ [
1642
  'post_title' => $data[ md5( 'bookings-person_' . $original_person_id . '_title' ) ],
1643
  'post_excerpt' => $data[ md5( 'bookings-person_' . $original_person_id . '_description' ) ],
1644
+ ],
1645
+ [
1646
+ 'ID' => $person_id,
1647
+ ]
1648
  );
1649
 
1650
  update_post_meta( $person_id, 'wcml_is_translated', true );
1651
 
1652
  }
1653
 
1654
+ // sync persons data
1655
  $this->sync_persons( $original_product_id, $tr_product_id, $language, false );
1656
 
1657
  }
1658
 
1659
+ add_action( 'save_post', [ $wpml_post_translations, 'save_post_actions' ], 100, 2 );
1660
 
1661
  }
1662
 
1663
+ public function duplicate_booking_for_translations( $booking_id, $lang = false ) {
1664
  $booking_object = get_post( $booking_id );
1665
 
1666
+ $booking_data = [
1667
  'post_type' => 'wc_booking',
1668
  'post_title' => $booking_object->post_title,
1669
  'post_status' => $booking_object->post_status,
1670
+ 'ping_status' => 'closed',
1671
+ ];
1672
 
1673
+ if ( $booking_object->post_parent && $lang ) {
1674
  $translated_parent = apply_filters( 'translate_object_id', $booking_object->post_parent, get_post_type( $booking_object->post_parent ), false, $lang );
1675
+ if ( $translated_parent ) {
1676
+ $booking_data['post_parent'] = $translated_parent;
1677
+ }
1678
  }
1679
 
1680
  $active_languages = $this->sitepress->get_active_languages();
1693
  }
1694
 
1695
  $booking_persons = maybe_unserialize( get_post_meta( $booking_id, '_booking_persons', true ) );
1696
+ $trnsl_booking_persons = [];
1697
 
1698
  if ( is_array( $booking_persons ) && ! empty( $booking_persons ) ) {
1699
  foreach ( $booking_persons as $person_id => $person_count ) {
1705
  } else {
1706
  $trnsl_booking_persons[ $trnsl_person_id ] = $person_count;
1707
  }
 
1708
  }
1709
  }
1710
 
1712
  $trid = $this->sitepress->get_element_trid( $booking_id );
1713
  $this->sitepress->set_element_language_details( $trnsl_booking_id, 'post_wc_booking', $trid, $language['code'] );
1714
 
1715
+ $meta_args = [
1716
  '_booking_order_item_id' => 0,
1717
  '_booking_product_id' => $this->get_translated_booking_product_id( $booking_id, $language['code'] ),
1718
  '_booking_resource_id' => $this->get_translated_booking_resource_id( $booking_id, $language['code'] ),
1725
  '_booking_customer_id' => get_post_meta( $booking_id, '_booking_customer_id', true ),
1726
  '_booking_duplicate_of' => $booking_id,
1727
  '_language_code' => $language['code'],
1728
+ ];
1729
 
1730
  foreach ( $meta_args as $key => $value ) {
1731
  update_post_meta( $trnsl_booking_id, $key, $value );
1735
 
1736
  }
1737
 
 
1738
  }
1739
 
1740
+ public function get_translated_booking_product_id( $booking_id, $language ) {
1741
 
1742
  $booking_product_id = get_post_meta( $booking_id, '_booking_product_id', true );
1743
  $trnsl_booking_product_id = '';
1753
 
1754
  }
1755
 
1756
+ public function get_translated_booking_resource_id( $booking_id, $language ) {
1757
 
1758
  $booking_resource_id = get_post_meta( $booking_id, '_booking_resource_id', true );
1759
  $trnsl_booking_resource_id = '';
1769
  return $trnsl_booking_resource_id;
1770
  }
1771
 
1772
+ public function get_translated_booking_persons_ids( $booking_id, $language ) {
1773
 
1774
  $booking_persons = maybe_unserialize( get_post_meta( $booking_id, '_booking_persons', true ) );
1775
+ $trnsl_booking_persons = [];
1776
 
1777
  if ( is_array( $booking_persons ) && ! empty( $booking_persons ) ) {
1778
  foreach ( $booking_persons as $person_id => $person_count ) {
1784
  } else {
1785
  $trnsl_booking_persons[ $trnsl_person_id ] = $person_count;
1786
  }
 
1787
  }
1788
  }
1789
 
1791
 
1792
  }
1793
 
1794
+ public function update_status_for_translations( $booking_id ) {
1795
 
1796
  foreach ( $this->get_translated_bookings( $booking_id ) as $translated_booking_id ) {
1797
 
1798
+ $status = $this->wpdb->get_var( $this->wpdb->prepare( "SELECT post_status FROM {$this->wpdb->posts} WHERE ID = %d", $booking_id ) ); // get_post_status( $booking_id );
1799
  $language = get_post_meta( $translated_booking_id, '_language_code', true );
1800
 
1801
  $this->wpdb->update(
1802
  $this->wpdb->posts,
1803
+ [
1804
  'post_status' => $status,
1805
  'post_parent' => wp_get_post_parent_id( $booking_id ),
1806
+ ],
1807
+ [
1808
+ 'ID' => $translated_booking_id,
1809
+ ]
1810
  );
1811
 
1812
  $this->update_translated_booking_meta( $translated_booking_id, $booking_id, $language );
1814
 
1815
  }
1816
 
1817
+ public function get_translated_bookings( $booking_id ) {
1818
 
1819
  return $this->wpml_post_translations->get_element_translations( $booking_id, false, true );
1820
  }
1826
 
1827
  $current_lang = $this->sitepress->get_current_language();
1828
 
1829
+ $product_ids = $this->wpdb->get_col(
1830
+ $this->wpdb->prepare(
1831
+ "SELECT element_id
1832
  FROM {$this->wpdb->prefix}icl_translations
1833
+ WHERE language_code = %s AND element_type = 'post_product'",
1834
+ $current_lang
1835
+ )
1836
+ );
1837
 
1838
+ $product_ids = array_diff( $product_ids, [ null ] );
1839
 
1840
  if ( ( ! isset( $_GET['lang'] ) || ( isset( $_GET['lang'] ) && $_GET['lang'] != 'all' ) ) ) {
1841
+ $query->query_vars['meta_query'][] = [
1842
  'relation' => 'OR',
1843
+ [
1844
  'key' => '_language_code',
1845
  'value' => $current_lang,
1846
+ 'compare ' => '=',
1847
+ ],
1848
+ [
1849
  'key' => '_booking_product_id',
1850
  'value' => $product_ids,
1851
+ 'compare ' => 'IN',
1852
+ ],
1853
+ ];
1854
  }
1855
  }
1856
 
1857
  return $query;
1858
  }
1859
 
1860
+ public function bookings_in_date_range_query( $booking_ids ) {
1861
  foreach ( $booking_ids as $key => $booking_id ) {
1862
 
1863
  $language_code = $this->sitepress->get_language_for_element( get_post_meta( $booking_id, '_booking_product_id', true ), 'post_product' );
1866
  if ( $language_code != $current_language ) {
1867
  unset( $booking_ids[ $key ] );
1868
  }
 
1869
  }
1870
 
1871
  return $booking_ids;
1872
 
1873
  }
1874
 
1875
+ public function clear_transient_fields() {
1876
 
1877
  if ( isset( $_GET['post_type'] ) && $_GET['post_type'] == 'wc_booking' && isset( $_GET['page'] ) && $_GET['page'] == 'booking_calendar' ) {
1878
 
1879
+ // delete transient fields
1880
+ $this->wpdb->query(
1881
+ "
1882
  DELETE FROM {$this->wpdb->options}
1883
  WHERE option_name LIKE '%book_dr_%'
1884
+ "
1885
+ );
1886
 
1887
  }
1888
 
1889
  }
1890
 
1891
+ public function delete_bookings( $booking_id ) {
1892
 
1893
  if (
1894
  ! $this->is_delete_all_action()
1895
  && $booking_id
1896
  && get_post_type( $booking_id ) == 'wc_booking'
1897
  ) {
1898
+ remove_action( 'before_delete_post', [ $this, 'delete_bookings' ] );
1899
 
1900
  foreach ( $this->get_translated_bookings( $booking_id ) as $translated_booking_id ) {
1901
  $this->wpdb->update(
1902
  $this->wpdb->posts,
1903
+ [
1904
+ 'post_parent' => 0,
1905
+ ],
1906
+ [
1907
+ 'ID' => $translated_booking_id,
1908
+ ]
1909
  );
1910
 
1911
  wp_delete_post( $translated_booking_id );
1912
 
1913
  }
1914
 
1915
+ add_action( 'before_delete_post', [ $this, 'delete_bookings' ] );
1916
  }
1917
  }
1918
 
1920
  return array_key_exists( 'delete_all', $_GET ) && $_GET['delete_all'];
1921
  }
1922
 
1923
+ public function trash_bookings( $booking_id ) {
1924
 
1925
  if ( $booking_id > 0 && get_post_type( $booking_id ) == 'wc_booking' ) {
1926
 
1928
 
1929
  $this->wpdb->update(
1930
  $this->wpdb->posts,
1931
+ [
1932
+ 'post_status' => 'trash',
1933
+ ],
1934
+ [
1935
+ 'ID' => $translated_booking_id,
1936
+ ]
1937
  );
1938
 
1939
  }
 
1940
  }
1941
 
1942
  }
1953
 
1954
  $bookable_person = get_post( $person_type->ID );
1955
 
1956
+ $package['contents'][ 'wc_bookings:person:' . $bookable_person->ID . ':name' ] = [
1957
  'translate' => 1,
1958
  'data' => $this->tp->encode_field_data( $bookable_person->post_title, 'base64' ),
1959
+ 'format' => 'base64',
1960
+ ];
1961
 
1962
+ $package['contents'][ 'wc_bookings:person:' . $bookable_person->ID . ':description' ] = [
1963
  'translate' => 1,
1964
  'data' => $this->tp->encode_field_data( $bookable_person->post_excerpt, 'base64' ),
1965
+ 'format' => 'base64',
1966
+ ];
1967
 
1968
  }
 
1969
  }
 
1970
  }
1971
 
1972
  return $package;
1973
  }
1974
 
1975
+ private function save_person_translation( $post_id, $data, $job ) {
1976
+ $person_translations = [];
1977
 
1978
  if ( $this->is_booking( $post_id ) ) {
1979
 
1989
  $person_translations[ $person_id ][ $field ] = $value['data'];
1990
 
1991
  }
 
1992
  }
1993
 
1994
  if ( $person_translations ) {
1997
 
1998
  $person_trid = $this->sitepress->get_element_trid( $person_id, 'post_bookable_person' );
1999
 
 
2000
  $person_id_translated = apply_filters( 'translate_object_id', $person_id, 'bookable_person', false, $job->language_code );
2001
 
2002
  if ( empty( $person_id_translated ) ) {
2003
 
2004
+ $person_post = [
2005
 
2006
  'post_type' => 'bookable_person',
2007
  'post_status' => 'publish',
2008
  'post_title' => $pt['name'],
2009
  'post_parent' => $post_id,
2010
+ 'post_excerpt' => isset( $pt['description'] ) ? $pt['description'] : '',
2011
 
2012
+ ];
2013
 
2014
  $person_id_translated = wp_insert_post( $person_post );
2015
 
2017
 
2018
  } else {
2019
 
2020
+ $person_post = [
2021
  'ID' => $person_id_translated,
2022
  'post_title' => $pt['name'],
2023
+ 'post_excerpt' => isset( $pt['description'] ) ? $pt['description'] : '',
2024
+ ];
2025
 
2026
  wp_update_post( $person_post );
2027
 
2028
  }
 
2029
  }
 
2030
  }
 
2031
  }
2032
 
2033
  }
2034
 
2035
+ public function append_resources_to_translation_package( $package, $post ) {
2036
 
2037
  if ( $post->post_type == 'product' ) {
2038
  $product = wc_get_product( $post->ID );
2042
 
2043
  foreach ( $resources as $resource ) {
2044
 
2045
+ $package['contents'][ 'wc_bookings:resource:' . $resource->ID . ':name' ] = [
2046
  'translate' => 1,
2047
  'data' => $this->tp->encode_field_data( $resource->post_title, 'base64' ),
2048
+ 'format' => 'base64',
2049
+ ];
2050
 
2051
  }
 
2052
  }
 
2053
  }
2054
 
2055
  return $package;
2056
 
2057
  }
2058
 
2059
+ private function save_resource_translation( $post_id, $data, $job ) {
2060
+ $resource_translations = [];
2061
 
2062
  if ( $this->is_booking( $post_id ) ) {
2063
 
2073
  $resource_translations[ $resource_id ][ $field ] = $value['data'];
2074
 
2075
  }
 
2076
  }
2077
 
2078
  if ( $resource_translations ) {
2085
 
2086
  if ( empty( $resource_id_translated ) ) {
2087
 
2088
+ $resource_post = [
2089
 
2090
  'post_type' => 'bookable_resource',
2091
  'post_status' => 'publish',
2092
  'post_title' => $rt['name'],
2093
+ 'post_parent' => $post_id,
2094
+ ];
2095
 
2096
  $resource_id_translated = wp_insert_post( $resource_post );
2097
 
2098
  $this->sitepress->set_element_language_details( $resource_id_translated, 'post_bookable_resource', $resource_trid, $job->language_code );
2099
 
2100
  $sort_order = $this->wpdb->get_var( $this->wpdb->prepare( "SELECT sort_order FROM {$this->wpdb->prefix}wc_booking_relationships WHERE resource_id=%d", $resource_id ) );
2101
+ $relationship = [
2102
  'product_id' => $post_id,
2103
  'resource_id' => $resource_id_translated,
2104
+ 'sort_order' => $sort_order,
2105
+ ];
2106
  $this->wpdb->insert( $this->wpdb->prefix . 'wc_booking_relationships', $relationship );
2107
 
2108
  } else {
2109
 
2110
+ $resource_post = [
2111
  'ID' => $resource_id_translated,
2112
+ 'post_title' => $rt['name'],
2113
+ ];
2114
 
2115
  wp_update_post( $resource_post );
2116
 
2117
  $sort_order = $this->wpdb->get_var( $this->wpdb->prepare( "SELECT sort_order FROM {$this->wpdb->prefix}wc_booking_relationships WHERE resource_id=%d", $resource_id ) );
2118
+ $this->wpdb->update(
2119
+ $this->wpdb->prefix . 'wc_booking_relationships',
2120
+ [ 'sort_order' => $sort_order ],
2121
+ [
2122
+ 'product_id' => $post_id,
2123
+ 'resource_id' => $resource_id_translated,
2124
+ ]
2125
+ );
2126
 
2127
  }
 
 
2128
  }
 
2129
  }
 
2130
  }
2131
 
2132
  }
2133
 
2134
+ public function wcml_js_lock_fields_ids( $ids ) {
2135
+ $ids = array_merge(
2136
+ $ids,
2137
+ [
2138
+ '_wc_booking_has_resources',
2139
+ '_wc_booking_has_persons',
2140
+ '_wc_booking_duration_type',
2141
+ '_wc_booking_duration',
2142
+ '_wc_booking_duration_unit',
2143
+ '_wc_booking_calendar_display_mode',
2144
+ '_wc_booking_requires_confirmation',
2145
+ '_wc_booking_user_can_cancel',
2146
+ '_wc_accommodation_booking_min_duration',
2147
+ '_wc_accommodation_booking_max_duration',
2148
+ '_wc_accommodation_booking_max_duration',
2149
+ '_wc_accommodation_booking_calendar_display_mode',
2150
+ '_wc_accommodation_booking_requires_confirmation',
2151
+ '_wc_accommodation_booking_user_can_cancel',
2152
+ '_wc_accommodation_booking_cancel_limit',
2153
+ '_wc_accommodation_booking_cancel_limit_unit',
2154
+ '_wc_accommodation_booking_qty',
2155
+ '_wc_accommodation_booking_min_date',
2156
+ '_wc_accommodation_booking_min_date_unit',
2157
+ '_wc_accommodation_booking_max_date',
2158
+ '_wc_accommodation_booking_max_date_unit',
2159
+ 'bookings_pricing select',
2160
+ 'bookings_resources select',
2161
+ 'bookings_availability select',
2162
+ 'bookings_persons input[type="checkbox"]',
2163
+ ]
2164
+ );
2165
 
2166
  return $ids;
2167
  }
2184
 
2185
  /**
2186
  * @param array $currencies
2187
+ * @param int $post_id
2188
  *
2189
  * @return bool
2190
  */
2191
+ private function update_booking_costs( $currencies = [], $post_id = 0 ) {
2192
+ $booking_options = [
2193
+ 'wcml_wc_booking_cost' => '_wc_booking_cost_',
2194
  'wcml_wc_booking_block_cost' => '_wc_booking_block_cost_',
2195
+ 'wcml_wc_display_cost' => '_wc_display_cost_',
2196
+ ];
2197
 
2198
  if ( $this->sitepress->get_wp_api()->version_compare( $this->sitepress->get_wp_api()->constant( 'WC_BOOKINGS_VERSION' ), '1.10.9', '<' ) ) {
2199
+ unset( $booking_options['wcml_wc_booking_block_cost'] );
2200
  $booking_options['wcml_wc_booking_base_cost'] = '_wc_booking_base_cost_';
2201
  }
2202
 
 
2203
  foreach ( $currencies as $code => $currency ) {
2204
  foreach ( $booking_options as $booking_options_post_key => $booking_options_meta_key_prefix ) {
2205
  if ( isset( $_POST[ $booking_options_post_key ][ $code ] ) ) {
2213
 
2214
  /**
2215
  * @param array $currencies
2216
+ * @param int $post_id
2217
  *
2218
  * @return bool
2219
  */
2220
+ private function update_booking_pricing( $currencies = [], $post_id = 0 ) {
2221
+ $updated_meta = [];
2222
  $booking_pricing = get_post_meta( $post_id, '_wc_booking_pricing', true );
2223
  if ( empty( $booking_pricing ) ) {
2224
  return false;
2234
  $updated_meta[ $key ][ 'cost_' . $code ] = sanitize_text_field( $_POST['wcml_wc_booking_pricing_cost'][ $code ][ $key ] );
2235
  }
2236
  }
 
2237
  }
2238
 
2239
  update_post_meta( $post_id, '_wc_booking_pricing', $updated_meta );
2247
  *
2248
  * @return bool
2249
  */
2250
+ private function update_booking_person_cost( $currencies = [], $person_costs = [] ) {
2251
  if ( empty( $person_costs ) ) {
2252
  return false;
2253
  }
2269
  *
2270
  * @return bool
2271
  */
2272
+ private function update_booking_person_block_cost( $currencies = [], $block_costs = [] ) {
2273
  if ( empty( $block_costs ) ) {
2274
  return false;
2275
  }
2287
 
2288
  /**
2289
  * @param array $currencies
2290
+ * @param int $post_id
2291
  * @param array $resource_cost
2292
  *
2293
  * @return bool
2294
  */
2295
+ private function update_booking_resource_cost( $currencies = [], $post_id = 0, $resource_cost = [] ) {
2296
  if ( empty( $resource_cost ) ) {
2297
  return false;
2298
  }
2299
 
2300
  $updated_meta = get_post_meta( $post_id, '_resource_base_costs', true );
2301
  if ( ! is_array( $updated_meta ) ) {
2302
+ $updated_meta = [];
2303
  }
2304
 
2305
+ $wc_booking_resource_costs = [];
2306
 
2307
  foreach ( $resource_cost as $resource_id => $costs ) {
2308
 
2311
  if ( isset( $costs[ $code ] ) ) {
2312
  $wc_booking_resource_costs[ $code ][ $resource_id ] = sanitize_text_field( $costs[ $code ] );
2313
  }
 
2314
  }
 
2315
  }
2316
 
2317
  $updated_meta['custom_costs'] = $wc_booking_resource_costs;
2325
 
2326
  /**
2327
  * @param array $currencies
2328
+ * @param int $post_id
2329
  *
2330
  * @return bool
2331
  */
2332
+ private function update_booking_resource_block_cost( $currencies = [], $post_id = 0, $resource_block_cost = [] ) {
2333
  if ( empty( $resource_block_cost ) ) {
2334
  return false;
2335
  }
2336
 
2337
  $updated_meta = get_post_meta( $post_id, '_resource_block_costs', true );
2338
 
2339
+ $wc_booking_resource_block_costs = [];
2340
 
2341
  foreach ( $resource_block_cost as $resource_id => $costs ) {
2342
 
2345
  if ( isset( $costs[ $code ] ) ) {
2346
  $wc_booking_resource_block_costs[ $code ][ $resource_id ] = sanitize_text_field( $costs[ $code ] );
2347
  }
 
2348
  }
 
2349
  }
2350
 
2351
  $updated_meta['custom_costs'] = $wc_booking_resource_block_costs;
2357
  return true;
2358
  }
2359
 
2360
+ public function extra_conditions_to_filter_bookings( $extra_conditions ) {
2361
 
2362
+ if ( isset( $_GET['post_type'] ) && $_GET['post_type'] == 'wc_booking' && ! isset( $_GET['post_status'] ) ) {
2363
+ $extra_conditions = str_replace( 'GROUP BY', " AND post_status = 'confirmed' GROUP BY", $extra_conditions );
2364
  }
2365
 
2366
  return $extra_conditions;
2367
  }
2368
 
2369
+ public function hide_bookings_type_on_tm_dashboard( $types ) {
2370
+ unset( $types['wc_booking'] );
2371
  return $types;
2372
  }
2373
 
2374
+ public function show_pointer_info() {
2375
 
2376
  $pointer_ui = new WCML_Pointer_UI(
2377
+ sprintf( __( 'You can translate the titles of your custom Resources on the %1$sWooCommerce product translation page%2$s', 'woocommerce-multilingual' ), '<a href="' . admin_url( 'admin.php?page=wpml-wcml' ) . '">', '</a>' ),
2378
  'https://wpml.org/documentation/woocommerce-extensions-compatibility/translating-woocommerce-bookings-woocommerce-multilingual/',
2379
  'bookings_resources .woocommerce_bookable_resources #message'
2380
  );
2382
  $pointer_ui->show();
2383
 
2384
  $pointer_ui = new WCML_Pointer_UI(
2385
+ sprintf( __( 'You can translate the Person Type Name and Description on the %1$sWooCommerce product translation page%2$s', 'woocommerce-multilingual' ), '<a href="' . admin_url( 'admin.php?page=wpml-wcml' ) . '">', '</a>' ),
2386
  'https://wpml.org/documentation/woocommerce-extensions-compatibility/translating-woocommerce-bookings-woocommerce-multilingual/',
2387
  'bookings_persons #persons-types>div.toolbar'
2388
  );
2391
 
2392
  }
2393
 
2394
+ public function add_to_cart_sold_individually( $sold_indiv, $cart_item_data, $product_id, $quantity ) {
2395
 
2396
+ if ( isset( $cart_item_data['booking'] ) ) {
2397
  $sold_indiv = false;
2398
+ foreach ( WC()->cart->cart_contents as $cart_item ) {
2399
+ if (
2400
+ isset( $cart_item['booking'] ) && isset( $cart_item['booking']['_booking_id'] ) &&
2401
+ $cart_item['booking']['_start_date'] == $cart_item_data['booking']['_start_date'] &&
2402
+ $cart_item['booking']['_end_date'] == $cart_item_data['booking']['_end_date'] &&
2403
+ $cart_item['booking']['_booking_id'] == $cart_item_data['booking']['_booking_id']
2404
+ ) {
2405
  $sold_indiv = true;
2406
  }
2407
  }
2411
  }
2412
 
2413
  // unset "bookings" from translatable documents to hide WPML languages section from booking edit page
2414
+ public function filter_translatable_documents( $icl_post_types ) {
2415
 
2416
+ if (
2417
+ ( isset( $_GET['post_type'] ) && 'wc_booking' === $_GET['post_type'] ) ||
2418
+ ( isset( $_GET['post'] ) && 'wc_booking' === get_post_type( $_GET['post'] ) )
2419
+ ) {
2420
+ unset( $icl_post_types['wc_booking'] );
2421
  }
2422
 
2423
  return $icl_post_types;
2424
  }
2425
 
2426
  // hide WPML languages links section from bookings list page
2427
+ public function filter_is_translated_post_type( $type ) {
2428
+
2429
+ $getData = wpml_collect( $_GET );
2430
 
2431
+ if( 'wc_booking' === $getData->get('post_type') && 'create_booking' !== $getData->get( 'page' ) ){
2432
  return false;
2433
  }
2434
 
2436
  }
2437
 
2438
  /**
2439
+ * @param int $post_id
2440
  * @param WP_Post $post
2441
+ * @param bool $update
 
2442
  */
2443
+ public function sync_booking_status( $post_id, $post, $update ) {
2444
 
2445
+ if ( $post->post_type === 'wc_booking' && $update ) {
2446
 
2447
+ foreach ( $this->get_translated_bookings( $post_id ) as $translated_booking_id ) {
2448
+ $this->wpdb->update(
2449
+ $this->wpdb->posts,
2450
+ [ 'post_status' => $post->post_status ],
2451
+ [ 'ID' => $translated_booking_id ]
2452
+ );
2453
  }
 
2454
  }
2455
 
2456
  }
2464
  if ( isset( $table['bookings'] ) ) {
2465
 
2466
  foreach ( $table['bookings'] as $key => $booking ) {
2467
+ $language_code = get_post_meta( $booking->get_id(), '_language_code', true );
2468
 
2469
+ if ( ! $language_code ) {
2470
+ $language_code = $this->sitepress->get_language_for_element( $booking->get_product_id(), 'post_product' );
2471
+ }
2472
 
2473
  if ( $language_code !== $current_language ) {
2474
  unset( $tables[ $table_key ]['bookings'][ $key ] );
2482
  return $tables;
2483
  }
2484
 
2485
+ public function emails_options_to_translate( $emails_options ) {
2486
  $emails_options[] = 'woocommerce_new_booking_settings';
2487
  $emails_options[] = 'woocommerce_booking_reminder_settings';
2488
  $emails_options[] = 'woocommerce_booking_confirmed_settings';
2492
  return $emails_options;
2493
  }
2494
 
2495
+ public function emails_text_keys_to_translate( $text_keys ) {
2496
  $text_keys[] = 'subject_confirmation';
2497
  $text_keys[] = 'heading_confirmation';
2498
 
2499
  return $text_keys;
2500
  }
2501
 
2502
+ public function translate_emails_text_strings( $value, $object, $old_value, $key ) {
2503
 
2504
+ $emails_ids = [ 'admin_booking_cancelled', 'new_booking', 'booking_cancelled', 'booking_confirmed', 'booking_reminder' ];
2505
+ $keys = [ 'subject', 'subject_confirmation', 'heading', 'heading_confirmation' ];
2506
 
2507
+ if ( in_array( $key, $keys ) && in_array( $object->id, $emails_ids ) ) {
2508
  $translated_value = $object->$key;
2509
  }
2510
 
2511
+ return ! empty( $translated_value ) ? $translated_value : $value;
2512
  }
2513
 
2514
+ public function translate_booking_confirmed_email_texts( $booking_id ) {
2515
+ if ( $this->email_class_exists( 'WC_Email_Booking_Confirmed' ) ) {
2516
  $this->translate_email_strings( 'WC_Email_Booking_Confirmed', 'woocommerce_booking_confirmed_settings', $booking_id );
2517
  }
2518
  }
2519
 
2520
+ public function translate_booking_cancelled_email_texts( $booking_id ) {
2521
+ if ( $this->email_class_exists( 'WC_Email_Booking_Cancelled' ) ) {
2522
  $this->translate_email_strings( 'WC_Email_Booking_Cancelled', 'woocommerce_booking_cancelled_settings', $booking_id );
2523
  }
2524
  }
2525
 
2526
+ public function translate_booking_reminder_email_texts( $booking_id ) {
2527
+ if ( $this->email_class_exists( 'WC_Email_Booking_Reminder' ) ) {
2528
  $this->translate_email_strings( 'WC_Email_Booking_Reminder', 'woocommerce_booking_reminder_settings', $booking_id );
2529
  }
2530
  }
2531
 
2532
+ public function translate_new_booking_email_texts( $booking_id ) {
2533
+ if ( $this->email_class_exists( 'WC_Email_New_Booking' ) ) {
2534
  $user_lang = $this->get_admin_user_email_language( 'WC_Email_New_Booking' );
2535
  $this->translate_email_strings( 'WC_Email_New_Booking', 'woocommerce_new_booking_settings', $booking_id, $user_lang );
2536
  $this->woocommerce->mailer()->emails['WC_Email_New_Booking']->heading_confirmation = $this->woocommerce_wpml->emails->wcml_get_translated_email_string( 'admin_texts_woocommerce_new_booking_settings', '[woocommerce_new_booking_settings]heading_confirmation', $user_lang );
2538
  }
2539
  }
2540
 
2541
+ public function translate_booking_cancelled_admin_email_texts( $booking_id ) {
2542
+ if ( $this->email_class_exists( 'WC_Email_Admin_Booking_Cancelled' ) ) {
2543
  $this->translate_email_strings( 'WC_Email_Admin_Booking_Cancelled', 'woocommerce_admin_booking_cancelled_settings', $booking_id, $this->get_admin_user_email_language( 'WC_Email_Admin_Booking_Cancelled' ) );
2544
  }
2545
  }
2558
  *
2559
  * @return bool|mixed|null|string
2560
  */
2561
+ private function get_admin_user_email_language( $email_class ) {
2562
 
2563
+ $user = get_user_by( 'email', $this->woocommerce->mailer()->emails[ $email_class ]->recipient );
2564
  if ( $user ) {
2565
  return $this->sitepress->get_user_admin_language( $user->ID, true );
2566
  }
2567
 
2568
  return null;
2569
+ }
2570
 
2571
  /**
2572
  * @param $booking_id
2573
  *
2574
  * @return bool|WC_Order
2575
  */
2576
+ private function get_booking_order( $booking_id ) {
2577
  return get_wc_booking( $booking_id )->get_order();
2578
+ }
2579
 
2580
 
2581
  /**
2596
  }
2597
 
2598
  /**
2599
+ * @param string $email_class
2600
+ * @param string $setting_slug
2601
+ * @param int $booking_id
2602
  * @param string|null $user_lang
2603
  */
2604
+ private function translate_email_strings( $email_class, $setting_slug, $booking_id, $user_lang = null ) {
2605
 
2606
  $order_id = false;
2607
+ if ( ! $user_lang ) {
2608
  $booking_order = $this->get_booking_order( $booking_id );
2609
+ if ( $booking_order ) {
2610
  $order_id = $booking_order->get_id();
2611
  }
2612
  }
2613
 
2614
+ if ( $order_id || $user_lang ) {
2615
+ $this->woocommerce->mailer()->emails[ $email_class ]->heading = $this->woocommerce_wpml->emails->wcml_get_translated_email_string( 'admin_texts_' . $setting_slug, '[' . $setting_slug . ']heading', $order_id, $user_lang );
2616
+ $this->woocommerce->mailer()->emails[ $email_class ]->subject = $this->woocommerce_wpml->emails->wcml_get_translated_email_string( 'admin_texts_' . $setting_slug, '[' . $setting_slug . ']subject', $order_id, $user_lang );
2617
+ }
2618
+ }
2619
 
2620
  public function maybe_set_booking_language( $booking_id ) {
2621
 
2678
  }
2679
 
2680
  public function remove_language_switcher() {
2681
+ remove_action( 'wp_before_admin_bar_render', [ $this->sitepress, 'admin_language_switcher' ] );
2682
  }
2683
 
2684
  /**
2687
  private function is_bookings_listing_page() {
2688
  return isset( $_GET['post_type'] ) && 'wc_booking' === $_GET['post_type'];
2689
  }
2690
+
2691
+ public function save_booking_data_to_translation( $post_id, $data, $job ){
2692
+ $this->save_person_translation( $post_id, $data, $job );
2693
+ $this->save_resource_translation( $post_id, $data, $job );
2694
+ }
2695
  }
compatibility/class-wcml-bulk-stock-management.php CHANGED
@@ -6,40 +6,40 @@
6
  * @author konrad
7
  */
8
  class WCML_Bulk_Stock_Management {
9
- function __construct() {
10
- if (is_admin() && isset($_GET['page']) && $_GET['page'] == 'woocommerce-bulk-stock-management') {
11
  global $sitepress;
12
- remove_action('admin_enqueue_scripts', array($sitepress, 'language_filter'));
13
  }
14
-
15
- add_action( 'wc_bulk_stock_after_process_qty', array($this, 'wc_bulk_stock_after_process_qty_action'), 10, 1 );
16
  }
17
-
18
- function wc_bulk_stock_after_process_qty_action($id) {
19
  global $sitepress;
20
-
21
- $new_quantity = get_post_meta($id, '_stock', true);
22
-
23
- if (is_numeric($new_quantity)) {
24
-
25
- $new_stock_status = ($new_quantity > 0) ? "instock" : "outofstock";
26
- wc_update_product_stock_status($id, $new_stock_status);
27
-
28
  $trid = $sitepress->get_element_trid( $id, 'post_product' );
29
- if (is_numeric($trid)) {
30
  $translations = $sitepress->get_element_translations( $trid, 'post_product' );
31
-
32
- if (is_array($translations)) {
33
- foreach ($translations as $translation) {
34
- if ( !isset($translation->element_id) || $translation->element_id == $id) {
35
  continue;
36
  }
37
- update_post_meta($translation->element_id, '_stock', $new_quantity);
38
- wc_update_product_stock_status($translation->element_id, $new_stock_status);
39
  }
40
  }
41
  }
42
  }
43
-
44
  }
45
  }
6
  * @author konrad
7
  */
8
  class WCML_Bulk_Stock_Management {
9
+ public function __construct() {
10
+ if ( is_admin() && isset( $_GET['page'] ) && $_GET['page'] == 'woocommerce-bulk-stock-management' ) {
11
  global $sitepress;
12
+ remove_action( 'admin_enqueue_scripts', [ $sitepress, 'language_filter' ] );
13
  }
14
+
15
+ add_action( 'wc_bulk_stock_after_process_qty', [ $this, 'wc_bulk_stock_after_process_qty_action' ], 10, 1 );
16
  }
17
+
18
+ public function wc_bulk_stock_after_process_qty_action( $id ) {
19
  global $sitepress;
20
+
21
+ $new_quantity = get_post_meta( $id, '_stock', true );
22
+
23
+ if ( is_numeric( $new_quantity ) ) {
24
+
25
+ $new_stock_status = ( $new_quantity > 0 ) ? 'instock' : 'outofstock';
26
+ wc_update_product_stock_status( $id, $new_stock_status );
27
+
28
  $trid = $sitepress->get_element_trid( $id, 'post_product' );
29
+ if ( is_numeric( $trid ) ) {
30
  $translations = $sitepress->get_element_translations( $trid, 'post_product' );
31
+
32
+ if ( is_array( $translations ) ) {
33
+ foreach ( $translations as $translation ) {
34
+ if ( ! isset( $translation->element_id ) || $translation->element_id == $id ) {
35
  continue;
36
  }
37
+ update_post_meta( $translation->element_id, '_stock', $new_quantity );
38
+ wc_update_product_stock_status( $translation->element_id, $new_stock_status );
39
  }
40
  }
41
  }
42
  }
43
+
44
  }
45
  }
compatibility/class-wcml-checkout-addons.php CHANGED
@@ -7,7 +7,7 @@
7
  class WCML_Checkout_Addons {
8
 
9
  public function add_hooks() {
10
- add_filter( 'option_wc_checkout_add_ons', array( $this, 'option_wc_checkout_add_ons' ), 10, 2 );
11
  }
12
 
13
  public function option_wc_checkout_add_ons( $option_value, $option_name = null ) {
@@ -48,8 +48,8 @@ class WCML_Checkout_Addons {
48
 
49
  private function adjust_price( $conf ) {
50
  if ( isset( $conf['adjustment'], $conf['adjustment_type'] )
51
- && $conf['adjustment_type'] === 'fixed'
52
- && ! $this->is_default_language() ) {
53
  $conf['adjustment'] = apply_filters( 'wcml_raw_price_amount', $conf['adjustment'] );
54
  }
55
  return $conf;
7
  class WCML_Checkout_Addons {
8
 
9
  public function add_hooks() {
10
+ add_filter( 'option_wc_checkout_add_ons', [ $this, 'option_wc_checkout_add_ons' ], 10, 2 );
11
  }
12
 
13
  public function option_wc_checkout_add_ons( $option_value, $option_name = null ) {
48
 
49
  private function adjust_price( $conf ) {
50
  if ( isset( $conf['adjustment'], $conf['adjustment_type'] )
51
+ && $conf['adjustment_type'] === 'fixed'
52
+ && ! $this->is_default_language() ) {
53
  $conf['adjustment'] = apply_filters( 'wcml_raw_price_amount', $conf['adjustment'] );
54
  }
55
  return $conf;
compatibility/class-wcml-checkout-field-editor.php CHANGED
@@ -2,154 +2,160 @@
2
 
3
  class WCML_Checkout_Field_Editor {
4
 
5
- protected $package, $billing, $shipping, $additional;
6
-
7
- function __construct( $package = false ){
8
- $this->package = $package ? $package : (object) array(
9
- 'kind' => 'WooCommerce Add-On',
10
- 'kind_slug' => 'woocommerce-add-on',
11
- 'name' => 'checkout-field-editor',
12
- 'title' => 'WooCommerce Checkout Field Editor'
13
- );
14
- }
15
-
16
- function add_hooks() {
17
- global $supress_field_modification;
18
- if ( ! is_admin() && ! $supress_field_modification ) {
19
- add_filter( 'pre_option_wc_fields_billing', array( $this, 'get_billing' ) );
20
- add_filter( 'pre_option_wc_fields_shipping', array( $this, 'get_shipping' ) );
21
- add_filter( 'pre_option_wc_fields_additional', array( $this, 'get_additional' ) );
22
- }
23
- add_filter( 'pre_update_option_wc_fields_billing', array( $this, 'register_fields' ) );
24
- add_filter( 'pre_update_option_wc_fields_shipping', array( $this, 'register_fields' ) );
25
- add_filter( 'pre_update_option_wc_fields_additional', array( $this, 'register_fields' ) );
26
- }
27
-
28
- private function get_exclude_fields() {
29
-
30
- $exclude_fields = array(
31
- 'shipping_address_1',
32
- 'shipping_city',
33
- 'shipping_state',
34
- 'shipping_postcode',
35
- 'billing_address_1',
36
- 'billing_city',
37
- 'billing_state',
38
- 'billing_postcode'
39
- );
40
-
41
- return apply_filters( 'wcml_cfe_exclude_fields_to_register', $exclude_fields );
42
-
43
- }
44
-
45
- public function register_fields( $fields ) {
46
- foreach ( $fields as $string_name => $field ) {
47
-
48
- if ( in_array( $string_name, $this->get_exclude_fields() ) ) {
49
- continue;
50
- }
51
-
52
- // Translate label
53
- if ( !empty( $field['label'] ) ) {
54
- do_action( 'wpml_register_string',
55
- $field['label'],
56
- "{$string_name}_label",
57
- $this->package,
58
- "{$string_name} Label",
59
- $this->package->kind
60
- );
61
- }
62
- // Translate placeholder
63
- if ( !empty( $field['placeholder'] ) ) {
64
- do_action( 'wpml_register_string',
65
- $field['placeholder'],
66
- "{$string_name}_placeholder",
67
- $this->package,
68
- "{$string_name} Placeholder",
69
- $this->package->kind
70
- );
71
- }
72
- // Translate options
73
- if ( !empty( $field['options'] ) ) {
74
- $i = 1;
75
- foreach ( $field['options'] as $option ) {
76
- do_action( 'wpml_register_string',
77
- $option,
78
- "{$string_name}_option_{$i}",
79
- $this->package,
80
- "{$string_name} Option {$i}",
81
- $this->package->kind
82
- );
83
- $i++;
84
- }
85
- }
86
- }
87
- return $fields;
88
- }
89
-
90
- public function translate_fields( $fields ) {
91
- foreach ( $fields as $string_name => &$field ) {
92
-
93
- if ( in_array( $string_name, $this->get_exclude_fields() ) ) {
94
- continue;
95
- }
96
-
97
- // Translate label
98
- if ( !empty( $field['label'] ) ) {
99
- $field['label'] = apply_filters( 'wpml_translate_string',
100
- $field['label'],
101
- "{$string_name}_label",
102
- $this->package
103
- );
104
- }
105
- // Translate placeholder
106
- if ( !empty( $field['placeholder'] ) ) {
107
- $field['placeholder'] = apply_filters( 'wpml_translate_string',
108
- $field['label'],
109
- "{$string_name}_placeholder",
110
- $this->package
111
- );
112
- }
113
- // Translate options
114
- if ( !empty( $field['options'] ) ) {
115
- $i = 1;
116
- foreach ( $field['options'] as $k => $option ) {
117
- $field['options'][$k] = apply_filters( 'wpml_translate_string',
118
- $option,
119
- "{$string_name}_option_{$i}",
120
- $this->package
121
- );
122
- $i++;
123
- }
124
- }
125
- }
126
- return $fields;
127
- }
128
-
129
- public function get_billing() {
130
- if ( is_null( $this->billing ) ) {
131
- remove_filter( 'pre_option_wc_fields_billing', array($this, 'get_billing') );
132
- $this->billing = $this->translate_fields( get_option( 'wc_fields_billing', array() ) );
133
- add_filter( 'pre_option_wc_fields_billing', array($this, 'get_billing') );
134
- }
135
- return $this->billing;
136
- }
137
-
138
- public function get_shipping() {
139
- if ( is_null( $this->shipping ) ) {
140
- remove_filter( 'pre_option_wc_fields_shipping', array($this, 'get_shipping') );
141
- $this->shipping = $this->translate_fields( get_option( 'wc_fields_shipping', array() ) );
142
- add_filter( 'pre_option_wc_fields_shipping', array($this, 'get_shipping') );
143
- }
144
- return $this->shipping;
145
- }
146
-
147
- public function get_additional() {
148
- if ( is_null( $this->additional ) ) {
149
- remove_filter( 'pre_option_wc_fields_additional', array($this, 'get_additional') );
150
- $this->additional = $this->translate_fields( get_option( 'wc_fields_additional', array() ) );
151
- add_filter( 'pre_option_wc_fields_additional', array($this, 'get_additional') );
152
- }
153
- return $this->additional;
154
- }
 
 
 
 
 
 
155
  }
2
 
3
  class WCML_Checkout_Field_Editor {
4
 
5
+ protected $package, $billing, $shipping, $additional;
6
+
7
+ public function __construct( $package = false ) {
8
+ $this->package = $package ? $package : (object) [
9
+ 'kind' => 'WooCommerce Add-On',
10
+ 'kind_slug' => 'woocommerce-add-on',
11
+ 'name' => 'checkout-field-editor',
12
+ 'title' => 'WooCommerce Checkout Field Editor',
13
+ ];
14
+ }
15
+
16
+ public function add_hooks() {
17
+ global $supress_field_modification;
18
+ if ( ! is_admin() && ! $supress_field_modification ) {
19
+ add_filter( 'pre_option_wc_fields_billing', [ $this, 'get_billing' ] );
20
+ add_filter( 'pre_option_wc_fields_shipping', [ $this, 'get_shipping' ] );
21
+ add_filter( 'pre_option_wc_fields_additional', [ $this, 'get_additional' ] );
22
+ }
23
+ add_filter( 'pre_update_option_wc_fields_billing', [ $this, 'register_fields' ] );
24
+ add_filter( 'pre_update_option_wc_fields_shipping', [ $this, 'register_fields' ] );
25
+ add_filter( 'pre_update_option_wc_fields_additional', [ $this, 'register_fields' ] );
26
+ }
27
+
28
+ private function get_exclude_fields() {
29
+
30
+ $exclude_fields = [
31
+ 'shipping_address_1',
32
+ 'shipping_city',
33
+ 'shipping_state',
34
+ 'shipping_postcode',
35
+ 'billing_address_1',
36
+ 'billing_city',
37
+ 'billing_state',
38
+ 'billing_postcode',
39
+ ];
40
+
41
+ return apply_filters( 'wcml_cfe_exclude_fields_to_register', $exclude_fields );
42
+
43
+ }
44
+
45
+ public function register_fields( $fields ) {
46
+ foreach ( $fields as $string_name => $field ) {
47
+
48
+ if ( in_array( $string_name, $this->get_exclude_fields() ) ) {
49
+ continue;
50
+ }
51
+
52
+ // Translate label
53
+ if ( ! empty( $field['label'] ) ) {
54
+ do_action(
55
+ 'wpml_register_string',
56
+ $field['label'],
57
+ "{$string_name}_label",
58
+ $this->package,
59
+ "{$string_name} Label",
60
+ $this->package->kind
61
+ );
62
+ }
63
+ // Translate placeholder
64
+ if ( ! empty( $field['placeholder'] ) ) {
65
+ do_action(
66
+ 'wpml_register_string',
67
+ $field['placeholder'],
68
+ "{$string_name}_placeholder",
69
+ $this->package,
70
+ "{$string_name} Placeholder",
71
+ $this->package->kind
72
+ );
73
+ }
74
+ // Translate options
75
+ if ( ! empty( $field['options'] ) ) {
76
+ $i = 1;
77
+ foreach ( $field['options'] as $option ) {
78
+ do_action(
79
+ 'wpml_register_string',
80
+ $option,
81
+ "{$string_name}_option_{$i}",
82
+ $this->package,
83
+ "{$string_name} Option {$i}",
84
+ $this->package->kind
85
+ );
86
+ $i++;
87
+ }
88
+ }
89
+ }
90
+ return $fields;
91
+ }
92
+
93
+ public function translate_fields( $fields ) {
94
+ foreach ( $fields as $string_name => &$field ) {
95
+
96
+ if ( in_array( $string_name, $this->get_exclude_fields() ) ) {
97
+ continue;
98
+ }
99
+
100
+ // Translate label
101
+ if ( ! empty( $field['label'] ) ) {
102
+ $field['label'] = apply_filters(
103
+ 'wpml_translate_string',
104
+ $field['label'],
105
+ "{$string_name}_label",
106
+ $this->package
107
+ );
108
+ }
109
+ // Translate placeholder
110
+ if ( ! empty( $field['placeholder'] ) ) {
111
+ $field['placeholder'] = apply_filters(
112
+ 'wpml_translate_string',
113
+ $field['label'],
114
+ "{$string_name}_placeholder",
115
+ $this->package
116
+ );
117
+ }
118
+ // Translate options
119
+ if ( ! empty( $field['options'] ) ) {
120
+ $i = 1;
121
+ foreach ( $field['options'] as $k => $option ) {
122
+ $field['options'][ $k ] = apply_filters(
123
+ 'wpml_translate_string',
124
+ $option,
125
+ "{$string_name}_option_{$i}",
126
+ $this->package
127
+ );
128
+ $i++;
129
+ }
130
+ }
131
+ }
132
+ return $fields;
133
+ }
134
+
135
+ public function get_billing() {
136
+ if ( is_null( $this->billing ) ) {
137
+ remove_filter( 'pre_option_wc_fields_billing', [ $this, 'get_billing' ] );
138
+ $this->billing = $this->translate_fields( get_option( 'wc_fields_billing', [] ) );
139
+ add_filter( 'pre_option_wc_fields_billing', [ $this, 'get_billing' ] );
140
+ }
141
+ return $this->billing;
142
+ }
143
+
144
+ public function get_shipping() {
145
+ if ( is_null( $this->shipping ) ) {
146
+ remove_filter( 'pre_option_wc_fields_shipping', [ $this, 'get_shipping' ] );
147
+ $this->shipping = $this->translate_fields( get_option( 'wc_fields_shipping', [] ) );
148
+ add_filter( 'pre_option_wc_fields_shipping', [ $this, 'get_shipping' ] );
149
+ }
150
+ return $this->shipping;
151
+ }
152
+
153
+ public function get_additional() {
154
+ if ( is_null( $this->additional ) ) {
155
+ remove_filter( 'pre_option_wc_fields_additional', [ $this, 'get_additional' ] );
156
+ $this->additional = $this->translate_fields( get_option( 'wc_fields_additional', [] ) );
157
+ add_filter( 'pre_option_wc_fields_additional', [ $this, 'get_additional' ] );
158
+ }
159
+ return $this->additional;
160
+ }
161
  }
compatibility/class-wcml-compatibility-helper.php CHANGED
@@ -1,19 +1,19 @@
1
  <?php
2
 
3
- class WCML_Compatibility_Helper{
4
 
5
- function get_product_type($product_id){
6
 
7
- if ( $terms = wp_get_object_terms( $product_id, 'product_type' ) ) {
8
- $product_type = sanitize_title( current( $terms )->name );
9
- } else {
10
- $product_type = apply_filters( 'default_product_type', 'simple' );
11
- }
12
 
13
- return $product_type;
14
 
15
- }
16
 
17
  }
18
 
19
- ?>
1
  <?php
2
 
3
+ class WCML_Compatibility_Helper {
4
 
5
+ public function get_product_type( $product_id ) {
6
 
7
+ if ( $terms = wp_get_object_terms( $product_id, 'product_type' ) ) {
8
+ $product_type = sanitize_title( current( $terms )->name );
9
+ } else {
10
+ $product_type = apply_filters( 'default_product_type', 'simple' );
11
+ }
12
 
13
+ return $product_type;
14
 
15
+ }
16
 
17
  }
18
 
19
+
compatibility/class-wcml-composite-products.php CHANGED
@@ -24,7 +24,7 @@ class WCML_Composite_Products extends WCML_Compatibility_Helper{
24
  * @param woocommerce_wpml $woocommerce_wpml
25
  * @param WPML_Element_Translation_Package $tp
26
  */
27
- function __construct( SitePress $sitepress, woocommerce_wpml $woocommerce_wpml, WPML_Element_Translation_Package $tp ) {
28
  $this->sitepress = $sitepress;
29
  $this->woocommerce_wpml = $woocommerce_wpml;
30
  $this->tp = $tp;
@@ -36,7 +36,7 @@ class WCML_Composite_Products extends WCML_Compatibility_Helper{
36
  add_filter( 'wcml_cart_contents', array($this, 'wpml_composites_compat'), 11, 4 );
37
  add_filter( 'woocommerce_composite_component_options_query_args', array($this, 'wpml_composites_transients_cache_per_language'), 10, 3 );
38
  add_action( 'wcml_before_sync_product', array( $this, 'sync_composite_data_across_translations'), 10, 2 );
39
-
40
  if( is_admin() ){
41
 
42
  add_action( 'wcml_gui_additional_box_html', array( $this, 'custom_box_html' ), 10, 3 );
@@ -46,7 +46,7 @@ class WCML_Composite_Products extends WCML_Compatibility_Helper{
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 );
49
- add_action( 'wpml_translation_job_saved', array( $this, 'save_composite_data_translation' ), 10, 3 );
50
  //lock fields on translations pages
51
  add_filter( 'wcml_js_lock_fields_input_names', array( $this, 'wcml_js_lock_fields_input_names' ) );
52
  add_filter( 'wcml_js_lock_fields_ids', array( $this, 'wcml_js_lock_fields_ids' ) );
@@ -79,7 +79,7 @@ class WCML_Composite_Products extends WCML_Compatibility_Helper{
79
  }
80
  }
81
 
82
- function woocommerce_composite_component_default_option($selected_value, $component_id, $object) {
83
 
84
  if( !empty( $selected_value ) )
85
  $selected_value = apply_filters( 'wpml_object_id', $selected_value, 'product', true );
@@ -88,7 +88,7 @@ class WCML_Composite_Products extends WCML_Compatibility_Helper{
88
  return $selected_value;
89
  }
90
 
91
- function wpml_composites_compat( $new_cart_data, $cart_contents, $key, $new_key ) {
92
 
93
  if ( isset( $cart_contents[ $key ][ 'composite_children' ] ) || isset( $cart_contents[ $key ][ 'composite_parent' ] ) ) {
94
 
@@ -102,14 +102,14 @@ class WCML_Composite_Products extends WCML_Compatibility_Helper{
102
  return $new_cart_data;
103
  }
104
 
105
- function wpml_composites_transients_cache_per_language( $args, $query_args, $component_data ) {
106
 
107
  $args[ 'wpml_lang' ] = apply_filters( 'wpml_current_language', NULL );
108
 
109
  return $args;
110
  }
111
 
112
- function sync_composite_data_across_translations( $original_product_id, $current_product_id ){
113
 
114
  if( $this->get_product_type( $original_product_id ) == 'composite' ){
115
 
@@ -162,7 +162,7 @@ class WCML_Composite_Products extends WCML_Compatibility_Helper{
162
 
163
  }
164
 
165
- function custom_box_html( $obj, $product_id, $data ){
166
 
167
  if( $this->get_product_type( $product_id ) == 'composite' ){
168
 
@@ -217,7 +217,7 @@ class WCML_Composite_Products extends WCML_Compatibility_Helper{
217
 
218
  }
219
 
220
- function custom_box_html_data( $data, $product_id, $translation, $lang ){
221
 
222
  if( $this->get_product_type( $product_id ) == 'composite' ){
223
 
@@ -386,7 +386,7 @@ class WCML_Composite_Products extends WCML_Compatibility_Helper{
386
  );
387
  }
388
 
389
- function append_composite_data_translation_package( $package, $post ){
390
 
391
  if( $post->post_type == 'product' ) {
392
 
@@ -420,7 +420,7 @@ class WCML_Composite_Products extends WCML_Compatibility_Helper{
420
 
421
  }
422
 
423
- function save_composite_data_translation( $post_id, $data, $job ){
424
 
425
 
426
  $translated_composite_data = array();
@@ -477,7 +477,7 @@ class WCML_Composite_Products extends WCML_Compatibility_Helper{
477
 
478
  }
479
 
480
- function wcml_js_lock_fields_input_names( $names ){
481
 
482
  $names[] = '_base_regular_price';
483
  $names[] = '_base_sale_price';
@@ -486,7 +486,7 @@ class WCML_Composite_Products extends WCML_Compatibility_Helper{
486
  return $names;
487
  }
488
 
489
- function wcml_js_lock_fields_ids( $names ){
490
 
491
  $names[] = '_per_product_pricing_bto';
492
  $names[] = '_per_product_shipping_bto';
@@ -495,11 +495,11 @@ class WCML_Composite_Products extends WCML_Compatibility_Helper{
495
  return $names;
496
  }
497
 
498
- function localize_lock_fields_js(){
499
  wp_localize_script( 'wcml-composite-js', 'lock_settings' , array( 'lock_fields' => 1 ) );
500
  }
501
 
502
- function load_assets( ){
503
  global $pagenow;
504
 
505
  $is_composite_edit_page = false;
@@ -519,7 +519,7 @@ class WCML_Composite_Products extends WCML_Compatibility_Helper{
519
 
520
  }
521
 
522
- function woocommerce_json_search_found_products( $found_products ){
523
  global $wpml_post_translations;
524
 
525
  foreach( $found_products as $id => $product_name ){
@@ -540,7 +540,7 @@ class WCML_Composite_Products extends WCML_Compatibility_Helper{
540
  }
541
 
542
 
543
- function filter_composite_product_cost( $value, $object_id, $meta_key, $single ) {
544
 
545
  if ( in_array( $meta_key, array(
546
  '_bto_base_regular_price',
@@ -590,7 +590,7 @@ class WCML_Composite_Products extends WCML_Compatibility_Helper{
590
  return $value;
591
  }
592
 
593
- function update_composite_custom_prices( $product_id, $product_price, $custom_prices, $code ){
594
 
595
  if( $this->get_product_type( $product_id ) == 'composite' ){
596
 
@@ -602,7 +602,7 @@ class WCML_Composite_Products extends WCML_Compatibility_Helper{
602
 
603
  }
604
 
605
- function replace_tm_editor_custom_fields_with_own_sections( $fields ){
606
  $fields[] = '_bto_data';
607
  $fields[] = '_bto_scenario_data';
608
 
24
  * @param woocommerce_wpml $woocommerce_wpml
25
  * @param WPML_Element_Translation_Package $tp
26
  */
27
+ public function __construct( SitePress $sitepress, woocommerce_wpml $woocommerce_wpml, WPML_Element_Translation_Package $tp ) {
28
  $this->sitepress = $sitepress;
29
  $this->woocommerce_wpml = $woocommerce_wpml;
30
  $this->tp = $tp;
36
  add_filter( 'wcml_cart_contents', array($this, 'wpml_composites_compat'), 11, 4 );
37
  add_filter( 'woocommerce_composite_component_options_query_args', array($this, 'wpml_composites_transients_cache_per_language'), 10, 3 );
38
  add_action( 'wcml_before_sync_product', array( $this, 'sync_composite_data_across_translations'), 10, 2 );
39
+ add_action( 'wpml_translation_job_saved', array( $this, 'save_composite_data_translation' ), 10, 3 );
40
  if( is_admin() ){
41
 
42
  add_action( 'wcml_gui_additional_box_html', array( $this, 'custom_box_html' ), 10, 3 );
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 );
49
+
50
  //lock fields on translations pages
51
  add_filter( 'wcml_js_lock_fields_input_names', array( $this, 'wcml_js_lock_fields_input_names' ) );
52
  add_filter( 'wcml_js_lock_fields_ids', array( $this, 'wcml_js_lock_fields_ids' ) );
79
  }
80
  }
81
 
82
+ public function woocommerce_composite_component_default_option($selected_value, $component_id, $object) {
83
 
84
  if( !empty( $selected_value ) )
85
  $selected_value = apply_filters( 'wpml_object_id', $selected_value, 'product', true );
88
  return $selected_value;
89
  }
90
 
91
+ public function wpml_composites_compat( $new_cart_data, $cart_contents, $key, $new_key ) {
92
 
93
  if ( isset( $cart_contents[ $key ][ 'composite_children' ] ) || isset( $cart_contents[ $key ][ 'composite_parent' ] ) ) {
94
 
102
  return $new_cart_data;
103
  }
104
 
105
+ public function wpml_composites_transients_cache_per_language( $args, $query_args, $component_data ) {
106
 
107
  $args[ 'wpml_lang' ] = apply_filters( 'wpml_current_language', NULL );
108
 
109
  return $args;
110
  }
111
 
112
+ public function sync_composite_data_across_translations( $original_product_id, $current_product_id ){
113
 
114
  if( $this->get_product_type( $original_product_id ) == 'composite' ){
115
 
162
 
163
  }
164
 
165
+ public function custom_box_html( $obj, $product_id, $data ){
166
 
167
  if( $this->get_product_type( $product_id ) == 'composite' ){
168
 
217
 
218
  }
219
 
220
+ public function custom_box_html_data( $data, $product_id, $translation, $lang ){
221
 
222
  if( $this->get_product_type( $product_id ) == 'composite' ){
223
 
386
  );
387
  }
388
 
389
+ public function append_composite_data_translation_package( $package, $post ){
390
 
391
  if( $post->post_type == 'product' ) {
392
 
420
 
421
  }
422
 
423
+ public function save_composite_data_translation( $post_id, $data, $job ){
424
 
425
 
426
  $translated_composite_data = array();
477
 
478
  }
479
 
480
+ public function wcml_js_lock_fields_input_names( $names ){
481
 
482
  $names[] = '_base_regular_price';
483
  $names[] = '_base_sale_price';
486
  return $names;
487
  }
488
 
489
+ public function wcml_js_lock_fields_ids( $names ){
490
 
491
  $names[] = '_per_product_pricing_bto';
492
  $names[] = '_per_product_shipping_bto';
495
  return $names;
496
  }
497
 
498
+ public function localize_lock_fields_js(){
499
  wp_localize_script( 'wcml-composite-js', 'lock_settings' , array( 'lock_fields' => 1 ) );
500
  }
501
 
502
+ public function load_assets( ){
503
  global $pagenow;
504
 
505
  $is_composite_edit_page = false;
519
 
520
  }
521
 
522
+ public function woocommerce_json_search_found_products( $found_products ){
523
  global $wpml_post_translations;
524
 
525
  foreach( $found_products as $id => $product_name ){
540
  }
541
 
542
 
543
+ public function filter_composite_product_cost( $value, $object_id, $meta_key, $single ) {
544
 
545
  if ( in_array( $meta_key, array(
546
  '_bto_base_regular_price',
590
  return $value;
591
  }
592
 
593
+ public function update_composite_custom_prices( $product_id, $product_price, $custom_prices, $code ){
594
 
595
  if( $this->get_product_type( $product_id ) == 'composite' ){
596
 
602
 
603
  }
604
 
605
+ public function replace_tm_editor_custom_fields_with_own_sections( $fields ){
606
  $fields[] = '_bto_data';
607
  $fields[] = '_bto_scenario_data';
608
 
compatibility/class-wcml-dynamic-pricing.php CHANGED
@@ -15,7 +15,7 @@ class WCML_Dynamic_Pricing {
15
  *
16
  * @param SitePress $sitepress
17
  */
18
- function __construct( SitePress $sitepress ) {
19
  $this->sitepress = $sitepress;
20
  }
21
 
@@ -28,11 +28,10 @@ class WCML_Dynamic_Pricing {
28
  add_filter( 'woocommerce_dynamic_pricing_is_applied_to', [ $this, 'woocommerce_dynamic_pricing_is_applied_to' ], 10, 5 );
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
 
37
  }
38
 
@@ -41,7 +40,7 @@ class WCML_Dynamic_Pricing {
41
  *
42
  * @return mixed
43
  */
44
- function filter_price( $modules ) {
45
 
46
  foreach ( $modules as $mod_key => $module ) {
47
  if ( isset( $module->available_rulesets ) ) {
@@ -76,8 +75,8 @@ class WCML_Dynamic_Pricing {
76
  *
77
  * @return boolean
78
  */
79
- function is_object_in_translated_terms( $result, $product_id, $categories ) {
80
- foreach ($categories as &$cat_id ) {
81
  $cat_id = apply_filters( 'translate_object_id', $cat_id, 'product_cat', true );
82
  }
83
 
@@ -149,15 +148,19 @@ class WCML_Dynamic_Pricing {
149
  ];
150
 
151
  $class_name = wpml_collect( array_keys( $requirements ) )
152
- ->first( function ( $class_name ) use ( $dynamic_pricing ) {
153
- return get_class( $dynamic_pricing ) === $class_name || is_subclass_of( $dynamic_pricing, $class_name );
154
- } );
 
 
155
 
156
  if ( $class_name ) {
157
  return wpml_collect( $requirements[ $class_name ] )
158
- ->filter( function ( $property ) use ( $dynamic_pricing ) {
159
- return isset( $dynamic_pricing->$property ) && $dynamic_pricing->$property;
160
- } )
 
 
161
  ->count();
162
  }
163
 
@@ -175,9 +178,12 @@ class WCML_Dynamic_Pricing {
175
  $cat_ids = [ $cat_ids ];
176
  }
177
 
178
- return array_map( function ( $cat_id ) use ( $taxonomy ) {
179
- return apply_filters( 'translate_object_id', $cat_id, $taxonomy, true );
180
- }, $cat_ids );
 
 
 
181
  }
182
 
183
  /**
@@ -186,7 +192,7 @@ class WCML_Dynamic_Pricing {
186
  *
187
  * @return mixed|void
188
  */
189
- function woocommerce_dynamic_pricing_get_rule_amount( $amount, $rule ) {
190
 
191
  if ( 'price_discount' === $rule['type'] || 'fixed_price' === $rule['type'] ) {
192
  $amount = apply_filters( 'wcml_raw_price_amount', $amount );
@@ -201,7 +207,7 @@ class WCML_Dynamic_Pricing {
201
  *
202
  * @return array
203
  */
204
- function dynamic_pricing_product_rules( $rules ) {
205
  if ( is_array( $rules ) ) {
206
  foreach ( $rules as $r_key => $rule ) {
207
  foreach ( $rule['rules'] as $key => $product_rule ) {
@@ -214,19 +220,12 @@ class WCML_Dynamic_Pricing {
214
  return $rules;
215
  }
216
 
217
- /**
218
- * @return bool
219
- */
220
- function calculate_totals_exception() {
221
- return false;
222
- }
223
-
224
  /**
225
  * @param $rules
226
  *
227
  * @return array
228
  */
229
- function translate_variations_in_rules( $rules ) {
230
  if ( is_array( $rules ) ) {
231
  foreach ( $rules as $r_key => $rule ) {
232
  if ( isset( $rule['variation_rules']['args']['variations'] ) ) {
@@ -246,4 +245,4 @@ class WCML_Dynamic_Pricing {
246
  }
247
  }
248
 
249
- }
15
  *
16
  * @param SitePress $sitepress
17
  */
18
+ public function __construct( SitePress $sitepress ) {
19
  $this->sitepress = $sitepress;
20
  }
21
 
28
  add_filter( 'woocommerce_dynamic_pricing_is_applied_to', [ $this, 'woocommerce_dynamic_pricing_is_applied_to' ], 10, 5 );
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
  }else{
32
  $this->hide_language_switcher_for_settings_page();
33
  }
34
+ add_filter( 'woocommerce_product_get__pricing_rules', [ $this, 'translate_variations_in_rules' ] );
35
 
36
  }
37
 
40
  *
41
  * @return mixed
42
  */
43
+ public function filter_price( $modules ) {
44
 
45
  foreach ( $modules as $mod_key => $module ) {
46
  if ( isset( $module->available_rulesets ) ) {
75
  *
76
  * @return boolean
77
  */
78
+ public function is_object_in_translated_terms( $result, $product_id, $categories ) {
79
+ foreach ( $categories as &$cat_id ) {
80
  $cat_id = apply_filters( 'translate_object_id', $cat_id, 'product_cat', true );
81
  }
82
 
148
  ];
149
 
150
  $class_name = wpml_collect( array_keys( $requirements ) )
151
+ ->first(
152
+ function ( $class_name ) use ( $dynamic_pricing ) {
153
+ return get_class( $dynamic_pricing ) === $class_name || is_subclass_of( $dynamic_pricing, $class_name );
154
+ }
155
+ );
156
 
157
  if ( $class_name ) {
158
  return wpml_collect( $requirements[ $class_name ] )
159
+ ->filter(
160
+ function ( $property ) use ( $dynamic_pricing ) {
161
+ return isset( $dynamic_pricing->$property ) && $dynamic_pricing->$property;
162
+ }
163
+ )
164
  ->count();
165
  }
166
 
178
  $cat_ids = [ $cat_ids ];
179
  }
180
 
181
+ return array_map(
182
+ function ( $cat_id ) use ( $taxonomy ) {
183
+ return apply_filters( 'translate_object_id', $cat_id, $taxonomy, true );
184
+ },
185
+ $cat_ids
186
+ );
187
  }
188
 
189
  /**
192
  *
193
  * @return mixed|void
194
  */
195
+ public function woocommerce_dynamic_pricing_get_rule_amount( $amount, $rule ) {
196
 
197
  if ( 'price_discount' === $rule['type'] || 'fixed_price' === $rule['type'] ) {
198
  $amount = apply_filters( 'wcml_raw_price_amount', $amount );
207
  *
208
  * @return array
209
  */
210
+ public function dynamic_pricing_product_rules( $rules ) {
211
  if ( is_array( $rules ) ) {
212
  foreach ( $rules as $r_key => $rule ) {
213
  foreach ( $rule['rules'] as $key => $product_rule ) {
220
  return $rules;
221
  }
222
 
 
 
 
 
 
 
 
223
  /**
224
  * @param $rules
225
  *
226
  * @return array
227
  */
228
+ public function translate_variations_in_rules( $rules ) {
229
  if ( is_array( $rules ) ) {
230
  foreach ( $rules as $r_key => $rule ) {
231
  if ( isset( $rule['variation_rules']['args']['variations'] ) ) {
245
  }
246
  }
247
 
248
+ }
compatibility/class-wcml-etheme-blanco.php DELETED
@@ -1,20 +0,0 @@
1
- <?php
2
-
3
- class WCML_Etheme_Blanco {
4
-
5
- public function add_hooks() {
6
- add_filter( 'wcml_calculate_totals_exception', array(
7
- $this,
8
- 'calculate_totals_on_et_refreshed_fragments'
9
- ), 9 );
10
- }
11
-
12
- public function calculate_totals_on_et_refreshed_fragments( $calculate ) {
13
- if ( isset( $_POST['action'] ) && 'et_refreshed_fragments' === $_POST['action'] ) {
14
- return false;
15
- }
16
-
17
- return $calculate;
18
- }
19
-
20
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
compatibility/class-wcml-extra-product-options.php CHANGED
@@ -1,107 +1,29 @@
1
  <?php
2
 
3
- class WCML_Extra_Product_Options{
4
 
5
- function __construct(){
6
 
7
- // commented out because of wcml-1218
8
- // add_filter( 'get_post_metadata', array( $this, 'product_options_filter'), 100, 4 );
9
- // add_action( 'updated_post_meta', array( $this, 'register_options_strings' ), 10, 4 );
10
 
11
- add_action( 'tm_before_extra_product_options', array( $this, 'inf_translate_product_page_strings' ) );
12
- add_action( 'tm_before_price_rules', array( $this, 'inf_translate_strings' ) );
13
- }
14
-
15
- // commented out because of wcml-1218
16
- /*
17
 
18
- function register_options_strings( $meta_id, $id, $meta_key, $options ){
19
- if( $meta_key != 'tm_meta' )
20
- return false;
21
 
22
- $this->filter_options( $options, $id, 'register' );
 
 
 
23
 
24
- }
25
-
26
- function product_options_filter( $null, $object_id, $meta_key, $single ){
27
- static $no_filter = false;
28
-
29
- if( empty($no_filter) && $meta_key == 'tm_meta' && !is_admin() ){
30
- $no_filter = true;
31
-
32
- $options = maybe_unserialize( get_post_meta( $object_id, $meta_key, $single ) );
33
-
34
- $options = $this->filter_options( $options, $object_id, 'translate' );
35
-
36
- $no_filter = false;
37
- }
38
-
39
- return isset( $options ) ? array( $options ) : $null;
40
- }
41
-
42
- function filter_options( $options, $id, $action ){
43
-
44
- if( !isset( $options[ 'tmfbuilder' ] ) ){
45
- return $options;
46
- }
47
-
48
- global $sitepress,$woocommerce_wpml;
49
- $keys_to_translate = array( 'header_title', 'header_subtitle', 'text_after_price', 'placeholder' );
50
-
51
- $id = apply_filters( 'translate_object_id', $id, get_post_type( $id ), true, $woocommerce_wpml->products->get_original_product_language( $id ) );
52
-
53
- foreach( $options[ 'tmfbuilder' ] as $key => $values ){
54
- foreach( $keys_to_translate as $key_text ){
55
- if ( preg_match('/.*'.$key_text.'$/', $key ) ) {
56
- foreach( $values as $value_key => $value ){
57
- if( $value ){
58
- if( $action == 'register'){
59
- do_action('wpml_register_single_string', 'wc_extra_product_options', $id.'_option_'.$value_key.'_'.$key, $value );
60
- }else{
61
- $options[ 'tmfbuilder' ][ $key ][ $value_key ] = apply_filters( 'wpml_translate_single_string', $value, 'wc_extra_product_options', $id.'_option_'.$value_key.'_'.$key);
62
- }
63
- }
64
-
65
- }
66
- }
67
- }
68
-
69
- //convert prices
70
- if( $action == 'translate' && preg_match('/.*price$/', $key ) && !preg_match('/.*text_after_price/', $key )){
71
- foreach( $values as $value_key => $value ){
72
- if( $value ){
73
- if( is_array( $value ) ){
74
- foreach( $value as $key_price => $price ){
75
- $options[ 'tmfbuilder' ][ $key ][ $value_key ][ $key_price ] = apply_filters( 'wcml_raw_price_amount', $price );
76
- }
77
- }else{
78
- $options[ 'tmfbuilder' ][ $key ][ $value_key ] = apply_filters( 'wcml_raw_price_amount', $value );
79
- }
80
- }
81
- }
82
- }
83
-
84
- }
85
-
86
- return $options;
87
- }
88
-
89
- */
90
-
91
- function inf_translate_strings(){
92
- if( isset( $_GET[ 'page' ] ) && $_GET[ 'page' ] == 'tm-global-epo' )
93
- $this->inf_message( 'Options Form' );
94
- }
95
-
96
- function inf_translate_product_page_strings(){
97
- $this->inf_message( 'Product' );
98
- }
99
-
100
- function inf_message( $text ){
101
- $message = '<div><p class="icl_cyan_box">';
102
- $message .= sprintf(__('To translate Extra Options strings please save %s and go to the <b><a href="%s">String Translation interface</a></b>', 'woocommerce-multilingual'), $text, admin_url('admin.php?page='.WPML_ST_FOLDER.'/menu/string-translation.php&context=wc_extra_product_options'));
103
- $message .= '</p></div>';
104
-
105
- echo $message;
106
- }
107
  }
1
  <?php
2
 
3
+ class WCML_Extra_Product_Options {
4
 
5
+ public function __construct() {
6
 
7
+ add_action( 'tm_before_extra_product_options', [ $this, 'inf_translate_product_page_strings' ] );
8
+ add_action( 'tm_before_price_rules', [ $this, 'inf_translate_strings' ] );
9
+ }
10
 
11
+ public function inf_translate_strings() {
12
+ if ( isset( $_GET['page'] ) && 'tm-global-epo' === $_GET['page'] ) {
13
+ $this->inf_message( 'Options Form' );
14
+ }
15
+ }
 
16
 
17
+ public function inf_translate_product_page_strings() {
18
+ $this->inf_message( 'Product' );
19
+ }
20
 
21
+ public function inf_message( $text ) {
22
+ $message = '<div><p class="icl_cyan_box">';
23
+ $message .= sprintf( __( 'To translate Extra Options strings please save %1$s and go to the <b><a href="%2$s">String Translation interface</a></b>', 'woocommerce-multilingual' ), esc_html( $text ), admin_url( 'admin.php?page=' . WPML_ST_FOLDER . '/menu/string-translation.php&context=wc_extra_product_options' ) );
24
+ $message .= '</p></div>';
25
 
26
+ // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
27
+ echo $message;
28
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
29
  }
compatibility/class-wcml-flatsome.php CHANGED
@@ -1,17 +1,17 @@
1
  <?php
2
 
3
- class WCML_Flatsome{
4
 
5
- function __construct(){
6
- add_filter( 'wcml_multi_currency_ajax_actions', array( $this, 'add_action_to_multi_currency_ajax' ) );
7
- }
8
 
9
- function add_action_to_multi_currency_ajax( $actions ){
10
 
11
- $actions[] = 'ux_quickview';
12
- $actions[] = 'flatsome_ajax_search_products';
13
 
14
- return $actions;
15
- }
16
 
17
  }
1
  <?php
2
 
3
+ class WCML_Flatsome {
4
 
5
+ public function __construct() {
6
+ add_filter( 'wcml_multi_currency_ajax_actions', [ $this, 'add_action_to_multi_currency_ajax' ] );
7
+ }
8
 
9
+ public function add_action_to_multi_currency_ajax( $actions ) {
10
 
11
+ $actions[] = 'ux_quickview';
12
+ $actions[] = 'flatsome_ajax_search_products';
13
 
14
+ return $actions;
15
+ }
16
 
17
  }
compatibility/class-wcml-gravityforms.php CHANGED
@@ -1,6 +1,6 @@
1
  <?php
2
 
3
- class WCML_gravityforms{
4
 
5
  /**
6
  * @param SitePress $sitepress
@@ -17,56 +17,56 @@ class WCML_gravityforms{
17
  $this->woocommerce_wpml = $woocommerce_wpml;
18
  }
19
 
20
- public function add_hooks(){
21
- add_filter( 'gform_formatted_money', array( $this, 'wcml_convert_price' ), 10, 2 );
22
- add_filter( 'wcml_multi_currency_ajax_actions', array( $this, 'add_ajax_action' ) );
23
 
24
- add_action( 'wcml_after_duplicate_product_post_meta', array( $this, 'sync_gf_data'), 10, 3 );
25
- }
26
-
27
- function wcml_convert_price($formatted, $unformatted){
28
- if ( ! is_admin() ) {
29
- $currency = apply_filters('wcml_price_currency', wcml_get_woocommerce_currency_option());
30
- $formatted = strip_tags(wc_price(apply_filters('wcml_raw_price_amount', $unformatted), array('currency'=>$currency)));
31
- }
32
- return $formatted;
33
  }
34
 
35
-
36
- function add_ajax_action($actions){
 
 
 
 
 
 
 
 
37
  $actions[] = 'get_updated_price';
38
  return $actions;
39
  }
40
 
41
- function sync_gf_data($original_product_id, $trnsl_product_id, $data){
42
- // sync only if WCML editor is in use
43
- if( $this->woocommerce_wpml->is_wpml_prior_4_2() ){
44
- $wcml_settings = get_option('_wcml_settings');
45
- $is_using_tm_editor = $wcml_settings['trnsl_interface'];
46
- }else{
47
- $is_using_tm_editor = WPML_TM_Post_Edit_TM_Editor_Mode::is_using_tm_editor( $this->sitepress, $original_product_id );
48
- }
49
 
50
- if( $is_using_tm_editor ){
51
- $orig_gf = maybe_unserialize( get_post_meta( $original_product_id, '_gravity_form_data' , true ) );
52
- $trnsl_gf = maybe_unserialize( get_post_meta( $trnsl_product_id, '_gravity_form_data' , true ) );
53
 
54
- if( !$trnsl_gf ){
55
- update_post_meta( $trnsl_product_id, '_gravity_form_data', $orig_gf );
56
- }else{
57
- $trnsl_gf['id'] = $orig_gf['id'];
58
- $trnsl_gf['display_title'] = $orig_gf['display_title'];
59
- $trnsl_gf['display_description'] = $orig_gf['display_description'];
60
- $trnsl_gf['disable_woocommerce_price'] = $orig_gf['disable_woocommerce_price'];
61
- $trnsl_gf['disable_calculations'] = $orig_gf['disable_calculations'];
62
- $trnsl_gf['disable_label_subtotal'] = $orig_gf['disable_label_subtotal'];
63
- $trnsl_gf['disable_label_options'] = $orig_gf['disable_label_options'];
64
- $trnsl_gf['disable_label_total'] = $orig_gf['disable_label_total'];
65
- $trnsl_gf['disable_anchor'] = $orig_gf['disable_anchor'];
 
 
 
 
 
66
 
67
- update_post_meta( $trnsl_product_id, '_gravity_form_data', $trnsl_gf );
68
- }
69
- }
70
- }
71
-
72
  }
1
  <?php
2
 
3
+ class WCML_gravityforms {
4
 
5
  /**
6
  * @param SitePress $sitepress
17
  $this->woocommerce_wpml = $woocommerce_wpml;
18
  }
19
 
20
+ public function add_hooks() {
21
+ add_filter( 'gform_formatted_money', [ $this, 'wcml_convert_price' ], 10, 2 );
22
+ add_filter( 'wcml_multi_currency_ajax_actions', [ $this, 'add_ajax_action' ] );
23
 
24
+ add_action( 'wcml_after_duplicate_product_post_meta', [ $this, 'sync_gf_data' ], 10, 3 );
 
 
 
 
 
 
 
 
25
  }
26
 
27
+ public function wcml_convert_price( $formatted, $unformatted ) {
28
+ if ( ! is_admin() ) {
29
+ $currency = apply_filters( 'wcml_price_currency', wcml_get_woocommerce_currency_option() );
30
+ $formatted = strip_tags( wc_price( apply_filters( 'wcml_raw_price_amount', $unformatted ), [ 'currency' => $currency ] ) );
31
+ }
32
+ return $formatted;
33
+ }
34
+
35
+
36
+ public function add_ajax_action( $actions ) {
37
  $actions[] = 'get_updated_price';
38
  return $actions;
39
  }
40
 
41
+ public function sync_gf_data( $original_product_id, $trnsl_product_id, $data ) {
42
+ // sync only if WCML editor is in use
43
+ if ( $this->woocommerce_wpml->is_wpml_prior_4_2() ) {
44
+ $wcml_settings = get_option( '_wcml_settings' );
45
+ $is_using_tm_editor = $wcml_settings['trnsl_interface'];
46
+ } else {
47
+ $is_using_tm_editor = WPML_TM_Post_Edit_TM_Editor_Mode::is_using_tm_editor( $this->sitepress, $original_product_id );
48
+ }
49
 
50
+ if ( $is_using_tm_editor ) {
51
+ $orig_gf = maybe_unserialize( get_post_meta( $original_product_id, '_gravity_form_data', true ) );
52
+ $trnsl_gf = maybe_unserialize( get_post_meta( $trnsl_product_id, '_gravity_form_data', true ) );
53
 
54
+ if ( ! $trnsl_gf ) {
55
+ update_post_meta( $trnsl_product_id, '_gravity_form_data', $orig_gf );
56
+ } else {
57
+ $trnsl_gf['id'] = $orig_gf['id'];
58
+ $trnsl_gf['display_title'] = $orig_gf['display_title'];
59
+ $trnsl_gf['display_description'] = $orig_gf['display_description'];
60
+ $trnsl_gf['disable_woocommerce_price'] = $orig_gf['disable_woocommerce_price'];
61
+ $trnsl_gf['disable_calculations'] = $orig_gf['disable_calculations'];
62
+ $trnsl_gf['disable_label_subtotal'] = $orig_gf['disable_label_subtotal'];
63
+ $trnsl_gf['disable_label_options'] = $orig_gf['disable_label_options'];
64
+ $trnsl_gf['disable_label_total'] = $orig_gf['disable_label_total'];
65
+ $trnsl_gf['disable_anchor'] = $orig_gf['disable_anchor'];
66
+
67
+ update_post_meta( $trnsl_product_id, '_gravity_form_data', $trnsl_gf );
68
+ }
69
+ }
70
+ }
71
 
 
 
 
 
 
72
  }
compatibility/class-wcml-jck-wssv.php CHANGED
@@ -1,24 +1,24 @@
1
  <?php
2
 
3
- class WCML_JCK_WSSV{
4
 
5
- private $transient_name = 'jck_wssv_term_counts';
6
 
7
- public function __construct(){
8
 
9
- add_filter( 'pre_transient_' . $this->transient_name, array( $this, 'get_language_specific_transient' ) );
10
- add_filter( 'set_transient_' . $this->transient_name, array( $this, 'set_language_specific_transient' ), 10, 2 );
11
- }
12
 
13
- public function get_language_specific_transient(){
14
- return get_transient( $this->transient_name . '_' . ICL_LANGUAGE_CODE );
15
- }
16
 
17
- public function set_language_specific_transient( $value, $expiration ){
18
 
19
- delete_transient( $this->transient_name );
20
- set_transient( $this->transient_name . '_' . ICL_LANGUAGE_CODE, $value, $expiration );
21
 
22
- }
23
 
24
- }
1
  <?php
2
 
3
+ class WCML_JCK_WSSV {
4
 
5
+ private $transient_name = 'jck_wssv_term_counts';
6
 
7
+ public function __construct() {
8
 
9
+ add_filter( 'pre_transient_' . $this->transient_name, [ $this, 'get_language_specific_transient' ] );
10
+ add_filter( 'set_transient_' . $this->transient_name, [ $this, 'set_language_specific_transient' ], 10, 2 );
11
+ }
12
 
13
+ public function get_language_specific_transient() {
14
+ return get_transient( $this->transient_name . '_' . ICL_LANGUAGE_CODE );
15
+ }
16
 
17
+ public function set_language_specific_transient( $value, $expiration ) {
18
 
19
+ delete_transient( $this->transient_name );
20
+ set_transient( $this->transient_name . '_' . ICL_LANGUAGE_CODE, $value, $expiration );
21
 
22
+ }
23
 
24
+ }
compatibility/class-wcml-klarna-gateway.php CHANGED
@@ -4,7 +4,7 @@ class WCML_Klarna_Gateway {
4
 
5
  public function add_hooks() {
6
 
7
- add_filter( 'wcml_multi_currency_ajax_actions', array( $this, 'ajax_action_needs_multi_currency' ) );
8
 
9
  }
10
 
4
 
5
  public function add_hooks() {
6
 
7
+ add_filter( 'wcml_multi_currency_ajax_actions', [ $this, 'ajax_action_needs_multi_currency' ] );
8
 
9
  }
10
 
compatibility/class-wcml-litespeed-cache.php CHANGED
@@ -2,21 +2,21 @@
2
 
3
  class WCML_LiteSpeed_Cache {
4
 
5
- function add_hooks() {
6
  // LiteSpeed_Cache_API::vary is available since 2.6.
7
  if ( method_exists( 'LiteSpeed_Cache_API', 'v' ) && LiteSpeed_Cache_API::v( '2.6' ) ) {
8
- add_filter( 'wcml_client_currency', array( $this, 'apply_client_currency' ) );
9
- add_action( 'wcml_set_client_currency', array( $this, 'set_client_currency' ) );
10
  }
11
  }
12
 
13
- function set_client_currency( $currency ) {
14
  $this->apply_client_currency( $currency );
15
 
16
  LiteSpeed_Cache_API::force_vary();
17
  }
18
 
19
- function apply_client_currency( $currency ) {
20
  LiteSpeed_Cache_API::vary( 'wcml_currency', $currency, wcml_get_woocommerce_currency_option() );
21
 
22
  return $currency;
2
 
3
  class WCML_LiteSpeed_Cache {
4
 
5
+ public function add_hooks() {
6
  // LiteSpeed_Cache_API::vary is available since 2.6.
7
  if ( method_exists( 'LiteSpeed_Cache_API', 'v' ) && LiteSpeed_Cache_API::v( '2.6' ) ) {
8
+ add_filter( 'wcml_client_currency', [ $this, 'apply_client_currency' ] );
9
+ add_action( 'wcml_set_client_currency', [ $this, 'set_client_currency' ] );
10
  }
11
  }
12
 
13
+ public function set_client_currency( $currency ) {
14
  $this->apply_client_currency( $currency );
15
 
16
  LiteSpeed_Cache_API::force_vary();
17
  }
18
 
19
+ public function apply_client_currency( $currency ) {
20
  LiteSpeed_Cache_API::vary( 'wcml_currency', $currency, wcml_get_woocommerce_currency_option() );
21
 
22
  return $currency;
compatibility/class-wcml-maxstore.php CHANGED
@@ -1,17 +1,17 @@
1
  <?php
2
 
3
- class WCML_MaxStore{
4
 
5
- function add_hooks(){
6
 
7
- add_filter( 'wcml_force_reset_cart_fragments', array( $this, 'wcml_force_reset_cart_fragments' ) );
8
 
9
- }
10
 
11
- public function wcml_force_reset_cart_fragments(){
12
 
13
- return 1;
14
 
15
- }
16
 
17
  }
1
  <?php
2
 
3
+ class WCML_MaxStore {
4
 
5
+ public function add_hooks() {
6
 
7
+ add_filter( 'wcml_force_reset_cart_fragments', [ $this, 'wcml_force_reset_cart_fragments' ] );
8
 
9
+ }
10
 
11
+ public function wcml_force_reset_cart_fragments() {
12
 
13
+ return 1;
14
 
15
+ }
16
 
17
  }
compatibility/class-wcml-mix-and-match-products.php CHANGED
@@ -1,66 +1,53 @@
1
  <?php
2
 
3
- class WCML_Mix_and_Match_Products{
4
 
5
- function __construct(){
6
- add_action( 'updated_post_meta', array( $this, 'sync_mnm_data'), 10, 4 );
7
- }
8
 
9
- function sync_mnm_data( $meta_id, $post_id, $meta_key, $meta_value ){
 
 
 
10
 
11
- if( $meta_key != '_mnm_data' )
12
- return false;
13
 
14
- global $sitepress, $woocommerce_wpml;
15
 
16
- $post = get_post( $post_id );
 
 
 
17
 
18
- // skip auto-drafts // skip autosave
19
- if ( $post->post_status == 'auto-draft' || isset( $_POST[ 'autosave' ] ) ) {
20
- return;
21
- }
22
 
23
- if( $post->post_type == 'product' ) {
 
 
 
 
24
 
25
- remove_action( 'updated_post_meta', array( $this, 'sync_mnm_data'), 10, 4 );
 
 
26
 
27
- if ( $woocommerce_wpml->products->is_original_product( $post_id ) ) {
 
 
28
 
29
- $original_product_id = $post_id;
30
-
31
- } else {
32
-
33
- $original_product_id = $this->woocommerce_wpml->products->get_original_product_id( $post_id );
34
-
35
- }
36
-
37
- $mnm_data = maybe_unserialize( get_post_meta( $original_product_id, '_mnm_data', true ) );
38
- $product_trid = $sitepress->get_element_trid( $original_product_id, 'post_product' );
39
- $product_translations = $sitepress->get_element_translations( $product_trid, 'post_product' );
40
-
41
- foreach ( $product_translations as $product_translation ) {
42
-
43
- if (empty($product_translation->original)) {
44
-
45
- foreach ($mnm_data as $key => $mnm_element) {
46
-
47
- $trnsl_prod = apply_filters( 'translate_object_id', $key, 'product', true, $product_translation->language_code );
48
- $mnm_element['product_id'] = $trnsl_prod;
49
- $mnm_data[ $trnsl_prod ] = $mnm_element;
50
- unset( $mnm_data[$key]);
51
- }
52
-
53
- update_post_meta($product_translation->element_id, '_mnm_data', $mnm_data);
54
-
55
- }
56
-
57
- }
58
-
59
- add_action( 'updated_post_meta', array( $this, 'sync_mnm_data'), 10, 4 );
60
-
61
- }
62
-
63
- }
64
 
 
 
 
65
 
 
 
 
66
  }
1
  <?php
2
 
3
+ class WCML_Mix_and_Match_Products {
4
 
5
+ public function __construct() {
6
+ add_action( 'updated_post_meta', [ $this, 'sync_mnm_data' ], 10, 4 );
7
+ }
8
 
9
+ public function sync_mnm_data( $meta_id, $post_id, $meta_key, $meta_value ) {
10
+ if ( '_mnm_data' !== $meta_key ) {
11
+ return;
12
+ }
13
 
14
+ global $sitepress, $woocommerce_wpml;
 
15
 
16
+ $post = get_post( $post_id );
17
 
18
+ // Skip auto-drafts, skip autosave.
19
+ if ( 'auto-draft' === $post->post_status || isset( $_POST['autosave'] ) ) {
20
+ return;
21
+ }
22
 
23
+ if ( 'product' === $post->post_type ) {
24
+ remove_action( 'updated_post_meta', [ $this, 'sync_mnm_data' ], 10, 4 );
 
 
25
 
26
+ if ( $woocommerce_wpml->products->is_original_product( $post_id ) ) {
27
+ $original_product_id = $post_id;
28
+ } else {
29
+ $original_product_id = $this->woocommerce_wpml->products->get_original_product_id( $post_id );
30
+ }
31
 
32
+ $mnm_data = maybe_unserialize( get_post_meta( $original_product_id, '_mnm_data', true ) );
33
+ $product_trid = $sitepress->get_element_trid( $original_product_id, 'post_product' );
34
+ $product_translations = $sitepress->get_element_translations( $product_trid, 'post_product' );
35
 
36
+ foreach ( $product_translations as $product_translation ) {
37
+ if ( empty( $product_translation->original ) ) {
38
+ foreach ( $mnm_data as $key => $mnm_element ) {
39
 
40
+ $trnsl_prod = apply_filters( 'translate_object_id', $key, 'product', true, $product_translation->language_code );
41
+ $mnm_element['product_id'] = $trnsl_prod;
42
+ $mnm_data[ $trnsl_prod ] = $mnm_element;
43
+ unset( $mnm_data[ $key ] );
44
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
45
 
46
+ update_post_meta( $product_translation->element_id, '_mnm_data', $mnm_data );
47
+ }
48
+ }
49
 
50
+ add_action( 'updated_post_meta', [ $this, 'sync_mnm_data' ], 10, 4 );
51
+ }
52
+ }
53
  }
compatibility/class-wcml-order-status-manager.php CHANGED
@@ -24,7 +24,7 @@ class WCML_Order_Status_Manager {
24
  * Adds WordPress hooks.
25
  */
26
  public function add_hooks() {
27
- add_action( 'pre_get_posts', array( $this, 'pre_get_posts' ), 10, 1 );
28
  }
29
 
30
  /**
@@ -45,16 +45,16 @@ class WCML_Order_Status_Manager {
45
  * Queries for all statuses in wp_posts table.
46
  */
47
  private function get_statuses() {
48
- remove_action( 'pre_get_posts', array( $this, 'pre_get_posts' ), 10 );
49
  $this->wp_query->query(
50
- array(
51
  'post_type' => 'wc_order_status',
52
  'posts_per_page' => -1,
53
  'suppress_filters' => false,
54
 
55
- )
56
  );
57
- add_action( 'pre_get_posts', array( $this, 'pre_get_posts' ), 10, 1 );
58
  return $this->wp_query->posts;
59
  }
60
 
@@ -67,12 +67,12 @@ class WCML_Order_Status_Manager {
67
  * @return array The post__not_in array.
68
  */
69
  private function prepare_post_not_in( $q, $statuses ) {
70
- $post__not_in = array();
71
 
72
  if ( $statuses ) {
73
  $current_language = apply_filters( 'wpml_current_language', null );
74
 
75
- foreach( $statuses as $status ) {
76
  $post_language_details = apply_filters( 'wpml_post_language_details', '', $status->ID );
77
  if ( isset( $post_language_details['language_code'] ) ) {
78
  if ( $post_language_details['language_code'] !== $current_language ) {
@@ -82,7 +82,7 @@ class WCML_Order_Status_Manager {
82
  }
83
  }
84
 
85
- $post__not_in_query = isset( $q->query_vars['post__not_in'] ) ? $q->query_vars['post__not_in'] : array();
86
  return array_merge( $post__not_in_query, $post__not_in );
87
  }
88
  }
24
  * Adds WordPress hooks.
25
  */
26
  public function add_hooks() {
27
+ add_action( 'pre_get_posts', [ $this, 'pre_get_posts' ], 10, 1 );
28
  }
29
 
30
  /**
45
  * Queries for all statuses in wp_posts table.
46
  */
47
  private function get_statuses() {
48
+ remove_action( 'pre_get_posts', [ $this, 'pre_get_posts' ], 10 );
49
  $this->wp_query->query(
50
+ [
51
  'post_type' => 'wc_order_status',
52
  'posts_per_page' => -1,
53
  'suppress_filters' => false,
54
 
55
+ ]
56
  );
57
+ add_action( 'pre_get_posts', [ $this, 'pre_get_posts' ], 10, 1 );
58
  return $this->wp_query->posts;
59
  }
60
 
67
  * @return array The post__not_in array.
68
  */
69
  private function prepare_post_not_in( $q, $statuses ) {
70
+ $post__not_in = [];
71
 
72
  if ( $statuses ) {
73
  $current_language = apply_filters( 'wpml_current_language', null );
74
 
75
+ foreach ( $statuses as $status ) {
76
  $post_language_details = apply_filters( 'wpml_post_language_details', '', $status->ID );
77
  if ( isset( $post_language_details['language_code'] ) ) {
78
  if ( $post_language_details['language_code'] !== $current_language ) {
82
  }
83
  }
84
 
85
+ $post__not_in_query = isset( $q->query_vars['post__not_in'] ) ? $q->query_vars['post__not_in'] : [];
86
  return array_merge( $post__not_in_query, $post__not_in );
87
  }
88
  }
compatibility/class-wcml-per-product-shipping.php CHANGED
@@ -1,30 +1,29 @@
1
  <?php
2
 
3
- class WCML_Per_Product_Shipping{
4
-
5
- function __construct(){
6
-
7
- if(!is_admin()){
8
-
9
- add_filter('woocommerce_per_product_shipping_get_matching_rule_product_id', array( $this, 'original_product_id' ) );
10
-
11
- }
12
-
13
-
14
- }
15
-
16
- function original_product_id( $product_id ){
17
- global $sitepress;
18
-
19
- $trid = $sitepress->get_element_trid($product_id, 'post_product');
20
- $translations = $sitepress->get_element_translations($trid, 'post_product');
21
- foreach($translations as $language_code =>$translation){
22
- if($translation->original){
23
- $product_id = $translation->element_id;
24
- }
25
- }
26
-
27
- return $product_id;
28
- }
29
 
30
  }
1
  <?php
2
 
3
+ class WCML_Per_Product_Shipping {
4
+
5
+ public function __construct() {
6
+
7
+ if ( ! is_admin() ) {
8
+
9
+ add_filter( 'woocommerce_per_product_shipping_get_matching_rule_product_id', [ $this, 'original_product_id' ] );
10
+
11
+ }
12
+
13
+ }
14
+
15
+ public function original_product_id( $product_id ) {
16
+ global $sitepress;
17
+
18
+ $trid = $sitepress->get_element_trid( $product_id, 'post_product' );
19
+ $translations = $sitepress->get_element_translations( $trid, 'post_product' );
20
+ foreach ( $translations as $language_code => $translation ) {
21
+ if ( $translation->original ) {
22
+ $product_id = $translation->element_id;
23
+ }
24
+ }
25
+
26
+ return $product_id;
27
+ }
 
28
 
29
  }
compatibility/class-wcml-pip.php CHANGED
@@ -1,94 +1,93 @@
1
  <?php
2
 
3
- class WCML_Pip{
4
 
5
- function __construct(){
6
 
7
- add_filter( 'wcml_send_email_order_id', array( $this, 'wcml_send_email_order_id') );
8
- add_filter( 'woocommerce_currency_symbol', array( $this, 'filter_pip_currency_symbol' ) );
9
- add_filter( 'wcml_filter_currency_position', array( $this, 'filter_pip_currency_position' ) );
10
 
11
- }
12
 
13
- public function wcml_send_email_order_id( $order_id ){
14
 
15
- $pip_order_id = $this->get_pip_order_id();
16
 
17
- if( $pip_order_id ){
18
- $order_id = $pip_order_id;
19
- }
20
 
21
- return $order_id;
22
 
23
- }
24
 
25
- public function filter_pip_currency_symbol( $currency_symbol ) {
26
 
27
- remove_filter( 'woocommerce_currency_symbol', array( $this, 'filter_pip_currency_symbol' ) );
28
 
29
- $currency = $this->get_pip_order_currency( );
30
 
31
- if( $currency ){
32
- $currency_symbol = get_woocommerce_currency_symbol( $currency );
33
- }
34
 
35
- add_filter( 'woocommerce_currency_symbol', array( $this, 'filter_pip_currency_symbol' ) );
36
 
37
- return $currency_symbol;
38
- }
39
 
40
- public function filter_pip_currency_position( $currency ){
41
 
42
- remove_filter( 'wcml_filter_currency_position', array( $this, 'filter_pip_currency_position' ) );
43
 
44
- $currency = $this->get_pip_order_currency( $currency );
45
 
46
- add_filter( 'wcml_filter_currency_position', array( $this, 'filter_pip_currency_position' ) );
47
 
48
- return $currency;
49
 
50
- }
51
 
52
- public function get_pip_order_id(){
53
 
54
- $order_id = false;
55
 
56
- if( isset( $_GET[ 'wc_pip_action' ] ) && isset( $_GET[ 'order_id' ] ) ){
57
- $order_id = $_GET[ 'order_id' ];
58
- }elseif(
59
- isset( $_POST[ 'action' ] ) &&
60
- (
61
- $_POST[ 'action' ] == 'wc_pip_order_send_email' ||
62
- $_POST[ 'action' ] == 'wc_pip_send_email_packing_list'
63
- ) &&
64
- isset( $_POST[ 'order_id' ] )
65
- ){
66
- $order_id = $_POST[ 'order_id' ];
67
- }
68
 
69
- return $order_id;
70
- }
71
 
72
- public function get_pip_order_currency( $currency = false ){
73
 
74
- $pip_order_id = $this->get_pip_order_id();
75
 
76
- if( $pip_order_id && isset( WC()->order_factory ) ){
77
 
78
- $the_order = WC()->order_factory->get_order( $pip_order_id );
79
 
80
- if( $the_order ){
81
- $currency = $the_order->get_currency();
82
 
83
- if( !$currency && isset( $_COOKIE[ '_wcml_order_currency' ] ) ){
84
- $currency = $_COOKIE[ '_wcml_order_currency' ];
85
- }
 
 
86
 
87
- }
88
- }
89
 
90
- return $currency;
91
-
92
- }
93
 
94
  }
1
  <?php
2
 
3
+ class WCML_Pip {
4
 
5
+ public function __construct() {
6
 
7
+ add_filter( 'wcml_send_email_order_id', [ $this, 'wcml_send_email_order_id' ] );
8
+ add_filter( 'woocommerce_currency_symbol', [ $this, 'filter_pip_currency_symbol' ] );
9
+ add_filter( 'wcml_filter_currency_position', [ $this, 'filter_pip_currency_position' ] );
10
 
11
+ }
12
 
13
+ public function wcml_send_email_order_id( $order_id ) {
14
 
15
+ $pip_order_id = $this->get_pip_order_id();
16
 
17
+ if ( $pip_order_id ) {
18
+ $order_id = $pip_order_id;
19
+ }
20
 
21
+ return $order_id;
22
 
23
+ }
24
 
25
+ public function filter_pip_currency_symbol( $currency_symbol ) {
26
 
27
+ remove_filter( 'woocommerce_currency_symbol', [ $this, 'filter_pip_currency_symbol' ] );
28
 
29
+ $currency = $this->get_pip_order_currency();
30
 
31
+ if ( $currency ) {
32
+ $currency_symbol = get_woocommerce_currency_symbol( $currency );
33
+ }
34
 
35
+ add_filter( 'woocommerce_currency_symbol', [ $this, 'filter_pip_currency_symbol' ] );
36
 
37
+ return $currency_symbol;
38
+ }
39
 
40
+ public function filter_pip_currency_position( $currency ) {
41
 
42
+ remove_filter( 'wcml_filter_currency_position', [ $this, 'filter_pip_currency_position' ] );
43
 
44
+ $currency = $this->get_pip_order_currency( $currency );
45
 
46
+ add_filter( 'wcml_filter_currency_position', [ $this, 'filter_pip_currency_position' ] );
47
 
48
+ return $currency;
49
 
50
+ }
51
 
52
+ public function get_pip_order_id() {
53
 
54
+ $order_id = false;
55
 
56
+ if ( isset( $_GET['wc_pip_action'] ) && isset( $_GET['order_id'] ) ) {
57
+ $order_id = $_GET['order_id'];
58
+ } elseif (
59
+ isset( $_POST['action'] ) &&
60
+ (
61
+ $_POST['action'] == 'wc_pip_order_send_email' ||
62
+ $_POST['action'] == 'wc_pip_send_email_packing_list'
63
+ ) &&
64
+ isset( $_POST['order_id'] )
65
+ ) {
66
+ $order_id = $_POST['order_id'];
67
+ }
68
 
69
+ return $order_id;
70
+ }
71
 
72
+ public function get_pip_order_currency( $currency = false ) {
73
 
74
+ $pip_order_id = $this->get_pip_order_id();
75
 
76
+ if ( $pip_order_id && isset( WC()->order_factory ) ) {
77
 
78
+ $the_order = WC()->order_factory->get_order( $pip_order_id );
79
 
80
+ if ( $the_order ) {
81
+ $currency = $the_order->get_currency();
82
 
83
+ if ( ! $currency && isset( $_COOKIE['_wcml_order_currency'] ) ) {
84
+ $currency = $_COOKIE['_wcml_order_currency'];
85
+ }
86
+ }
87
+ }
88
 
89
+ return $currency;
 
90
 
91
+ }
 
 
92
 
93
  }
compatibility/class-wcml-product-addons.php CHANGED
@@ -5,10 +5,10 @@
5
  */
6
  class WCML_Product_Addons {
7
 
8
- const TEMPLATE_FOLDER = '/templates/compatibility/';
9
- const DIALOG_TEMPLATE = 'product-addons-prices-dialog.twig';
10
  const SETTINGS_TEMPLATE = 'product-addons-prices-settings.twig';
11
- const PRICE_OPTION_KEY = '_product_addon_prices';
12
 
13
  /**
14
  * @var SitePress
@@ -25,62 +25,70 @@ class WCML_Product_Addons {
25
 
26
  /**
27
  * WCML_Product_Addons constructor.
28
- * @param SitePress $sitepress
 
29
  * @param woocommerce_wpml $woocommerce_wpml
30
  */
31
- function __construct( SitePress $sitepress, woocommerce_wpml $woocommerce_wpml ) {
32
  $this->sitepress = $sitepress;
33
  $this->woocommerce_wpml = $woocommerce_wpml;
34
  $this->multi_currency_mode = $woocommerce_wpml->settings['enable_multi_currency'];
35
  }
36
 
37
- public function add_hooks(){
38
 
39
- add_action( 'init', array( $this, 'load_assets' ) );
40
- add_filter( 'get_product_addons_product_terms', array( $this, 'addons_product_terms' ) );
41
- add_filter( 'get_product_addons_fields', array( $this, 'product_addons_price_filter' ), 10, 2 );
42
 
43
- add_action( 'updated_post_meta', array( $this, 'register_addons_strings' ), 10, 4 );
44
- add_action( 'added_post_meta', array( $this, 'register_addons_strings' ), 10, 4 );
45
 
46
- add_action( 'woocommerce-product-addons_panel_start', array( $this, 'show_pointer_info' ) );
47
 
48
  if ( is_admin() ) {
49
 
50
- if ( $this->is_global_addon_edit_page() ) {
51
- if( ! isset( $_GET['edit'] ) ){
52
- add_action( 'admin_notices', array( $this, 'inf_translate_strings' ) );
53
  }
54
  }
55
 
56
- add_action( 'wcml_gui_additional_box_html', array( $this, 'custom_box_html' ), 10, 3 );
57
- add_filter( 'wcml_gui_additional_box_data', array( $this, 'custom_box_html_data' ), 10, 3 );
58
- add_action( 'wcml_update_extra_fields', array( $this, 'addons_update' ), 10, 3 );
59
 
60
- add_action( 'woocommerce_product_data_panels', array( $this, 'show_pointer_info' ) );
61
 
62
- add_filter( 'wcml_do_not_display_custom_fields_for_product', array( $this, 'replace_tm_editor_custom_fields_with_own_sections' ) );
63
 
64
- if( $this->is_multi_currency_on() ){
65
- add_action( 'woocommerce_product_addons_panel_start', array( $this, 'load_dialog_resources' ) );
66
- add_action( 'woocommerce_product_addons_panel_option_row', array( $this, 'dialog_button_after_option_row' ), 10, 4 );
67
- add_action( 'woocommerce_product_addons_panel_before_options', array( $this, 'dialog_button_before_options' ), 10, 3 );
68
- add_action( 'wcml_before_sync_product', array( $this, 'update_custom_prices_values' ) );
69
- add_action( 'woocommerce_product_addons_global_edit_objects', array( $this, 'custom_prices_settings_block' ) );
70
  }
71
- }else{
72
- add_filter( 'get_post_metadata', array( $this, 'translate_addons_strings' ), 10, 4 );
73
  }
74
 
75
- add_filter( 'wcml_cart_contents_not_changed', array(
76
- $this,
77
- 'filter_booking_addon_product_in_cart_contents'
78
- ), 20 );
 
 
 
 
79
 
80
- add_filter( 'get_product_addons_global_query_args', array(
81
- $this,
82
- 'set_global_ids_in_query_args'
83
- ) );
 
 
 
84
  }
85
 
86
 
@@ -88,10 +96,10 @@ class WCML_Product_Addons {
88
  global $pagenow;
89
 
90
  return 'edit.php' === $pagenow &&
91
- isset( $_GET['post_type'] ) &&
92
- 'product' === $_GET['post_type'] &&
93
- isset( $_GET['page'] ) &&
94
- ( 'global_addons' === $_GET['page'] || 'addons' === $_GET['page'] );
95
  }
96
 
97
  /**
@@ -109,22 +117,21 @@ class WCML_Product_Addons {
109
  * @param $meta_key
110
  * @param $addons
111
  */
112
- function register_addons_strings( $meta_id, $id, $meta_key, $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
- $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
  }
@@ -139,33 +146,33 @@ class WCML_Product_Addons {
139
  *
140
  * @return array
141
  */
142
- function translate_addons_strings( $null, $object_id, $meta_key, $single ) {
143
 
144
  if ( '_product_addons' === $meta_key && 'global_product_addon' === get_post_type( $object_id ) ) {
145
 
146
- remove_filter( 'get_post_metadata', array( $this, 'translate_addons_strings' ), 10, 4 );
147
  $addons = get_post_meta( $object_id, $meta_key, true );
148
- add_filter( 'get_post_metadata', array( $this, 'translate_addons_strings' ), 10, 4 );
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
  }
167
 
168
- return array( 0 => $addons );
169
  }
170
 
171
  return $null;
@@ -178,7 +185,7 @@ class WCML_Product_Addons {
178
  *
179
  * @return mixed
180
  */
181
- function product_addons_price_filter( $addons, $post_id ) {
182
 
183
  if ( $this->is_multi_currency_on() ) {
184
 
@@ -186,16 +193,15 @@ class WCML_Product_Addons {
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
 
@@ -204,16 +210,16 @@ class WCML_Product_Addons {
204
 
205
  /**
206
  * @param array $addon
207
- * @param int $post_id
208
  *
209
  * @return string
210
  */
211
- private function converted_addon_price( $addon, $post_id ){
212
 
213
  $addonData = wpml_collect( $addon );
214
 
215
  $is_custom_prices_on = $this->is_product_custom_prices_on( $post_id );
216
- $field = 'price_' . $this->woocommerce_wpml->multi_currency->get_client_currency();
217
 
218
  if (
219
  $is_custom_prices_on &&
@@ -222,7 +228,7 @@ class WCML_Product_Addons {
222
  return $addonData->get( $field );
223
  }
224
 
225
- if( wpml_collect( [ 'flat_fee', 'quantity_based' ] )->contains( $addonData->get( 'price_type' ) ) ) {
226
  return apply_filters( 'wcml_raw_price_amount', $addonData->get( 'price' ) );
227
  }
228
 
@@ -234,7 +240,7 @@ class WCML_Product_Addons {
234
  *
235
  * @return array
236
  */
237
- function addons_product_terms( $product_terms ) {
238
  foreach ( $product_terms as $key => $product_term ) {
239
  $product_terms[ $key ] = apply_filters( 'translate_object_id', $product_term, 'product_cat', true, $this->sitepress->get_default_language() );
240
  }
@@ -242,10 +248,10 @@ class WCML_Product_Addons {
242
  return $product_terms;
243
  }
244
 
245
- function inf_translate_strings() {
246
 
247
  $pointer_ui = new WCML_Pointer_UI(
248
- sprintf( __( 'You can translate strings related to global add-ons on the %sWPML String Translation page%s. Use the search on the top of that page to find the strings.', 'woocommerce-multilingual' ), '<a href="'.admin_url('admin.php?page='.WPML_ST_FOLDER.'/menu/string-translation.php&context=wc_product_addons_strings').'">', '</a>' ),
249
  'https://wpml.org/documentation/woocommerce-extensions-compatibility/translating-woocommerce-product-add-ons-woocommerce-multilingual/',
250
  'wpbody-content .woocommerce>h2'
251
  );
@@ -258,7 +264,7 @@ class WCML_Product_Addons {
258
  * @param $product_id
259
  * @param $data
260
  */
261
- function custom_box_html( $obj, $product_id, $data ) {
262
 
263
  $product_addons = $this->get_product_addons( $product_id );
264
 
@@ -266,22 +272,22 @@ class WCML_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 );
273
  $group->add_field( $addon_field );
274
- $addon_field = new WPML_Editor_UI_Single_Line_Field( 'addon_'.$addon_id.'_description' , __( 'Description', 'woocommerce-multilingual' ), $data, false );
275
  $group->add_field( $addon_field );
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
  }
287
  $addons_section->add_field( $labels_group );
@@ -298,18 +304,18 @@ class WCML_Product_Addons {
298
  *
299
  * @return mixed
300
  */
301
- function custom_box_html_data( $data, $product_id, $translation ) {
302
 
303
  $product_addons = $this->get_product_addons( $product_id );
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,12 +324,12 @@ class WCML_Product_Addons {
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
  }
@@ -339,20 +345,20 @@ class WCML_Product_Addons {
339
  * @param $product_id
340
  * @param $data
341
  */
342
- function addons_update( $original_product_id, $product_id, $data ) {
343
 
344
  $product_addons = $this->get_product_addons( $original_product_id );
345
 
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
  }
358
  }
@@ -361,10 +367,10 @@ class WCML_Product_Addons {
361
  update_post_meta( $product_id, '_product_addons', $product_addons );
362
  }
363
 
364
- public function show_pointer_info(){
365
 
366
  $pointer_ui = new WCML_Pointer_UI(
367
- sprintf( __( 'You can translate the Group Name, Group Description and every Option Label of your product add-on on the %sWooCommerce product translation page%s', 'woocommerce-multilingual' ), '<a href="'.admin_url('admin.php?page=wpml-wcml').'">', '</a>' ),
368
  'https://wpml.org/documentation/woocommerce-extensions-compatibility/translating-woocommerce-product-add-ons-woocommerce-multilingual/',
369
  'product_addons_data>p'
370
  );
@@ -372,7 +378,7 @@ class WCML_Product_Addons {
372
  $pointer_ui->show();
373
  }
374
 
375
- function replace_tm_editor_custom_fields_with_own_sections( $fields ){
376
  $fields[] = '_product_addons';
377
 
378
  return $fields;
@@ -386,7 +392,7 @@ class WCML_Product_Addons {
386
  if ( $this->is_multi_currency_on() && $is_booking_product_with_addons ) {
387
  $cost = $cart_item['data']->get_price();
388
 
389
- foreach( $cart_item['addons'] as $addon ){
390
  $cost += $addon['price'];
391
  }
392
 
@@ -398,11 +404,11 @@ class WCML_Product_Addons {
398
 
399
  public function set_global_ids_in_query_args( $args ) {
400
 
401
- if ( !is_archive() ) {
402
 
403
- remove_filter( 'get_terms_args', array( $this->sitepress, 'get_terms_args_filter' ), 10, 2 );
404
- remove_filter( 'get_term', array( $this->sitepress, 'get_term_adjust_id' ), 1 );
405
- remove_filter( 'terms_clauses', array( $this->sitepress, 'terms_clauses' ), 10 );
406
 
407
  $matched_addons_ids = wp_list_pluck( get_posts( $args ), 'ID' );
408
 
@@ -411,9 +417,9 @@ class WCML_Product_Addons {
411
  unset( $args['tax_query'] );
412
  }
413
 
414
- add_filter( 'get_terms_args', array( $this->sitepress, 'get_terms_args_filter' ), 10, 2 );
415
- add_filter( 'get_term', array( $this->sitepress, 'get_term_adjust_id' ), 1 );
416
- add_filter( 'terms_clauses', array( $this->sitepress, 'terms_clauses' ), 10, 3 );
417
  }
418
 
419
  return $args;
@@ -422,22 +428,22 @@ class WCML_Product_Addons {
422
  /**
423
  * @return bool
424
  */
425
- private function is_multi_currency_on(){
426
  return $this->multi_currency_mode === $this->sitepress->get_wp_api()->constant( 'WCML_MULTI_CURRENCIES_INDEPENDENT' );
427
  }
428
 
429
- public function load_dialog_resources(){
430
- wp_enqueue_script( 'wcml-dialogs', WCML_PLUGIN_URL . '/res/js/dialogs' . WCML_JS_MIN . '.js', array( 'jquery-ui-dialog', 'underscore' ), WCML_VERSION );
431
  }
432
 
433
  /**
434
  * @param WP_Post|null $product
435
- * @param array $product_addons
436
- * @param int $loop
437
- * @param array $option
438
  */
439
- public function dialog_button_after_option_row( $product, $product_addons, $loop, $option ){
440
- if( $option ){
441
  $this->render_edit_price_element( $this->get_prices_dialog_model( $product_addons, $option, $loop, $this->is_product_custom_prices_on( $product ? $product->ID : false ) ) );
442
  }
443
 
@@ -445,39 +451,40 @@ class WCML_Product_Addons {
445
 
446
  /**
447
  * @param WP_Post|null $product
448
- * @param array $product_addons
449
- * @param int $loop
450
  */
451
- public function dialog_button_before_options( $product, $product_addons, $loop ){
452
- $this->render_edit_price_element( $this->get_prices_dialog_model( array(), $product_addons, $loop, $this->is_product_custom_prices_on( $product ? $product->ID : false ) ) );
453
  }
454
 
455
  /**
456
  * @param array $model
457
  */
458
- private function render_edit_price_element( $model ){
459
  $twig_loader = $this->get_twig_loader();
 
460
  echo $twig_loader->get_template()->show( $model, self::DIALOG_TEMPLATE );
461
  }
462
 
463
  /**
464
  * @return array
465
  */
466
- private function get_one_price_types(){
467
 
468
- return array(
469
  'custom_text',
470
  'custom_textarea',
471
  'file_upload',
472
- 'input_multiplier'
473
- );
474
  }
475
 
476
  /**
477
  * @return WPML_Twig_Template_Loader
478
  */
479
- private function get_twig_loader(){
480
- return new WPML_Twig_Template_Loader( array( $this->sitepress->get_wp_api()->constant( 'WCML_PLUGIN_PATH' ) . self::TEMPLATE_FOLDER ) );
481
  }
482
 
483
  /**
@@ -485,13 +492,13 @@ class WCML_Product_Addons {
485
  *
486
  * @return mixed
487
  */
488
- private function is_product_custom_prices_on( $product_id ){
489
 
490
- if( $product_id ){
491
  return get_post_meta( $product_id, '_wcml_custom_prices_status', true );
492
  }
493
 
494
- if( $this->is_global_addon_edit_page() ){
495
  return $this->get_global_addon_prices_status();
496
  }
497
 
@@ -515,11 +522,11 @@ class WCML_Product_Addons {
515
  public function load_assets() {
516
  global $pagenow;
517
 
518
- $is_product_page = 'post.php' === $pagenow && isset( $_GET['post'] );
519
  $is_product_new_page = 'post-new.php' === $pagenow && isset( $_GET['post_type'] ) && 'product' === $_GET['post_type'];
520
 
521
  if ( $is_product_page || $is_product_new_page || $this->is_global_addon_edit_page() ) {
522
- wp_enqueue_script( 'wcml-product-addons', WCML_PLUGIN_URL . '/compatibility/res/js/wcml-product-addons' . WCML_JS_MIN . '.js', array( 'jquery' ), WCML_VERSION );
523
  wp_enqueue_style( 'wcml-product-addons', WCML_PLUGIN_URL . '/compatibility/res/css/wcml-product-addons.css', '', WCML_VERSION );
524
  }
525
 
@@ -530,7 +537,7 @@ class WCML_Product_Addons {
530
  */
531
  public function update_custom_prices_values( $product_id ) {
532
 
533
- if( $this->is_multi_currency_on() ){
534
  $this->save_global_addon_prices_setting( $product_id );
535
  $product_addons = $this->get_product_addons( $product_id );
536
 
@@ -542,9 +549,9 @@ class WCML_Product_Addons {
542
  foreach ( $active_currencies as $code => $currency ) {
543
  $price_option_key = self::PRICE_OPTION_KEY;
544
 
545
- if( in_array( $product_addon['type'], $this->get_one_price_types() ) ){
546
  $product_addons = $this->update_single_option_prices( $product_addons, $price_option_key, $addon_key, $code );
547
- }else{
548
  $product_addons = $this->update_multiple_options_prices( $product_addons, $price_option_key, $addon_key, $code );
549
  }
550
  }
@@ -556,37 +563,37 @@ class WCML_Product_Addons {
556
  }
557
 
558
  /**
559
- * @param array $product_addons
560
  * @param string $price_option_key
561
  * @param string $addon_key
562
  * @param string $code
563
  *
564
  * @return array
565
  */
566
- private function update_single_option_prices( $product_addons, $price_option_key, $addon_key, $code ){
567
- if ( isset( $_POST[ $price_option_key ][ $addon_key ][ 'price_'.$code ][ 0 ] ) ) {
568
- $product_addons[ $addon_key ][ 'price_' . $code ] = wc_format_decimal( $_POST[ $price_option_key ][ $addon_key ][ 'price_'.$code ][ 0 ] );
569
  }
570
 
571
  return $product_addons;
572
  }
573
 
574
  /**
575
- * @param array $product_addons
576
  * @param string $price_option_key
577
  * @param string $addon_key
578
  * @param string $code
579
  *
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
  }
@@ -595,9 +602,9 @@ class WCML_Product_Addons {
595
  }
596
 
597
  /**
598
- * @param array $product_addons
599
- * @param array $option
600
- * @param int $loop
601
  * @param string|bool $custom_prices_on
602
  *
603
  * @return array
@@ -606,38 +613,39 @@ class WCML_Product_Addons {
606
 
607
  $label = isset( $option['label'] ) ? $option['label'] : $option['name'];
608
 
609
- return array(
610
- 'strings' => array(
611
- 'dialog_title' => __( 'Multi-currency settings', 'woocommerce-multilingual' ),
612
- 'description' => sprintf(__( 'Here you can set different prices for the %s in multiple currencies:', 'woocommerce-multilingual' ), '<strong>' . $label . '</strong>' ),
613
  'apply' => __( 'Apply', 'woocommerce-multilingual' ),
614
- 'cancel' => __( 'Cancel', 'woocommerce-multilingual' )
615
- ),
616
  'custom_prices_on' => $custom_prices_on,
617
- 'dialog_id' => '_product_addon_option_' . md5( uniqid( $loop . $label ) ),
618
  'option_id' => isset( $product_addons[ $loop ]['options'] ) ? array_search( $option, $product_addons[ $loop ]['options'] ) : '',
619
  'addon_id' => $loop,
620
  'option_details' => $option,
621
  'default_currency' => wcml_get_woocommerce_currency_option(),
622
  'active_currencies' => $this->woocommerce_wpml->multi_currency->get_currencies(),
623
- );
624
  }
625
 
626
  public function custom_prices_settings_block() {
627
  $twig_loader = $this->get_twig_loader();
 
628
  echo $twig_loader->get_template()->show( $this->get_custom_prices_settings_model(), self::SETTINGS_TEMPLATE );
629
  }
630
 
631
  private function get_custom_prices_settings_model() {
632
- return array(
633
- 'strings' => array(
634
  'label' => __( 'Multi-currency settings', 'woocommerce-multilingual' ),
635
  'auto' => __( 'Calculate prices in other currencies automatically', 'woocommerce-multilingual' ),
636
- 'manually' => __( 'Set prices in other currencies manually', 'woocommerce-multilingual' )
637
- ),
638
  'custom_prices_on' => $this->get_global_addon_prices_status(),
639
- 'nonce' => wp_create_nonce( 'wcml_save_custom_prices' )
640
- );
641
  }
642
 
643
  /**
5
  */
6
  class WCML_Product_Addons {
7
 
8
+ const TEMPLATE_FOLDER = '/templates/compatibility/';
9
+ const DIALOG_TEMPLATE = 'product-addons-prices-dialog.twig';
10
  const SETTINGS_TEMPLATE = 'product-addons-prices-settings.twig';
11
+ const PRICE_OPTION_KEY = '_product_addon_prices';
12
 
13
  /**
14
  * @var SitePress
25
 
26
  /**
27
  * WCML_Product_Addons constructor.
28
+ *
29
+ * @param SitePress $sitepress
30
  * @param woocommerce_wpml $woocommerce_wpml
31
  */
32
+ public function __construct( SitePress $sitepress, woocommerce_wpml $woocommerce_wpml ) {
33
  $this->sitepress = $sitepress;
34
  $this->woocommerce_wpml = $woocommerce_wpml;
35
  $this->multi_currency_mode = $woocommerce_wpml->settings['enable_multi_currency'];
36
  }
37
 
38
+ public function add_hooks() {
39
 
40
+ add_action( 'init', [ $this, 'load_assets' ] );
41
+ add_filter( 'get_product_addons_product_terms', [ $this, 'addons_product_terms' ] );
42
+ add_filter( 'get_product_addons_fields', [ $this, 'product_addons_price_filter' ], 10, 2 );
43
 
44
+ add_action( 'updated_post_meta', [ $this, 'register_addons_strings' ], 10, 4 );
45
+ add_action( 'added_post_meta', [ $this, 'register_addons_strings' ], 10, 4 );
46
 
47
+ add_action( 'woocommerce-product-addons_panel_start', [ $this, 'show_pointer_info' ] );
48
 
49
  if ( is_admin() ) {
50
 
51
+ if ( $this->is_global_addon_edit_page() ) {
52
+ if ( ! isset( $_GET['edit'] ) ) {
53
+ add_action( 'admin_notices', [ $this, 'inf_translate_strings' ] );
54
  }
55
  }
56
 
57
+ add_action( 'wcml_gui_additional_box_html', [ $this, 'custom_box_html' ], 10, 3 );
58
+ add_filter( 'wcml_gui_additional_box_data', [ $this, 'custom_box_html_data' ], 10, 3 );
59
+ add_action( 'wcml_update_extra_fields', [ $this, 'addons_update' ], 10, 3 );
60
 
61
+ add_action( 'woocommerce_product_data_panels', [ $this, 'show_pointer_info' ] );
62
 
63
+ add_filter( 'wcml_do_not_display_custom_fields_for_product', [ $this, 'replace_tm_editor_custom_fields_with_own_sections' ] );
64
 
65
+ if ( $this->is_multi_currency_on() ) {
66
+ add_action( 'woocommerce_product_addons_panel_start', [ $this, 'load_dialog_resources' ] );
67
+ add_action( 'woocommerce_product_addons_panel_option_row', [ $this, 'dialog_button_after_option_row' ], 10, 4 );
68
+ add_action( 'woocommerce_product_addons_panel_before_options', [ $this, 'dialog_button_before_options' ], 10, 3 );
69
+ add_action( 'wcml_before_sync_product', [ $this, 'update_custom_prices_values' ] );
70
+ add_action( 'woocommerce_product_addons_global_edit_objects', [ $this, 'custom_prices_settings_block' ] );
71
  }
72
+ } else {
73
+ add_filter( 'get_post_metadata', [ $this, 'translate_addons_strings' ], 10, 4 );
74
  }
75
 
76
+ add_filter(
77
+ 'wcml_cart_contents_not_changed',
78
+ [
79
+ $this,
80
+ 'filter_booking_addon_product_in_cart_contents',
81
+ ],
82
+ 20
83
+ );
84
 
85
+ add_filter(
86
+ 'get_product_addons_global_query_args',
87
+ [
88
+ $this,
89
+ 'set_global_ids_in_query_args',
90
+ ]
91
+ );
92
  }
93
 
94
 
96
  global $pagenow;
97
 
98
  return 'edit.php' === $pagenow &&
99
+ isset( $_GET['post_type'] ) &&
100
+ 'product' === $_GET['post_type'] &&
101
+ isset( $_GET['page'] ) &&
102
+ ( 'global_addons' === $_GET['page'] || 'addons' === $_GET['page'] );
103
  }
104
 
105
  /**
117
  * @param $meta_key
118
  * @param $addons
119
  */
120
+ public function register_addons_strings( $meta_id, $id, $meta_key, $addons ) {
121
  if ( '_product_addons' === $meta_key && 'global_product_addon' === get_post_type( $id ) ) {
122
  $this->update_custom_prices_values( $id );
123
  foreach ( $addons as $addon ) {
124
+ $addon_data = wpml_collect( $addon );
125
+ $addon_type = $addon_data->get( 'type' );
126
+ $addon_position = $addon_data->get( 'position' );
127
+ // register name
128
+ do_action( 'wpml_register_single_string', 'wc_product_addons_strings', $id . '_addon_' . $addon_type . '_' . $addon_position . '_name', $addon_data->get( 'name' ) );
129
+ // register description
130
+ do_action( 'wpml_register_single_string', 'wc_product_addons_strings', $id . '_addon_' . $addon_type . '_' . $addon_position . '_description', $addon_data->get( 'description' ) );
131
+ // register options labels
132
+ if ( $addon_data->offsetExists( 'options' ) ) {
133
+ foreach ( $addon_data->get( 'options' ) as $key => $option ) {
134
+ do_action( 'wpml_register_single_string', 'wc_product_addons_strings', $id . '_addon_' . $addon_type . '_' . $addon_position . '_option_label_' . $key, wpml_collect( $option )->get( 'label' ) );
 
135
  }
136
  }
137
  }
146
  *
147
  * @return array
148
  */
149
+ public function translate_addons_strings( $null, $object_id, $meta_key, $single ) {
150
 
151
  if ( '_product_addons' === $meta_key && 'global_product_addon' === get_post_type( $object_id ) ) {
152
 
153
+ remove_filter( 'get_post_metadata', [ $this, 'translate_addons_strings' ], 10, 4 );
154
  $addons = get_post_meta( $object_id, $meta_key, true );
155
+ add_filter( 'get_post_metadata', [ $this, 'translate_addons_strings' ], 10, 4 );
156
 
157
  if ( is_array( $addons ) ) {
158
  foreach ( $addons as $key => $addon ) {
159
+ $addon_data = wpml_collect( $addon );
160
+ $addon_type = $addon_data->get( 'type' );
161
+ $addon_position = $addon_data->get( 'position' );
162
+ // register name
163
+ $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' );
164
+ // register description
165
+ $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' );
166
+ // register options labels
167
+ if ( $addon_data->offsetExists( 'options' ) ) {
168
  foreach ( $addon['options'] as $opt_key => $option ) {
169
+ $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 );
170
  }
171
  }
172
  }
173
  }
174
 
175
+ return [ 0 => $addons ];
176
  }
177
 
178
  return $null;
185
  *
186
  * @return mixed
187
  */
188
+ public function product_addons_price_filter( $addons, $post_id ) {
189
 
190
  if ( $this->is_multi_currency_on() ) {
191
 
193
 
194
  $addon_data = wpml_collect( $addon );
195
 
196
+ if ( $addon_data->offsetExists( 'price' ) && $addon_data->get( 'price' ) ) {
197
  $addons[ $add_id ]['price'] = $this->converted_addon_price( $addon, $post_id );
198
  }
199
 
200
+ if ( $addon_data->offsetExists( 'options' ) ) {
201
+ foreach ( $addon_data->get( 'options' ) as $key => $option ) {
202
  $addons[ $add_id ]['options'][ $key ]['price'] = $this->converted_addon_price( $option, $post_id );
203
  }
204
  }
 
205
  }
206
  }
207
 
210
 
211
  /**
212
  * @param array $addon
213
+ * @param int $post_id
214
  *
215
  * @return string
216
  */
217
+ private function converted_addon_price( $addon, $post_id ) {
218
 
219
  $addonData = wpml_collect( $addon );
220
 
221
  $is_custom_prices_on = $this->is_product_custom_prices_on( $post_id );
222
+ $field = 'price_' . $this->woocommerce_wpml->multi_currency->get_client_currency();
223
 
224
  if (
225
  $is_custom_prices_on &&
228
  return $addonData->get( $field );
229
  }
230
 
231
+ if ( wpml_collect( [ 'flat_fee', 'quantity_based' ] )->contains( $addonData->get( 'price_type' ) ) ) {
232
  return apply_filters( 'wcml_raw_price_amount', $addonData->get( 'price' ) );
233
  }
234
 
240
  *
241
  * @return array
242
  */
243
+ public function addons_product_terms( $product_terms ) {
244
  foreach ( $product_terms as $key => $product_term ) {
245
  $product_terms[ $key ] = apply_filters( 'translate_object_id', $product_term, 'product_cat', true, $this->sitepress->get_default_language() );
246
  }
248
  return $product_terms;
249
  }
250
 
251
+ public function inf_translate_strings() {
252
 
253
  $pointer_ui = new WCML_Pointer_UI(
254
+ sprintf( __( 'You can translate strings related to global add-ons on the %1$sWPML String Translation page%2$s. Use the search on the top of that page to find the strings.', 'woocommerce-multilingual' ), '<a href="' . admin_url( 'admin.php?page=' . WPML_ST_FOLDER . '/menu/string-translation.php&context=wc_product_addons_strings' ) . '">', '</a>' ),
255
  'https://wpml.org/documentation/woocommerce-extensions-compatibility/translating-woocommerce-product-add-ons-woocommerce-multilingual/',
256
  'wpbody-content .woocommerce>h2'
257
  );
264
  * @param $product_id
265
  * @param $data
266
  */
267
+ public function custom_box_html( $obj, $product_id, $data ) {
268
 
269
  $product_addons = $this->get_product_addons( $product_id );
270
 
272
  foreach ( $product_addons as $addon_id => $product_addon ) {
273
  $addon_data = wpml_collect( $product_addon );
274
 
275
+ $addons_section = new WPML_Editor_UI_Field_Section( sprintf( __( 'Product Add-ons Group "%s"', 'woocommerce-multilingual' ), $addon_data->get( 'name' ) ) );
276
 
277
+ $group = new WPML_Editor_UI_Field_Group( '', true );
278
+ $addon_field = new WPML_Editor_UI_Single_Line_Field( 'addon_' . $addon_id . '_name', __( 'Name', 'woocommerce-multilingual' ), $data, false );
279
  $group->add_field( $addon_field );
280
+ $addon_field = new WPML_Editor_UI_Single_Line_Field( 'addon_' . $addon_id . '_description', __( 'Description', 'woocommerce-multilingual' ), $data, false );
281
  $group->add_field( $addon_field );
282
 
283
  $addons_section->add_field( $group );
284
 
285
+ if ( $addon_data->offsetExists( 'options' ) && $addon_data->get( 'options' ) ) {
286
 
287
+ $labels_group = new WPML_Editor_UI_Field_Group( __( 'Options', 'woocommerce-multilingual' ), true );
288
 
289
+ foreach ( $addon_data->get( 'options' ) as $option_id => $option ) {
290
+ $option_label_field = new WPML_Editor_UI_Single_Line_Field( 'addon_' . $addon_id . '_option_' . $option_id . '_label', __( 'Label', 'woocommerce-multilingual' ), $data, false );
291
  $labels_group->add_field( $option_label_field );
292
  }
293
  $addons_section->add_field( $labels_group );
304
  *
305
  * @return mixed
306
  */
307
+ public function custom_box_html_data( $data, $product_id, $translation ) {
308
 
309
  $product_addons = $this->get_product_addons( $product_id );
310
 
311
  if ( ! empty( $product_addons ) ) {
312
  foreach ( $product_addons as $addon_id => $product_addon ) {
313
+ $addon_data = wpml_collect( $product_addon );
314
+ $data[ 'addon_' . $addon_id . '_name' ] = [ 'original' => $addon_data->get( 'name' ) ];
315
+ $data[ 'addon_' . $addon_id . '_description' ] = [ 'original' => $addon_data->get( 'description' ) ];
316
+ if ( $addon_data->offsetExists( 'options' ) && $addon_data->get( 'options' ) ) {
317
+ foreach ( $addon_data->get( 'options' ) as $option_id => $option ) {
318
+ $data[ 'addon_' . $addon_id . '_option_' . $option_id . '_label' ] = [ 'original' => wpml_collect( $option )->get( 'label' ) ];
319
  }
320
  }
321
  }
324
  $translated_product_addons = $this->get_product_addons( $translation->ID );
325
  if ( ! empty( $translated_product_addons ) ) {
326
  foreach ( $translated_product_addons as $addon_id => $transalted_product_addon ) {
327
+ $translated_addon_data = wpml_collect( $transalted_product_addon );
328
+ $data[ 'addon_' . $addon_id . '_name' ]['translation'] = $translated_addon_data->get( 'name' );
329
+ $data[ 'addon_' . $addon_id . '_description' ]['translation'] = $translated_addon_data->get( 'description' );
330
+ if ( $translated_addon_data->offsetExists( 'options' ) && $translated_addon_data->get( 'options' ) ) {
331
+ foreach ( $translated_addon_data->get( 'options' ) as $option_id => $option ) {
332
+ $data[ 'addon_' . $addon_id . '_option_' . $option_id . '_label' ]['translation'] = wpml_collect( $option )->get( 'label' );
333
  }
334
  }
335
  }
345
  * @param $product_id
346
  * @param $data
347
  */
348
+ public function addons_update( $original_product_id, $product_id, $data ) {
349
 
350
  $product_addons = $this->get_product_addons( $original_product_id );
351
 
352
  if ( ! empty( $product_addons ) ) {
353
 
354
  foreach ( $product_addons as $addon_id => $product_addon ) {
355
+ $addon_data = wpml_collect( $product_addon );
356
+ $product_addons[ $addon_id ]['name'] = $data[ md5( 'addon_' . $addon_id . '_name' ) ];
357
  $product_addons[ $addon_id ]['description'] = $data[ md5( 'addon_' . $addon_id . '_description' ) ];
358
 
359
+ if ( $addon_data->offsetExists( 'options' ) && $addon_data->get( 'options' ) ) {
360
+ foreach ( $addon_data->get( 'options' ) as $option_id => $option ) {
361
+ $product_addons[ $addon_id ]['options'][ $option_id ]['label'] = $data[ md5( 'addon_' . $addon_id . '_option_' . $option_id . '_label' ) ];
362
  }
363
  }
364
  }
367
  update_post_meta( $product_id, '_product_addons', $product_addons );
368
  }
369
 
370
+ public function show_pointer_info() {
371
 
372
  $pointer_ui = new WCML_Pointer_UI(
373
+ sprintf( __( 'You can translate the Group Name, Group Description and every Option Label of your product add-on on the %1$sWooCommerce product translation page%2$s', 'woocommerce-multilingual' ), '<a href="' . admin_url( 'admin.php?page=wpml-wcml' ) . '">', '</a>' ),
374
  'https://wpml.org/documentation/woocommerce-extensions-compatibility/translating-woocommerce-product-add-ons-woocommerce-multilingual/',
375
  'product_addons_data>p'
376
  );
378
  $pointer_ui->show();
379
  }
380
 
381
+ public function replace_tm_editor_custom_fields_with_own_sections( $fields ) {
382
  $fields[] = '_product_addons';
383
 
384
  return $fields;
392
  if ( $this->is_multi_currency_on() && $is_booking_product_with_addons ) {
393
  $cost = $cart_item['data']->get_price();
394
 
395
+ foreach ( $cart_item['addons'] as $addon ) {
396
  $cost += $addon['price'];
397
  }
398
 
404
 
405
  public function set_global_ids_in_query_args( $args ) {
406
 
407
+ if ( ! is_archive() ) {
408
 
409
+ remove_filter( 'get_terms_args', [ $this->sitepress, 'get_terms_args_filter' ], 10, 2 );
410
+ remove_filter( 'get_term', [ $this->sitepress, 'get_term_adjust_id' ], 1 );
411
+ remove_filter( 'terms_clauses', [ $this->sitepress, 'terms_clauses' ], 10 );
412
 
413
  $matched_addons_ids = wp_list_pluck( get_posts( $args ), 'ID' );
414
 
417
  unset( $args['tax_query'] );
418
  }
419
 
420
+ add_filter( 'get_terms_args', [ $this->sitepress, 'get_terms_args_filter' ], 10, 2 );
421
+ add_filter( 'get_term', [ $this->sitepress, 'get_term_adjust_id' ], 1 );
422
+ add_filter( 'terms_clauses', [ $this->sitepress, 'terms_clauses' ], 10, 3 );
423
  }
424
 
425
  return $args;
428
  /**
429
  * @return bool
430
  */
431
+ private function is_multi_currency_on() {
432
  return $this->multi_currency_mode === $this->sitepress->get_wp_api()->constant( 'WCML_MULTI_CURRENCIES_INDEPENDENT' );
433
  }
434
 
435
+ public function load_dialog_resources() {
436
+ wp_enqueue_script( 'wcml-dialogs', WCML_PLUGIN_URL . '/res/js/dialogs' . WCML_JS_MIN . '.js', [ 'jquery-ui-dialog', 'underscore' ], WCML_VERSION );
437
  }
438
 
439
  /**
440
  * @param WP_Post|null $product
441
+ * @param array $product_addons
442
+ * @param int $loop
443
+ * @param array $option
444
  */
445
+ public function dialog_button_after_option_row( $product, $product_addons, $loop, $option ) {
446
+ if ( $option ) {
447
  $this->render_edit_price_element( $this->get_prices_dialog_model( $product_addons, $option, $loop, $this->is_product_custom_prices_on( $product ? $product->ID : false ) ) );
448
  }
449
 
451
 
452
  /**
453
  * @param WP_Post|null $product
454
+ * @param array $product_addons
455
+ * @param int $loop
456
  */
457
+ public function dialog_button_before_options( $product, $product_addons, $loop ) {
458
+ $this->render_edit_price_element( $this->get_prices_dialog_model( [], $product_addons, $loop, $this->is_product_custom_prices_on( $product ? $product->ID : false ) ) );
459
  }
460
 
461
  /**
462
  * @param array $model
463
  */
464
+ private function render_edit_price_element( $model ) {
465
  $twig_loader = $this->get_twig_loader();
466
+ // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
467
  echo $twig_loader->get_template()->show( $model, self::DIALOG_TEMPLATE );
468
  }
469
 
470
  /**
471
  * @return array
472
  */
473
+ private function get_one_price_types() {
474
 
475
+ return [
476
  'custom_text',
477
  'custom_textarea',
478
  'file_upload',
479
+ 'input_multiplier',
480
+ ];
481
  }
482
 
483
  /**
484
  * @return WPML_Twig_Template_Loader
485
  */
486
+ private function get_twig_loader() {
487
+ return new WPML_Twig_Template_Loader( [ $this->sitepress->get_wp_api()->constant( 'WCML_PLUGIN_PATH' ) . self::TEMPLATE_FOLDER ] );
488
  }
489
 
490
  /**
492
  *
493
  * @return mixed
494
  */
495
+ private function is_product_custom_prices_on( $product_id ) {
496
 
497
+ if ( $product_id ) {
498
  return get_post_meta( $product_id, '_wcml_custom_prices_status', true );
499
  }
500
 
501
+ if ( $this->is_global_addon_edit_page() ) {
502
  return $this->get_global_addon_prices_status();
503
  }
504
 
522
  public function load_assets() {
523
  global $pagenow;
524
 
525
+ $is_product_page = 'post.php' === $pagenow && isset( $_GET['post'] );
526
  $is_product_new_page = 'post-new.php' === $pagenow && isset( $_GET['post_type'] ) && 'product' === $_GET['post_type'];
527
 
528
  if ( $is_product_page || $is_product_new_page || $this->is_global_addon_edit_page() ) {
529
+ wp_enqueue_script( 'wcml-product-addons', WCML_PLUGIN_URL . '/compatibility/res/js/wcml-product-addons' . WCML_JS_MIN . '.js', [ 'jquery' ], WCML_VERSION );
530
  wp_enqueue_style( 'wcml-product-addons', WCML_PLUGIN_URL . '/compatibility/res/css/wcml-product-addons.css', '', WCML_VERSION );
531
  }
532
 
537
  */
538
  public function update_custom_prices_values( $product_id ) {
539
 
540
+ if ( $this->is_multi_currency_on() ) {
541
  $this->save_global_addon_prices_setting( $product_id );
542
  $product_addons = $this->get_product_addons( $product_id );
543
 
549
  foreach ( $active_currencies as $code => $currency ) {
550
  $price_option_key = self::PRICE_OPTION_KEY;
551
 
552
+ if ( in_array( $product_addon['type'], $this->get_one_price_types() ) ) {
553
  $product_addons = $this->update_single_option_prices( $product_addons, $price_option_key, $addon_key, $code );
554
+ } else {
555
  $product_addons = $this->update_multiple_options_prices( $product_addons, $price_option_key, $addon_key, $code );
556
  }
557
  }
563
  }
564
 
565
  /**
566
+ * @param array $product_addons
567
  * @param string $price_option_key
568
  * @param string $addon_key
569
  * @param string $code
570
  *
571
  * @return array
572
  */
573
+ private function update_single_option_prices( $product_addons, $price_option_key, $addon_key, $code ) {
574
+ if ( isset( $_POST[ $price_option_key ][ $addon_key ][ 'price_' . $code ][0] ) ) {
575
+ $product_addons[ $addon_key ][ 'price_' . $code ] = wc_format_decimal( $_POST[ $price_option_key ][ $addon_key ][ 'price_' . $code ][0] );
576
  }
577
 
578
  return $product_addons;
579
  }
580
 
581
  /**
582
+ * @param array $product_addons
583
  * @param string $price_option_key
584
  * @param string $addon_key
585
  * @param string $code
586
  *
587
  * @return array
588
  */
589
+ private function update_multiple_options_prices( $product_addons, $price_option_key, $addon_key, $code ) {
590
 
591
  $addon_data = wpml_collect( $product_addons[ $addon_key ] );
592
 
593
+ if ( $addon_data->offsetExists( 'options' ) ) {
594
+ foreach ( $addon_data->get( 'options' ) as $option_key => $option ) {
595
+ if ( isset( $_POST[ $price_option_key ][ $addon_key ][ 'price_' . $code ][ $option_key ] ) ) {
596
+ $product_addons[ $addon_key ]['options'][ $option_key ][ 'price_' . $code ] = wc_format_decimal( $_POST[ $price_option_key ][ $addon_key ][ 'price_' . $code ][ $option_key ] );
597
  }
598
  }
599
  }
602
  }
603
 
604
  /**
605
+ * @param array $product_addons
606
+ * @param array $option
607
+ * @param int $loop
608
  * @param string|bool $custom_prices_on
609
  *
610
  * @return array
613
 
614
  $label = isset( $option['label'] ) ? $option['label'] : $option['name'];
615
 
616
+ return [
617
+ 'strings' => [
618
+ 'dialog_title' => __( 'Multi-currency settings', 'woocommerce-multilingual' ),
619
+ 'description' => sprintf( __( 'Here you can set different prices for the %s in multiple currencies:', 'woocommerce-multilingual' ), '<strong>' . $label . '</strong>' ),
620
  'apply' => __( 'Apply', 'woocommerce-multilingual' ),
621
+ 'cancel' => __( 'Cancel', 'woocommerce-multilingual' ),
622
+ ],
623
  'custom_prices_on' => $custom_prices_on,
624
+ 'dialog_id' => '_product_addon_option_' . md5( uniqid( $loop . $label ) ),
625
  'option_id' => isset( $product_addons[ $loop ]['options'] ) ? array_search( $option, $product_addons[ $loop ]['options'] ) : '',
626
  'addon_id' => $loop,
627
  'option_details' => $option,
628
  'default_currency' => wcml_get_woocommerce_currency_option(),
629
  'active_currencies' => $this->woocommerce_wpml->multi_currency->get_currencies(),
630
+ ];
631
  }
632
 
633
  public function custom_prices_settings_block() {
634
  $twig_loader = $this->get_twig_loader();
635
+ // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
636
  echo $twig_loader->get_template()->show( $this->get_custom_prices_settings_model(), self::SETTINGS_TEMPLATE );
637
  }
638
 
639
  private function get_custom_prices_settings_model() {
640
+ return [
641
+ 'strings' => [
642
  'label' => __( 'Multi-currency settings', 'woocommerce-multilingual' ),
643
  'auto' => __( 'Calculate prices in other currencies automatically', 'woocommerce-multilingual' ),
644
+ 'manually' => __( 'Set prices in other currencies manually', 'woocommerce-multilingual' ),
645
+ ],
646
  'custom_prices_on' => $this->get_global_addon_prices_status(),
647
+ 'nonce' => wp_create_nonce( 'wcml_save_custom_prices' ),
648
+ ];
649
  }
650
 
651
  /**
compatibility/class-wcml-product-bundles.php CHANGED
@@ -30,51 +30,56 @@ class WCML_Product_Bundles {
30
  /**
31
  * WCML_Product_Bundles constructor.
32
  */
33
- function __construct( SitePress $sitepress, woocommerce_wpml $woocommerce_wpml, $product_bundles_items, wpdb $wpdb ) {
34
 
35
  $this->sitepress = $sitepress;
36
  $this->woocommerce_wpml = $woocommerce_wpml;
37
  $this->product_bundles_items = $product_bundles_items;
38
  $this->wpdb = $wpdb;
39
 
40
- add_action( 'woocommerce_get_cart_item_from_session', array( $this, 'resync_bundle' ), 5, 3 );
41
- add_filter( 'woocommerce_cart_loaded_from_session', array( $this, 'resync_bundle_clean' ), 10 );
 
42
 
43
  if ( is_admin() ) {
44
  $this->tp = new WPML_Element_Translation_Package();
45
 
46
- add_filter( 'wpml_tm_translation_job_data', array(
47
- $this,
48
- 'append_bundle_data_translation_package'
49
- ), 10, 2 );
50
- add_action( 'wpml_translation_job_saved', array( $this, 'save_bundle_data_translation' ), 10, 3 );
 
 
 
 
51
 
52
- add_action( 'wcml_gui_additional_box_html', array( $this, 'custom_box_html' ), 10, 3 );
53
- add_filter( 'wcml_gui_additional_box_data', array( $this, 'custom_box_html_data' ), 10, 4 );
54
 
55
- add_action( 'wcml_after_duplicate_product_post_meta', array( $this, 'sync_bundled_ids' ), 10, 2 );
56
- add_action( 'wcml_update_extra_fields', array( $this, 'bundle_update' ), 10, 4 );
57
 
58
- add_action( 'wp_insert_post', array( $this, 'sync_product_bundle_meta_with_translations' ), 10 );
59
 
60
- add_filter( 'woocommerce_json_search_found_products', array( $this, 'woocommerce_json_search_filter_found_products' ) );
61
 
62
- add_action( 'woocommerce_before_delete_bundled_item', array( $this, 'delete_bundled_item_relationship' ) );
63
  }
64
 
65
  // product bundle using separate custom fields for prices.
66
  if ( wcml_is_multi_currency_on() ) {
67
- add_filter( 'wcml_price_custom_fields_filtered', array( $this, 'get_price_custom_fields' ), 10, 2 );
68
- add_filter( 'wcml_update_custom_prices_values', array( $this, 'update_bundles_custom_prices_values' ), 10, 2 );
69
- add_filter( 'wcml_after_save_custom_prices', array( $this, 'update_bundles_base_price' ), 10, 4 );
70
  }
71
 
72
- add_action( 'init', array( $this, 'upgrade_bundles_items_relationships' ) );
73
 
74
  }
75
 
76
  private function get_product_bundle_data( $bundle_id ) {
77
- $product_bundle_data = array();
78
 
79
  $bundle_items = $this->product_bundles_items->get_items( $bundle_id );
80
  foreach ( $bundle_items as $key => $bundle_item ) {
@@ -102,7 +107,7 @@ class WCML_Product_Bundles {
102
  public function sync_product_bundle_meta( $bundle_id, $translated_bundle_id ) {
103
 
104
  $bundle_items = $this->product_bundles_items->get_items( $bundle_id );
105
- $fields_to_sync = array(
106
  'optional',
107
  'stock_status',
108
  'max_stock',
@@ -119,11 +124,11 @@ class WCML_Product_Bundles {
119
  'discount',
120
  'override_variations',
121
  'override_default_variation_attributes',
122
- 'hide_filtered_variations'
123
- );
124
 
125
  $target_lang = $this->sitepress->get_language_for_element( $translated_bundle_id, 'post_product' );
126
- $translated_item_ids = array();
127
  foreach ( $bundle_items as $item_id => $bundle_item ) {
128
 
129
  $item_meta = $this->product_bundles_items->get_item_data( $bundle_item );
@@ -140,13 +145,12 @@ class WCML_Product_Bundles {
140
  }
141
  }
142
 
143
-
144
- if( isset( $item_meta['allowed_variations'] ) ){
145
- if( is_array( $item_meta['allowed_variations'] ) ){
146
  $allowed_variations =
147
  $this->translate_allowed_variations( $item_meta['allowed_variations'], $target_lang );
148
  $this->product_bundles_items->update_item_meta( $translated_item, 'allowed_variations', $allowed_variations );
149
- }else{
150
  $this->product_bundles_items->update_item_meta( $translated_item, 'allowed_variations', $item_meta['allowed_variations'] );
151
  }
152
  }
@@ -159,10 +163,9 @@ class WCML_Product_Bundles {
159
  $this->product_bundles_items->save_item_meta( $translated_item );
160
 
161
  }
162
-
163
  }
164
 
165
- // Delete removed items
166
  $translated_bundle_items = $this->product_bundles_items->get_items( $translated_bundle_id );
167
  foreach ( $translated_bundle_items as $item_id => $bundle_item ) {
168
  if ( ! in_array( $item_id, $translated_item_ids ) ) {
@@ -185,7 +188,6 @@ class WCML_Product_Bundles {
185
  $original_bundle_id = $translation->element_id;
186
  break;
187
  }
188
-
189
  }
190
 
191
  foreach ( $translations as $language => $translation ) {
@@ -193,13 +195,12 @@ class WCML_Product_Bundles {
193
  $this->sync_product_bundle_meta( $original_bundle_id, $translation->element_id );
194
  }
195
  }
196
-
197
  }
198
 
199
  }
200
 
201
  /**
202
- * @param array $allowed_variations
203
  * @param string $lang
204
  *
205
  * @return array
@@ -215,15 +216,15 @@ class WCML_Product_Bundles {
215
  }
216
 
217
  /**
218
- * @param array $original_default_variation_attributes
219
  * @param string $target_lang
220
- * @param int $product_id
221
- * @param int $translated_product_id
222
  *
223
  * @return array
224
  */
225
  public function translate_default_variation_attributes( $original_default_variation_attributes, $target_lang, $product_id, $translated_product_id ) {
226
- $default_variation_attributes = array();
227
 
228
  if ( is_array( $original_default_variation_attributes ) ) {
229
  foreach ( $original_default_variation_attributes as $attribute_taxonomy => $attribute_slug ) {
@@ -233,7 +234,7 @@ class WCML_Product_Bundles {
233
  $translated_term = $this->woocommerce_wpml->terms->wcml_get_term_by_id( $translated_attribute_term_id, $attribute_taxonomy );
234
 
235
  $default_variation_attributes[ $attribute_taxonomy ] = $translated_term->slug;
236
- }else{
237
  $default_variation_attributes[ $attribute_taxonomy ] = $this->woocommerce_wpml->attributes->get_custom_attr_translation( $product_id, $translated_product_id, $attribute_taxonomy, $attribute_slug );
238
  }
239
  }
@@ -244,41 +245,51 @@ class WCML_Product_Bundles {
244
 
245
  private function get_product_id_for_item_id( $item_id ) {
246
 
247
- return $this->wpdb->get_var( $this->wpdb->prepare(
248
- "SELECT product_id FROM {$this->wpdb->prefix}woocommerce_bundled_items WHERE bundled_item_id=%d", $item_id ) );
 
 
 
 
249
  }
250
 
251
  /**
252
- * @param array $item_id
253
  * @param string $language
254
  *
255
  * @return string
256
  */
257
  public function get_item_id_for_language( $item_id, $language ) {
258
 
259
- return $this->wpdb->get_var( $this->wpdb->prepare(
260
- "SELECT meta_value FROM {$this->wpdb->prefix}woocommerce_bundled_itemmeta WHERE bundled_item_id=%d AND meta_key=%s", $item_id, 'translation_item_id_of_'.$language ) );
 
 
 
 
 
261
 
262
  }
263
 
264
  /**
265
- * @param int $original_item_id
266
- * @param int $translated_item_id
267
  * @param string $language
268
  */
269
  public function set_translated_item_id_relationship( $original_item_id, $translated_item_id, $language ) {
270
 
271
- $this->wpdb->insert( $this->wpdb->prefix . 'woocommerce_bundled_itemmeta',
272
- array(
273
- 'bundled_item_id' => $original_item_id,
274
- 'meta_key' => 'translation_item_id_of_'.$language,
275
- 'meta_value' => $translated_item_id,
276
- )
 
277
  );
278
 
279
  }
280
 
281
- // Add Bundles Box to WCML Translation GUI
282
  public function custom_box_html( $obj, $bundle_id, $data ) {
283
 
284
  $bundle_items = $this->product_bundles_items->get_items( $bundle_id );
@@ -334,9 +345,7 @@ class WCML_Product_Bundles {
334
  $bundles_section->add_field( $group );
335
  $flag = true;
336
  }
337
-
338
  }
339
-
340
  }
341
 
342
  if ( $flag ) {
@@ -370,7 +379,7 @@ class WCML_Product_Bundles {
370
  }
371
 
372
  if ( $bundle_data[ $item_id ]['override_title'] == 'yes' ) {
373
- $data[ 'bundle_' . $product_id . '_title' ] = array( 'original' => $bundle_data[ $item_id ]['title'] );
374
  if ( $translation && isset( $translated_bundle_data[ $translated_item_id ]['override_title'] ) ) {
375
  $data[ 'bundle_' . $product_id . '_title' ]['translation'] = $translated_bundle_data[ $translated_item_id ]['title'];
376
  } else {
@@ -379,7 +388,7 @@ class WCML_Product_Bundles {
379
  }
380
 
381
  if ( $bundle_data[ $item_id ]['override_description'] == 'yes' ) {
382
- $data[ 'bundle_' . $product_id . '_desc' ] = array( 'original' => $bundle_data[ $item_id ]['description'] );
383
  if ( $translation && isset( $translated_bundle_data[ $translated_item_id ]['override_description'] ) ) {
384
  $data[ 'bundle_' . $product_id . '_desc' ]['translation'] = $translated_bundle_data[ $translated_item_id ]['description'];
385
  } else {
@@ -399,18 +408,18 @@ class WCML_Product_Bundles {
399
 
400
  if ( $bundle_data ) {
401
 
402
- $fields = array( 'title', 'description' );
403
 
404
  foreach ( $bundle_data as $item_id => $product_data ) {
405
 
406
  $product_id = $this->get_product_id_for_item_id( $item_id );
407
  foreach ( $fields as $field ) {
408
  if ( $product_data[ 'override_' . $field ] == 'yes' && ! empty( $product_data[ $field ] ) ) {
409
- $package['contents'][ 'product_bundles:' . $product_id . ':'.$item_id.':'. $field ] = array(
410
  'translate' => 1,
411
  'data' => $this->tp->encode_field_data( $product_data[ $field ], 'base64' ),
412
- 'format' => 'base64'
413
- );
414
  }
415
  }
416
  }
@@ -421,7 +430,7 @@ class WCML_Product_Bundles {
421
 
422
  }
423
 
424
- // Update Bundled products title and description after saving the translation
425
  public function bundle_update( $bundle_id, $translated_bundle_id, $data, $lang ) {
426
 
427
  $bundle_data = $this->get_product_bundle_data( $bundle_id );
@@ -431,8 +440,12 @@ class WCML_Product_Bundles {
431
  return;
432
  }
433
 
434
- $translate_bundled_item_ids = $this->wpdb->get_col( $this->wpdb->prepare(
435
- "SELECT product_id FROM {$this->wpdb->prefix}woocommerce_bundled_items WHERE bundle_id = %d", $translated_bundle_id ) );
 
 
 
 
436
 
437
  foreach ( $bundle_data as $item_id => $bundle_item_data ) {
438
 
@@ -443,17 +456,24 @@ class WCML_Product_Bundles {
443
 
444
  if ( ! in_array( $translated_product_id, $translate_bundled_item_ids ) ) {
445
 
446
- $menu_order = $this->wpdb->get_var( $this->wpdb->prepare( "
 
 
447
  SELECT menu_order FROM {$this->wpdb->prefix}woocommerce_bundled_items
448
  WHERE bundle_id=%d AND product_id=%d
449
- ", $bundle_id, $bundle_item_data['product_id'] ) );
 
 
 
 
450
 
451
- $this->wpdb->insert( $this->wpdb->prefix . 'woocommerce_bundled_items',
452
- array(
 
453
  'product_id' => $translated_product_id,
454
  'bundle_id' => $translated_bundle_id,
455
  'menu_order' => $menu_order,
456
- )
457
  );
458
 
459
  $translated_item_id = $this->wpdb->insert_id;
@@ -462,8 +482,7 @@ class WCML_Product_Bundles {
462
 
463
  $translated_item_id = $this->get_item_id_for_language( $item_id, $lang );
464
 
465
- //$this->product_bundles_items->copy_item_data( $item_id, $translated_item_id );
466
-
467
  if ( isset( $data[ md5( 'bundle_' . $product_id . '_title' ) ] ) ) {
468
  $translated_bundle_data[ $translated_item_id ]['title'] = $data[ md5( 'bundle_' . $product_id . '_title' ) ];
469
  $translated_bundle_data[ $translated_item_id ]['override_title'] = $bundle_item_data['override_title'];
@@ -474,19 +493,16 @@ class WCML_Product_Bundles {
474
  $translated_bundle_data[ $translated_item_id ]['override_description'] = $bundle_item_data['override_description'];
475
  }
476
 
477
- if( isset( $bundle_item_data['allowed_variations'] ) ){
478
- if( is_array( $bundle_item_data['allowed_variations'] ) ){
479
  $translated_bundle_data[ $translated_item_id ]['allowed_variations'] =
480
  $this->translate_allowed_variations( $bundle_item_data['allowed_variations'], $lang );
481
- }else{
482
  $translated_bundle_data[ $translated_item_id ]['allowed_variations'] =
483
  $bundle_item_data['allowed_variations'];
484
  }
485
-
486
  }
487
-
488
  }
489
-
490
  }
491
 
492
  $this->save_product_bundle_data( $translated_bundle_id, $translated_bundle_data );
@@ -497,12 +513,12 @@ class WCML_Product_Bundles {
497
  return $translated_bundle_data;
498
  }
499
 
500
- // Sync product bundle data with translated values when the product is duplicated
501
  public function sync_bundled_ids( $bundle_id, $translated_bundle_id ) {
502
 
503
  $bundle_data = $this->get_product_bundle_data( $bundle_id );
504
  if ( $bundle_data ) {
505
- $lang = $this->sitepress->get_language_for_element( $translated_bundle_id, 'post_product' );
506
  $translated_bundle_data_before_update = $this->get_product_bundle_data( $translated_bundle_id );
507
 
508
  foreach ( $bundle_data as $item_id => $product_data ) {
@@ -514,37 +530,44 @@ class WCML_Product_Bundles {
514
 
515
  $translated_item_id = $this->get_item_id_for_language( $item_id, $lang );
516
  if ( ! $translated_item_id ) {
517
- $menu_order = $this->wpdb->get_var( $this->wpdb->prepare( "
 
 
518
  SELECT menu_order FROM {$this->wpdb->prefix}woocommerce_bundled_items
519
  WHERE bundle_id=%d AND product_id=%d
520
- ", $bundle_id, $product_id ) );
 
 
 
 
521
 
522
- $this->wpdb->insert( $this->wpdb->prefix . 'woocommerce_bundled_items',
523
- array(
 
524
  'product_id' => $translated_product_id,
525
  'bundle_id' => $translated_bundle_id,
526
  'menu_order' => $menu_order,
527
- )
528
  );
529
  $translated_item_id = $this->wpdb->insert_id;
530
  $this->set_translated_item_id_relationship( $item_id, $translated_item_id, $lang );
531
  }
532
 
533
- $translated_bundle_data[ $translated_item_id ] = $product_data;
534
  $translated_bundle_data[ $translated_item_id ]['product_id'] = $translated_product_id;
535
 
536
  if ( isset( $product_data['title'] ) ) {
537
- if ( $product_data['override_title'] != 'yes' ) {
538
  $translated_bundle_data[ $translated_item_id ]['title'] = get_the_title( $translated_product_id );
539
- }else{
540
  $translated_bundle_data[ $translated_item_id ]['title'] = isset( $translated_bundle_data_before_update[ $translated_item_id ] ) ? $translated_bundle_data_before_update[ $translated_item_id ]['title'] : '';
541
  }
542
  }
543
 
544
  if ( isset( $product_data['title'] ) ) {
545
- if ( $product_data['override_description'] != 'yes' ) {
546
  $translated_bundle_data[ $translated_item_id ]['description'] = get_the_title( $translated_product_id );
547
- }else{
548
  $translated_bundle_data[ $translated_item_id ]['description'] = isset( $translated_bundle_data_before_update[ $translated_item_id ] ) ? $translated_bundle_data_before_update[ $translated_item_id ]['description'] : '';
549
  }
550
  }
@@ -553,7 +576,7 @@ class WCML_Product_Bundles {
553
  $allowed_var = maybe_unserialize( $product_data['allowed_variations'] );
554
  $translated_bundle_data[ $translated_item_id ]['allowed_variations'] = maybe_unserialize( $translated_bundle_data[ $translated_item_id ]['allowed_variations'] );
555
  foreach ( $allowed_var as $key => $var_id ) {
556
- $translated_var_id = apply_filters( 'translate_object_id', $var_id, get_post_type( $var_id ), true, $lang );
557
  $translated_bundle_data[ $translated_item_id ]['allowed_variations'][ $key ] = $translated_var_id;
558
  }
559
  $translated_bundle_data[ $translated_item_id ]['allowed_variations'] = maybe_serialize( $translated_bundle_data[ $translated_item_id ]['allowed_variations'] );
@@ -565,29 +588,29 @@ class WCML_Product_Bundles {
565
 
566
  $term_id = $this->woocommerce_wpml->terms->wcml_get_term_id_by_slug( $tax, $term_slug );
567
  if ( $term_id ) {
568
- // Global Attribute
569
- $tr_def_id = apply_filters( 'translate_object_id', $term_id, $tax, true, $lang );
570
- $tr_term = $this->woocommerce_wpml->terms->wcml_get_term_by_id( $tr_def_id, $tax );
571
  $translated_bundle_data[ $translated_item_id ]['bundle_defaults'][ $tax ] = $tr_term->slug;
572
  } else {
573
- // Custom Attribute
574
- $args = array(
575
  'post_type' => 'product_variation',
576
  'meta_key' => 'attribute_' . $tax,
577
  'meta_value' => $term_slug,
578
- 'meta_compare' => '='
579
- );
580
  $variationloop = new WP_Query( $args );
581
- while ( $variationloop->have_posts() ) : $variationloop->the_post();
582
- $tr_var_id = apply_filters( 'translate_object_id', get_the_ID(), 'product_variation', true, $lang );
583
- $tr_meta = get_post_meta( $tr_var_id, 'attribute_' . $tax, true );
 
584
  $translated_bundle_data[ $translated_item_id ]['bundle_defaults'][ $tax ] = $tr_meta;
585
  endwhile;
586
  }
587
  }
588
  $translated_bundle_data[ $translated_item_id ]['bundle_defaults'] = maybe_serialize( $translated_bundle_data[ $translated_item_id ]['bundle_defaults'] );
589
  }
590
-
591
  }
592
  }
593
 
@@ -608,13 +631,13 @@ class WCML_Product_Bundles {
608
  $cart_item['data'] = wc_get_product( $current_bundle_id );
609
  if ( isset( $cart_item['data']->bundle_data ) && is_array( $cart_item['data']->bundle_data ) ) {
610
  $new_bundled_item_ids = array_keys( $cart_item['data']->bundle_data );
611
- $remapped_bundled_item_ids = array();
612
  foreach ( $old_bundled_item_ids as $old_item_id_index => $old_item_id ) {
613
  $remapped_bundled_item_ids[ $old_item_id ] = $new_bundled_item_ids[ $old_item_id_index ];
614
  }
615
  $cart_item['remapped_bundled_item_ids'] = $remapped_bundled_item_ids;
616
  if ( isset( $cart_item['stamp'] ) ) {
617
- $new_stamp = array();
618
  foreach ( $cart_item['stamp'] as $bundled_item_id => $stamp_data ) {
619
  $new_stamp[ $remapped_bundled_item_ids[ $bundled_item_id ] ] = $stamp_data;
620
  }
@@ -635,7 +658,7 @@ class WCML_Product_Bundles {
635
  $remapped_bundled_item_ids = $bundle_cart_item['remapped_bundled_item_ids'];
636
  $cart_item['bundled_item_id'] = $remapped_bundled_item_ids[ $cart_item['bundled_item_id'] ];
637
  if ( isset( $cart_item['stamp'] ) ) {
638
- $new_stamp = array();
639
  foreach ( $cart_item['stamp'] as $bundled_item_id => $stamp_data ) {
640
  $new_stamp[ $remapped_bundled_item_ids[ $bundled_item_id ] ] = $stamp_data;
641
  }
@@ -661,7 +684,7 @@ class WCML_Product_Bundles {
661
 
662
  if ( $this->is_bundle_product( $translated_bundle_id ) ) {
663
 
664
- remove_action( 'wcml_after_duplicate_product_post_meta', array( $this, 'sync_bundled_ids' ), 10, 2 );
665
 
666
  $translated_bundle_data = $this->get_product_bundle_data( $translated_bundle_id );
667
 
@@ -677,7 +700,6 @@ class WCML_Product_Bundles {
677
  $item_id = $matches[2];
678
  $field = $matches[3];
679
 
680
-
681
  $translated_product_id = apply_filters( 'translate_object_id', $product_id, get_post_type( $product_id ), false, $job->language_code );
682
  $translated_item_id = $this->get_item_id_for_language( $item_id, $job->language_code );
683
  if ( empty( $translated_item_id ) ) {
@@ -685,35 +707,34 @@ class WCML_Product_Bundles {
685
  }
686
 
687
  if ( ! isset( $translated_bundle_data[ $translated_item_id ] ) ) {
688
- $translated_bundle_data[ $translated_item_id ] = array(
689
- 'product_id' => $translated_product_id,
690
- 'hide_thumbnail' => $bundle_data[ $item_id ]['hide_thumbnail'],
691
- 'override_title' => $bundle_data[ $item_id ]['override_title'],
692
- 'product_title' => '',
693
- 'override_description' => $bundle_data[ $item_id ]['override_description'],
694
- 'product_description' => '',
695
- 'optional' => $bundle_data[ $item_id ]['optional'],
696
- 'bundle_quantity' => $bundle_data[ $item_id ]['bundle_quantity'],
697
- 'bundle_quantity_max' => $bundle_data[ $item_id ]['bundle_quantity_max'],
698
- 'bundle_discount' => $bundle_data[ $item_id ]['bundle_discount'],
699
- 'single_product_visibility' => $bundle_data[ $item_id ]['single_product_visibility'],
700
- 'cart_visibility' => $bundle_data[ $item_id ]['cart_visibility'],
701
- 'order_visibility' => $bundle_data[ $item_id ]['order_visibility'],
702
- 'stock_status' => $bundle_data[ $item_id ]['stock_status'],
703
- 'max_stock' => $bundle_data[ $item_id ]['max_stock'],
704
- 'quantity_min' => $bundle_data[ $item_id ]['quantity_min'],
705
- 'quantity_max' => $bundle_data[ $item_id ]['quantity_max'],
706
- 'shipped_individually' => $bundle_data[ $item_id ]['shipped_individually'],
707
- 'priced_individually' => $bundle_data[ $item_id ]['priced_individually'],
708
  'single_product_price_visibility' => $bundle_data[ $item_id ]['single_product_price_visibility'],
709
- 'cart_price_visibility' => $bundle_data[ $item_id ]['cart_price_visibility'],
710
- 'order_price_visibility' => $bundle_data[ $item_id ]['order_price_visibility']
711
- );
712
  }
713
 
714
  $translated_bundle_data[ $translated_item_id ][ $field ] = $value['data'];
715
  }
716
-
717
  }
718
 
719
  $this->save_product_bundle_data( $translated_bundle_id, $translated_bundle_data );
@@ -722,17 +743,23 @@ class WCML_Product_Bundles {
722
 
723
  private function add_product_to_bundle( $product_id, $bundle_id, $item_id, $language ) {
724
 
725
- $menu_order = $this->wpdb->get_var( $this->wpdb->prepare( "
 
 
726
  SELECT menu_order FROM {$this->wpdb->prefix}woocommerce_bundled_items
727
  WHERE bundled_item_id=%d
728
- ", $item_id ) );
 
 
 
729
 
730
- $this->wpdb->insert( $this->wpdb->prefix . 'woocommerce_bundled_items',
731
- array(
 
732
  'product_id' => $product_id,
733
  'bundle_id' => $bundle_id,
734
  'menu_order' => $menu_order,
735
- )
736
  );
737
 
738
  $translated_item_id = $this->wpdb->insert_id;
@@ -748,41 +775,44 @@ class WCML_Product_Bundles {
748
  */
749
  public function get_price_custom_fields( $custom_fields ) {
750
 
751
- $custom_fields = array_merge( $custom_fields, array(
752
- '_wc_pb_base_regular_price',
753
- '_wc_pb_base_sale_price',
754
- '_wc_pb_base_price',
755
- '_wc_sw_max_price',
756
- '_wc_sw_max_regular_price'
757
- ) );
 
 
 
758
 
759
  return $custom_fields;
760
  }
761
 
762
 
763
- function update_bundles_custom_prices_values( $prices, $code ){
764
 
765
- if( isset( $_POST[ '_custom_regular_price' ][ $code ] ) ){
766
- $prices[ '_wc_pb_base_regular_price' ] = wc_format_decimal( $_POST[ '_custom_regular_price' ][ $code ] );
767
  }
768
 
769
- if( isset( $_POST[ '_custom_sale_price' ][ $code ] ) ){
770
- $prices[ '_wc_pb_base_sale_price' ] = wc_format_decimal( $_POST[ '_custom_sale_price' ][ $code ] );
771
  }
772
 
773
  return $prices;
774
 
775
  }
776
 
777
- function update_bundles_base_price( $post_id, $product_price, $custom_prices, $code ){
778
 
779
- if( isset ( $custom_prices[ '_wc_pb_base_regular_price' ] ) ){
780
- update_post_meta( $post_id, '_wc_pb_base_price_'.$code, $product_price );
781
  }
782
 
783
  }
784
 
785
- public function is_bundle_product( $product_id ){
786
 
787
  $product = wc_get_product( $product_id );
788
 
@@ -793,7 +823,7 @@ class WCML_Product_Bundles {
793
  return false;
794
  }
795
 
796
- // #wcml-2241
797
  public function upgrade_bundles_items_relationships() {
798
 
799
  $table_exists = $this->wpdb->get_var( "SHOW TABLES LIKE '{$this->wpdb->prefix}woocommerce_bundled_items'" );
@@ -814,17 +844,21 @@ class WCML_Product_Bundles {
814
  $translated_bundle_id = apply_filters( 'translate_object_id', $bundled_item->bundle_id, get_post_type( $bundled_item->bundle_id ), false, $lang['code'] );
815
  $translated_product_id = apply_filters( 'translate_object_id', $bundled_item->product_id, get_post_type( $bundled_item->product_id ), false, $lang['code'] );
816
 
817
- $translated_item_id = $this->wpdb->get_var( $this->wpdb->prepare(
818
- "SELECT bundled_item_id FROM {$this->wpdb->prefix}woocommerce_bundled_items WHERE product_id=%d AND bundle_id=%d",
819
- $translated_product_id, $translated_bundle_id
820
- ) );
 
 
 
821
 
822
- $this->wpdb->insert( $this->wpdb->prefix . 'woocommerce_bundled_itemmeta',
823
- array(
 
824
  'bundled_item_id' => $bundled_item->bundled_item_id,
825
  'meta_key' => 'translation_item_id_of_' . $lang['code'],
826
  'meta_value' => $translated_item_id,
827
- )
828
  );
829
  }
830
  }
@@ -847,11 +881,14 @@ class WCML_Product_Bundles {
847
  return $found_products;
848
  }
849
 
850
- public function delete_bundled_item_relationship( $bundle_item ){
851
 
852
- $this->wpdb->query( $this->wpdb->prepare(
853
- "DELETE FROM {$this->wpdb->prefix}woocommerce_bundled_itemmeta WHERE `meta_value` = %d AND `meta_key` LIKE 'translation_item_id_of_%'", $bundle_item->get_id()
854
- ) );
 
 
 
855
 
856
  }
857
 
30
  /**
31
  * WCML_Product_Bundles constructor.
32
  */
33
+ public function __construct( SitePress $sitepress, woocommerce_wpml $woocommerce_wpml, $product_bundles_items, wpdb $wpdb ) {
34
 
35
  $this->sitepress = $sitepress;
36
  $this->woocommerce_wpml = $woocommerce_wpml;
37
  $this->product_bundles_items = $product_bundles_items;
38
  $this->wpdb = $wpdb;
39
 
40
+ add_action( 'woocommerce_get_cart_item_from_session', [ $this, 'resync_bundle' ], 5, 3 );
41
+ add_filter( 'woocommerce_cart_loaded_from_session', [ $this, 'resync_bundle_clean' ], 10 );
42
+ add_action( 'wpml_translation_job_saved', [ $this, 'save_bundle_data_translation' ], 10, 3 );
43
 
44
  if ( is_admin() ) {
45
  $this->tp = new WPML_Element_Translation_Package();
46
 
47
+ add_filter(
48
+ 'wpml_tm_translation_job_data',
49
+ [
50
+ $this,
51
+ 'append_bundle_data_translation_package',
52
+ ],
53
+ 10,
54
+ 2
55
+ );
56
 
57
+ add_action( 'wcml_gui_additional_box_html', [ $this, 'custom_box_html' ], 10, 3 );
58
+ add_filter( 'wcml_gui_additional_box_data', [ $this, 'custom_box_html_data' ], 10, 4 );
59
 
60
+ add_action( 'wcml_after_duplicate_product_post_meta', [ $this, 'sync_bundled_ids' ], 10, 2 );
61
+ add_action( 'wcml_update_extra_fields', [ $this, 'bundle_update' ], 10, 4 );
62
 
63
+ add_action( 'wp_insert_post', [ $this, 'sync_product_bundle_meta_with_translations' ], 10 );
64
 
65
+ add_filter( 'woocommerce_json_search_found_products', [ $this, 'woocommerce_json_search_filter_found_products' ] );
66
 
67
+ add_action( 'woocommerce_before_delete_bundled_item', [ $this, 'delete_bundled_item_relationship' ] );
68
  }
69
 
70
  // product bundle using separate custom fields for prices.
71
  if ( wcml_is_multi_currency_on() ) {
72
+ add_filter( 'wcml_price_custom_fields_filtered', [ $this, 'get_price_custom_fields' ], 10, 2 );
73
+ add_filter( 'wcml_update_custom_prices_values', [ $this, 'update_bundles_custom_prices_values' ], 10, 2 );
74
+ add_filter( 'wcml_after_save_custom_prices', [ $this, 'update_bundles_base_price' ], 10, 4 );
75
  }
76
 
77
+ add_action( 'init', [ $this, 'upgrade_bundles_items_relationships' ] );
78
 
79
  }
80
 
81
  private function get_product_bundle_data( $bundle_id ) {
82
+ $product_bundle_data = [];
83
 
84
  $bundle_items = $this->product_bundles_items->get_items( $bundle_id );
85
  foreach ( $bundle_items as $key => $bundle_item ) {
107
  public function sync_product_bundle_meta( $bundle_id, $translated_bundle_id ) {
108
 
109
  $bundle_items = $this->product_bundles_items->get_items( $bundle_id );
110
+ $fields_to_sync = [
111
  'optional',
112
  'stock_status',
113
  'max_stock',
124
  'discount',
125
  'override_variations',
126
  'override_default_variation_attributes',
127
+ 'hide_filtered_variations',
128
+ ];
129
 
130
  $target_lang = $this->sitepress->get_language_for_element( $translated_bundle_id, 'post_product' );
131
+ $translated_item_ids = [];
132
  foreach ( $bundle_items as $item_id => $bundle_item ) {
133
 
134
  $item_meta = $this->product_bundles_items->get_item_data( $bundle_item );
145
  }
146
  }
147
 
148
+ if ( isset( $item_meta['allowed_variations'] ) ) {
149
+ if ( is_array( $item_meta['allowed_variations'] ) ) {
 
150
  $allowed_variations =
151
  $this->translate_allowed_variations( $item_meta['allowed_variations'], $target_lang );
152
  $this->product_bundles_items->update_item_meta( $translated_item, 'allowed_variations', $allowed_variations );
153
+ } else {
154
  $this->product_bundles_items->update_item_meta( $translated_item, 'allowed_variations', $item_meta['allowed_variations'] );
155
  }
156
  }
163
  $this->product_bundles_items->save_item_meta( $translated_item );
164
 
165
  }
 
166
  }
167
 
168
+ // Delete removed items.
169
  $translated_bundle_items = $this->product_bundles_items->get_items( $translated_bundle_id );
170
  foreach ( $translated_bundle_items as $item_id => $bundle_item ) {
171
  if ( ! in_array( $item_id, $translated_item_ids ) ) {
188
  $original_bundle_id = $translation->element_id;
189
  break;
190
  }
 
191
  }
192
 
193
  foreach ( $translations as $language => $translation ) {
195
  $this->sync_product_bundle_meta( $original_bundle_id, $translation->element_id );
196
  }
197
  }
 
198
  }
199
 
200
  }
201
 
202
  /**
203
+ * @param array $allowed_variations
204
  * @param string $lang
205
  *
206
  * @return array
216
  }
217
 
218
  /**
219
+ * @param array $original_default_variation_attributes
220
  * @param string $target_lang
221
+ * @param int $product_id
222
+ * @param int $translated_product_id
223
  *
224
  * @return array
225
  */
226
  public function translate_default_variation_attributes( $original_default_variation_attributes, $target_lang, $product_id, $translated_product_id ) {
227
+ $default_variation_attributes = [];
228
 
229
  if ( is_array( $original_default_variation_attributes ) ) {
230
  foreach ( $original_default_variation_attributes as $attribute_taxonomy => $attribute_slug ) {
234
  $translated_term = $this->woocommerce_wpml->terms->wcml_get_term_by_id( $translated_attribute_term_id, $attribute_taxonomy );
235
 
236
  $default_variation_attributes[ $attribute_taxonomy ] = $translated_term->slug;
237
+ } else {
238
  $default_variation_attributes[ $attribute_taxonomy ] = $this->woocommerce_wpml->attributes->get_custom_attr_translation( $product_id, $translated_product_id, $attribute_taxonomy, $attribute_slug );
239
  }
240
  }
245
 
246
  private function get_product_id_for_item_id( $item_id ) {
247
 
248
+ return $this->wpdb->get_var(
249
+ $this->wpdb->prepare(
250
+ "SELECT product_id FROM {$this->wpdb->prefix}woocommerce_bundled_items WHERE bundled_item_id=%d",
251
+ $item_id
252
+ )
253
+ );
254
  }
255
 
256
  /**
257
+ * @param array $item_id
258
  * @param string $language
259
  *
260
  * @return string
261
  */
262
  public function get_item_id_for_language( $item_id, $language ) {
263
 
264
+ return $this->wpdb->get_var(
265
+ $this->wpdb->prepare(
266
+ "SELECT meta_value FROM {$this->wpdb->prefix}woocommerce_bundled_itemmeta WHERE bundled_item_id=%d AND meta_key=%s",
267
+ $item_id,
268
+ 'translation_item_id_of_' . $language
269
+ )
270
+ );
271
 
272
  }
273
 
274
  /**
275
+ * @param int $original_item_id
276
+ * @param int $translated_item_id
277
  * @param string $language
278
  */
279
  public function set_translated_item_id_relationship( $original_item_id, $translated_item_id, $language ) {
280
 
281
+ $this->wpdb->insert(
282
+ $this->wpdb->prefix . 'woocommerce_bundled_itemmeta',
283
+ [
284
+ 'bundled_item_id' => $original_item_id,
285
+ 'meta_key' => 'translation_item_id_of_' . $language,
286
+ 'meta_value' => $translated_item_id,
287
+ ]
288
  );
289
 
290
  }
291
 
292
+ // Add Bundles Box to WCML Translation GUI.
293
  public function custom_box_html( $obj, $bundle_id, $data ) {
294
 
295
  $bundle_items = $this->product_bundles_items->get_items( $bundle_id );
345
  $bundles_section->add_field( $group );
346
  $flag = true;
347
  }
 
348
  }
 
349
  }
350
 
351
  if ( $flag ) {
379
  }
380
 
381
  if ( $bundle_data[ $item_id ]['override_title'] == 'yes' ) {
382
+ $data[ 'bundle_' . $product_id . '_title' ] = [ 'original' => $bundle_data[ $item_id ]['title'] ];
383
  if ( $translation && isset( $translated_bundle_data[ $translated_item_id ]['override_title'] ) ) {
384
  $data[ 'bundle_' . $product_id . '_title' ]['translation'] = $translated_bundle_data[ $translated_item_id ]['title'];
385
  } else {
388
  }
389
 
390
  if ( $bundle_data[ $item_id ]['override_description'] == 'yes' ) {
391
+ $data[ 'bundle_' . $product_id . '_desc' ] = [ 'original' => $bundle_data[ $item_id ]['description'] ];
392
  if ( $translation && isset( $translated_bundle_data[ $translated_item_id ]['override_description'] ) ) {
393
  $data[ 'bundle_' . $product_id . '_desc' ]['translation'] = $translated_bundle_data[ $translated_item_id ]['description'];
394
  } else {
408
 
409
  if ( $bundle_data ) {
410
 
411
+ $fields = [ 'title', 'description' ];
412
 
413
  foreach ( $bundle_data as $item_id => $product_data ) {
414
 
415
  $product_id = $this->get_product_id_for_item_id( $item_id );
416
  foreach ( $fields as $field ) {
417
  if ( $product_data[ 'override_' . $field ] == 'yes' && ! empty( $product_data[ $field ] ) ) {
418
+ $package['contents'][ 'product_bundles:' . $product_id . ':' . $item_id . ':' . $field ] = [
419
  'translate' => 1,
420
  'data' => $this->tp->encode_field_data( $product_data[ $field ], 'base64' ),
421
+ 'format' => 'base64',
422
+ ];
423
  }
424
  }
425
  }
430
 
431
  }
432
 
433
+ // Update Bundled products title and description after saving the translation.
434
  public function bundle_update( $bundle_id, $translated_bundle_id, $data, $lang ) {
435
 
436
  $bundle_data = $this->get_product_bundle_data( $bundle_id );
440
  return;
441
  }
442
 
443
+ $translate_bundled_item_ids = $this->wpdb->get_col(
444
+ $this->wpdb->prepare(
445
+ "SELECT product_id FROM {$this->wpdb->prefix}woocommerce_bundled_items WHERE bundle_id = %d",
446
+ $translated_bundle_id
447
+ )
448
+ );
449
 
450
  foreach ( $bundle_data as $item_id => $bundle_item_data ) {
451
 
456
 
457
  if ( ! in_array( $translated_product_id, $translate_bundled_item_ids ) ) {
458
 
459
+ $menu_order = $this->wpdb->get_var(
460
+ $this->wpdb->prepare(
461
+ "
462
  SELECT menu_order FROM {$this->wpdb->prefix}woocommerce_bundled_items
463
  WHERE bundle_id=%d AND product_id=%d
464
+ ",
465
+ $bundle_id,
466
+ $bundle_item_data['product_id']
467
+ )
468
+ );
469
 
470
+ $this->wpdb->insert(
471
+ $this->wpdb->prefix . 'woocommerce_bundled_items',
472
+ [
473
  'product_id' => $translated_product_id,
474
  'bundle_id' => $translated_bundle_id,
475
  'menu_order' => $menu_order,
476
+ ]
477
  );
478
 
479
  $translated_item_id = $this->wpdb->insert_id;
482
 
483
  $translated_item_id = $this->get_item_id_for_language( $item_id, $lang );
484
 
485
+ // $this->product_bundles_items->copy_item_data( $item_id, $translated_item_id );
 
486
  if ( isset( $data[ md5( 'bundle_' . $product_id . '_title' ) ] ) ) {
487
  $translated_bundle_data[ $translated_item_id ]['title'] = $data[ md5( 'bundle_' . $product_id . '_title' ) ];
488
  $translated_bundle_data[ $translated_item_id ]['override_title'] = $bundle_item_data['override_title'];
493
  $translated_bundle_data[ $translated_item_id ]['override_description'] = $bundle_item_data['override_description'];
494
  }
495
 
496
+ if ( isset( $bundle_item_data['allowed_variations'] ) ) {
497
+ if ( is_array( $bundle_item_data['allowed_variations'] ) ) {
498
  $translated_bundle_data[ $translated_item_id ]['allowed_variations'] =
499
  $this->translate_allowed_variations( $bundle_item_data['allowed_variations'], $lang );
500
+ } else {
501
  $translated_bundle_data[ $translated_item_id ]['allowed_variations'] =
502
  $bundle_item_data['allowed_variations'];
503
  }
 
504
  }
 
505
  }
 
506
  }
507
 
508
  $this->save_product_bundle_data( $translated_bundle_id, $translated_bundle_data );
513
  return $translated_bundle_data;
514
  }
515
 
516
+ // Sync product bundle data with translated values when the product is duplicated.
517
  public function sync_bundled_ids( $bundle_id, $translated_bundle_id ) {
518
 
519
  $bundle_data = $this->get_product_bundle_data( $bundle_id );
520
  if ( $bundle_data ) {
521
+ $lang = $this->sitepress->get_language_for_element( $translated_bundle_id, 'post_product' );
522
  $translated_bundle_data_before_update = $this->get_product_bundle_data( $translated_bundle_id );
523
 
524
  foreach ( $bundle_data as $item_id => $product_data ) {
530
 
531
  $translated_item_id = $this->get_item_id_for_language( $item_id, $lang );
532
  if ( ! $translated_item_id ) {
533
+ $menu_order = $this->wpdb->get_var(
534
+ $this->wpdb->prepare(
535
+ "
536
  SELECT menu_order FROM {$this->wpdb->prefix}woocommerce_bundled_items
537
  WHERE bundle_id=%d AND product_id=%d
538
+ ",
539
+ $bundle_id,
540
+ $product_id
541
+ )
542
+ );
543
 
544
+ $this->wpdb->insert(
545
+ $this->wpdb->prefix . 'woocommerce_bundled_items',
546
+ [
547
  'product_id' => $translated_product_id,
548
  'bundle_id' => $translated_bundle_id,
549
  'menu_order' => $menu_order,
550
+ ]
551
  );
552
  $translated_item_id = $this->wpdb->insert_id;
553
  $this->set_translated_item_id_relationship( $item_id, $translated_item_id, $lang );
554
  }
555
 
556
+ $translated_bundle_data[ $translated_item_id ] = $product_data;
557
  $translated_bundle_data[ $translated_item_id ]['product_id'] = $translated_product_id;
558
 
559
  if ( isset( $product_data['title'] ) ) {
560
+ if ( $product_data['override_title'] !== 'yes' ) {
561
  $translated_bundle_data[ $translated_item_id ]['title'] = get_the_title( $translated_product_id );
562
+ } else {
563
  $translated_bundle_data[ $translated_item_id ]['title'] = isset( $translated_bundle_data_before_update[ $translated_item_id ] ) ? $translated_bundle_data_before_update[ $translated_item_id ]['title'] : '';
564
  }
565
  }
566
 
567
  if ( isset( $product_data['title'] ) ) {
568
+ if ( $product_data['override_description'] !== 'yes' ) {
569
  $translated_bundle_data[ $translated_item_id ]['description'] = get_the_title( $translated_product_id );
570
+ } else {
571
  $translated_bundle_data[ $translated_item_id ]['description'] = isset( $translated_bundle_data_before_update[ $translated_item_id ] ) ? $translated_bundle_data_before_update[ $translated_item_id ]['description'] : '';
572
  }
573
  }
576
  $allowed_var = maybe_unserialize( $product_data['allowed_variations'] );
577
  $translated_bundle_data[ $translated_item_id ]['allowed_variations'] = maybe_unserialize( $translated_bundle_data[ $translated_item_id ]['allowed_variations'] );
578
  foreach ( $allowed_var as $key => $var_id ) {
579
+ $translated_var_id = apply_filters( 'translate_object_id', $var_id, get_post_type( $var_id ), true, $lang );
580
  $translated_bundle_data[ $translated_item_id ]['allowed_variations'][ $key ] = $translated_var_id;
581
  }
582
  $translated_bundle_data[ $translated_item_id ]['allowed_variations'] = maybe_serialize( $translated_bundle_data[ $translated_item_id ]['allowed_variations'] );
588
 
589
  $term_id = $this->woocommerce_wpml->terms->wcml_get_term_id_by_slug( $tax, $term_slug );
590
  if ( $term_id ) {
591
+ // Global Attribute.
592
+ $tr_def_id = apply_filters( 'translate_object_id', $term_id, $tax, true, $lang );
593
+ $tr_term = $this->woocommerce_wpml->terms->wcml_get_term_by_id( $tr_def_id, $tax );
594
  $translated_bundle_data[ $translated_item_id ]['bundle_defaults'][ $tax ] = $tr_term->slug;
595
  } else {
596
+ // Custom Attribute.
597
+ $args = [
598
  'post_type' => 'product_variation',
599
  'meta_key' => 'attribute_' . $tax,
600
  'meta_value' => $term_slug,
601
+ 'meta_compare' => '=',
602
+ ];
603
  $variationloop = new WP_Query( $args );
604
+ while ( $variationloop->have_posts() ) :
605
+ $variationloop->the_post();
606
+ $tr_var_id = apply_filters( 'translate_object_id', get_the_ID(), 'product_variation', true, $lang );
607
+ $tr_meta = get_post_meta( $tr_var_id, 'attribute_' . $tax, true );
608
  $translated_bundle_data[ $translated_item_id ]['bundle_defaults'][ $tax ] = $tr_meta;
609
  endwhile;
610
  }
611
  }
612
  $translated_bundle_data[ $translated_item_id ]['bundle_defaults'] = maybe_serialize( $translated_bundle_data[ $translated_item_id ]['bundle_defaults'] );
613
  }
 
614
  }
615
  }
616
 
631
  $cart_item['data'] = wc_get_product( $current_bundle_id );
632
  if ( isset( $cart_item['data']->bundle_data ) && is_array( $cart_item['data']->bundle_data ) ) {
633
  $new_bundled_item_ids = array_keys( $cart_item['data']->bundle_data );
634
+ $remapped_bundled_item_ids = [];
635
  foreach ( $old_bundled_item_ids as $old_item_id_index => $old_item_id ) {
636
  $remapped_bundled_item_ids[ $old_item_id ] = $new_bundled_item_ids[ $old_item_id_index ];
637
  }
638
  $cart_item['remapped_bundled_item_ids'] = $remapped_bundled_item_ids;
639
  if ( isset( $cart_item['stamp'] ) ) {
640
+ $new_stamp = [];
641
  foreach ( $cart_item['stamp'] as $bundled_item_id => $stamp_data ) {
642
  $new_stamp[ $remapped_bundled_item_ids[ $bundled_item_id ] ] = $stamp_data;
643
  }
658
  $remapped_bundled_item_ids = $bundle_cart_item['remapped_bundled_item_ids'];
659
  $cart_item['bundled_item_id'] = $remapped_bundled_item_ids[ $cart_item['bundled_item_id'] ];
660
  if ( isset( $cart_item['stamp'] ) ) {
661
+ $new_stamp = [];
662
  foreach ( $cart_item['stamp'] as $bundled_item_id => $stamp_data ) {
663
  $new_stamp[ $remapped_bundled_item_ids[ $bundled_item_id ] ] = $stamp_data;
664
  }
684
 
685
  if ( $this->is_bundle_product( $translated_bundle_id ) ) {
686
 
687
+ remove_action( 'wcml_after_duplicate_product_post_meta', [ $this, 'sync_bundled_ids' ], 10, 2 );
688
 
689
  $translated_bundle_data = $this->get_product_bundle_data( $translated_bundle_id );
690
 
700
  $item_id = $matches[2];
701
  $field = $matches[3];
702
 
 
703
  $translated_product_id = apply_filters( 'translate_object_id', $product_id, get_post_type( $product_id ), false, $job->language_code );
704
  $translated_item_id = $this->get_item_id_for_language( $item_id, $job->language_code );
705
  if ( empty( $translated_item_id ) ) {
707
  }
708
 
709
  if ( ! isset( $translated_bundle_data[ $translated_item_id ] ) ) {
710
+ $translated_bundle_data[ $translated_item_id ] = [
711
+ 'product_id' => $translated_product_id,
712
+ 'hide_thumbnail' => $bundle_data[ $item_id ]['hide_thumbnail'],
713
+ 'override_title' => $bundle_data[ $item_id ]['override_title'],
714
+ 'product_title' => '',
715
+ 'override_description' => $bundle_data[ $item_id ]['override_description'],
716
+ 'product_description' => '',
717
+ 'optional' => $bundle_data[ $item_id ]['optional'],
718
+ 'bundle_quantity' => $bundle_data[ $item_id ]['bundle_quantity'],
719
+ 'bundle_quantity_max' => $bundle_data[ $item_id ]['bundle_quantity_max'],
720
+ 'bundle_discount' => $bundle_data[ $item_id ]['bundle_discount'],
721
+ 'single_product_visibility' => $bundle_data[ $item_id ]['single_product_visibility'],
722
+ 'cart_visibility' => $bundle_data[ $item_id ]['cart_visibility'],
723
+ 'order_visibility' => $bundle_data[ $item_id ]['order_visibility'],
724
+ 'stock_status' => $bundle_data[ $item_id ]['stock_status'],
725
+ 'max_stock' => $bundle_data[ $item_id ]['max_stock'],
726
+ 'quantity_min' => $bundle_data[ $item_id ]['quantity_min'],
727
+ 'quantity_max' => $bundle_data[ $item_id ]['quantity_max'],
728
+ 'shipped_individually' => $bundle_data[ $item_id ]['shipped_individually'],
729
+ 'priced_individually' => $bundle_data[ $item_id ]['priced_individually'],
730
  'single_product_price_visibility' => $bundle_data[ $item_id ]['single_product_price_visibility'],
731
+ 'cart_price_visibility' => $bundle_data[ $item_id ]['cart_price_visibility'],
732
+ 'order_price_visibility' => $bundle_data[ $item_id ]['order_price_visibility'],
733
+ ];
734
  }
735
 
736
  $translated_bundle_data[ $translated_item_id ][ $field ] = $value['data'];
737
  }
 
738
  }
739
 
740
  $this->save_product_bundle_data( $translated_bundle_id, $translated_bundle_data );
743
 
744
  private function add_product_to_bundle( $product_id, $bundle_id, $item_id, $language ) {
745
 
746
+ $menu_order = $this->wpdb->get_var(
747
+ $this->wpdb->prepare(
748
+ "
749
  SELECT menu_order FROM {$this->wpdb->prefix}woocommerce_bundled_items
750
  WHERE bundled_item_id=%d
751
+ ",
752
+ $item_id
753
+ )
754
+ );
755
 
756
+ $this->wpdb->insert(
757
+ $this->wpdb->prefix . 'woocommerce_bundled_items',
758
+ [
759
  'product_id' => $product_id,
760
  'bundle_id' => $bundle_id,
761
  'menu_order' => $menu_order,
762
+ ]
763
  );
764
 
765
  $translated_item_id = $this->wpdb->insert_id;
775
  */
776
  public function get_price_custom_fields( $custom_fields ) {
777
 
778
+ $custom_fields = array_merge(
779
+ $custom_fields,
780
+ [
781
+ '_wc_pb_base_regular_price',
782
+ '_wc_pb_base_sale_price',
783
+ '_wc_pb_base_price',
784
+ '_wc_sw_max_price',
785
+ '_wc_sw_max_regular_price',
786
+ ]
787
+ );
788
 
789
  return $custom_fields;
790
  }
791
 
792
 
793
+ public function update_bundles_custom_prices_values( $prices, $code ) {
794
 
795
+ if ( isset( $_POST['_custom_regular_price'][ $code ] ) ) {
796
+ $prices['_wc_pb_base_regular_price'] = wc_format_decimal( $_POST['_custom_regular_price'][ $code ] );
797
  }
798
 
799
+ if ( isset( $_POST['_custom_sale_price'][ $code ] ) ) {
800
+ $prices['_wc_pb_base_sale_price'] = wc_format_decimal( $_POST['_custom_sale_price'][ $code ] );
801
  }
802
 
803
  return $prices;
804
 
805
  }
806
 
807
+ public function update_bundles_base_price( $post_id, $product_price, $custom_prices, $code ) {
808
 
809
+ if ( isset( $custom_prices['_wc_pb_base_regular_price'] ) ) {
810
+ update_post_meta( $post_id, '_wc_pb_base_price_' . $code, $product_price );
811
  }
812
 
813
  }
814
 
815
+ public function is_bundle_product( $product_id ) {
816
 
817
  $product = wc_get_product( $product_id );
818
 
823
  return false;
824
  }
825
 
826
+ // #wcml-2241.
827
  public function upgrade_bundles_items_relationships() {
828
 
829
  $table_exists = $this->wpdb->get_var( "SHOW TABLES LIKE '{$this->wpdb->prefix}woocommerce_bundled_items'" );
844
  $translated_bundle_id = apply_filters( 'translate_object_id', $bundled_item->bundle_id, get_post_type( $bundled_item->bundle_id ), false, $lang['code'] );
845
  $translated_product_id = apply_filters( 'translate_object_id', $bundled_item->product_id, get_post_type( $bundled_item->product_id ), false, $lang['code'] );
846
 
847
+ $translated_item_id = $this->wpdb->get_var(
848
+ $this->wpdb->prepare(
849
+ "SELECT bundled_item_id FROM {$this->wpdb->prefix}woocommerce_bundled_items WHERE product_id=%d AND bundle_id=%d",
850
+ $translated_product_id,
851
+ $translated_bundle_id
852
+ )
853
+ );
854
 
855
+ $this->wpdb->insert(
856
+ $this->wpdb->prefix . 'woocommerce_bundled_itemmeta',
857
+ [
858
  'bundled_item_id' => $bundled_item->bundled_item_id,
859
  'meta_key' => 'translation_item_id_of_' . $lang['code'],
860
  'meta_value' => $translated_item_id,
861
+ ]
862
  );
863
  }
864
  }
881
  return $found_products;
882
  }
883
 
884
+ public function delete_bundled_item_relationship( $bundle_item ) {
885
 
886
+ $this->wpdb->query(
887
+ $this->wpdb->prepare(
888
+ "DELETE FROM {$this->wpdb->prefix}woocommerce_bundled_itemmeta WHERE `meta_value` = %d AND `meta_key` LIKE 'translation_item_id_of_%'",
889
+ $bundle_item->get_id()
890
+ )
891
+ );
892
 
893
  }
894
 
compatibility/class-wcml-relevanssi.php CHANGED
@@ -4,7 +4,7 @@ class WCML_Relevanssi {
4
 
5
  public function add_hooks() {
6
  // Re-index translated product to add missing terms (wcml-2282)
7
- add_action( 'wcml_update_extra_fields', array( $this, 'index_product' ), 10, 4 );
8
  }
9
 
10
  public function index_product( $product_id, $tr_product_id, $translations, $target_language ) {
@@ -14,4 +14,4 @@ class WCML_Relevanssi {
14
  do_action( 'wpml_switch_language', $current_language );
15
  }
16
 
17
- }
4
 
5
  public function add_hooks() {
6
  // Re-index translated product to add missing terms (wcml-2282)
7
+ add_action( 'wcml_update_extra_fields', [ $this, 'index_product' ], 10, 4 );
8
  }
9
 
10
  public function index_product( $product_id, $tr_product_id, $translations, $target_language ) {
14
  do_action( 'wpml_switch_language', $current_language );
15
  }
16
 
17
+ }
compatibility/class-wcml-sensei.php CHANGED
@@ -12,8 +12,8 @@ class WCML_Sensei {
12
  /**
13
  * WCML_Sensei constructor.
14
  *
15
- * @param Sitepress $sitepress
16
- * @param wpdb $wpdb
17
  * @param WPML_Custom_Columns $custom_columns
18
  */
19
  public function __construct( SitePress $sitepress, wpdb $wpdb, WPML_Custom_Columns $custom_columns ) {
@@ -24,19 +24,19 @@ class WCML_Sensei {
24
 
25
  public function add_hooks() {
26
 
27
- add_filter( 'manage_edit-lesson_columns', array( $this->custom_columns, 'add_posts_management_column' ) );
28
- add_filter( 'manage_edit-course_columns', array( $this->custom_columns, 'add_posts_management_column' ) );
29
- add_filter( 'manage_edit-question_columns', array( $this->custom_columns, 'add_posts_management_column' ) );
30
 
31
- add_action( 'save_post', array( $this, 'save_post_actions' ), 100, 2 );
32
- add_action( 'sensei_log_activity_after', array( $this, 'log_activity_after' ), 10, 3 );
33
- add_filter( 'sensei_bought_product_id', array( $this, 'filter_bought_product_id' ), 10, 2 );
34
- add_action( 'delete_comment', array( $this, 'delete_user_activity' ) );
35
 
36
- add_action( 'pre_get_comments', array( $this, 'pre_get_comments' ) );
37
 
38
  if ( $this->is_sensei_admin_without_language_switcher() ) {
39
- remove_action( 'wp_before_admin_bar_render', array( $this->sitepress, 'admin_language_switcher' ) );
40
  }
41
  }
42
 
@@ -52,7 +52,7 @@ class WCML_Sensei {
52
  global $sitepress;
53
 
54
  // skip not related post types
55
- if ( ! in_array( $post->post_type, array( 'lesson', 'course', 'quiz' ) ) ) {
56
  return;
57
  }
58
  // skip auto-drafts
@@ -68,7 +68,6 @@ class WCML_Sensei {
68
  $this->save_post_actions( $_POST['ID'], get_post( $_POST['ID'] ) );
69
  }
70
 
71
-
72
  // sync fields from original
73
  $trid = $sitepress->get_element_trid( $post_id, 'post_' . $post->post_type );
74
  $translations = $sitepress->get_element_translations( $trid, 'post_' . $post->post_type );
@@ -96,13 +95,13 @@ class WCML_Sensei {
96
  }
97
 
98
 
99
- function sync_custom_fields( $original_post_id, $post_id, $post_type ) {
100
  global $sitepress;
101
 
102
  $language = $sitepress->get_language_for_element( $post_id, 'post_' . $post_type );
103
  if ( $post_type == 'quiz' ) {
104
 
105
- //sync quiz lesson
106
  $lesson_id = get_post_meta( $original_post_id, '_quiz_lesson', true );
107
 
108
  if ( $lesson_id ) {
@@ -114,9 +113,8 @@ class WCML_Sensei {
114
  } else {
115
  delete_post_meta( $post_id, '_quiz_lesson' );
116
  }
117
-
118
  } elseif ( $post_type == 'lesson' ) {
119
- //sync lesson course
120
  $course_id = get_post_meta( $original_post_id, '_lesson_course', true );
121
 
122
  if ( $course_id ) {
@@ -129,7 +127,7 @@ class WCML_Sensei {
129
  delete_post_meta( $post_id, '_lesson_course' );
130
  }
131
 
132
- //sync lesson prerequisite
133
  $lesson_id = get_post_meta( $original_post_id, '_lesson_prerequisite', true );
134
 
135
  if ( $lesson_id ) {
@@ -141,10 +139,9 @@ class WCML_Sensei {
141
  } else {
142
  delete_post_meta( $post_id, '_lesson_prerequisite' );
143
  }
144
-
145
  } else {
146
 
147
- //sync course woocommerce_product
148
  $product_id = get_post_meta( $original_post_id, '_course_woocommerce_product', true );
149
 
150
  if ( $product_id ) {
@@ -157,7 +154,7 @@ class WCML_Sensei {
157
  delete_post_meta( $post_id, '_course_woocommerce_product' );
158
  }
159
 
160
- //sync course prerequisite
161
  $course_id = get_post_meta( $original_post_id, '_course_prerequisite', true );
162
 
163
  if ( $course_id ) {
@@ -169,12 +166,11 @@ class WCML_Sensei {
169
  } else {
170
  delete_post_meta( $post_id, '_course_prerequisite' );
171
  }
172
-
173
  }
174
 
175
  }
176
 
177
- function log_activity_after( $args, $data, $comment_id = false ) {
178
  global $sitepress;
179
 
180
  if ( ! $comment_id ) {
@@ -201,12 +197,11 @@ class WCML_Sensei {
201
  $sitepress->set_element_language_details( $tr_comment_id, 'comment', $trid, $translation->language_code );
202
  }
203
  }
204
-
205
  }
206
 
207
  }
208
 
209
- function filter_bought_product_id( $product_id, $order ) {
210
 
211
  $order_id = method_exists( 'WC_Order', 'get_id' ) ? $order->get_id() : $order->id;
212
  $order_language = get_post_meta( $order_id, 'wpml_language', true );
@@ -220,34 +215,32 @@ class WCML_Sensei {
220
  }
221
  }
222
 
223
- function delete_user_activity( $comment_id ) {
224
  global $sitepress;
225
 
226
  $comment_type = get_comment_type( $comment_id );
227
 
228
- if ( strstr( $comment_type, "sensei" ) ) {
229
 
230
  $trid = $sitepress->get_element_trid( $comment_id, 'comment' );
231
  $translations = $sitepress->get_element_translations( $trid, 'comment' );
232
 
233
- remove_action( 'delete_comment', array( $this, 'delete_user_activity' ) );
234
  foreach ( $translations as $translation ) {
235
  if ( $comment_id != $translation->element_id ) {
236
  wp_delete_comment( $translation->element_id, true );
237
  }
238
  }
239
-
240
  }
241
 
242
-
243
  }
244
 
245
- function pre_get_comments( $obj ) {
246
  global $sitepress;
247
 
248
  if ( $obj->query_vars['type'] == 'sensei_course_start' ) {
249
 
250
- remove_filter( 'comments_clauses', array( $sitepress, 'comments_clauses' ), 10, 2 );
251
 
252
  }
253
 
12
  /**
13
  * WCML_Sensei constructor.
14
  *
15
+ * @param Sitepress $sitepress
16
+ * @param wpdb $wpdb
17
  * @param WPML_Custom_Columns $custom_columns
18
  */
19
  public function __construct( SitePress $sitepress, wpdb $wpdb, WPML_Custom_Columns $custom_columns ) {
24
 
25
  public function add_hooks() {
26
 
27
+ add_filter( 'manage_edit-lesson_columns', [ $this->custom_columns, 'add_posts_management_column' ] );
28
+ add_filter( 'manage_edit-course_columns', [ $this->custom_columns, 'add_posts_management_column' ] );
29
+ add_filter( 'manage_edit-question_columns', [ $this->custom_columns, 'add_posts_management_column' ] );
30
 
31
+ add_action( 'save_post', [ $this, 'save_post_actions' ], 100, 2 );
32
+ add_action( 'sensei_log_activity_after', [ $this, 'log_activity_after' ], 10, 3 );
33
+ add_filter( 'sensei_bought_product_id', [ $this, 'filter_bought_product_id' ], 10, 2 );
34
+ add_action( 'delete_comment', [ $this, 'delete_user_activity' ] );
35
 
36
+ add_action( 'pre_get_comments', [ $this, 'pre_get_comments' ] );
37
 
38
  if ( $this->is_sensei_admin_without_language_switcher() ) {
39
+ remove_action( 'wp_before_admin_bar_render', [ $this->sitepress, 'admin_language_switcher' ] );
40
  }
41
  }
42
 
52
  global $sitepress;
53
 
54
  // skip not related post types
55
+ if ( ! in_array( $post->post_type, [ 'lesson', 'course', 'quiz' ] ) ) {
56
  return;
57
  }
58
  // skip auto-drafts
68
  $this->save_post_actions( $_POST['ID'], get_post( $_POST['ID'] ) );
69
  }
70
 
 
71
  // sync fields from original
72
  $trid = $sitepress->get_element_trid( $post_id, 'post_' . $post->post_type );
73
  $translations = $sitepress->get_element_translations( $trid, 'post_' . $post->post_type );
95
  }
96
 
97
 
98
+ public function sync_custom_fields( $original_post_id, $post_id, $post_type ) {
99
  global $sitepress;
100
 
101
  $language = $sitepress->get_language_for_element( $post_id, 'post_' . $post_type );
102
  if ( $post_type == 'quiz' ) {
103
 
104
+ // sync quiz lesson
105
  $lesson_id = get_post_meta( $original_post_id, '_quiz_lesson', true );
106
 
107
  if ( $lesson_id ) {
113
  } else {
114
  delete_post_meta( $post_id, '_quiz_lesson' );
115
  }
 
116
  } elseif ( $post_type == 'lesson' ) {
117
+ // sync lesson course
118
  $course_id = get_post_meta( $original_post_id, '_lesson_course', true );
119
 
120
  if ( $course_id ) {
127
  delete_post_meta( $post_id, '_lesson_course' );
128
  }
129
 
130
+ // sync lesson prerequisite
131
  $lesson_id = get_post_meta( $original_post_id, '_lesson_prerequisite', true );
132
 
133
  if ( $lesson_id ) {
139
  } else {
140
  delete_post_meta( $post_id, '_lesson_prerequisite' );
141
  }
 
142
  } else {
143
 
144
+ // sync course woocommerce_product
145
  $product_id = get_post_meta( $original_post_id, '_course_woocommerce_product', true );
146
 
147
  if ( $product_id ) {
154
  delete_post_meta( $post_id, '_course_woocommerce_product' );
155
  }
156
 
157
+ // sync course prerequisite
158
  $course_id = get_post_meta( $original_post_id, '_course_prerequisite', true );
159
 
160
  if ( $course_id ) {
166
  } else {
167
  delete_post_meta( $post_id, '_course_prerequisite' );
168
  }
 
169
  }
170
 
171
  }
172
 
173
+ public function log_activity_after( $args, $data, $comment_id = false ) {
174
  global $sitepress;
175
 
176
  if ( ! $comment_id ) {
197
  $sitepress->set_element_language_details( $tr_comment_id, 'comment', $trid, $translation->language_code );
198
  }
199
  }
 
200
  }
201
 
202
  }
203
 
204
+ public function filter_bought_product_id( $product_id, $order ) {
205
 
206
  $order_id = method_exists( 'WC_Order', 'get_id' ) ? $order->get_id() : $order->id;
207
  $order_language = get_post_meta( $order_id, 'wpml_language', true );
215
  }
216
  }
217
 
218
+ public function delete_user_activity( $comment_id ) {
219
  global $sitepress;
220
 
221
  $comment_type = get_comment_type( $comment_id );
222
 
223
+ if ( strstr( $comment_type, 'sensei' ) ) {
224
 
225
  $trid = $sitepress->get_element_trid( $comment_id, 'comment' );
226
  $translations = $sitepress->get_element_translations( $trid, 'comment' );
227
 
228
+ remove_action( 'delete_comment', [ $this, 'delete_user_activity' ] );
229
  foreach ( $translations as $translation ) {
230
  if ( $comment_id != $translation->element_id ) {
231
  wp_delete_comment( $translation->element_id, true );
232
  }
233
  }
 
234
  }
235
 
 
236
  }
237
 
238
+ public function pre_get_comments( $obj ) {
239
  global $sitepress;
240
 
241
  if ( $obj->query_vars['type'] == 'sensei_course_start' ) {
242
 
243
+ remove_filter( 'comments_clauses', [ $sitepress, 'comments_clauses' ], 10, 2 );
244
 
245
  }
246
 
compatibility/class-wcml-tab-manager.php CHANGED
@@ -32,13 +32,13 @@ class WCML_Tab_Manager {
32
  /**
33
  * WCML_Tab_Manager constructor.
34
  *
35
- * @param SitePress $sitepress
36
- * @param WooCommerce $woocommerce
37
- * @param woocommerce_wpml $woocommerce_wpml
38
- * @param wpdb $wpdb
39
  * @param WPML_Element_Translation_Package $tp
40
  */
41
- function __construct( SitePress $sitepress, WooCommerce $woocommerce, woocommerce_wpml $woocommerce_wpml, wpdb $wpdb, WPML_Element_Translation_Package $tp ) {
42
  $this->sitepress = $sitepress;
43
  $this->woocommerce = $woocommerce;
44
  $this->woocommerce_wpml = $woocommerce_wpml;
@@ -46,32 +46,33 @@ class WCML_Tab_Manager {
46
  $this->tp = $tp;
47
  }
48
 
49
- public function add_hooks(){
50
- add_action( 'wcml_update_extra_fields', array( $this, 'sync_tabs' ), 10, 4 );
51
- add_action( 'wcml_gui_additional_box_html', array( $this, 'custom_box_html' ), 10, 3 );
52
- add_filter( 'wcml_gui_additional_box_data', array( $this, 'custom_box_html_data' ), 10, 4 );
53
- add_filter( 'wpml_duplicate_custom_fields_exceptions', array( $this, 'duplicate_custom_fields_exceptions' ) );
54
- add_action( 'wcml_after_duplicate_product', array( $this, 'duplicate_product_tabs' ) , 10, 2 );
55
 
56
- add_filter( 'wc_tab_manager_tab_id', array( $this, 'wc_tab_manager_tab_id' ), 10, 1 );
57
- add_filter( 'option_wpml_config_files_arr', array( $this, 'make__product_tabs_not_translatable_by_default' ), 0 );
 
 
58
 
59
  if ( is_admin() ) {
60
 
61
- add_action( 'save_post', array( $this, 'force_set_language_information_on_product_tabs' ), 10, 2 );
62
- add_action( 'save_post', array( $this, 'sync_product_tabs' ), 10, 2 );
63
 
64
- add_filter( 'wpml_tm_translation_job_data', array( $this, 'append_custom_tabs_to_translation_package' ), 10, 2 );
65
- add_action( 'wpml_translation_job_saved', array( $this, 'save_custom_tabs_translation' ), 10, 3 );
66
- add_action( 'woocommerce_product_data_panels', array( $this, 'show_pointer_info' ) );
67
 
68
- add_filter( 'wcml_do_not_display_custom_fields_for_product', array( $this, 'replace_tm_editor_custom_fields_with_own_sections' ) );
69
 
70
- add_filter( 'wpml_duplicate_custom_fields_exceptions', array( $this, 'duplicate_categories_exception' ) );
71
- add_action( 'wpml_after_copy_custom_field', array( $this, 'translate_categories' ), 10, 3 );
72
 
73
- }else{
74
- add_filter( 'option_wc_tab_manager_default_layout', array( $this, 'filter_default_layout' ) );
75
  }
76
 
77
  }
@@ -81,11 +82,12 @@ class WCML_Tab_Manager {
81
  *
82
  * @return mixed
83
  */
84
- function make__product_tabs_not_translatable_by_default( $wpml_config_array ) {
85
 
86
  if ( isset( $wpml_config_array->plugins['WooCommerce Tab Manager'] ) ) {
87
  $wpml_config_array->plugins['WooCommerce Tab Manager'] =
88
- str_replace( '<custom-field action="translate">_product_tabs</custom-field>',
 
89
  '<custom-field action="nothing">_product_tabs</custom-field>',
90
  $wpml_config_array->plugins['WooCommerce Tab Manager']
91
  );
@@ -102,25 +104,25 @@ class WCML_Tab_Manager {
102
  *
103
  * @return bool
104
  */
105
- function sync_tabs( $original_product_id, $trnsl_product_id, $data, $lang ) {
106
- //check if "duplicate" product
107
- if ( ( isset( $_POST['icl_ajx_action'] ) && ( 'make_duplicates' === $_POST['icl_ajx_action'] ) ) || ( get_post_meta( $trnsl_product_id , '_icl_lang_duplicate_of', true ) ) ) {
108
  $this->duplicate_tabs( $original_product_id, $trnsl_product_id, $lang );
109
  }
110
 
111
  $orig_prod_tabs = $this->get_product_tabs( $original_product_id );
112
 
113
  if ( $orig_prod_tabs ) {
114
- $trnsl_product_tabs = array();
115
- $i = 0;
116
  foreach ( $orig_prod_tabs as $key => $orig_prod_tab ) {
117
  switch ( $orig_prod_tab['type'] ) {
118
  case 'core':
119
- $default_language = $this->woocommerce_wpml->products->get_original_product_language( $original_product_id );
120
- $current_language = $this->sitepress->get_current_language();
121
  $trnsl_product_tabs[ $key ] = $orig_prod_tabs[ $key ];
122
- $title = isset( $data[ md5( 'coretab_'.$orig_prod_tab['id'].'_title' ) ] ) ? $data[ md5( 'coretab_'.$orig_prod_tab['id'].'_title' ) ] : '';
123
- $heading = isset( $data[ md5( 'coretab_'.$orig_prod_tab['id'].'_heading' ) ] ) ? $data[ md5( 'coretab_'.$orig_prod_tab['id'].'_heading' ) ] : '';
124
 
125
  if ( $default_language !== $lang ) {
126
 
@@ -139,18 +141,18 @@ class WCML_Tab_Manager {
139
  $this->refresh_text_domain( $current_language );
140
  }
141
 
142
- $trnsl_product_tabs[ $key ]['title'] = $title;
143
  $trnsl_product_tabs[ $key ]['heading'] = $heading;
144
  break;
145
  case 'global':
146
  $trnsl_product_tabs = $this->set_global_tab( $orig_prod_tab, $trnsl_product_tabs, $lang );
147
  break;
148
  case 'product':
149
- $tab_id = false;
150
- $title_key = md5( 'tab_' . $orig_prod_tab['position'] . '_title' );
151
  $heading_key = md5( 'tab_' . $orig_prod_tab['position'] . '_heading' );
152
- $title = isset( $data[ $title_key ] ) ? sanitize_text_field( $data[ $title_key ] ) : '';
153
- $content = isset( $data[ $heading_key ] ) ? wp_kses_post( $data[ $heading_key ] ) : '';
154
 
155
  $trnsl_product_tabs = $this->set_product_tab( $orig_prod_tab, $trnsl_product_tabs, $lang, $trnsl_product_id, $tab_id, $title, $content );
156
 
@@ -171,9 +173,9 @@ class WCML_Tab_Manager {
171
  * @param $trnsl_product_id
172
  * @param $lang
173
  */
174
- function duplicate_tabs( $original_product_id, $trnsl_product_id, $lang ) {
175
  $orig_prod_tabs = maybe_unserialize( get_post_meta( $original_product_id, '_product_tabs', true ) );
176
- $prod_tabs = array();
177
  foreach ( $orig_prod_tabs as $key => $orig_prod_tab ) {
178
  switch ( $orig_prod_tab['type'] ) {
179
  case 'core':
@@ -185,14 +187,14 @@ class WCML_Tab_Manager {
185
  }
186
  $orig_lang = $this->sitepress->get_language_for_element( $original_product_id, 'post_product' );
187
  $this->refresh_text_domain( $orig_lang );
188
- break;
189
  case 'global':
190
  $prod_tabs = $this->set_global_tab( $orig_prod_tab, $prod_tabs, $lang );
191
- break;
192
  case 'product':
193
  $original_tab = get_post( $orig_prod_tab['id'] );
194
- $prod_tabs = $this->set_product_tab( $orig_prod_tab, $prod_tabs, $lang, $trnsl_product_id, false, $original_tab->post_title , $original_tab->post_content );
195
- break;
196
  }
197
  }
198
 
@@ -202,7 +204,7 @@ class WCML_Tab_Manager {
202
  /**
203
  * @param $lang
204
  */
205
- function refresh_text_domain( $lang ) {
206
  $this->sitepress->switch_lang( $lang );
207
  }
208
 
@@ -213,14 +215,14 @@ class WCML_Tab_Manager {
213
  *
214
  * @return mixed
215
  */
216
- function set_global_tab( $orig_prod_tab, $trnsl_product_tabs, $lang ) {
217
  $tr_tab_id = apply_filters( 'translate_object_id', $orig_prod_tab['id'], 'wc_product_tab', true, $lang );
218
- $trnsl_product_tabs[ $orig_prod_tab['type'].'_tab_'. $tr_tab_id ] = array(
219
  'position' => $orig_prod_tab['position'],
220
  'type' => $orig_prod_tab['type'],
221
  'id' => $tr_tab_id,
222
  'name' => get_post( $tr_tab_id )->post_name,
223
- );
224
  return $trnsl_product_tabs;
225
  }
226
 
@@ -235,7 +237,7 @@ class WCML_Tab_Manager {
235
  *
236
  * @return mixed
237
  */
238
- function set_product_tab( $orig_prod_tab, $trnsl_product_tabs, $lang, $trnsl_product_id, $tab_id, $title, $content ) {
239
  if ( ! $tab_id ) {
240
  $tr_tab_id = apply_filters( 'translate_object_id', $orig_prod_tab['id'], 'wc_product_tab', false, $lang );
241
 
@@ -245,14 +247,14 @@ class WCML_Tab_Manager {
245
  }
246
 
247
  if ( $tab_id ) {
248
- //update existing tab
249
- $args = array();
250
- $args['post_title'] = $title;
251
  $args['post_content'] = $content;
252
- $this->wpdb->update( $this->wpdb->posts, $args, array( 'ID' => $tab_id ) );
253
  } else {
254
- //tab not exist creating new
255
- $args = array();
256
  $args['post_title'] = $title;
257
  $args['post_content'] = $content;
258
  $args['post_author'] = get_current_user_id();
@@ -262,7 +264,7 @@ class WCML_Tab_Manager {
262
  $args['post_status'] = 'publish';
263
  $this->wpdb->insert( $this->wpdb->posts, $args );
264
 
265
- $tab_id = $this->wpdb->insert_id;
266
  $tab_trid = $this->sitepress->get_element_trid( $orig_prod_tab['id'], 'post_wc_product_tab' );
267
  if ( ! $tab_trid ) {
268
  $this->sitepress->set_element_language_details( $orig_prod_tab['id'], 'post_wc_product_tab', false, $this->sitepress->get_default_language() );
@@ -271,19 +273,18 @@ class WCML_Tab_Manager {
271
  $this->sitepress->set_element_language_details( $tab_id, 'post_wc_product_tab', $tab_trid, $lang );
272
  }
273
 
274
-
275
  if ( empty( $title ) || strlen( $title ) != strlen( utf8_encode( $title ) ) ) {
276
- $tab_name = "product-tab-". $tab_id;
277
  } else {
278
  $tab_name = sanitize_title( $title );
279
  }
280
 
281
- $trnsl_product_tabs[ $orig_prod_tab['type'] . '_tab_' . $tab_id ] = array(
282
  'position' => $orig_prod_tab['position'],
283
  'type' => $orig_prod_tab['type'],
284
  'id' => $tab_id,
285
  'name' => $tab_name,
286
- );
287
 
288
  return $trnsl_product_tabs;
289
  }
@@ -293,7 +294,7 @@ class WCML_Tab_Manager {
293
  *
294
  * @return array
295
  */
296
- function duplicate_custom_fields_exceptions( $exceptions ) {
297
  $exceptions[] = '_product_tabs';
298
  return $exceptions;
299
  }
@@ -305,7 +306,7 @@ class WCML_Tab_Manager {
305
  *
306
  * @return bool
307
  */
308
- function custom_box_html( $obj, $product_id, $data ) {
309
 
310
  if ( 'yes' !== get_post_meta( $product_id, '_override_tab_layout', true ) ) {
311
  return false;
@@ -318,28 +319,28 @@ class WCML_Tab_Manager {
318
 
319
  $tabs_section = new WPML_Editor_UI_Field_Section( __( 'Product tabs', 'woocommerce-multilingual' ) );
320
 
321
- $keys = array_keys( $orig_prod_tabs );
322
  $last_key = end( $keys );
323
- $divider = true;
324
 
325
  foreach ( $orig_prod_tabs as $key => $prod_tab ) {
326
  if ( $key === $last_key ) {
327
  $divider = false;
328
  }
329
 
330
- if ( in_array( $prod_tab['type'], array( 'product', 'core' ) ) ) {
331
  if ( 'core' === $prod_tab['type'] ) {
332
- $group = new WPML_Editor_UI_Field_Group( $prod_tab['title'], $divider );
333
- $tab_field = new WPML_Editor_UI_Single_Line_Field( 'coretab_' . $prod_tab['id'].'_title', __( 'Title', 'woocommerce-multilingual' ), $data, false );
334
  $group->add_field( $tab_field );
335
- $tab_field = new WPML_Editor_UI_Single_Line_Field( 'coretab_' . $prod_tab['id'].'_heading' , __( 'Heading', 'woocommerce-multilingual' ), $data, false );
336
  $group->add_field( $tab_field );
337
  $tabs_section->add_field( $group );
338
  } else {
339
- $group = new WPML_Editor_UI_Field_Group( ucfirst( str_replace( '-', ' ', $prod_tab['name'] ) ), $divider );
340
- $tab_field = new WPML_Editor_UI_Single_Line_Field( 'tab_'.$prod_tab['position'].'_title', __( 'Title', 'woocommerce-multilingual' ), $data, false );
341
  $group->add_field( $tab_field );
342
- $tab_field = new WCML_Editor_UI_WYSIWYG_Field( 'tab_'.$prod_tab['position'].'_heading' , null, $data, false );
343
  $group->add_field( $tab_field );
344
  $tabs_section->add_field( $group );
345
  }
@@ -358,7 +359,7 @@ class WCML_Tab_Manager {
358
  *
359
  * @return mixed
360
  */
361
- function custom_box_html_data( $data, $product_id, $translation, $lang ) {
362
 
363
  $orig_prod_tabs = $this->get_product_tabs( $product_id );
364
 
@@ -367,13 +368,13 @@ class WCML_Tab_Manager {
367
  }
368
 
369
  foreach ( $orig_prod_tabs as $key => $prod_tab ) {
370
- if ( in_array( $prod_tab['type'], array( 'product', 'core' ) ) ) {
371
  if ( 'core' === $prod_tab['type'] ) {
372
- $data[ 'coretab_' . $prod_tab['id'] . '_title' ] = array( 'original' => $prod_tab['title'] );
373
- $data[ 'coretab_' . $prod_tab['id'] . '_heading' ] = array( 'original' => isset( $prod_tab['heading'] ) ? $prod_tab['heading'] : '' );
374
  } else {
375
- $data[ 'tab_' . $prod_tab['position'] . '_title' ] = array( 'original' => get_the_title( $prod_tab['id'] ) );
376
- $data[ 'tab_' . $prod_tab['position'] . '_heading' ] = array( 'original' => get_post( $prod_tab['id'] )->post_content );
377
  }
378
  }
379
  }
@@ -381,19 +382,18 @@ class WCML_Tab_Manager {
381
  if ( $translation ) {
382
  $tr_prod_tabs = $this->get_product_tabs( $translation->ID );
383
 
384
-
385
  if ( ! is_array( $tr_prod_tabs ) ) {
386
  return $data; // __('Please update original product','woocommerce-multilingual');
387
  }
388
 
389
  foreach ( $tr_prod_tabs as $key => $prod_tab ) {
390
- if ( in_array( $prod_tab['type'], array( 'product', 'core' ) ) ) {
391
  if ( 'core' === $prod_tab['type'] ) {
392
- $data[ 'coretab_' . $prod_tab['id'] . '_title' ]['translation'] = $prod_tab['title'];
393
  $data[ 'coretab_' . $prod_tab['id'] . '_heading' ]['translation'] = isset( $prod_tab['heading'] ) ? $prod_tab['heading'] : '';
394
  } else {
395
- $data[ 'tab_'.$prod_tab['position'].'_title' ]['translation'] = get_the_title( $prod_tab['id'] );
396
- $data[ 'tab_'.$prod_tab['position'].'_heading' ]['translation'] = get_post( $prod_tab['id'] )->post_content;
397
  }
398
  }
399
  }
@@ -408,7 +408,7 @@ class WCML_Tab_Manager {
408
  }
409
 
410
  if ( ! isset( $prod_tab['heading'] ) ) {
411
- $data[ 'coretab_'.$prod_tab['id'].'_heading' ]['translation'] = '';
412
  } else {
413
  $heading = __( $prod_tab['heading'], 'woocommerce' );
414
  if ( $prod_tab['heading'] !== $heading ) {
@@ -429,7 +429,7 @@ class WCML_Tab_Manager {
429
  * @param $new_id
430
  * @param $original_post
431
  */
432
- function duplicate_product_tabs( $new_id, $original_post ) {
433
  if ( function_exists( 'wc_tab_manager_duplicate_product' ) ) {
434
  wc_tab_manager_duplicate_product( $new_id, $original_post );
435
  }
@@ -439,7 +439,7 @@ class WCML_Tab_Manager {
439
  * @param $post_id
440
  * @param $post
441
  */
442
- function force_set_language_information_on_product_tabs( $post_id, $post ) {
443
  if ( 'wc_product_tab' === $post->post_type ) {
444
 
445
  $language = $this->sitepress->get_language_for_element( $post_id, 'post_wc_product_tab' );
@@ -459,11 +459,11 @@ class WCML_Tab_Manager {
459
  *
460
  * @return mixed
461
  */
462
- function append_custom_tabs_to_translation_package( $package, $post ) {
463
 
464
  if ( 'product' === $post->post_type ) {
465
 
466
- $override_tab_layout = get_post_meta( $post->ID , '_override_tab_layout', true );
467
 
468
  if ( 'yes' === $override_tab_layout ) {
469
 
@@ -474,34 +474,34 @@ class WCML_Tab_Manager {
474
  if ( preg_match( '/product_tab_([0-9]+)/', $key, $matches ) ) {
475
 
476
  $wc_product_tab_id = $matches[1];
477
- $wc_product_tab = get_post( $wc_product_tab_id );
478
 
479
- $package['contents'][ 'product_tabs:product_tab:' . $wc_product_tab_id . ':title' ] = array(
480
  'translate' => 1,
481
  'data' => $this->tp->encode_field_data( $wc_product_tab->post_title, 'base64' ),
482
  'format' => 'base64',
483
- );
484
 
485
- $package['contents'][ 'product_tabs:product_tab:' . $wc_product_tab_id . ':description' ] = array(
486
  'translate' => 1,
487
  'data' => $this->tp->encode_field_data( $wc_product_tab->post_content, 'base64' ),
488
  'format' => 'base64',
489
- );
490
 
491
  } elseif ( preg_match( '/^core_tab_(.+)$/', $key, $matches ) ) {
492
 
493
- $package['contents'][ 'product_tabs:core_tab_title:' . $matches[1] ] = array(
494
  'translate' => 1,
495
  'data' => $this->tp->encode_field_data( $value['title'], 'base64' ),
496
  'format' => 'base64',
497
- );
498
 
499
  if ( isset( $value['heading'] ) ) {
500
- $package['contents'][ 'product_tabs:core_tab_heading:' . $matches[1] ] = array(
501
  'translate' => 1,
502
  'data' => $this->tp->encode_field_data( $value['heading'], 'base64' ),
503
  'format' => 'base64',
504
- );
505
  }
506
  }
507
  }
@@ -516,22 +516,22 @@ class WCML_Tab_Manager {
516
  * @param $data
517
  * @param $job
518
  */
519
- function save_custom_tabs_translation( $post_id, $data, $job ) {
520
- $translated_product_tabs_updated = false;
521
 
522
  $original_product_tabs = get_post_meta( $job->original_doc_id, '_product_tabs', true );
523
 
524
  if ( $original_product_tabs ) {
525
 
526
  // custom tabs
527
- $product_tab_translations = array();
528
 
529
  foreach ( $data as $value ) {
530
 
531
  if ( preg_match( '/product_tabs:product_tab:([0-9]+):(.+)/', $value['field_type'], $matches ) ) {
532
 
533
  $wc_product_tab_id = $matches[1];
534
- $field = $matches[2];
535
 
536
  $product_tab_translations[ $wc_product_tab_id ][ $field ] = $value['data'];
537
  }
@@ -540,15 +540,16 @@ class WCML_Tab_Manager {
540
  if ( $product_tab_translations ) {
541
 
542
  $translated_product_tabs = get_post_meta( $post_id, '_product_tabs', true );
 
543
 
544
  foreach ( $product_tab_translations as $wc_product_tab_id => $value ) {
545
 
546
- $new_wc_product_tab = array(
547
  'post_type' => 'wp_product_tab',
548
  'post_title' => $value['title'],
549
  'post_content' => $value['description'],
550
  'post_status' => 'publish',
551
- );
552
 
553
  $wc_product_tab_id_translated = wp_insert_post( $new_wc_product_tab );
554
 
@@ -559,13 +560,13 @@ class WCML_Tab_Manager {
559
 
560
  $wc_product_tab_translated = get_post( $wc_product_tab_id_translated );
561
 
562
- $translated_product_tabs[ 'product_tab_' . $wc_product_tab_id_translated ] = array(
563
  'position' => $original_product_tabs[ 'product_tab_' . $wc_product_tab_id ]['position'],
564
  'type' => 'product',
565
  'id' => $wc_product_tab_id_translated,
566
  'name' => $wc_product_tab_translated->post_name,
567
 
568
- );
569
  }
570
  }
571
 
@@ -573,14 +574,14 @@ class WCML_Tab_Manager {
573
  }
574
 
575
  // the other tabs
576
- $product_tab_translations = array();
577
 
578
  foreach ( $data as $value ) {
579
 
580
  if ( preg_match( '/product_tabs:core_tab_(.+):(.+)/', $value['field_type'], $matches ) ) {
581
 
582
- $tab_field = $matches[1];
583
- $tab_id = $matches[2];
584
 
585
  $product_tab_translations[ $tab_id ][ $tab_field ] = $value['data'];
586
  }
@@ -589,16 +590,14 @@ class WCML_Tab_Manager {
589
  if ( $product_tab_translations ) {
590
  foreach ( $product_tab_translations as $id => $tab ) {
591
 
592
- $translated_product_tabs[ 'core_tab_' . $id ] = array(
593
- 'type' => 'core',
594
- 'position' => $original_product_tabs[ 'core_tab_' . $id ]['position'],
595
- 'id' => $id,
596
- 'title' => $tab['title'],
597
- );
598
 
599
- if ( isset( $tab['heading'] ) ) {
600
- $translated_product_tabs[ 'core_tab_' . $id ]['heading'] = $tab['heading'];
601
- }
602
  }
603
 
604
  $translated_product_tabs_updated = true;
@@ -630,48 +629,44 @@ class WCML_Tab_Manager {
630
  return $product_tabs;
631
  }
632
 
633
- public function sync_product_tabs( $post_id, $post ){
634
 
635
  $override_tab_layout = get_post_meta( $post_id, '_override_tab_layout', true );
636
 
637
- if ( $override_tab_layout && $this->woocommerce_wpml->products->is_original_product( $post_id ) ){
638
 
639
  $original_product_tabs = $this->get_product_tabs( $post_id );
640
 
641
- $trid = $this->sitepress->get_element_trid( $post_id, 'post_' . $post->post_type );
642
- $translations = $this->sitepress->get_element_translations( $trid, 'post_' . $post->post_type, true );
643
-
644
 
 
645
 
646
- foreach( $translations as $language => $translation ){
647
-
648
- if( empty( $translation->original ) ){
649
 
650
  $translated_product_tabs = $this->get_product_tabs( $translation->element_id );
651
 
652
  // sync tab positions for product tabs
653
- foreach( $original_product_tabs as $tab ){
654
- if( $tab['type'] == 'product' ){
655
  $translated_tab_product_id = apply_filters( 'translate_object_id', $tab['id'], 'wc_product_tab', false, $language );
656
- if( $translated_tab_product_id && is_array( $translated_product_tabs['product_tab_' . $translated_tab_product_id ] ) ){
657
- $translated_product_tabs['product_tab_' . $translated_tab_product_id ]['position'] = $tab['position'];
658
  }
659
  }
660
  }
661
 
662
  // sync translated core tabs with original tabs
663
- foreach( $translated_product_tabs as $tab_key => $tab ){
664
- if( $tab['type'] === 'core' && !isset( $original_product_tabs[$tab_key] ) ){
665
- unset( $translated_product_tabs[$tab_key] );
666
  }
667
  }
668
 
669
  update_post_meta( $translation->element_id, '_product_tabs', $translated_product_tabs );
670
 
671
  }
672
-
673
  }
674
-
675
  }
676
 
677
  }
@@ -681,21 +676,21 @@ class WCML_Tab_Manager {
681
  *
682
  * @return mixed|void
683
  */
684
- function wc_tab_manager_tab_id( $tab_id ) {
685
  return apply_filters( 'wpml_object_id', $tab_id, 'wc_product_tab', true );
686
  }
687
 
688
- public function filter_default_layout( $default_tabs ){
689
 
690
- if( is_array( $default_tabs ) ){
691
- foreach( $default_tabs as $tab_key => $default_tab ){
692
- if( substr( $tab_key, 0, 10 ) == 'global_tab' ){
693
- $trnsl_tab_id = apply_filters( 'translate_object_id', $default_tab[ 'id' ], 'wc_product_tab', true, $this->sitepress->get_current_language() );
694
 
695
- if( $trnsl_tab_id != $default_tab[ 'id' ] ){
696
- $default_tabs[ 'global_tab_'.$trnsl_tab_id ] = $default_tab;
697
- $default_tabs[ 'global_tab_'.$trnsl_tab_id ][ 'id' ] = $trnsl_tab_id;
698
- $default_tabs[ 'global_tab_'.$trnsl_tab_id ][ 'name' ] = get_post( $trnsl_tab_id )->post_name;
699
  unset( $default_tabs[ $tab_key ] );
700
  }
701
  }
@@ -705,10 +700,10 @@ class WCML_Tab_Manager {
705
  return $default_tabs;
706
  }
707
 
708
- public function show_pointer_info(){
709
 
710
  $pointer_ui = new WCML_Pointer_UI(
711
- sprintf( __( 'You can translate your custom product tabs on the %sWooCommerce product translation page%s', 'woocommerce-multilingual' ), '<a href="'.admin_url('admin.php?page=wpml-wcml').'">', '</a>' ),
712
  'https://wpml.org/documentation/woocommerce-extensions-compatibility/translating-woocommerce-tab-manager-woocommerce-multilingual/',
713
  'woocommerce_product_tabs>p'
714
  );
@@ -717,28 +712,31 @@ class WCML_Tab_Manager {
717
 
718
  }
719
 
720
- function replace_tm_editor_custom_fields_with_own_sections( $fields ){
721
  $fields[] = '_product_tabs';
722
 
723
  return $fields;
724
  }
725
 
726
- function duplicate_categories_exception( $fields ) {
727
  $fields[] = '_wc_tab_categories';
728
 
729
  return $fields;
730
  }
731
 
732
- function translate_categories( $post_id_from, $post_id_to, $meta_key ) {
733
  if ( '_wc_tab_categories' === $meta_key ) {
734
  // Saving has already been processed, remove nonce so that we dont
735
  // process translations too (which would overwrite _wc_tab_categories.
736
  unset( $_POST['wc_tab_manager_metabox_nonce'] );
737
 
738
- $args = array('element_id' => $post_id_to, 'element_type' => 'wc_product_tab' );
 
 
 
739
  $language = apply_filters( 'wpml_element_language_code', false, $args );
740
 
741
- $categories = array();
742
  $meta_value = get_post_meta( $post_id_from, $meta_key, true );
743
  foreach ( $meta_value as $category ) {
744
  $categories[] = apply_filters( 'wpml_object_id', $category, 'product_cat', true, $language );
32
  /**
33
  * WCML_Tab_Manager constructor.
34
  *
35
+ * @param SitePress $sitepress
36
+ * @param WooCommerce $woocommerce
37
+ * @param woocommerce_wpml $woocommerce_wpml
38
+ * @param wpdb $wpdb
39
  * @param WPML_Element_Translation_Package $tp
40
  */
41
+ public function __construct( SitePress $sitepress, WooCommerce $woocommerce, woocommerce_wpml $woocommerce_wpml, wpdb $wpdb, WPML_Element_Translation_Package $tp ) {
42
  $this->sitepress = $sitepress;
43
  $this->woocommerce = $woocommerce;
44
  $this->woocommerce_wpml = $woocommerce_wpml;
46
  $this->tp = $tp;
47
  }
48
 
49
+ public function add_hooks() {
50
+ add_action( 'wcml_update_extra_fields', [ $this, 'sync_tabs' ], 10, 4 );
51
+ add_action( 'wcml_gui_additional_box_html', [ $this, 'custom_box_html' ], 10, 3 );
52
+ add_filter( 'wcml_gui_additional_box_data', [ $this, 'custom_box_html_data' ], 10, 4 );
53
+ add_filter( 'wpml_duplicate_custom_fields_exceptions', [ $this, 'duplicate_custom_fields_exceptions' ] );
54
+ add_action( 'wcml_after_duplicate_product', [ $this, 'duplicate_product_tabs' ], 10, 2 );
55
 
56
+ add_filter( 'wc_tab_manager_tab_id', [ $this, 'wc_tab_manager_tab_id' ], 10, 1 );
57
+ add_filter( 'option_wpml_config_files_arr', [ $this, 'make__product_tabs_not_translatable_by_default' ], 0 );
58
+
59
+ add_action( 'wpml_translation_job_saved', [ $this, 'save_custom_tabs_translation' ], 10, 3 );
60
 
61
  if ( is_admin() ) {
62
 
63
+ add_action( 'save_post', [ $this, 'force_set_language_information_on_product_tabs' ], 10, 2 );
64
+ add_action( 'save_post', [ $this, 'sync_product_tabs' ], 10, 2 );
65
 
66
+ add_filter( 'wpml_tm_translation_job_data', [ $this, 'append_custom_tabs_to_translation_package' ], 10, 2 );
67
+ add_action( 'woocommerce_product_data_panels', [ $this, 'show_pointer_info' ] );
 
68
 
69
+ add_filter( 'wcml_do_not_display_custom_fields_for_product', [ $this, 'replace_tm_editor_custom_fields_with_own_sections' ] );
70
 
71
+ add_filter( 'wpml_duplicate_custom_fields_exceptions', [ $this, 'duplicate_categories_exception' ] );
72
+ add_action( 'wpml_after_copy_custom_field', [ $this, 'translate_categories' ], 10, 3 );
73
 
74
+ } else {
75
+ add_filter( 'option_wc_tab_manager_default_layout', [ $this, 'filter_default_layout' ] );
76
  }
77
 
78
  }
82
  *
83
  * @return mixed
84
  */
85
+ public function make__product_tabs_not_translatable_by_default( $wpml_config_array ) {
86
 
87
  if ( isset( $wpml_config_array->plugins['WooCommerce Tab Manager'] ) ) {
88
  $wpml_config_array->plugins['WooCommerce Tab Manager'] =
89
+ str_replace(
90
+ '<custom-field action="translate">_product_tabs</custom-field>',
91
  '<custom-field action="nothing">_product_tabs</custom-field>',
92
  $wpml_config_array->plugins['WooCommerce Tab Manager']
93
  );
104
  *
105
  * @return bool
106
  */
107
+ public function sync_tabs( $original_product_id, $trnsl_product_id, $data, $lang ) {
108
+ // check if "duplicate" product
109
+ if ( ( isset( $_POST['icl_ajx_action'] ) && ( 'make_duplicates' === $_POST['icl_ajx_action'] ) ) || ( get_post_meta( $trnsl_product_id, '_icl_lang_duplicate_of', true ) ) ) {
110
  $this->duplicate_tabs( $original_product_id, $trnsl_product_id, $lang );
111
  }
112
 
113
  $orig_prod_tabs = $this->get_product_tabs( $original_product_id );
114
 
115
  if ( $orig_prod_tabs ) {
116
+ $trnsl_product_tabs = [];
117
+ $i = 0;
118
  foreach ( $orig_prod_tabs as $key => $orig_prod_tab ) {
119
  switch ( $orig_prod_tab['type'] ) {
120
  case 'core':
121
+ $default_language = $this->woocommerce_wpml->products->get_original_product_language( $original_product_id );
122
+ $current_language = $this->sitepress->get_current_language();
123
  $trnsl_product_tabs[ $key ] = $orig_prod_tabs[ $key ];
124
+ $title = isset( $data[ md5( 'coretab_' . $orig_prod_tab['id'] . '_title' ) ] ) ? $data[ md5( 'coretab_' . $orig_prod_tab['id'] . '_title' ) ] : '';
125
+ $heading = isset( $data[ md5( 'coretab_' . $orig_prod_tab['id'] . '_heading' ) ] ) ? $data[ md5( 'coretab_' . $orig_prod_tab['id'] . '_heading' ) ] : '';
126
 
127
  if ( $default_language !== $lang ) {
128
 
141
  $this->refresh_text_domain( $current_language );
142
  }
143
 
144
+ $trnsl_product_tabs[ $key ]['title'] = $title;
145
  $trnsl_product_tabs[ $key ]['heading'] = $heading;
146
  break;
147
  case 'global':
148
  $trnsl_product_tabs = $this->set_global_tab( $orig_prod_tab, $trnsl_product_tabs, $lang );
149
  break;
150
  case 'product':
151
+ $tab_id = false;
152
+ $title_key = md5( 'tab_' . $orig_prod_tab['position'] . '_title' );
153
  $heading_key = md5( 'tab_' . $orig_prod_tab['position'] . '_heading' );
154
+ $title = isset( $data[ $title_key ] ) ? sanitize_text_field( $data[ $title_key ] ) : '';
155
+ $content = isset( $data[ $heading_key ] ) ? wp_kses_post( $data[ $heading_key ] ) : '';
156
 
157
  $trnsl_product_tabs = $this->set_product_tab( $orig_prod_tab, $trnsl_product_tabs, $lang, $trnsl_product_id, $tab_id, $title, $content );
158
 
173
  * @param $trnsl_product_id
174
  * @param $lang
175
  */
176
+ public function duplicate_tabs( $original_product_id, $trnsl_product_id, $lang ) {
177
  $orig_prod_tabs = maybe_unserialize( get_post_meta( $original_product_id, '_product_tabs', true ) );
178
+ $prod_tabs = [];
179
  foreach ( $orig_prod_tabs as $key => $orig_prod_tab ) {
180
  switch ( $orig_prod_tab['type'] ) {
181
  case 'core':
187
  }
188
  $orig_lang = $this->sitepress->get_language_for_element( $original_product_id, 'post_product' );
189
  $this->refresh_text_domain( $orig_lang );
190
+ break;
191
  case 'global':
192
  $prod_tabs = $this->set_global_tab( $orig_prod_tab, $prod_tabs, $lang );
193
+ break;
194
  case 'product':
195
  $original_tab = get_post( $orig_prod_tab['id'] );
196
+ $prod_tabs = $this->set_product_tab( $orig_prod_tab, $prod_tabs, $lang, $trnsl_product_id, false, $original_tab->post_title, $original_tab->post_content );
197
+ break;
198
  }
199
  }
200
 
204
  /**
205
  * @param $lang
206
  */
207
+ public function refresh_text_domain( $lang ) {
208
  $this->sitepress->switch_lang( $lang );
209
  }
210
 
215
  *
216
  * @return mixed
217
  */
218
+ public function set_global_tab( $orig_prod_tab, $trnsl_product_tabs, $lang ) {
219
  $tr_tab_id = apply_filters( 'translate_object_id', $orig_prod_tab['id'], 'wc_product_tab', true, $lang );
220
+ $trnsl_product_tabs[ $orig_prod_tab['type'] . '_tab_' . $tr_tab_id ] = [
221
  'position' => $orig_prod_tab['position'],
222
  'type' => $orig_prod_tab['type'],
223
  'id' => $tr_tab_id,
224
  'name' => get_post( $tr_tab_id )->post_name,
225
+ ];
226
  return $trnsl_product_tabs;
227
  }
228
 
237
  *
238
  * @return mixed
239
  */
240
+ public function set_product_tab( $orig_prod_tab, $trnsl_product_tabs, $lang, $trnsl_product_id, $tab_id, $title, $content ) {
241
  if ( ! $tab_id ) {
242
  $tr_tab_id = apply_filters( 'translate_object_id', $orig_prod_tab['id'], 'wc_product_tab', false, $lang );
243
 
247
  }
248
 
249
  if ( $tab_id ) {
250
+ // update existing tab
251
+ $args = [];
252
+ $args['post_title'] = $title;
253
  $args['post_content'] = $content;
254
+ $this->wpdb->update( $this->wpdb->posts, $args, [ 'ID' => $tab_id ] );
255
  } else {
256
+ // tab not exist creating new
257
+ $args = [];
258
  $args['post_title'] = $title;
259
  $args['post_content'] = $content;
260
  $args['post_author'] = get_current_user_id();
264
  $args['post_status'] = 'publish';
265
  $this->wpdb->insert( $this->wpdb->posts, $args );
266
 
267
+ $tab_id = $this->wpdb->insert_id;
268
  $tab_trid = $this->sitepress->get_element_trid( $orig_prod_tab['id'], 'post_wc_product_tab' );
269
  if ( ! $tab_trid ) {
270
  $this->sitepress->set_element_language_details( $orig_prod_tab['id'], 'post_wc_product_tab', false, $this->sitepress->get_default_language() );
273
  $this->sitepress->set_element_language_details( $tab_id, 'post_wc_product_tab', $tab_trid, $lang );
274
  }
275
 
 
276
  if ( empty( $title ) || strlen( $title ) != strlen( utf8_encode( $title ) ) ) {
277
+ $tab_name = 'product-tab-' . $tab_id;
278
  } else {
279
  $tab_name = sanitize_title( $title );
280
  }
281
 
282
+ $trnsl_product_tabs[ $orig_prod_tab['type'] . '_tab_' . $tab_id ] = [
283
  'position' => $orig_prod_tab['position'],
284
  'type' => $orig_prod_tab['type'],
285
  'id' => $tab_id,
286
  'name' => $tab_name,
287
+ ];
288
 
289
  return $trnsl_product_tabs;
290
  }
294
  *
295
  * @return array
296
  */
297
+ public function duplicate_custom_fields_exceptions( $exceptions ) {
298
  $exceptions[] = '_product_tabs';
299
  return $exceptions;
300
  }
306
  *
307
  * @return bool
308
  */
309
+ public function custom_box_html( $obj, $product_id, $data ) {
310
 
311
  if ( 'yes' !== get_post_meta( $product_id, '_override_tab_layout', true ) ) {
312
  return false;
319
 
320
  $tabs_section = new WPML_Editor_UI_Field_Section( __( 'Product tabs', 'woocommerce-multilingual' ) );
321
 
322
+ $keys = array_keys( $orig_prod_tabs );
323
  $last_key = end( $keys );
324
+ $divider = true;
325
 
326
  foreach ( $orig_prod_tabs as $key => $prod_tab ) {
327
  if ( $key === $last_key ) {
328
  $divider = false;
329
  }
330
 
331
+ if ( in_array( $prod_tab['type'], [ 'product', 'core' ] ) ) {
332
  if ( 'core' === $prod_tab['type'] ) {
333
+ $group = new WPML_Editor_UI_Field_Group( $prod_tab['title'], $divider );
334
+ $tab_field = new WPML_Editor_UI_Single_Line_Field( 'coretab_' . $prod_tab['id'] . '_title', __( 'Title', 'woocommerce-multilingual' ), $data, false );
335
  $group->add_field( $tab_field );
336
+ $tab_field = new WPML_Editor_UI_Single_Line_Field( 'coretab_' . $prod_tab['id'] . '_heading', __( 'Heading', 'woocommerce-multilingual' ), $data, false );
337
  $group->add_field( $tab_field );
338
  $tabs_section->add_field( $group );
339
  } else {
340
+ $group = new WPML_Editor_UI_Field_Group( ucfirst( str_replace( '-', ' ', $prod_tab['name'] ) ), $divider );
341
+ $tab_field = new WPML_Editor_UI_Single_Line_Field( 'tab_' . $prod_tab['position'] . '_title', __( 'Title', 'woocommerce-multilingual' ), $data, false );
342
  $group->add_field( $tab_field );
343
+ $tab_field = new WCML_Editor_UI_WYSIWYG_Field( 'tab_' . $prod_tab['position'] . '_heading', null, $data, false );
344
  $group->add_field( $tab_field );
345
  $tabs_section->add_field( $group );
346
  }
359
  *
360
  * @return mixed
361
  */
362
+ public function custom_box_html_data( $data, $product_id, $translation, $lang ) {
363
 
364
  $orig_prod_tabs = $this->get_product_tabs( $product_id );
365
 
368
  }
369
 
370
  foreach ( $orig_prod_tabs as $key => $prod_tab ) {
371
+ if ( in_array( $prod_tab['type'], [ 'product', 'core' ] ) ) {
372
  if ( 'core' === $prod_tab['type'] ) {
373
+ $data[ 'coretab_' . $prod_tab['id'] . '_title' ] = [ 'original' => $prod_tab['title'] ];
374
+ $data[ 'coretab_' . $prod_tab['id'] . '_heading' ] = [ 'original' => isset( $prod_tab['heading'] ) ? $prod_tab['heading'] : '' ];
375
  } else {
376
+ $data[ 'tab_' . $prod_tab['position'] . '_title' ] = [ 'original' => get_the_title( $prod_tab['id'] ) ];
377
+ $data[ 'tab_' . $prod_tab['position'] . '_heading' ] = [ 'original' => get_post( $prod_tab['id'] )->post_content ];
378
  }
379
  }
380
  }
382
  if ( $translation ) {
383
  $tr_prod_tabs = $this->get_product_tabs( $translation->ID );
384
 
 
385
  if ( ! is_array( $tr_prod_tabs ) ) {
386
  return $data; // __('Please update original product','woocommerce-multilingual');
387
  }
388
 
389
  foreach ( $tr_prod_tabs as $key => $prod_tab ) {
390
+ if ( in_array( $prod_tab['type'], [ 'product', 'core' ] ) ) {
391
  if ( 'core' === $prod_tab['type'] ) {
392
+ $data[ 'coretab_' . $prod_tab['id'] . '_title' ]['translation'] = $prod_tab['title'];
393
  $data[ 'coretab_' . $prod_tab['id'] . '_heading' ]['translation'] = isset( $prod_tab['heading'] ) ? $prod_tab['heading'] : '';
394
  } else {
395
+ $data[ 'tab_' . $prod_tab['position'] . '_title' ]['translation'] = get_the_title( $prod_tab['id'] );
396
+ $data[ 'tab_' . $prod_tab['position'] . '_heading' ]['translation'] = get_post( $prod_tab['id'] )->post_content;
397
  }
398
  }
399
  }
408
  }
409
 
410
  if ( ! isset( $prod_tab['heading'] ) ) {
411
+ $data[ 'coretab_' . $prod_tab['id'] . '_heading' ]['translation'] = '';
412
  } else {
413
  $heading = __( $prod_tab['heading'], 'woocommerce' );
414
  if ( $prod_tab['heading'] !== $heading ) {
429
  * @param $new_id
430
  * @param $original_post
431
  */
432
+ public function duplicate_product_tabs( $new_id, $original_post ) {
433
  if ( function_exists( 'wc_tab_manager_duplicate_product' ) ) {
434
  wc_tab_manager_duplicate_product( $new_id, $original_post );
435
  }
439
  * @param $post_id
440
  * @param $post
441
  */
442
+ public function force_set_language_information_on_product_tabs( $post_id, $post ) {
443
  if ( 'wc_product_tab' === $post->post_type ) {
444
 
445
  $language = $this->sitepress->get_language_for_element( $post_id, 'post_wc_product_tab' );
459
  *
460
  * @return mixed
461
  */
462
+ public function append_custom_tabs_to_translation_package( $package, $post ) {
463
 
464
  if ( 'product' === $post->post_type ) {
465
 
466
+ $override_tab_layout = get_post_meta( $post->ID, '_override_tab_layout', true );
467
 
468
  if ( 'yes' === $override_tab_layout ) {
469
 
474
  if ( preg_match( '/product_tab_([0-9]+)/', $key, $matches ) ) {
475
 
476
  $wc_product_tab_id = $matches[1];
477
+ $wc_product_tab = get_post( $wc_product_tab_id );
478
 
479
+ $package['contents'][ 'product_tabs:product_tab:' . $wc_product_tab_id . ':title' ] = [
480
  'translate' => 1,
481
  'data' => $this->tp->encode_field_data( $wc_product_tab->post_title, 'base64' ),
482
  'format' => 'base64',
483
+ ];
484
 
485
+ $package['contents'][ 'product_tabs:product_tab:' . $wc_product_tab_id . ':description' ] = [
486
  'translate' => 1,
487
  'data' => $this->tp->encode_field_data( $wc_product_tab->post_content, 'base64' ),
488
  'format' => 'base64',
489
+ ];
490
 
491
  } elseif ( preg_match( '/^core_tab_(.+)$/', $key, $matches ) ) {
492
 
493
+ $package['contents'][ 'product_tabs:core_tab_title:' . $matches[1] ] = [
494
  'translate' => 1,
495
  'data' => $this->tp->encode_field_data( $value['title'], 'base64' ),
496
  'format' => 'base64',
497
+ ];
498
 
499
  if ( isset( $value['heading'] ) ) {
500
+ $package['contents'][ 'product_tabs:core_tab_heading:' . $matches[1] ] = [
501
  'translate' => 1,
502
  'data' => $this->tp->encode_field_data( $value['heading'], 'base64' ),
503
  'format' => 'base64',
504
+ ];
505
  }
506
  }
507
  }
516
  * @param $data
517
  * @param $job
518
  */
519
+ public function save_custom_tabs_translation( $post_id, $data, $job ) {
520
+ $translated_product_tabs_updated = false;
521
 
522
  $original_product_tabs = get_post_meta( $job->original_doc_id, '_product_tabs', true );
523
 
524
  if ( $original_product_tabs ) {
525
 
526
  // custom tabs
527
+ $product_tab_translations = [];
528
 
529
  foreach ( $data as $value ) {
530
 
531
  if ( preg_match( '/product_tabs:product_tab:([0-9]+):(.+)/', $value['field_type'], $matches ) ) {
532
 
533
  $wc_product_tab_id = $matches[1];
534
+ $field = $matches[2];
535
 
536
  $product_tab_translations[ $wc_product_tab_id ][ $field ] = $value['data'];
537
  }
540
  if ( $product_tab_translations ) {
541
 
542
  $translated_product_tabs = get_post_meta( $post_id, '_product_tabs', true );
543
+ $translated_product_tabs = $translated_product_tabs ?: [];
544
 
545
  foreach ( $product_tab_translations as $wc_product_tab_id => $value ) {
546
 
547
+ $new_wc_product_tab = [
548
  'post_type' => 'wp_product_tab',
549
  'post_title' => $value['title'],
550
  'post_content' => $value['description'],
551
  'post_status' => 'publish',
552
+ ];
553
 
554
  $wc_product_tab_id_translated = wp_insert_post( $new_wc_product_tab );
555
 
560
 
561
  $wc_product_tab_translated = get_post( $wc_product_tab_id_translated );
562
 
563
+ $translated_product_tabs[ 'product_tab_' . $wc_product_tab_id_translated ] = [
564
  'position' => $original_product_tabs[ 'product_tab_' . $wc_product_tab_id ]['position'],
565
  'type' => 'product',
566
  'id' => $wc_product_tab_id_translated,
567
  'name' => $wc_product_tab_translated->post_name,
568
 
569
+ ];
570
  }
571
  }
572
 
574
  }
575
 
576
  // the other tabs
577
+ $product_tab_translations = [];
578
 
579
  foreach ( $data as $value ) {
580
 
581
  if ( preg_match( '/product_tabs:core_tab_(.+):(.+)/', $value['field_type'], $matches ) ) {
582
 
583
+ $tab_field = $matches[1];
584
+ $tab_id = $matches[2];
585
 
586
  $product_tab_translations[ $tab_id ][ $tab_field ] = $value['data'];
587
  }
590
  if ( $product_tab_translations ) {
591
  foreach ( $product_tab_translations as $id => $tab ) {
592
 
593
+ $translated_product_tabs[ 'core_tab_' . $id ] = [
594
+ 'type' => 'core',
595
+ 'position' => $original_product_tabs[ 'core_tab_' . $id ]['position'],
596
+ 'id' => $id,
597
+ 'title' => $tab['title'],
598
+ ];
599
 
600
+ $translated_product_tabs[ 'core_tab_' . $id ]['heading'] = isset( $tab['heading'] ) ? $tab['heading'] : '';
 
 
601
  }
602
 
603
  $translated_product_tabs_updated = true;
629
  return $product_tabs;
630
  }
631
 
632
+ public function sync_product_tabs( $post_id, $post ) {
633
 
634
  $override_tab_layout = get_post_meta( $post_id, '_override_tab_layout', true );
635
 
636
+ if ( $override_tab_layout && $this->woocommerce_wpml->products->is_original_product( $post_id ) ) {
637
 
638
  $original_product_tabs = $this->get_product_tabs( $post_id );
639
 
640
+ $trid = $this->sitepress->get_element_trid( $post_id, 'post_' . $post->post_type );
641
+ $translations = $this->sitepress->get_element_translations( $trid, 'post_' . $post->post_type, true );
 
642
 
643
+ foreach ( $translations as $language => $translation ) {
644
 
645
+ if ( empty( $translation->original ) ) {
 
 
646
 
647
  $translated_product_tabs = $this->get_product_tabs( $translation->element_id );
648
 
649
  // sync tab positions for product tabs
650
+ foreach ( $original_product_tabs as $tab ) {
651
+ if ( $tab['type'] == 'product' ) {
652
  $translated_tab_product_id = apply_filters( 'translate_object_id', $tab['id'], 'wc_product_tab', false, $language );
653
+ if ( $translated_tab_product_id && is_array( $translated_product_tabs[ 'product_tab_' . $translated_tab_product_id ] ) ) {
654
+ $translated_product_tabs[ 'product_tab_' . $translated_tab_product_id ]['position'] = $tab['position'];
655
  }
656
  }
657
  }
658
 
659
  // sync translated core tabs with original tabs
660
+ foreach ( $translated_product_tabs as $tab_key => $tab ) {
661
+ if ( $tab['type'] === 'core' && ! isset( $original_product_tabs[ $tab_key ] ) ) {
662
+ unset( $translated_product_tabs[ $tab_key ] );
663
  }
664
  }
665
 
666
  update_post_meta( $translation->element_id, '_product_tabs', $translated_product_tabs );
667
 
668
  }
 
669
  }
 
670
  }
671
 
672
  }
676
  *
677
  * @return mixed|void
678
  */
679
+ public function wc_tab_manager_tab_id( $tab_id ) {
680
  return apply_filters( 'wpml_object_id', $tab_id, 'wc_product_tab', true );
681
  }
682
 
683
+ public function filter_default_layout( $default_tabs ) {
684
 
685
+ if ( is_array( $default_tabs ) ) {
686
+ foreach ( $default_tabs as $tab_key => $default_tab ) {
687
+ if ( substr( $tab_key, 0, 10 ) == 'global_tab' ) {
688
+ $trnsl_tab_id = apply_filters( 'translate_object_id', $default_tab['id'], 'wc_product_tab', true, $this->sitepress->get_current_language() );
689
 
690
+ if ( $trnsl_tab_id != $default_tab['id'] ) {
691
+ $default_tabs[ 'global_tab_' . $trnsl_tab_id ] = $default_tab;
692
+ $default_tabs[ 'global_tab_' . $trnsl_tab_id ]['id'] = $trnsl_tab_id;
693
+ $default_tabs[ 'global_tab_' . $trnsl_tab_id ]['name'] = get_post( $trnsl_tab_id )->post_name;
694
  unset( $default_tabs[ $tab_key ] );
695
  }
696
  }
700
  return $default_tabs;
701
  }
702
 
703
+ public function show_pointer_info() {
704
 
705
  $pointer_ui = new WCML_Pointer_UI(
706
+ sprintf( __( 'You can translate your custom product tabs on the %1$sWooCommerce product translation page%2$s', 'woocommerce-multilingual' ), '<a href="' . admin_url( 'admin.php?page=wpml-wcml' ) . '">', '</a>' ),
707
  'https://wpml.org/documentation/woocommerce-extensions-compatibility/translating-woocommerce-tab-manager-woocommerce-multilingual/',
708
  'woocommerce_product_tabs>p'
709
  );
712
 
713
  }
714
 
715
+ public function replace_tm_editor_custom_fields_with_own_sections( $fields ) {
716
  $fields[] = '_product_tabs';
717
 
718
  return $fields;
719
  }
720
 
721
+ public function duplicate_categories_exception( $fields ) {
722
  $fields[] = '_wc_tab_categories';
723
 
724
  return $fields;
725
  }
726
 
727
+ public function translate_categories( $post_id_from, $post_id_to, $meta_key ) {
728
  if ( '_wc_tab_categories' === $meta_key ) {
729
  // Saving has already been processed, remove nonce so that we dont
730
  // process translations too (which would overwrite _wc_tab_categories.
731
  unset( $_POST['wc_tab_manager_metabox_nonce'] );
732
 
733
+ $args = [
734
+ 'element_id' => $post_id_to,
735
+ 'element_type' => 'wc_product_tab',
736
+ ];
737
  $language = apply_filters( 'wpml_element_language_code', false, $args );
738
 
739
+ $categories = [];
740
  $meta_value = get_post_meta( $post_id_from, $meta_key, true );
741
  foreach ( $meta_value as $category ) {
742
  $categories[] = apply_filters( 'wpml_object_id', $category, 'product_cat', true, $language );
compatibility/class-wcml-table-rate-shipping.php CHANGED
@@ -18,33 +18,35 @@ class WCML_Table_Rate_Shipping {
18
  /**
19
  * WCML_Table_Rate_Shipping constructor.
20
  *
21
- * @param SitePress $sitepress
22
  * @param woocommerce_wpml $woocommerce_wpml
23
  */
24
- function __construct( SitePress $sitepress, woocommerce_wpml $woocommerce_wpml ) {
25
- $this->sitepress = $sitepress;
26
  $this->woocommerce_wpml = $woocommerce_wpml;
27
  }
28
 
29
- public function add_hooks(){
30
 
31
- add_action( 'init', array( $this, 'init' ), 9 );
32
 
33
  if ( ! is_admin() ) {
34
- add_filter( 'get_the_terms', array( $this, 'shipping_class_id_in_default_language' ), 10, 3 );
35
- add_filter( 'woocommerce_shipping_table_rate_is_available', array( $this, 'shipping_table_rate_is_available' ), 10, 3 );
36
  }
37
 
38
  if ( wcml_is_multi_currency_on() ) {
39
  $wpml_api = $this->sitepress->get_wp_api();
40
  if ( $wpml_api->version_compare( $wpml_api->constant( 'TABLE_RATE_SHIPPING_VERSION' ), '3.0.11', '<' ) ) {
41
- add_filter( 'woocommerce_table_rate_query_rates_args', array( $this, 'filter_query_rates_args' ) );
42
  }
43
 
44
- add_filter( 'woocommerce_table_rate_package_row_base_price', array(
45
- $this,
46
- 'filter_product_base_price'
47
- ), 10, 3 );
 
 
48
  }
49
 
50
  }
@@ -53,29 +55,29 @@ class WCML_Table_Rate_Shipping {
53
  * Register shipping labels for string translation.
54
  */
55
  public function init() {
56
- // Register shipping label
57
  if (
58
- isset( $_GET[ 'page' ] ) &&
59
  (
60
- $_GET[ 'page' ] === 'shipping_zones' ||
61
  (
62
- $_GET['page'] == 'wc-settings' &&
63
- isset( $_GET[ 'tab' ] ) &&
64
- $_GET['tab'] == 'shipping'
65
  )
66
  )
67
  ) {
68
 
69
  $this->show_pointer_info();
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
  }
@@ -92,35 +94,37 @@ class WCML_Table_Rate_Shipping {
92
  global $icl_adjust_id_url_filter_off;
93
 
94
  $is_product_object = 'product' === get_post_type( $post_id ) || 'product_variation' === get_post_type( $post_id );
95
- if( $terms && $is_product_object && 'product_shipping_class' === $taxonomy ){
96
 
97
- if( is_admin() ){
98
  $shipp_class_language = $this->woocommerce_wpml->products->get_original_product_language( $post_id );
99
- }else {
100
  $shipp_class_language = $this->sitepress->get_default_language();
101
  }
102
 
103
- $cache_key = md5( json_encode ( $terms ) );
104
- $cache_key .= ":".$post_id.$shipp_class_language;
105
 
106
  $cache_group = 'trnsl_shipping_class';
107
  $cache_terms = wp_cache_get( $cache_key, $cache_group );
108
 
109
- if( $cache_terms ) return $cache_terms;
 
 
110
 
111
  foreach ( $terms as $k => $term ) {
112
 
113
  $shipping_class_id = apply_filters( 'translate_object_id', $term->term_id, 'product_shipping_class', false, $shipp_class_language );
114
 
115
- $icl_adjust_id_url_filter = $icl_adjust_id_url_filter_off;
116
  $icl_adjust_id_url_filter_off = true;
117
 
118
- $terms[ $k ] = get_term( $shipping_class_id, 'product_shipping_class' );
119
 
120
  $icl_adjust_id_url_filter_off = $icl_adjust_id_url_filter;
121
  }
122
 
123
- wp_cache_set ( $cache_key, $terms, $cache_group );
124
  }
125
 
126
  return $terms;
@@ -128,29 +132,30 @@ class WCML_Table_Rate_Shipping {
128
 
129
  /**
130
  * It's not possible to filter rate_min and rate_max so we use the original price to compare against these values
 
 
 
 
131
  */
132
- public function filter_query_rates_args( $args ){
133
-
134
- if( isset( $args['price'] ) && wcml_get_woocommerce_currency_option() !== $this->woocommerce_wpml->multi_currency->get_client_currency() ){
135
  $args['price'] = $this->woocommerce_wpml->multi_currency->prices->unconvert_price_amount( $args['price'] );
136
  }
137
 
138
  return $args;
139
  }
140
 
141
- public function show_pointer_info(){
142
-
143
  $pointer_ui = new WCML_Pointer_UI(
144
- sprintf( __( 'You can translate this method title on the %sWPML String Translation page%s. Use the search on the top of that page to find the method title string.', 'woocommerce-multilingual' ), '<a href="'.admin_url('admin.php?page='.WPML_ST_FOLDER.'/menu/string-translation.php').'">', '</a>' ),
145
  'https://wpml.org/documentation/woocommerce-extensions-compatibility/translating-woocommerce-table-rate-shipping-woocommerce-multilingual/',
146
  'woocommerce_table_rate_title'
147
  );
148
 
149
  $pointer_ui->show();
150
 
151
-
152
  $pointer_ui = new WCML_Pointer_UI(
153
- sprintf( __( 'You can translate the labels of your table rates on the %sWPML String Translation page%s. Use the search on the top of that page to find the labels strings.', 'woocommerce-multilingual' ), '<a href="'.admin_url('admin.php?page='.WPML_ST_FOLDER.'/menu/string-translation.php').'">', '</a>' ),
154
  'https://wpml.org/documentation/woocommerce-extensions-compatibility/translating-woocommerce-table-rate-shipping-woocommerce-multilingual/',
155
  'shipping_rates .shipping_label a'
156
  );
@@ -160,15 +165,14 @@ class WCML_Table_Rate_Shipping {
160
 
161
  /**
162
  * @param $row_base_price
163
- * @param WC_Product $_product
164
  * @param $qty
165
  *
166
  * @return mixed
167
- *
168
  */
169
- public function filter_product_base_price( $row_base_price, $_product, $qty ){
170
 
171
- if( $_product && wcml_get_woocommerce_currency_option() !== $this->woocommerce_wpml->multi_currency->get_client_currency() ){
172
  $row_base_price = $this->woocommerce_wpml->products->get_product_price_from_db( $_product->get_id() ) * $qty;
173
  }
174
 
@@ -176,29 +180,33 @@ class WCML_Table_Rate_Shipping {
176
  }
177
 
178
  /**
179
- * @param bool $available
180
- * @param array $package
181
  * @param WC_Shipping_Method $object
182
  *
183
  * @return bool
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
  }
@@ -221,5 +229,4 @@ class WCML_Table_Rate_Shipping {
221
 
222
  return $priorities;
223
  }
224
-
225
- }
18
  /**
19
  * WCML_Table_Rate_Shipping constructor.
20
  *
21
+ * @param SitePress $sitepress
22
  * @param woocommerce_wpml $woocommerce_wpml
23
  */
24
+ public function __construct( SitePress $sitepress, woocommerce_wpml $woocommerce_wpml ) {
25
+ $this->sitepress = $sitepress;
26
  $this->woocommerce_wpml = $woocommerce_wpml;
27
  }
28
 
29
+ public function add_hooks() {
30
 
31
+ add_action( 'init', [ $this, 'init' ], 9 );
32
 
33
  if ( ! is_admin() ) {
34
+ add_filter( 'get_the_terms', [ $this, 'shipping_class_id_in_default_language' ], 10, 3 );
35
+ add_filter( 'woocommerce_shipping_table_rate_is_available', [ $this, 'shipping_table_rate_is_available' ], 10, 3 );
36
  }
37
 
38
  if ( wcml_is_multi_currency_on() ) {
39
  $wpml_api = $this->sitepress->get_wp_api();
40
  if ( $wpml_api->version_compare( $wpml_api->constant( 'TABLE_RATE_SHIPPING_VERSION' ), '3.0.11', '<' ) ) {
41
+ add_filter( 'woocommerce_table_rate_query_rates_args', [ $this, 'filter_query_rates_args' ] );
42
  }
43
 
44
+ add_filter(
45
+ 'woocommerce_table_rate_package_row_base_price',
46
+ [ $this, 'filter_product_base_price' ],
47
+ 10,
48
+ 3
49
+ );
50
  }
51
 
52
  }
55
  * Register shipping labels for string translation.
56
  */
57
  public function init() {
58
+ // Register shipping label.
59
  if (
60
+ isset( $_GET['page'] ) &&
61
  (
62
+ 'shipping_zones' === $_GET['page'] ||
63
  (
64
+ 'wc-settings' === $_GET['page'] &&
65
+ isset( $_GET['tab'] ) &&
66
+ 'shipping' === $_GET['tab']
67
  )
68
  )
69
  ) {
70
 
71
  $this->show_pointer_info();
72
 
73
+ if ( isset( $_POST['shipping_label'] ) &&
74
+ isset( $_POST['woocommerce_table_rate_title'] ) ) {
75
+ 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'] ) );
76
 
77
+ $shipping_labels = array_map( 'wc_clean', $_POST['shipping_label'] );
78
  foreach ( $shipping_labels as $key => $shipping_label ) {
79
+ $rate_key = isset( $_GET['instance_id'] ) ? 'table_rate' . $_GET['instance_id'] . $_POST['rate_id'][ $key ] : $shipping_label;
80
+ do_action( 'wpml_register_single_string', WCML_WC_Shipping::STRINGS_CONTEXT, $rate_key . '_shipping_method_title', $shipping_label );
81
  }
82
  }
83
  }
94
  global $icl_adjust_id_url_filter_off;
95
 
96
  $is_product_object = 'product' === get_post_type( $post_id ) || 'product_variation' === get_post_type( $post_id );
97
+ if ( $terms && $is_product_object && 'product_shipping_class' === $taxonomy ) {
98
 
99
+ if ( is_admin() ) {
100
  $shipp_class_language = $this->woocommerce_wpml->products->get_original_product_language( $post_id );
101
+ } else {
102
  $shipp_class_language = $this->sitepress->get_default_language();
103
  }
104
 
105
+ $cache_key = md5( wp_json_encode( $terms ) );
106
+ $cache_key .= ':' . $post_id . $shipp_class_language;
107
 
108
  $cache_group = 'trnsl_shipping_class';
109
  $cache_terms = wp_cache_get( $cache_key, $cache_group );
110
 
111
+ if ( $cache_terms ) {
112
+ return $cache_terms;
113
+ }
114
 
115
  foreach ( $terms as $k => $term ) {
116
 
117
  $shipping_class_id = apply_filters( 'translate_object_id', $term->term_id, 'product_shipping_class', false, $shipp_class_language );
118
 
119
+ $icl_adjust_id_url_filter = $icl_adjust_id_url_filter_off;
120
  $icl_adjust_id_url_filter_off = true;
121
 
122
+ $terms[ $k ] = get_term( $shipping_class_id, 'product_shipping_class' );
123
 
124
  $icl_adjust_id_url_filter_off = $icl_adjust_id_url_filter;
125
  }
126
 
127
+ wp_cache_set( $cache_key, $terms, $cache_group );
128
  }
129
 
130
  return $terms;
132
 
133
  /**
134
  * It's not possible to filter rate_min and rate_max so we use the original price to compare against these values
135
+ *
136
+ * @param array $args
137
+ *
138
+ * @return mixed
139
  */
140
+ public function filter_query_rates_args( $args ) {
141
+ if ( isset( $args['price'] ) && wcml_get_woocommerce_currency_option() !== $this->woocommerce_wpml->multi_currency->get_client_currency() ) {
 
142
  $args['price'] = $this->woocommerce_wpml->multi_currency->prices->unconvert_price_amount( $args['price'] );
143
  }
144
 
145
  return $args;
146
  }
147
 
148
+ public function show_pointer_info() {
 
149
  $pointer_ui = new WCML_Pointer_UI(
150
+ sprintf( __( 'You can translate this method title on the %1$sWPML String Translation page%2$s. Use the search on the top of that page to find the method title string.', 'woocommerce-multilingual' ), '<a href="' . admin_url( 'admin.php?page=' . WPML_ST_FOLDER . '/menu/string-translation.php' ) . '">', '</a>' ),
151
  'https://wpml.org/documentation/woocommerce-extensions-compatibility/translating-woocommerce-table-rate-shipping-woocommerce-multilingual/',
152
  'woocommerce_table_rate_title'
153
  );
154
 
155
  $pointer_ui->show();
156
 
 
157
  $pointer_ui = new WCML_Pointer_UI(
158
+ sprintf( __( 'You can translate the labels of your table rates on the %1$sWPML String Translation page%2$s. Use the search on the top of that page to find the labels strings.', 'woocommerce-multilingual' ), '<a href="' . admin_url( 'admin.php?page=' . WPML_ST_FOLDER . '/menu/string-translation.php' ) . '">', '</a>' ),
159
  'https://wpml.org/documentation/woocommerce-extensions-compatibility/translating-woocommerce-table-rate-shipping-woocommerce-multilingual/',
160
  'shipping_rates .shipping_label a'
161
  );
165
 
166
  /**
167
  * @param $row_base_price
168
+ * @param WC_Product $_product
169
  * @param $qty
170
  *
171
  * @return mixed
 
172
  */
173
+ public function filter_product_base_price( $row_base_price, $_product, $qty ) {
174
 
175
+ if ( $_product && wcml_get_woocommerce_currency_option() !== $this->woocommerce_wpml->multi_currency->get_client_currency() ) {
176
  $row_base_price = $this->woocommerce_wpml->products->get_product_price_from_db( $_product->get_id() ) * $qty;
177
  }
178
 
180
  }
181
 
182
  /**
183
+ * @param bool $available
184
+ * @param array $package
185
  * @param WC_Shipping_Method $object
186
  *
187
  * @return bool
188
  */
189
  public function shipping_table_rate_is_available( $available, $package, $object ) {
190
 
191
+ add_filter(
192
+ 'option_woocommerce_table_rate_priorities_' . $object->instance_id,
193
+ [ $this, 'filter_table_rate_priorities' ]
194
+ );
195
+ remove_filter(
196
+ 'woocommerce_shipping_table_rate_is_available',
197
+ [ $this, 'shipping_table_rate_is_available' ],
198
+ 10,
199
+ 3
200
+ );
201
 
202
  $available = $object->is_available( $package );
203
 
204
+ add_filter(
205
+ 'woocommerce_shipping_table_rate_is_available',
206
+ [ $this, 'shipping_table_rate_is_available' ],
207
+ 10,
208
+ 3
209
+ );
210
 
211
  return $available;
212
  }
229
 
230
  return $priorities;
231
  }
232
+ }
 
compatibility/class-wcml-the-events-calendar.php CHANGED
@@ -1,6 +1,6 @@
1
  <?php
2
 
3
- class WCML_The_Events_Calendar{
4
 
5
  /** @var SitePress */
6
  private $sitepress;
@@ -18,336 +18,318 @@ class WCML_The_Events_Calendar{
18
  */
19
  public function __construct( $sitepress, $woocommerce_wpml ) {
20
  // @todo Cover by tests, required for wcml-3037.
21
-
22
  $this->sitepress = $sitepress;
23
  $this->woocommerce_wpml = $woocommerce_wpml;
24
 
25
- if( isset( $_POST['action'] ) && strpos( $_POST['action'], 'tribe-ticket-add-') === 0 ){
26
- add_action( 'tribe_tickets_ticket_add', array( $this, 'unset_post_post_id' ) );
27
- add_action( 'event_tickets_after_save_ticket', array( $this, 'restore_post_post_id' ) );
28
 
29
- }
30
 
31
- if( is_admin() ){
32
- $this->tp = new WPML_Element_Translation_Package;
33
 
34
- add_action( 'save_post', array( $this, 'synchronize_event_for_ticket' ), 20, 3 );
35
 
36
- add_action( 'wpml_pb_shortcode_content_for_translation' , array( $this, 'maybe_mark_event_as_needs_update' ), 100, 2 );
37
 
38
- add_filter( 'wpml_tm_translation_job_data', array( $this, 'append_RSVP_tickets_to_translation_job' ), 10, 2 );
39
- add_action( 'wpml_pro_translation_completed', array( $this, 'save_RSVP_tickets_translations' ), 10, 3 );
40
 
41
- add_filter( 'wpml_tm_translation_job_data', array( $this, 'append_woo_tickets_to_translation_job' ), 10, 2 );
42
- add_action( 'wpml_pro_translation_completed', array( $this, 'save_woo_tickets_translations' ), 10, 3 );
43
 
44
- add_action( 'save_post', array( $this, 'synchronize_venue_for_event' ), 20, 3 );
45
- add_action( 'admin_footer', array( $this, 'pre_select_translated_venue' ), 1000 );
46
- add_action( 'wpml_pro_translation_completed', array( $this, 'save_venue_for_translation' ), 10, 3 );
47
 
48
- } else {
49
- add_action( 'event_tickets_rsvp_tickets_generated', array( $this, 'sync_rsvp_fields_on_attendee_created' ), 10, 3 );
50
- add_filter( 'tribe_get_organizer_ids', array( $this, 'get_translated_organizer_ids' ), 10, 2 );
51
- add_filter( 'tribe_events_cost_unformatted', array( $this, 'convert_events_cost' ), 10, 1 );
52
- }
53
 
54
- }
55
 
56
- public function unset_post_post_id(){
57
- if( isset( $_POST['post_ID'] ) ){
58
  $this->ticket_post_id_backup = $_POST['post_ID'];
59
  unset( $_POST['post_ID'] );
60
  }
61
- }
62
-
63
- public function restore_post_post_id(){
64
- if( isset( $this->ticket_post_id_backup ) ){
65
- $_POST['post_ID'] = $this->ticket_post_id_backup;
66
- }
67
  }
68
 
69
- public function synchronize_event_for_ticket( $post_id, $post, $update ){
70
-
71
- if( $post->post_type == 'product' ){
72
-
73
- if( !$this->woocommerce_wpml->products->is_original_product( $post_id ) ){
74
 
 
 
 
75
  $original_product_id = apply_filters( 'translate_object_id', $post_id, 'product', false, $this->sitepress->get_default_language() );
76
- if( $original_product_id ){
77
  $original_event_id = get_post_meta( $original_product_id, '_tribe_wooticket_for_event', true );
78
- if( $original_event_id ){
79
  $event_id = apply_filters( 'translate_object_id', $original_event_id, 'tribe_events', false );
80
- if( $event_id ){
81
  update_post_meta( $post_id, '_tribe_wooticket_for_event', $event_id );
82
  }
83
  }
84
  }
85
-
86
  }
 
 
87
 
88
- }
89
- }
90
-
91
- public function maybe_mark_event_as_needs_update( $content, $post_id ){
92
- $post = get_post( $post_id );
93
-
94
- if( $post->post_type == 'tribe_events' ){
95
-
96
- if( $post_id == $this->sitepress->get_original_element_id( $post_id, 'post_tribe_events' ) ){
97
 
98
- $tickets = array();
99
- $ticket_meta = array();
 
 
100
 
101
- if( class_exists('Tribe__Tickets__RSVP') ){
102
- $ticket_ids = Tribe__Tickets__RSVP::get_instance()->get_tickets_ids( $post_id );
103
- foreach ( $ticket_ids as $ticket_id ) {
104
- $ticket = Tribe__Tickets__RSVP::get_instance()->get_ticket( $post_id, $ticket_id );
105
- $tickets[] = $ticket->name . "|#|" . $ticket->description;
106
- $ticket_meta[] = get_post_meta( $ticket_id, '_tribe_tickets_meta', true );
107
- }
108
- }
109
 
110
- if( class_exists('Tribe__Tickets_Plus__Commerce__WooCommerce__Main') ){
111
- $ticket_ids = Tribe__Tickets_Plus__Commerce__WooCommerce__Main::get_instance()->get_tickets_ids( $post->ID );
112
- foreach ( $ticket_ids as $ticket_id ) {
113
- $ticket = Tribe__Tickets_Plus__Commerce__WooCommerce__Main::get_instance()->get_ticket( $post_id, $ticket_id );
114
- $tickets[] = $ticket->name . "|#|" . $ticket->description;
115
- $ticket_meta[] = get_post_meta( $ticket_id, '_tribe_tickets_meta', true );
116
- }
117
- }
118
 
119
- $content .= md5( serialize( $tickets ) );
120
- $content .= md5( serialize( $ticket_meta ) );
121
- }
 
122
 
 
 
123
 
124
- }
125
 
126
- return $content;
127
- }
128
 
129
- public function append_RSVP_tickets_to_translation_job( $package, $post ){
 
 
 
130
 
131
- if( $post->post_type == 'tribe_events' && class_exists('Tribe__Tickets__RSVP') ){
 
132
 
133
- $ticket_lang = $this->sitepress->get_language_for_element( $post->ID, 'post_tribe_events' );
134
- $this->sitepress->switch_lang( $ticket_lang );
135
- $ticket_ids = Tribe__Tickets__RSVP::get_instance()->get_tickets_ids( $post->ID );
136
- $this->sitepress->switch_lang();
137
 
138
- if( $ticket_ids ){
139
- foreach( $ticket_ids as $ticket_id ){
 
 
 
 
 
 
 
 
 
 
 
 
140
 
141
- $ticket_post = get_post( $ticket_id );
142
- $original_ticket_id = $this->sitepress->get_original_element_id( $ticket_id, 'post_tribe_rsvp_tickets' );
143
 
144
- if( !empty( $ticket_post->post_title ) ) {
145
- $package['contents'][ 'rsvp_tickets_' . $original_ticket_id . '_title' ] = array(
146
- 'translate' => 1,
147
- 'data' => $this->tp->encode_field_data( $ticket_post->post_title, 'base64' ),
148
- 'format' => 'base64',
149
- );
150
- }
151
- if( !empty( $ticket_post->post_excerpt ) ) {
152
- $package['contents'][ 'rsvp_tickets_' . $original_ticket_id . '_excerpt' ] = array(
153
- 'translate' => 1,
154
- 'data' => $this->tp->encode_field_data( $ticket_post->post_excerpt, 'base64' ),
155
- 'format' => 'base64',
156
- );
157
- }
158
 
159
- // fieldsets
160
- $package = $this->append_tickets_meta( $package, $ticket_id, $original_ticket_id );
161
 
162
- }
163
- }
164
 
 
165
 
166
- }
167
 
168
- return $package;
169
- }
 
 
 
 
 
 
 
 
 
 
170
 
171
- public function save_RSVP_tickets_translations( $post_id, $data, $job ){
172
 
173
- $translations = array();
174
 
175
- foreach ( $data as $key => $value ) {
 
 
 
 
 
 
176
 
177
- if ( preg_match( '/rsvp_tickets_([0-9]+)_title/', $key, $matches ) ) {
178
- $rsvp_post_id = $matches[1];
179
- if( $value['finished'] == 'on' ){
180
- $translations[ $rsvp_post_id ]['post_title'] = $value['data'];
181
- }
182
- } elseif ( preg_match( '/rsvp_tickets_([0-9]+)_excerpt/', $key, $matches ) ) {
183
- $rsvp_post_id = $matches[1];
184
- if( $value['finished'] == 'on' ){
185
- $translations[ $rsvp_post_id ]['post_excerpt'] = $value['data'];
186
- }
187
- }
188
-
189
- }
190
-
191
- foreach ( $translations as $rsvp_post_id => $translation ){
192
-
193
- $translated_rsvp_post_id = apply_filters( 'translate_object_id', $rsvp_post_id, 'tribe_rsvp_tickets', false, $job->language_code );
194
-
195
- $postarr = array(
196
- 'post_type' => 'tribe_rsvp_tickets',
197
- 'post_status' => 'publish',
198
- 'post_title' => $translation['post_title'],
199
- 'post_excerpt' => $translation['post_excerpt'],
200
- 'post_name' => sanitize_title_with_dashes( $translation['post_title'] )
201
- );
202
-
203
- if( $translated_rsvp_post_id && $translated_rsvp_post_id != $rsvp_post_id ){
204
- global $wpml_post_translations;
205
- $postarr['ID'] = $translated_rsvp_post_id;
206
- remove_action( 'save_post', array( $wpml_post_translations, 'save_post_actions' ), 100 );
207
  wp_update_post( $postarr );
208
- add_action( 'save_post', array( $wpml_post_translations, 'save_post_actions' ), 100 );
209
 
210
- } else{
211
- $translated_rsvp_post_id = wp_insert_post( $postarr );
212
- $trid = $this->sitepress->get_element_trid( $rsvp_post_id, 'post_tribe_rsvp_tickets' );
213
- $this->sitepress->set_element_language_details( $translated_rsvp_post_id, 'post_tribe_rsvp_tickets', $trid, $job->language_code );
214
- }
215
 
216
- $event_id = get_post_meta( $rsvp_post_id, '_tribe_rsvp_for_event', true);
217
 
218
- $translated_event_id = apply_filters( 'translate_object_id', $event_id, 'tribe_events', false, $job->language_code);
219
- update_post_meta( $translated_rsvp_post_id, '_tribe_rsvp_for_event', $translated_event_id);
220
 
221
- $this->sync_custom_fields( $rsvp_post_id, $translated_rsvp_post_id );
222
 
223
  $this->save_ticket_meta_translations( $rsvp_post_id, $translated_rsvp_post_id );
224
 
225
- }
226
- }
227
 
228
- public function append_woo_tickets_to_translation_job( $package, $post ){
229
 
230
- if( $post->post_type == 'tribe_events' && class_exists('Tribe__Tickets_Plus__Commerce__WooCommerce__Main') ){
231
 
232
  $ticket_lang = $this->sitepress->get_language_for_element( $post->ID, 'post_tribe_events' );
233
  $this->sitepress->switch_lang( $ticket_lang );
234
- $ticket_ids = Tribe__Tickets_Plus__Commerce__WooCommerce__Main::get_instance()->get_tickets_ids( $post->ID );
235
  $this->sitepress->switch_lang();
236
 
237
- if( $ticket_ids ){
238
- foreach( $ticket_ids as $ticket_id ){
239
 
240
- $ticket_post = get_post( $ticket_id );
241
  $original_ticket_id = $this->sitepress->get_original_element_id( $ticket_id, 'post_product' );
242
 
243
- if( !empty( $ticket_post->post_title ) ) {
244
- $package['contents'][ 'woo_tickets_' . $original_ticket_id . '_title' ] = array(
245
  'translate' => 1,
246
  'data' => $this->tp->encode_field_data( $ticket_post->post_title, 'base64' ),
247
  'format' => 'base64',
248
- );
249
  }
250
- if( !empty( $ticket_post->post_excerpt ) ) {
251
- $package['contents'][ 'woo_tickets_' . $original_ticket_id . '_excerpt' ] = array(
252
  'translate' => 1,
253
  'data' => $this->tp->encode_field_data( $ticket_post->post_excerpt, 'base64' ),
254
  'format' => 'base64',
255
- );
256
  }
257
 
258
- // fieldsets
259
  $package = $this->append_tickets_meta( $package, $ticket_id, $original_ticket_id );
260
 
261
  }
262
  }
263
-
264
  }
265
 
266
  return $package;
267
  }
268
 
269
- public function save_woo_tickets_translations( $post_id, $data, $job ){
270
  global $wpml_post_translations;
271
 
272
- $translations = array();
273
 
274
  foreach ( $data as $key => $value ) {
275
 
276
  if ( preg_match( '/woo_tickets_([0-9]+)_title/', $key, $matches ) ) {
277
  $ticket_post_id = $matches[1];
278
- if( $value['finished'] == 'on' ){
279
  $translations[ $ticket_post_id ]['post_title'] = $value['data'];
280
  }
281
  } elseif ( preg_match( '/woo_tickets_([0-9]+)_excerpt/', $key, $matches ) ) {
282
  $ticket_post_id = $matches[1];
283
- if( $value['finished'] == 'on' ){
284
  $translations[ $ticket_post_id ]['post_excerpt'] = $value['data'];
285
  }
286
  }
287
-
288
  }
289
 
290
- foreach ( $translations as $ticket_post_id => $translation ){
291
-
292
  $translated_ticket_post_id = apply_filters( 'translate_object_id', $ticket_post_id, 'product', false, $job->language_code );
293
 
294
- $postarr = array(
295
- 'post_type' => 'product',
296
- 'post_status' => 'publish',
297
  'post_title' => $translation['post_title'],
298
  'post_excerpt' => $translation['post_excerpt'],
299
- 'post_name' => sanitize_title_with_dashes( $translation['post_title'] )
300
- );
301
 
302
- remove_action( 'save_post', array( $wpml_post_translations, 'save_post_actions' ), 100, 2 );
303
- if( $translated_ticket_post_id && $translated_ticket_post_id != $ticket_post_id ){
304
  $postarr['ID'] = $translated_ticket_post_id;
305
  wp_update_post( $postarr );
306
- } else{
307
  $translated_ticket_post_id = wp_insert_post( $postarr );
308
- $trid = $this->sitepress->get_element_trid( $ticket_post_id, 'post_product' );
309
  $this->sitepress->set_element_language_details( $translated_ticket_post_id, 'post_product', $trid, $job->language_code );
310
  }
311
- add_action( 'save_post', array( $wpml_post_translations, 'save_post_actions' ), 100, 2 );
312
 
313
- $event_id = get_post_meta( $ticket_post_id, '_tribe_wooticket_for_event', true);
314
 
315
- $translated_event_id = apply_filters( 'translate_object_id', $event_id, 'tribe_events', false, $job->language_code);
316
- update_post_meta( $translated_ticket_post_id, '_tribe_wooticket_for_event', $translated_event_id);
317
 
318
  $this->sync_custom_fields( $ticket_post_id, $translated_ticket_post_id );
319
 
320
  $this->save_ticket_meta_translations( $ticket_post_id, $translated_ticket_post_id );
321
-
322
  }
323
  }
324
 
325
- private function append_tickets_meta( $package, $ticket_id, $original_ticket_id ){
326
 
327
  $ticket_meta = get_post_meta( $ticket_id, '_tribe_tickets_meta', true );
328
- if( is_array( $ticket_meta ) ) {
329
  foreach ( $ticket_meta as $k => $meta ) {
330
- $package['contents'][ 'rsvp_tickets_' . $original_ticket_id . '_meta_' . $k . '_label' ] = array(
331
  'translate' => 1,
332
  'data' => $this->tp->encode_field_data( $meta['label'], 'base64' ),
333
  'format' => 'base64',
334
- );
335
- $package['contents'][ 'rsvp_tickets_' . $original_ticket_id . '_meta_' . $k . '_slug' ] = array(
336
  'translate' => 1,
337
  'data' => $this->tp->encode_field_data( $meta['slug'], 'base64' ),
338
  'format' => 'base64',
339
- );
340
  if ( isset( $meta['extra']['options'] ) ) {
341
  foreach ( $meta['extra']['options'] as $option_id => $option_name ) {
342
 
343
- $package['contents'][ 'rsvp_tickets_' . $original_ticket_id . '_meta_' . $k . '_option_' . $option_id ] = array(
344
  'translate' => 1,
345
  'data' => $this->tp->encode_field_data( $option_name, 'base64' ),
346
  'format' => 'base64',
347
- );
348
 
349
  }
350
-
351
  }
352
  }
353
  }
@@ -355,102 +337,98 @@ class WCML_The_Events_Calendar{
355
  return $package;
356
  }
357
 
358
- private function save_ticket_meta_translations( $ticket_id, $translated_ticket_id ){
359
-
360
- $ticket_meta = get_post_meta( $ticket_id, '_tribe_tickets_meta', true );
361
  $translated_ticket_meta = $ticket_meta;
362
- if( is_array( $ticket_meta ) ){
363
 
364
  foreach ( $ticket_meta as $k => $meta ) {
365
-
366
  $key = 'rsvp_tickets_' . $ticket_id . '_meta_' . $k . '_label';
367
- if( isset( $data[$key] ) && $data[$key]['finished'] == 'on' ){
368
- $translated_ticket_meta[$k]['label'] = $data[$key]['data'];
369
  }
370
 
371
  $key = 'rsvp_tickets_' . $ticket_id . '_meta_' . $k . '_slug';
372
- if( isset( $data[$key] ) && $data[$key]['finished'] == 'on' ){
373
- $translated_ticket_meta[$k]['slug'] = $data[$key]['data'];
374
  }
375
 
376
  if ( isset( $meta['extra']['options'] ) ) {
377
  foreach ( $meta['extra']['options'] as $option_id => $option_name ) {
378
  $key = 'rsvp_tickets_' . $ticket_id . '_meta_' . $k . '_option_' . $option_id;
379
- if( isset( $data[$key] ) && $data[$key]['finished'] == 'on' ){
380
- $translated_ticket_meta[$k]['extra']['options'][$option_id] = $data[$key]['data'];
381
  }
382
  }
383
  }
384
-
385
  }
386
-
387
  }
388
 
389
  update_post_meta( $translated_ticket_id, '_tribe_tickets_meta', $translated_ticket_meta );
390
 
391
- update_post_meta( $translated_ticket_id, '_tribe_tickets_meta_enabled',
 
 
392
  get_post_meta( $ticket_id, '_tribe_tickets_meta_enabled', true )
393
  );
394
 
395
-
396
  }
397
 
398
- private function sync_custom_fields( $original_ticket_id, $translated_ticket_id ){
399
- // sync custom fields
400
- $custom_fields_sync = array( '_stock', '_manage_stock', 'total_sales', '_price' );
401
- foreach( $custom_fields_sync as $custom_field ){
402
  $value = get_post_meta( $original_ticket_id, $custom_field, true );
403
- if( $value !== false ){
404
- update_post_meta( $translated_ticket_id, $custom_field, $value);
405
  }
406
  }
407
  }
408
 
409
- public function synchronize_venue_for_event( $post_id, $post, $update ){
410
 
411
- if( $post->post_type == 'tribe_event' ){
412
 
413
- $venue_id = get_post_meta( $post_id, '_EventVenueID', true );
414
 
415
- $original_event_id = $this->sitepress->get_original_element_id( $post_id, 'post_tribe_event' );
416
 
417
- if( $original_event_id == $post_id ) {
418
- $event_trid = $this->sitepress->get_element_trid( $post_id, 'post_tribe_venue' );
419
- $event_translations = $this->sitepress->get_element_translations( $event_trid, 'post_tribe_venue' );
420
 
421
- if ( $venue_id ) {
422
- foreach ( $event_translations as $language_code => $event_translation ) {
423
- if ( $event_translation->element_id != $original_event_id ) {
424
- $translated_venue_id = apply_filters( 'translate_object_id', $venue_id, 'tribe_venue', false, $language_code );
425
- if ( $translated_venue_id ) {
426
- update_post_meta( $event_translation->element_id, '_EventVenueID', $translated_venue_id );
427
- }
428
- }
429
- }
430
- } else { // delete venue from translations
431
- foreach ( $event_translations as $language_code => $event_translation ) {
432
- if ( $event_translation->element_id != $original_event_id ) {
433
- delete_post_meta( $event_translation->element_id, '_EventVenueID' );
434
- }
435
- }
436
- }
437
-
438
- }
439
-
440
- }
441
 
442
- }
443
 
444
- public function pre_select_translated_venue(){
445
  $current_screen = get_current_screen();
446
- if( $current_screen->base === 'post' && $current_screen->action === 'add' && $current_screen->id === 'tribe_events' ){
447
- if( isset( $_GET['trid'] ) && isset( $_GET['lang'] ) && isset( $_GET['source_lang'] ) ){
448
  $event_translations = $this->sitepress->get_element_translations( $_GET['trid'], 'post_tribe_events' );
449
- $original_event_id = $event_translations[ $_GET['source_lang'] ]->element_id;
450
- $original_venue_id = get_post_meta( $original_event_id, '_EventVenueID', true );
451
- if( $original_venue_id ){
452
  $translated_venue_id = apply_filters( 'translate_object_id', $original_venue_id, 'tribe_venue', false, $_GET['lang'] );
453
- if( $translated_venue_id ){
 
454
  echo "<script type=\"text/javascript\">
455
  jQuery('#saved_tribe_venue').val($translated_venue_id);
456
  </script>";
@@ -458,48 +436,47 @@ class WCML_The_Events_Calendar{
458
  }
459
  }
460
  }
461
- }
462
-
463
- public function save_venue_for_translation( $post_id, $data, $job ){
464
 
465
- $original_event_id = $this->sitepress->get_original_element_id( $post_id, 'post_tribe_event' );
466
- $original_venue_id = get_post_meta( $original_event_id, '_EventVenueID', true );
467
 
468
- if( $original_venue_id ){
469
- $translated_venue_id = apply_filters( 'translate_object_id', $original_venue_id, 'tribe_venue', false, $job->language_code );
470
- if( $translated_venue_id ){
471
- update_post_meta( $post_id, '_EventVenueID', $translated_venue_id );
472
- }
473
 
474
- }
 
 
 
 
 
475
 
476
- }
477
 
478
- public function sync_rsvp_fields_on_attendee_created( $order_id, $post_id, $attendee_order_status ){
479
 
480
- $rsvp_post_id = isset( $_POST['product_id'][0] ) ? $_POST['product_id'][0] : false;
481
- if( $rsvp_post_id ) {
482
- $rsvp_trid = $this->sitepress->get_element_trid( $rsvp_post_id, 'post_tribe_rsvp_tickets' );
483
- $rsvp_translations = $this->sitepress->get_element_translations( $rsvp_trid, 'post_tribe_rsvp_tickets' );
484
 
485
- foreach ( $rsvp_translations as $translation ) {
486
- if ( $translation->element_id != $rsvp_post_id ) {
487
- $this->sync_custom_fields( $rsvp_post_id, $translation->element_id );
488
- }
489
- }
490
- }
491
- }
492
 
493
- public function get_translated_organizer_ids( $organizer_ids, $event_id ){
494
- foreach( $organizer_ids as $key => $organizer_id ){
495
- $organizer_ids[$key] = apply_filters( 'translate_object_id', $organizer_id, 'tribe_organizer', true );
496
- }
497
- return $organizer_ids;
498
- }
499
 
500
- public function convert_events_cost( $cost ) {
501
  return apply_filters( 'wcml_raw_price_amount', $cost );
502
- }
503
 
504
  }
505
 
1
  <?php
2
 
3
+ class WCML_The_Events_Calendar {
4
 
5
  /** @var SitePress */
6
  private $sitepress;
18
  */
19
  public function __construct( $sitepress, $woocommerce_wpml ) {
20
  // @todo Cover by tests, required for wcml-3037.
 
21
  $this->sitepress = $sitepress;
22
  $this->woocommerce_wpml = $woocommerce_wpml;
23
 
24
+ if ( isset( $_POST['action'] ) && 0 === strpos( $_POST['action'], 'tribe-ticket-add-' ) ) {
25
+ add_action( 'tribe_tickets_ticket_add', [ $this, 'unset_post_post_id' ] );
26
+ add_action( 'event_tickets_after_save_ticket', [ $this, 'restore_post_post_id' ] );
27
 
28
+ }
29
 
30
+ if ( is_admin() ) {
31
+ $this->tp = new WPML_Element_Translation_Package();
32
 
33
+ add_action( 'save_post', [ $this, 'synchronize_event_for_ticket' ], 20, 3 );
34
 
35
+ add_action( 'wpml_pb_shortcode_content_for_translation', [ $this, 'maybe_mark_event_as_needs_update' ], 100, 2 );
36
 
37
+ add_filter( 'wpml_tm_translation_job_data', [ $this, 'append_RSVP_tickets_to_translation_job' ], 10, 2 );
38
+ add_action( 'wpml_pro_translation_completed', [ $this, 'save_RSVP_tickets_translations' ], 10, 3 );
39
 
40
+ add_filter( 'wpml_tm_translation_job_data', [ $this, 'append_woo_tickets_to_translation_job' ], 10, 2 );
41
+ add_action( 'wpml_pro_translation_completed', [ $this, 'save_woo_tickets_translations' ], 10, 3 );
42
 
43
+ add_action( 'save_post', [ $this, 'synchronize_venue_for_event' ], 20, 3 );
44
+ add_action( 'admin_footer', [ $this, 'pre_select_translated_venue' ], 1000 );
45
+ add_action( 'wpml_pro_translation_completed', [ $this, 'save_venue_for_translation' ], 10, 3 );
46
 
47
+ } else {
48
+ add_action( 'event_tickets_rsvp_tickets_generated', [ $this, 'sync_rsvp_fields_on_attendee_created' ], 10, 3 );
49
+ add_filter( 'tribe_get_organizer_ids', [ $this, 'get_translated_organizer_ids' ], 10, 2 );
50
+ add_filter( 'tribe_events_cost_unformatted', [ $this, 'convert_events_cost' ], 10, 1 );
51
+ }
52
 
53
+ }
54
 
55
+ public function unset_post_post_id() {
56
+ if ( isset( $_POST['post_ID'] ) ) {
57
  $this->ticket_post_id_backup = $_POST['post_ID'];
58
  unset( $_POST['post_ID'] );
59
  }
 
 
 
 
 
 
60
  }
61
 
62
+ public function restore_post_post_id() {
63
+ if ( isset( $this->ticket_post_id_backup ) ) {
64
+ $_POST['post_ID'] = $this->ticket_post_id_backup;
65
+ }
66
+ }
67
 
68
+ public function synchronize_event_for_ticket( $post_id, $post, $update ) {
69
+ if ( 'product' === $post->post_type ) {
70
+ if ( ! $this->woocommerce_wpml->products->is_original_product( $post_id ) ) {
71
  $original_product_id = apply_filters( 'translate_object_id', $post_id, 'product', false, $this->sitepress->get_default_language() );
72
+ if ( $original_product_id ) {
73
  $original_event_id = get_post_meta( $original_product_id, '_tribe_wooticket_for_event', true );
74
+ if ( $original_event_id ) {
75
  $event_id = apply_filters( 'translate_object_id', $original_event_id, 'tribe_events', false );
76
+ if ( $event_id ) {
77
  update_post_meta( $post_id, '_tribe_wooticket_for_event', $event_id );
78
  }
79
  }
80
  }
 
81
  }
82
+ }
83
+ }
84
 
85
+ public function maybe_mark_event_as_needs_update( $content, $post_id ) {
86
+ $post = get_post( $post_id );
 
 
 
 
 
 
 
87
 
88
+ if ( 'tribe_events' === $post->post_type ) {
89
+ if ( $post_id == $this->sitepress->get_original_element_id( $post_id, 'post_tribe_events' ) ) {
90
+ $tickets = [];
91
+ $ticket_meta = [];
92
 
93
+ if ( class_exists( 'Tribe__Tickets__RSVP' ) ) {
94
+ $ticket_ids = Tribe__Tickets__RSVP::get_instance()->get_tickets_ids( $post_id );
95
+ foreach ( $ticket_ids as $ticket_id ) {
96
+ $ticket = Tribe__Tickets__RSVP::get_instance()->get_ticket( $post_id, $ticket_id );
97
+ $tickets[] = $ticket->name . '|#|' . $ticket->description;
98
+ $ticket_meta[] = get_post_meta( $ticket_id, '_tribe_tickets_meta', true );
99
+ }
100
+ }
101
 
102
+ if ( class_exists( 'Tribe__Tickets_Plus__Commerce__WooCommerce__Main' ) ) {
103
+ $ticket_ids = Tribe__Tickets_Plus__Commerce__WooCommerce__Main::get_instance()->get_tickets_ids( $post->ID );
104
+ foreach ( $ticket_ids as $ticket_id ) {
105
+ $ticket = Tribe__Tickets_Plus__Commerce__WooCommerce__Main::get_instance()->get_ticket( $post_id, $ticket_id );
106
+ $tickets[] = $ticket->name . '|#|' . $ticket->description;
107
+ $ticket_meta[] = get_post_meta( $ticket_id, '_tribe_tickets_meta', true );
108
+ }
109
+ }
110
 
111
+ $content .= md5( serialize( $tickets ) );
112
+ $content .= md5( serialize( $ticket_meta ) );
113
+ }
114
+ }
115
 
116
+ return $content;
117
+ }
118
 
119
+ public function append_RSVP_tickets_to_translation_job( $package, $post ) {
120
 
121
+ if ( 'tribe_events' === $post->post_type && class_exists( 'Tribe__Tickets__RSVP' ) ) {
 
122
 
123
+ $ticket_lang = $this->sitepress->get_language_for_element( $post->ID, 'post_tribe_events' );
124
+ $this->sitepress->switch_lang( $ticket_lang );
125
+ $ticket_ids = Tribe__Tickets__RSVP::get_instance()->get_tickets_ids( $post->ID );
126
+ $this->sitepress->switch_lang();
127
 
128
+ if ( $ticket_ids ) {
129
+ foreach ( $ticket_ids as $ticket_id ) {
130
 
131
+ $ticket_post = get_post( $ticket_id );
132
+ $original_ticket_id = $this->sitepress->get_original_element_id( $ticket_id, 'post_tribe_rsvp_tickets' );
 
 
133
 
134
+ if ( ! empty( $ticket_post->post_title ) ) {
135
+ $package['contents'][ 'rsvp_tickets_' . $original_ticket_id . '_title' ] = [
136
+ 'translate' => 1,
137
+ 'data' => $this->tp->encode_field_data( $ticket_post->post_title, 'base64' ),
138
+ 'format' => 'base64',
139
+ ];
140
+ }
141
+ if ( ! empty( $ticket_post->post_excerpt ) ) {
142
+ $package['contents'][ 'rsvp_tickets_' . $original_ticket_id . '_excerpt' ] = [
143
+ 'translate' => 1,
144
+ 'data' => $this->tp->encode_field_data( $ticket_post->post_excerpt, 'base64' ),
145
+ 'format' => 'base64',
146
+ ];
147
+ }
148
 
149
+ // fieldsets.
150
+ $package = $this->append_tickets_meta( $package, $ticket_id, $original_ticket_id );
151
 
152
+ }
153
+ }
154
+ }
 
 
 
 
 
 
 
 
 
 
 
155
 
156
+ return $package;
157
+ }
158
 
159
+ public function save_RSVP_tickets_translations( $post_id, $data, $job ) {
 
160
 
161
+ $translations = [];
162
 
163
+ foreach ( $data as $key => $value ) {
164
 
165
+ if ( preg_match( '/rsvp_tickets_([0-9]+)_title/', $key, $matches ) ) {
166
+ $rsvp_post_id = $matches[1];
167
+ if ( 'on' === $value['finished'] ) {
168
+ $translations[ $rsvp_post_id ]['post_title'] = $value['data'];
169
+ }
170
+ } elseif ( preg_match( '/rsvp_tickets_([0-9]+)_excerpt/', $key, $matches ) ) {
171
+ $rsvp_post_id = $matches[1];
172
+ if ( 'on' === $value['finished'] ) {
173
+ $translations[ $rsvp_post_id ]['post_excerpt'] = $value['data'];
174
+ }
175
+ }
176
+ }
177
 
178
+ foreach ( $translations as $rsvp_post_id => $translation ) {
179
 
180
+ $translated_rsvp_post_id = apply_filters( 'translate_object_id', $rsvp_post_id, 'tribe_rsvp_tickets', false, $job->language_code );
181
 
182
+ $postarr = [
183
+ 'post_type' => 'tribe_rsvp_tickets',
184
+ 'post_status' => 'publish',
185
+ 'post_title' => $translation['post_title'],
186
+ 'post_excerpt' => $translation['post_excerpt'],
187
+ 'post_name' => sanitize_title_with_dashes( $translation['post_title'] ),
188
+ ];
189
 
190
+ if ( $translated_rsvp_post_id && $translated_rsvp_post_id != $rsvp_post_id ) {
191
+ global $wpml_post_translations;
192
+ $postarr['ID'] = $translated_rsvp_post_id;
193
+ remove_action( 'save_post', [ $wpml_post_translations, 'save_post_actions' ], 100 );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
194
  wp_update_post( $postarr );
195
+ add_action( 'save_post', [ $wpml_post_translations, 'save_post_actions' ], 100 );
196
 
197
+ } else {
198
+ $translated_rsvp_post_id = wp_insert_post( $postarr );
199
+ $trid = $this->sitepress->get_element_trid( $rsvp_post_id, 'post_tribe_rsvp_tickets' );
200
+ $this->sitepress->set_element_language_details( $translated_rsvp_post_id, 'post_tribe_rsvp_tickets', $trid, $job->language_code );
201
+ }
202
 
203
+ $event_id = get_post_meta( $rsvp_post_id, '_tribe_rsvp_for_event', true );
204
 
205
+ $translated_event_id = apply_filters( 'translate_object_id', $event_id, 'tribe_events', false, $job->language_code );
206
+ update_post_meta( $translated_rsvp_post_id, '_tribe_rsvp_for_event', $translated_event_id );
207
 
208
+ $this->sync_custom_fields( $rsvp_post_id, $translated_rsvp_post_id );
209
 
210
  $this->save_ticket_meta_translations( $rsvp_post_id, $translated_rsvp_post_id );
211
 
212
+ }
213
+ }
214
 
215
+ public function append_woo_tickets_to_translation_job( $package, $post ) {
216
 
217
+ if ( 'tribe_events' === $post->post_type && class_exists( 'Tribe__Tickets_Plus__Commerce__WooCommerce__Main' ) ) {
218
 
219
  $ticket_lang = $this->sitepress->get_language_for_element( $post->ID, 'post_tribe_events' );
220
  $this->sitepress->switch_lang( $ticket_lang );
221
+ $ticket_ids = Tribe__Tickets_Plus__Commerce__WooCommerce__Main::get_instance()->get_tickets_ids( $post->ID );
222
  $this->sitepress->switch_lang();
223
 
224
+ if ( $ticket_ids ) {
225
+ foreach ( $ticket_ids as $ticket_id ) {
226
 
227
+ $ticket_post = get_post( $ticket_id );
228
  $original_ticket_id = $this->sitepress->get_original_element_id( $ticket_id, 'post_product' );
229
 
230
+ if ( ! empty( $ticket_post->post_title ) ) {
231
+ $package['contents'][ 'woo_tickets_' . $original_ticket_id . '_title' ] = [
232
  'translate' => 1,
233
  'data' => $this->tp->encode_field_data( $ticket_post->post_title, 'base64' ),
234
  'format' => 'base64',
235
+ ];
236
  }
237
+ if ( ! empty( $ticket_post->post_excerpt ) ) {
238
+ $package['contents'][ 'woo_tickets_' . $original_ticket_id . '_excerpt' ] = [
239
  'translate' => 1,
240
  'data' => $this->tp->encode_field_data( $ticket_post->post_excerpt, 'base64' ),
241
  'format' => 'base64',
242
+ ];
243
  }
244
 
245
+ // Fieldsets.
246
  $package = $this->append_tickets_meta( $package, $ticket_id, $original_ticket_id );
247
 
248
  }
249
  }
 
250
  }
251
 
252
  return $package;
253
  }
254
 
255
+ public function save_woo_tickets_translations( $post_id, $data, $job ) {
256
  global $wpml_post_translations;
257
 
258
+ $translations = [];
259
 
260
  foreach ( $data as $key => $value ) {
261
 
262
  if ( preg_match( '/woo_tickets_([0-9]+)_title/', $key, $matches ) ) {
263
  $ticket_post_id = $matches[1];
264
+ if ( 'on' === $value['finished'] ) {
265
  $translations[ $ticket_post_id ]['post_title'] = $value['data'];
266
  }
267
  } elseif ( preg_match( '/woo_tickets_([0-9]+)_excerpt/', $key, $matches ) ) {
268
  $ticket_post_id = $matches[1];
269
+ if ( 'on' === $value['finished'] ) {
270
  $translations[ $ticket_post_id ]['post_excerpt'] = $value['data'];
271
  }
272
  }
 
273
  }
274
 
275
+ foreach ( $translations as $ticket_post_id => $translation ) {
 
276
  $translated_ticket_post_id = apply_filters( 'translate_object_id', $ticket_post_id, 'product', false, $job->language_code );
277
 
278
+ $postarr = [
279
+ 'post_type' => 'product',
280
+ 'post_status' => 'publish',
281
  'post_title' => $translation['post_title'],
282
  'post_excerpt' => $translation['post_excerpt'],
283
+ 'post_name' => sanitize_title_with_dashes( $translation['post_title'] ),
284
+ ];
285
 
286
+ remove_action( 'save_post', [ $wpml_post_translations, 'save_post_actions' ], 100, 2 );
287
+ if ( $translated_ticket_post_id && $translated_ticket_post_id != $ticket_post_id ) {
288
  $postarr['ID'] = $translated_ticket_post_id;
289
  wp_update_post( $postarr );
290
+ } else {
291
  $translated_ticket_post_id = wp_insert_post( $postarr );
292
+ $trid = $this->sitepress->get_element_trid( $ticket_post_id, 'post_product' );
293
  $this->sitepress->set_element_language_details( $translated_ticket_post_id, 'post_product', $trid, $job->language_code );
294
  }
295
+ add_action( 'save_post', [ $wpml_post_translations, 'save_post_actions' ], 100, 2 );
296
 
297
+ $event_id = get_post_meta( $ticket_post_id, '_tribe_wooticket_for_event', true );
298
 
299
+ $translated_event_id = apply_filters( 'translate_object_id', $event_id, 'tribe_events', false, $job->language_code );
300
+ update_post_meta( $translated_ticket_post_id, '_tribe_wooticket_for_event', $translated_event_id );
301
 
302
  $this->sync_custom_fields( $ticket_post_id, $translated_ticket_post_id );
303
 
304
  $this->save_ticket_meta_translations( $ticket_post_id, $translated_ticket_post_id );
 
305
  }
306
  }
307
 
308
+ private function append_tickets_meta( $package, $ticket_id, $original_ticket_id ) {
309
 
310
  $ticket_meta = get_post_meta( $ticket_id, '_tribe_tickets_meta', true );
311
+ if ( is_array( $ticket_meta ) ) {
312
  foreach ( $ticket_meta as $k => $meta ) {
313
+ $package['contents'][ 'rsvp_tickets_' . $original_ticket_id . '_meta_' . $k . '_label' ] = [
314
  'translate' => 1,
315
  'data' => $this->tp->encode_field_data( $meta['label'], 'base64' ),
316
  'format' => 'base64',
317
+ ];
318
+ $package['contents'][ 'rsvp_tickets_' . $original_ticket_id . '_meta_' . $k . '_slug' ] = [
319
  'translate' => 1,
320
  'data' => $this->tp->encode_field_data( $meta['slug'], 'base64' ),
321
  'format' => 'base64',
322
+ ];
323
  if ( isset( $meta['extra']['options'] ) ) {
324
  foreach ( $meta['extra']['options'] as $option_id => $option_name ) {
325
 
326
+ $package['contents'][ 'rsvp_tickets_' . $original_ticket_id . '_meta_' . $k . '_option_' . $option_id ] = [
327
  'translate' => 1,
328
  'data' => $this->tp->encode_field_data( $option_name, 'base64' ),
329
  'format' => 'base64',
330
+ ];
331
 
332
  }
 
333
  }
334
  }
335
  }
337
  return $package;
338
  }
339
 
340
+ private function save_ticket_meta_translations( $ticket_id, $translated_ticket_id ) {
341
+ $ticket_meta = get_post_meta( $ticket_id, '_tribe_tickets_meta', true );
 
342
  $translated_ticket_meta = $ticket_meta;
343
+ if ( is_array( $ticket_meta ) ) {
344
 
345
  foreach ( $ticket_meta as $k => $meta ) {
 
346
  $key = 'rsvp_tickets_' . $ticket_id . '_meta_' . $k . '_label';
347
+ if ( isset( $data[ $key ] ) && 'on' === $data[ $key ]['finished'] ) {
348
+ $translated_ticket_meta[ $k ]['label'] = $data[ $key ]['data'];
349
  }
350
 
351
  $key = 'rsvp_tickets_' . $ticket_id . '_meta_' . $k . '_slug';
352
+ if ( isset( $data[ $key ] ) && 'on' === $data[ $key ]['finished'] ) {
353
+ $translated_ticket_meta[ $k ]['slug'] = $data[ $key ]['data'];
354
  }
355
 
356
  if ( isset( $meta['extra']['options'] ) ) {
357
  foreach ( $meta['extra']['options'] as $option_id => $option_name ) {
358
  $key = 'rsvp_tickets_' . $ticket_id . '_meta_' . $k . '_option_' . $option_id;
359
+ if ( isset( $data[ $key ] ) && 'on' === $data[ $key ]['finished'] ) {
360
+ $translated_ticket_meta[ $k ]['extra']['options'][ $option_id ] = $data[ $key ]['data'];
361
  }
362
  }
363
  }
 
364
  }
 
365
  }
366
 
367
  update_post_meta( $translated_ticket_id, '_tribe_tickets_meta', $translated_ticket_meta );
368
 
369
+ update_post_meta(
370
+ $translated_ticket_id,
371
+ '_tribe_tickets_meta_enabled',
372
  get_post_meta( $ticket_id, '_tribe_tickets_meta_enabled', true )
373
  );
374
 
 
375
  }
376
 
377
+ private function sync_custom_fields( $original_ticket_id, $translated_ticket_id ) {
378
+ // Sync custom fields.
379
+ $custom_fields_sync = [ '_stock', '_manage_stock', 'total_sales', '_price' ];
380
+ foreach ( $custom_fields_sync as $custom_field ) {
381
  $value = get_post_meta( $original_ticket_id, $custom_field, true );
382
+ if ( $value !== false ) {
383
+ update_post_meta( $translated_ticket_id, $custom_field, $value );
384
  }
385
  }
386
  }
387
 
388
+ public function synchronize_venue_for_event( $post_id, $post, $update ) {
389
 
390
+ if ( $post->post_type === 'tribe_event' ) {
391
 
392
+ $venue_id = get_post_meta( $post_id, '_EventVenueID', true );
393
 
394
+ $original_event_id = $this->sitepress->get_original_element_id( $post_id, 'post_tribe_event' );
395
 
396
+ if ( $original_event_id == $post_id ) {
397
+ $event_trid = $this->sitepress->get_element_trid( $post_id, 'post_tribe_venue' );
398
+ $event_translations = $this->sitepress->get_element_translations( $event_trid, 'post_tribe_venue' );
399
 
400
+ if ( $venue_id ) {
401
+ foreach ( $event_translations as $language_code => $event_translation ) {
402
+ if ( $event_translation->element_id != $original_event_id ) {
403
+ $translated_venue_id = apply_filters( 'translate_object_id', $venue_id, 'tribe_venue', false, $language_code );
404
+ if ( $translated_venue_id ) {
405
+ update_post_meta( $event_translation->element_id, '_EventVenueID', $translated_venue_id );
406
+ }
407
+ }
408
+ }
409
+ } else { // delete venue from translations.
410
+ foreach ( $event_translations as $language_code => $event_translation ) {
411
+ if ( $event_translation->element_id != $original_event_id ) {
412
+ delete_post_meta( $event_translation->element_id, '_EventVenueID' );
413
+ }
414
+ }
415
+ }
416
+ }
417
+ }
 
 
418
 
419
+ }
420
 
421
+ public function pre_select_translated_venue() {
422
  $current_screen = get_current_screen();
423
+ if ( $current_screen->base === 'post' && $current_screen->action === 'add' && $current_screen->id === 'tribe_events' ) {
424
+ if ( isset( $_GET['trid'] ) && isset( $_GET['lang'] ) && isset( $_GET['source_lang'] ) ) {
425
  $event_translations = $this->sitepress->get_element_translations( $_GET['trid'], 'post_tribe_events' );
426
+ $original_event_id = $event_translations[ $_GET['source_lang'] ]->element_id;
427
+ $original_venue_id = get_post_meta( $original_event_id, '_EventVenueID', true );
428
+ if ( $original_venue_id ) {
429
  $translated_venue_id = apply_filters( 'translate_object_id', $original_venue_id, 'tribe_venue', false, $_GET['lang'] );
430
+ if ( $translated_venue_id ) {
431
+ // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
432
  echo "<script type=\"text/javascript\">
433
  jQuery('#saved_tribe_venue').val($translated_venue_id);
434
  </script>";
436
  }
437
  }
438
  }
439
+ }
 
 
440
 
441
+ public function save_venue_for_translation( $post_id, $data, $job ) {
 
442
 
443
+ $original_event_id = $this->sitepress->get_original_element_id( $post_id, 'post_tribe_event' );
444
+ $original_venue_id = get_post_meta( $original_event_id, '_EventVenueID', true );
 
 
 
445
 
446
+ if ( $original_venue_id ) {
447
+ $translated_venue_id = apply_filters( 'translate_object_id', $original_venue_id, 'tribe_venue', false, $job->language_code );
448
+ if ( $translated_venue_id ) {
449
+ update_post_meta( $post_id, '_EventVenueID', $translated_venue_id );
450
+ }
451
+ }
452
 
453
+ }
454
 
455
+ public function sync_rsvp_fields_on_attendee_created( $order_id, $post_id, $attendee_order_status ) {
456
 
457
+ $rsvp_post_id = isset( $_POST['product_id'][0] ) ? $_POST['product_id'][0] : false;
458
+ if ( $rsvp_post_id ) {
459
+ $rsvp_trid = $this->sitepress->get_element_trid( $rsvp_post_id, 'post_tribe_rsvp_tickets' );
460
+ $rsvp_translations = $this->sitepress->get_element_translations( $rsvp_trid, 'post_tribe_rsvp_tickets' );
461
 
462
+ foreach ( $rsvp_translations as $translation ) {
463
+ if ( $translation->element_id != $rsvp_post_id ) {
464
+ $this->sync_custom_fields( $rsvp_post_id, $translation->element_id );
465
+ }
466
+ }
467
+ }
468
+ }
469
 
470
+ public function get_translated_organizer_ids( $organizer_ids, $event_id ) {
471
+ foreach ( $organizer_ids as $key => $organizer_id ) {
472
+ $organizer_ids[ $key ] = apply_filters( 'translate_object_id', $organizer_id, 'tribe_organizer', true );
473
+ }
474
+ return $organizer_ids;
475
+ }
476
 
477
+ public function convert_events_cost( $cost ) {
478
  return apply_filters( 'wcml_raw_price_amount', $cost );
479
+ }
480
 
481
  }
482
 
compatibility/class-wcml-variation-swatches-and-photos.php CHANGED
@@ -8,8 +8,8 @@ class WCML_Variation_Swatches_And_Photos {
8
  /** @var woocommerce_wpml */
9
  private $woocommerce_wpml;
10
 
11
- function __construct( woocommerce_wpml $woocommerce_wpml ) {
12
- $this->woocommerce_wpml = $woocommerce_wpml;
13
  }
14
 
15
  public function add_hooks() {
@@ -19,14 +19,14 @@ class WCML_Variation_Swatches_And_Photos {
19
  /**
20
  * Synchronize Variation Swatches and Photos
21
  *
22
- * @param int $original_product_id Original product ID.
23
- * @param int $translated_product_id Translated product ID.
24
  * @param string $language
25
  */
26
  public function sync_variation_swatches_and_photos( $original_product_id, $translated_product_id, $language ) {
27
 
28
  $swatch_options = maybe_unserialize( get_post_meta( $original_product_id, '_swatch_type_options', true ) );
29
- $translated_swatch_options = $swatch_options;
30
 
31
  if ( $swatch_options ) {
32
  $original_product_attributes = $this->woocommerce_wpml->attributes->get_product_attributes( $original_product_id );
@@ -64,7 +64,7 @@ class WCML_Variation_Swatches_And_Photos {
64
  wpml_collect( $swatch_options[ $attribute_name_hash ]['attributes'] )->each(
65
  function ( $swatch_attribute, $swatch_attribute_key ) use ( $term, $attribute_term_slug_md5, $taxonomy, $attribute_name_hash, &$translated_swatch_options, $language ) {
66
  if ( $attribute_term_slug_md5 === $swatch_attribute_key ) {
67
- $translated_term = $this->woocommerce_wpml->terms->wcml_get_translated_term( $term->term_id, $taxonomy, $language );
68
  $translated_swatch_options[ $attribute_name_hash ]['attributes'][ md5( $translated_term->slug ) ] = $swatch_attribute;
69
  unset( $translated_swatch_options[ $attribute_name_hash ]['attributes'][ $swatch_attribute_key ] );
70
  }
@@ -79,7 +79,7 @@ class WCML_Variation_Swatches_And_Photos {
79
 
80
  wpml_collect( $attribute_values )->each(
81
  function ( $attribute_value ) use ( $attribute_key, $attribute, $attribute_name_hash, $swatch_options, &$translated_swatch_options, $original_product_id, $translated_product_id ) {
82
- $attribute_value = trim( $attribute_value, " " );
83
  $attribute_value_md5 = md5( sanitize_title( strtolower( $attribute_value ) ) );
84
  $translated_swatch_options = $this->translate_custom_attribute_value( $attribute_key, $attribute_value, $attribute_value_md5, $attribute_name_hash, $swatch_options, $translated_swatch_options, $original_product_id, $translated_product_id );
85
  }
@@ -92,7 +92,7 @@ class WCML_Variation_Swatches_And_Photos {
92
  wpml_collect( $swatch_options[ $attribute_name_hash ]['attributes'] )->each(
93
  function ( $swatch_attribute, $swatch_attribute_key ) use ( $attribute_key, $attribute_value, $attribute_value_md5, $attribute_name_hash, &$translated_swatch_options, $original_product_id, $translated_product_id ) {
94
  if ( $attribute_value_md5 === $swatch_attribute_key ) {
95
- $translated_attribute_value = $this->woocommerce_wpml->attributes->get_custom_attr_translation( $original_product_id, $translated_product_id, $attribute_key, $attribute_value );
96
  $translated_swatch_options[ $attribute_name_hash ]['attributes'][ md5( sanitize_title( strtolower( $translated_attribute_value ) ) ) ] = $swatch_attribute;
97
  unset( $translated_swatch_options[ $attribute_name_hash ]['attributes'][ $swatch_attribute_key ] );
98
  }
8
  /** @var woocommerce_wpml */
9
  private $woocommerce_wpml;
10
 
11
+ public function __construct( woocommerce_wpml $woocommerce_wpml ) {
12
+ $this->woocommerce_wpml = $woocommerce_wpml;
13
  }
14
 
15
  public function add_hooks() {
19
  /**
20
  * Synchronize Variation Swatches and Photos
21
  *
22
+ * @param int $original_product_id Original product ID.
23
+ * @param int $translated_product_id Translated product ID.
24
  * @param string $language
25
  */
26
  public function sync_variation_swatches_and_photos( $original_product_id, $translated_product_id, $language ) {
27
 
28
  $swatch_options = maybe_unserialize( get_post_meta( $original_product_id, '_swatch_type_options', true ) );
29
+ $translated_swatch_options = $swatch_options;
30
 
31
  if ( $swatch_options ) {
32
  $original_product_attributes = $this->woocommerce_wpml->attributes->get_product_attributes( $original_product_id );
64
  wpml_collect( $swatch_options[ $attribute_name_hash ]['attributes'] )->each(
65
  function ( $swatch_attribute, $swatch_attribute_key ) use ( $term, $attribute_term_slug_md5, $taxonomy, $attribute_name_hash, &$translated_swatch_options, $language ) {
66
  if ( $attribute_term_slug_md5 === $swatch_attribute_key ) {
67
+ $translated_term = $this->woocommerce_wpml->terms->wcml_get_translated_term( $term->term_id, $taxonomy, $language );
68
  $translated_swatch_options[ $attribute_name_hash ]['attributes'][ md5( $translated_term->slug ) ] = $swatch_attribute;
69
  unset( $translated_swatch_options[ $attribute_name_hash ]['attributes'][ $swatch_attribute_key ] );
70
  }
79
 
80
  wpml_collect( $attribute_values )->each(
81
  function ( $attribute_value ) use ( $attribute_key, $attribute, $attribute_name_hash, $swatch_options, &$translated_swatch_options, $original_product_id, $translated_product_id ) {
82
+ $attribute_value = trim( $attribute_value, ' ' );
83
  $attribute_value_md5 = md5( sanitize_title( strtolower( $attribute_value ) ) );
84
  $translated_swatch_options = $this->translate_custom_attribute_value( $attribute_key, $attribute_value, $attribute_value_md5, $attribute_name_hash, $swatch_options, $translated_swatch_options, $original_product_id, $translated_product_id );
85
  }
92
  wpml_collect( $swatch_options[ $attribute_name_hash ]['attributes'] )->each(
93
  function ( $swatch_attribute, $swatch_attribute_key ) use ( $attribute_key, $attribute_value, $attribute_value_md5, $attribute_name_hash, &$translated_swatch_options, $original_product_id, $translated_product_id ) {
94
  if ( $attribute_value_md5 === $swatch_attribute_key ) {
95
+ $translated_attribute_value = $this->woocommerce_wpml->attributes->get_custom_attr_translation( $original_product_id, $translated_product_id, $attribute_key, $attribute_value );
96
  $translated_swatch_options[ $attribute_name_hash ]['attributes'][ md5( sanitize_title( strtolower( $translated_attribute_value ) ) ) ] = $swatch_attribute;
97
  unset( $translated_swatch_options[ $attribute_name_hash ]['attributes'][ $swatch_attribute_key ] );
98
  }
compatibility/class-wcml-vpc.php DELETED
@@ -1,20 +0,0 @@
1
- <?php
2
-
3
- class WCML_Vpc {
4
-
5
- function __construct() {
6
- add_filter( 'wcml_calculate_totals_exception', array( $this, 'wcml_vpc_cart_exc' ), 10, 2 );
7
- }
8
-
9
- function wcml_vpc_cart_exc( $exc, $cart ) {
10
-
11
- foreach( $cart->cart_contents as $cart_item ){
12
- if ( array_key_exists( 'visual-product-configuration', $cart_item ) ) {
13
- return false;
14
- }
15
- }
16
-
17
- return $exc;
18
- }
19
-
20
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
compatibility/class-wcml-wc-ajax-cart.php DELETED
@@ -1,16 +0,0 @@
1
- <?php
2
-
3
- class WCML_WC_Ajax_Cart{
4
-
5
- function __construct() {
6
- add_filter( 'wcml_calculate_totals_exception', array( $this, 'wac_update_ajax' ), 9 );
7
- }
8
-
9
- function wac_update_ajax( $exc ) {
10
- if ( !empty($_POST['is_wac_ajax'])) {
11
- return false;
12
- }
13
- return $exc;
14
- }
15
-
16
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
compatibility/class-wcml-wc-memberships.php CHANGED
@@ -13,12 +13,12 @@ class WCML_WC_Memberships {
13
 
14
  public function add_hooks() {
15
 
16
- add_filter( 'parse_request', array( $this, 'adjust_query_vars' ) );
17
- add_filter( 'wcml_register_endpoints_query_vars', array( $this, 'register_endpoints_query_vars' ), 10, 3 );
18
- add_filter( 'wcml_endpoint_permalink_filter', array( $this, 'endpoint_permalink_filter' ), 10, 2 );
19
- add_filter( 'wc_memberships_members_area_my-memberships_actions', array( $this, 'filter_actions_links' ) );
20
 
21
- add_action( 'wp_enqueue_scripts', array( $this, 'load_assets' ) );
22
  }
23
 
24
  public function register_endpoints_query_vars( $query_vars, $wc_vars, $object ) {
@@ -73,7 +73,7 @@ class WCML_WC_Memberships {
73
  if ( isset( $post->ID ) && wc_get_page_id( 'myaccount' ) == $post->ID ) {
74
  $wcml_plugin_url = $this->wp_api->constant( 'WCML_PLUGIN_URL' );
75
  $wcml_version = $this->wp_api->constant( 'WCML_VERSION' );
76
- wp_register_script( 'wcml-members-js', $wcml_plugin_url . '/compatibility/res/js/wcml-members.js', array( 'jquery' ), $wcml_version, true );
77
  wp_enqueue_script( 'wcml-members-js' );
78
  wp_localize_script( 'wcml-members-js', 'wc_memberships_memebers_area_endpoint', $this->get_members_area_endpoint() );
79
  }
@@ -86,10 +86,10 @@ class WCML_WC_Memberships {
86
  $string_context = class_exists( 'WPML_Endpoints_Support' ) ? WPML_Endpoints_Support::STRING_CONTEXT : 'WooCommerce Endpoints';
87
  $translated_endpoint = apply_filters( 'wpml_translate_single_string', $endpoint, $string_context, 'members_area' );
88
 
89
- return array(
90
  'original' => $endpoint,
91
- 'translated' => $translated_endpoint
92
- );
93
  }
94
 
95
 
13
 
14
  public function add_hooks() {
15
 
16
+ add_filter( 'parse_request', [ $this, 'adjust_query_vars' ] );
17
+ add_filter( 'wcml_register_endpoints_query_vars', [ $this, 'register_endpoints_query_vars' ], 10, 3 );
18
+ add_filter( 'wcml_endpoint_permalink_filter', [ $this, 'endpoint_permalink_filter' ], 10, 2 );
19
+ add_filter( 'wc_memberships_members_area_my-memberships_actions', [ $this, 'filter_actions_links' ] );
20
 
21
+ add_action( 'wp_enqueue_scripts', [ $this, 'load_assets' ] );
22
  }
23
 
24
  public function register_endpoints_query_vars( $query_vars, $wc_vars, $object ) {
73
  if ( isset( $post->ID ) && wc_get_page_id( 'myaccount' ) == $post->ID ) {
74
  $wcml_plugin_url = $this->wp_api->constant( 'WCML_PLUGIN_URL' );
75
  $wcml_version = $this->wp_api->constant( 'WCML_VERSION' );
76
+ wp_register_script( 'wcml-members-js', $wcml_plugin_url . '/compatibility/res/js/wcml-members.js', [ 'jquery' ], $wcml_version, true );
77
  wp_enqueue_script( 'wcml-members-js' );
78
  wp_localize_script( 'wcml-members-js', 'wc_memberships_memebers_area_endpoint', $this->get_members_area_endpoint() );
79
  }
86
  $string_context = class_exists( 'WPML_Endpoints_Support' ) ? WPML_Endpoints_Support::STRING_CONTEXT : 'WooCommerce Endpoints';
87
  $translated_endpoint = apply_filters( 'wpml_translate_single_string', $endpoint, $string_context, 'members_area' );
88
 
89
+ return [
90
  'original' => $endpoint,
91
+ 'translated' => $translated_endpoint,
92
+ ];
93
  }
94
 
95
 
compatibility/class-wcml-wc-name-your-price.php CHANGED
@@ -1,24 +1,24 @@
1
  <?php
2
 
3
- class WCML_WC_Name_Your_Price{
4
 
5
- function __construct(){
6
 
7
- add_action('init', array($this, 'init'),9);
8
 
9
- }
10
 
11
- function init(){
12
- if( !is_admin() ){
13
- add_filter('woocommerce_raw_suggested_price', array($this, 'product_price_filter'), 10, 2);
14
- add_filter('woocommerce_raw_minimum_price', array($this, 'product_price_filter'), 10, 2);
15
- }
16
- }
17
-
18
- function product_price_filter($price, $product){
19
-
20
- return apply_filters('wcml_raw_price_amount', $price );
21
 
22
- }
 
 
 
 
23
 
24
  }
1
  <?php
2
 
3
+ class WCML_WC_Name_Your_Price {
4
 
5
+ public function __construct() {
6
 
7
+ add_action( 'init', [ $this, 'init' ], 9 );
8
 
9
+ }
10
 
11
+ public function init() {
12
+ if ( ! is_admin() ) {
13
+ add_filter( 'woocommerce_raw_suggested_price', [ $this, 'product_price_filter' ], 10, 2 );
14
+ add_filter( 'woocommerce_raw_minimum_price', [ $this, 'product_price_filter' ], 10, 2 );
15
+ }
16
+ }
 
 
 
 
17
 
18
+ public function product_price_filter( $price, $product ) {
19
+
20
+ return apply_filters( 'wcml_raw_price_amount', $price );
21
+
22
+ }
23
 
24
  }
compatibility/class-wcml-wc-product-type-column.php CHANGED
@@ -4,7 +4,7 @@ class WCML_WC_Product_Type_Column {
4
 
5
  public function add_hooks() {
6
 
7
- add_filter( 'wcml_show_type_column', array( $this, 'show_type_column' ) );
8
 
9
  }
10
 
4
 
5
  public function add_hooks() {
6
 
7
+ add_filter( 'wcml_show_type_column', [ $this, 'show_type_column' ] );
8
 
9
  }
10
 
compatibility/class-wcml-wc-subscriptions.php CHANGED
@@ -1,6 +1,6 @@
1
  <?php
2
 
3
- class WCML_WC_Subscriptions{
4
 
5
  private $new_subscription = false;
6
 
@@ -9,79 +9,94 @@ class WCML_WC_Subscriptions{
9
  /** @var wpdb */
10
  private $wpdb;
11
 
12
- function __construct( woocommerce_wpml $woocommerce_wpml, wpdb $wpdb ){
13
  $this->woocommerce_wpml = $woocommerce_wpml;
14
  $this->wpdb = $wpdb;
15
  }
16
 
17
- public function add_hooks(){
18
 
19
- add_action( 'init', array( $this, 'init' ), 9 );
20
- add_filter( 'wcml_variation_term_taxonomy_ids', array( $this, 'wcml_variation_term_taxonomy_ids' ) );
21
- add_filter( 'woocommerce_subscription_lengths', array( $this, 'woocommerce_subscription_lengths' ), 10, 2 );
22
 
23
- add_filter( 'wcml_register_endpoints_query_vars', array( $this, 'register_endpoint' ), 10, 3 );
24
- add_filter( 'wcml_endpoint_permalink_filter', array( $this, 'endpoint_permalink_filter' ), 10, 2 );
25
 
26
- //custom prices
27
- add_filter( 'wcml_custom_prices_fields', array( $this, 'set_prices_fields' ), 10, 2 );
28
- add_filter( 'wcml_custom_prices_strings', array( $this, 'set_labels_for_prices_fields' ), 10, 2 );
29
- add_filter( 'wcml_custom_prices_fields_labels', array( $this, 'set_labels_for_prices_fields' ), 10, 2 );
30
- add_filter( 'wcml_update_custom_prices_values', array( $this, 'update_custom_prices_values' ), 10, 3 );
31
- add_action( 'wcml_after_custom_prices_block', array( $this, 'new_subscription_prices_block' ) );
32
 
33
- add_action( 'woocommerce_subscriptions_product_options_pricing', array( $this, 'show_pointer_info' ) );
34
- add_action( 'woocommerce_variable_subscription_pricing', array( $this, 'show_pointer_info' ) );
35
 
36
- add_filter( 'woocommerce_subscriptions_product_price', array(
37
- $this,
38
- 'woocommerce_subscription_price_from'
39
- ), 10, 2 );
 
 
 
 
 
 
 
40
 
41
- add_filter( 'wcml_xliff_allowed_variations_types', array( $this, 'set_allowed_variations_types_in_xliff') );
42
-
43
- //Add language links to email settings
44
- add_filter( 'wcml_emails_options_to_translate', array( $this, 'translate_email_options' ) );
45
- add_filter( 'wcml_emails_section_name_prefix', array( $this, 'email_option_section_prefix' ), 10, 2 );
46
 
47
  }
48
 
49
- function init(){
50
- if( !is_admin() ){
51
- add_filter( 'woocommerce_subscriptions_product_sign_up_fee', array(
52
- $this,
53
- 'subscriptions_product_sign_up_fee_filter'
54
- ), 10, 2 );
 
 
 
 
 
55
 
56
- add_action( 'woocommerce_before_calculate_totals', array( $this, 'maybe_backup_recurring_carts'), 1 );
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
65
- add_filter( 'woocommerce_generated_manual_renewal_order_renewal_notification', array( $this, 'translate_renewal_notification'), 9 );
66
- add_filter( 'woocommerce_order_status_failed_renewal_notification', array( $this, 'translate_renewal_notification'), 9 );
67
  }
68
 
69
 
70
  /**
71
  * Filter Subscription Sign-up fee cost
72
  *
73
- * @param string $subscription_sign_up_fee
74
  * @param WC_Product $product
75
  * @return string
76
  */
77
- function subscriptions_product_sign_up_fee_filter( $subscription_sign_up_fee, $product ) {
78
 
79
  if ( $product && wcml_is_multi_currency_on() ) {
80
  $currency = $this->woocommerce_wpml->multi_currency->get_client_currency();
81
 
82
  if ( $currency !== wcml_get_woocommerce_currency_option() ) {
83
 
84
- $original_product_id = $this->woocommerce_wpml->products->get_original_product_id( $product->get_id() );
 
 
 
 
 
85
 
86
  if ( get_post_meta( $original_product_id, '_wcml_custom_prices_status', true ) ) {
87
  $subscription_sign_up_fee = get_post_meta( $original_product_id, '_subscription_sign_up_fee_' . $currency, true );
@@ -94,37 +109,37 @@ class WCML_WC_Subscriptions{
94
  return $subscription_sign_up_fee;
95
  }
96
 
97
- function wcml_variation_term_taxonomy_ids($get_variation_term_taxonomy_ids){
98
 
99
- $get_variation_term_taxonomy_id = $this->wpdb->get_var("SELECT tt.term_taxonomy_id FROM {$this->wpdb->terms} AS t LEFT JOIN {$this->wpdb->term_taxonomy} AS tt ON t.term_id = tt.term_id WHERE t.slug = 'variable-subscription'");
100
 
101
- if(!empty($get_variation_term_taxonomy_id)){
102
  $get_variation_term_taxonomy_ids[] = $get_variation_term_taxonomy_id;
103
  }
104
 
105
  return $get_variation_term_taxonomy_ids;
106
  }
107
 
108
- public function woocommerce_subscription_lengths($subscription_ranges, $subscription_period) {
109
 
110
- if (is_array($subscription_ranges)) {
111
- foreach ($subscription_ranges as $period => $ranges) {
112
- if (is_array($ranges)) {
113
- foreach ($ranges as $range) {
114
- if ($range == "9 months") {
115
  $breakpoint = true;
116
  }
117
- $new_subscription_ranges[$period][] = apply_filters( 'wpml_translate_single_string', $range, 'wc_subscription_ranges', $range);
118
  }
119
  }
120
  }
121
  }
122
 
123
- return isset($new_subscription_ranges) ? $new_subscription_ranges : $subscription_ranges;
124
  }
125
 
126
- function set_prices_fields( $fields, $product_id ){
127
- if( $this->is_subscriptions_product( $product_id ) || $this->new_subscription ){
128
  $fields[] = '_subscription_sign_up_fee';
129
  }
130
 
@@ -132,115 +147,116 @@ class WCML_WC_Subscriptions{
132
 
133
  }
134
 
135
- function set_labels_for_prices_fields( $labels, $product_id ){
136
 
137
- if( $this->is_subscriptions_product( $product_id ) || $this->new_subscription ){
138
- $labels[ '_regular_price' ] = __( 'Subscription Price', 'woocommerce-multilingual' );
139
- $labels[ '_subscription_sign_up_fee' ] = __( 'Sign-up Fee', 'woocommerce-multilingual' );
140
  }
141
 
142
  return $labels;
143
 
144
  }
145
 
146
- function update_custom_prices_values( $prices, $code, $variation_id = false ){
147
 
148
- if( isset( $_POST[ '_custom_subscription_sign_up_fee' ][ $code ] ) ){
149
- $prices[ '_subscription_sign_up_fee' ] = wc_format_decimal( $_POST[ '_custom_subscription_sign_up_fee' ][ $code ] );
150
  }
151
 
152
- if( $variation_id && isset( $_POST[ '_custom_variation_subscription_sign_up_fee' ][ $code ][ $variation_id ] ) ){
153
- $prices[ '_subscription_sign_up_fee' ] = wc_format_decimal( $_POST[ '_custom_variation_subscription_sign_up_fee' ][ $code ][ $variation_id ] );
154
  }
155
 
156
  return $prices;
157
 
158
  }
159
 
160
- function is_subscriptions_product( $product_id ){
161
 
162
- $get_variation_term_taxonomy_ids = $this->wpdb->get_col("SELECT tt.term_taxonomy_id FROM {$this->wpdb->terms} AS t LEFT JOIN {$this->wpdb->term_taxonomy} AS tt ON t.term_id = tt.term_id WHERE t.slug IN ( 'subscription', 'variable-subscription' ) AND tt.taxonomy = 'product_type'");
163
 
164
- if( get_post_type( $product_id ) == 'product_variation' ){
165
  $product_id = wp_get_post_parent_id( $product_id );
166
  }
167
 
168
  $is_subscriptions_product = $this->wpdb->get_var(
169
  $this->wpdb->prepare(
170
  "SELECT count(object_id) FROM {$this->wpdb->term_relationships}
171
- WHERE object_id = %d AND term_taxonomy_id IN (" . wpml_prepare_in( $get_variation_term_taxonomy_ids, '%d' ) . ")",
172
- $product_id )
 
173
  );
174
  return $is_subscriptions_product;
175
  }
176
 
177
- function new_subscription_prices_block( $product_id ){
178
 
179
- if( $product_id == 'new' ){
180
  $this->new_subscription = true;
181
  echo '<div class="wcml_prices_if_subscription" style="display: none">';
182
  $custom_prices_ui = new WCML_Custom_Prices_UI( $this->woocommerce_wpml, 'new' );
183
  $custom_prices_ui->show();
184
  echo '</div>';
185
  ?>
186
- <script>
187
- jQuery(document).ready(function($) {
188
- jQuery('.wcml_prices_if_subscription .wcml_custom_prices_input').attr('name', '_wcml_custom_prices[new_subscription]').attr( 'id', '_wcml_custom_prices[new_subscription]');
189
- jQuery('.wcml_prices_if_subscription .wcml_custom_prices_options_block>label').attr('for', '_wcml_custom_prices[new_subscription]');
190
- jQuery('.wcml_prices_if_subscription .wcml_schedule_input').each( function(){
191
- jQuery(this).attr('name', jQuery(this).attr('name')+'_subscription');
192
- });
193
-
194
- jQuery('.options_group>.wcml_custom_prices_block .wcml_custom_prices_input:first-child').click();
195
- jQuery('.options_group>.wcml_custom_prices_block .wcml_schedule_options .wcml_schedule_input:first-child').click();
196
-
197
- jQuery(document).on('change', 'select#product-type', function () {
198
- if (jQuery(this).val() == 'subscription') {
199
- jQuery('.wcml_prices_if_subscription').show();
200
- jQuery('.options_group>.wcml_custom_prices_block').hide();
201
- } else if (jQuery(this).val() != 'variable-subscription') {
202
- jQuery('.wcml_prices_if_subscription').hide();
203
- jQuery('.options_group>.wcml_custom_prices_block').show();
204
- }
205
- });
206
-
207
- jQuery(document).on('click', '#publish', function () {
208
- if ( jQuery('.wcml_prices_if_subscription').is( ':visible' ) ) {
209
- jQuery('.options_group>.wcml_custom_prices_block').remove();
210
- jQuery('.wcml_prices_if_subscription .wcml_custom_prices_input').attr('name', '_wcml_custom_prices[new]');
211
- jQuery('.wcml_prices_if_subscription .wcml_schedule_input').each( function(){
212
- jQuery(this).attr('name', jQuery(this).attr('name').replace('_subscription','') );
213
- });
214
- }else{
215
- jQuery('.wcml_prices_if_subscription').remove();
216
- }
217
- });
218
- });
219
- </script>
220
  <?php
221
  }
222
  }
223
 
224
- function register_endpoint( $query_vars, $wc_vars, $obj ){
225
 
226
- $query_vars[ 'view-subscription' ] = $obj->get_endpoint_translation( 'view-subscription', isset( $wc_vars['view-subscription'] ) ? $wc_vars['view-subscription'] : 'view-subscription' );
227
- $query_vars[ 'subscriptions' ] = $obj->get_endpoint_translation( 'subscriptions', isset( $wc_vars['subscriptions'] ) ? $wc_vars['subscriptions'] : 'subscriptions' );
228
  return $query_vars;
229
  }
230
 
231
- function endpoint_permalink_filter( $endpoint, $key ){
232
 
233
- if( $key == 'view-subscription' ){
234
  return 'view-subscription';
235
  }
236
 
237
  return $endpoint;
238
  }
239
 
240
- public function show_pointer_info(){
241
 
242
  $pointer_ui = new WCML_Pointer_UI(
243
- sprintf( __( 'You can translate strings related to subscription products on the %sWPML String Translation page%s. Use the search on the top of that page to find the strings.', 'woocommerce-multilingual' ), '<a href="'.admin_url('admin.php?page='.WPML_ST_FOLDER.'/menu/string-translation.php&context=woocommerce_subscriptions').'">', '</a>' ),
244
  'https://wpml.org/documentation/woocommerce-extensions-compatibility/translating-woocommerce-subscriptions-woocommerce-multilingual/',
245
  'general_product_data .subscription_pricing',
246
  'prepend'
@@ -252,8 +268,8 @@ class WCML_WC_Subscriptions{
252
  /**
253
  * @param WC_Cart $cart
254
  */
255
- public function maybe_backup_recurring_carts( $cart ){
256
- if( ! empty( $cart->recurring_carts ) ){
257
  $this->recurring_carts = $cart->recurring_carts;
258
  }
259
  }
@@ -261,27 +277,31 @@ class WCML_WC_Subscriptions{
261
  /**
262
  * @param WC_Cart $cart
263
  */
264
- public function maybe_restore_recurring_carts( $cart ){
265
- if( ! empty( $this->recurring_carts ) ){
266
  $cart->recurring_carts = $this->recurring_carts;
267
  $this->recurring_carts = null;
268
  }
269
  }
270
 
271
- function woocommerce_subscription_price_from( $price, $product ){
272
-
273
- if ( $product && in_array( $product->get_type(), array( 'variable-subscription', 'subscription_variation' ) ) ) {
 
 
 
 
274
 
275
- $variation_id = $product->get_meta( '_min_price_variation_id', true );
276
 
277
- if( $variation_id && get_post_meta( $variation_id, '_wcml_custom_prices_status', true ) ){
 
278
  $client_currency = $this->woocommerce_wpml->multi_currency->get_client_currency();
279
 
280
- $price = get_post_meta( $variation_id, '_price_'.$client_currency, true );
281
- }else{
282
  $price = apply_filters( 'wcml_raw_price_amount', $price );
283
  }
284
-
285
  }
286
 
287
  return $price;
@@ -289,19 +309,36 @@ class WCML_WC_Subscriptions{
289
 
290
  /**
291
  * Force client currency for resubscribe subscription
292
- *
293
  */
294
- function maybe_force_client_currency_for_resubscribe_subscription( ){
295
 
296
- if ( wcml_is_multi_currency_on() && ( isset( $_GET['resubscribe'] ) || false !== ( $resubscribe_cart_item = wcs_cart_contains_resubscribe() ) ) ) {
297
- $subscription_id = ( isset( $_GET['resubscribe'] ) ) ? (int) $_GET['resubscribe'] : $resubscribe_cart_item['subscription_resubscribe']['subscription_id'];
298
 
299
- $subscription_currency = get_post_meta( $subscription_id, '_order_currency', true );
300
- $client_currency = $this->woocommerce_wpml->multi_currency->get_client_currency();
301
 
302
- if( $subscription_currency && $client_currency !== $subscription_currency ){
303
- $this->woocommerce_wpml->multi_currency->set_client_currency( $subscription_currency );
304
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
305
  }
306
  }
307
 
@@ -310,78 +347,82 @@ class WCML_WC_Subscriptions{
310
  *
311
  * @return array
312
  */
313
- public function set_allowed_variations_types_in_xliff( $allowed_types ){
314
 
315
  $allowed_types[] = 'variable-subscription';
316
  $allowed_types[] = 'subscription_variation';
317
 
318
- return $allowed_types;
319
- }
320
 
321
  /**
322
  * Translate strings of renewal notifications
 
323
  * @param integer $order_id Order ID
324
  */
325
  public function translate_renewal_notification( $order_id ) {
326
-
327
  if ( isset( WC()->mailer()->emails['WCS_Email_Customer_Renewal_Invoice'] ) ) {
328
  $this->woocommerce_wpml->emails->refresh_email_lang( $order_id );
329
-
330
  $WCS_Email_Customer_Renewal_Invoice = WC()->mailer()->emails['WCS_Email_Customer_Renewal_Invoice'];
331
  $WCS_Email_Customer_Renewal_Invoice->heading = __( $WCS_Email_Customer_Renewal_Invoice->heading, 'woocommerce-subscriptions' );
332
  $WCS_Email_Customer_Renewal_Invoice->subject = __( $WCS_Email_Customer_Renewal_Invoice->subject, 'woocommerce-subscriptions' );
333
 
334
- add_filter( 'woocommerce_email_get_option', array( $this, 'translate_heading_subject' ), 10, 4 );
335
- }
336
  }
337
-
338
  /**
339
  * Translate custom heading and subject for renewal notification
340
- * @param string $return_value original string
 
341
  * @param WCS_Email_Customer_Renewal_Invoice $obj Object of email class
342
- * @param string $value Original value from setting
343
- * @param string $key Name of the key
344
  * @return string Translated value or original value incase of not translated
345
  */
346
  public function translate_heading_subject( $return_value, $obj, $value, $key ) {
347
 
348
- if ( $obj instanceof WCS_Email_Customer_Renewal_Invoice ) {
349
- if ( $key == 'subject' || $key == 'heading' ) {
350
- $translated_admin_string = $this->woocommerce_wpml->emails->wcml_get_translated_email_string( 'admin_texts_woocommerce_customer_renewal_invoice_settings', '[woocommerce_customer_renewal_invoice_settings]' . $key );
351
- return empty( $translated_admin_string ) ? $return_value : $translated_admin_string;
 
352
  }
353
- }
354
-
355
- return $return_value;
356
  }
357
-
358
  /**
359
  * Add customer renewal invoice option to translate
 
360
  * @param array $emails_options list of option to translate
361
  * @return array $emails_options
362
  */
363
  public function translate_email_options( $emails_options ) {
364
-
365
- if ( is_array( $emails_options ) ) {
366
- $emails_options[] = 'woocommerce_customer_renewal_invoice_settings';
367
- }
368
-
369
- return $emails_options;
370
  }
371
-
372
  /**
373
  * Change section name prefix to add language links
 
374
  * @param string $section_prefix section prefix
375
  * @param string $emails_option current option name
376
  * @return string $section_prefix
377
  */
378
  public function email_option_section_prefix( $section_prefix, $emails_option ) {
379
-
380
- if ( $emails_option === 'woocommerce_customer_renewal_invoice_settings' ) {
381
- return 'wcs_email_';
382
- }
383
-
384
- return $section_prefix;
385
  }
386
 
387
  /**
@@ -389,7 +430,7 @@ class WCML_WC_Subscriptions{
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
 
1
  <?php
2
 
3
+ class WCML_WC_Subscriptions {
4
 
5
  private $new_subscription = false;
6
 
9
  /** @var wpdb */
10
  private $wpdb;
11
 
12
+ public function __construct( woocommerce_wpml $woocommerce_wpml, wpdb $wpdb ) {
13
  $this->woocommerce_wpml = $woocommerce_wpml;
14
  $this->wpdb = $wpdb;
15
  }
16
 
17
+ public function add_hooks() {
18
 
19
+ add_action( 'init', [ $this, 'init' ], 9 );
20
+ add_filter( 'wcml_variation_term_taxonomy_ids', [ $this, 'wcml_variation_term_taxonomy_ids' ] );
21
+ add_filter( 'woocommerce_subscription_lengths', [ $this, 'woocommerce_subscription_lengths' ], 10, 2 );
22
 
23
+ add_filter( 'wcml_register_endpoints_query_vars', [ $this, 'register_endpoint' ], 10, 3 );
24
+ add_filter( 'wcml_endpoint_permalink_filter', [ $this, 'endpoint_permalink_filter' ], 10, 2 );
25
 
26
+ // custom prices
27
+ add_filter( 'wcml_custom_prices_fields', [ $this, 'set_prices_fields' ], 10, 2 );
28
+ add_filter( 'wcml_custom_prices_strings', [ $this, 'set_labels_for_prices_fields' ], 10, 2 );
29
+ add_filter( 'wcml_custom_prices_fields_labels', [ $this, 'set_labels_for_prices_fields' ], 10, 2 );
30
+ add_filter( 'wcml_update_custom_prices_values', [ $this, 'update_custom_prices_values' ], 10, 3 );
31
+ add_action( 'wcml_after_custom_prices_block', [ $this, 'new_subscription_prices_block' ] );
32
 
33
+ add_action( 'woocommerce_subscriptions_product_options_pricing', [ $this, 'show_pointer_info' ] );
34
+ add_action( 'woocommerce_variable_subscription_pricing', [ $this, 'show_pointer_info' ] );
35
 
36
+ add_filter(
37
+ 'woocommerce_subscriptions_product_price',
38
+ [
39
+ $this,
40
+ 'woocommerce_subscription_price_from',
41
+ ],
42
+ 10,
43
+ 2
44
+ );
45
+
46
+ add_filter( 'wcml_xliff_allowed_variations_types', [ $this, 'set_allowed_variations_types_in_xliff' ] );
47
 
48
+ // Add language links to email settings
49
+ add_filter( 'wcml_emails_options_to_translate', [ $this, 'translate_email_options' ] );
50
+ add_filter( 'wcml_emails_section_name_prefix', [ $this, 'email_option_section_prefix' ], 10, 2 );
 
 
51
 
52
  }
53
 
54
+ public function init() {
55
+ if ( ! is_admin() ) {
56
+ add_filter(
57
+ 'woocommerce_subscriptions_product_sign_up_fee',
58
+ [
59
+ $this,
60
+ 'subscriptions_product_sign_up_fee_filter',
61
+ ],
62
+ 10,
63
+ 2
64
+ );
65
 
66
+ add_action( 'woocommerce_before_calculate_totals', [ $this, 'maybe_backup_recurring_carts' ], 1 );
67
+ add_action( 'woocommerce_after_calculate_totals', [ $this, 'maybe_restore_recurring_carts' ], 200 );
68
 
69
+ $this->maybe_force_client_currency_for_subscription();
70
 
71
+ add_filter( 'wcs_get_subscription', [ $this, 'filter_subscription_items' ] );
72
  }
73
+
74
+ // Translate emails
75
+ add_filter( 'woocommerce_generated_manual_renewal_order_renewal_notification', [ $this, 'translate_renewal_notification' ], 9 );
76
+ add_filter( 'woocommerce_order_status_failed_renewal_notification', [ $this, 'translate_renewal_notification' ], 9 );
77
  }
78
 
79
 
80
  /**
81
  * Filter Subscription Sign-up fee cost
82
  *
83
+ * @param string $subscription_sign_up_fee
84
  * @param WC_Product $product
85
  * @return string
86
  */
87
+ public function subscriptions_product_sign_up_fee_filter( $subscription_sign_up_fee, $product ) {
88
 
89
  if ( $product && wcml_is_multi_currency_on() ) {
90
  $currency = $this->woocommerce_wpml->multi_currency->get_client_currency();
91
 
92
  if ( $currency !== wcml_get_woocommerce_currency_option() ) {
93
 
94
+ $product_id = $product->get_id();
95
+ if( $product instanceof WC_Product_Variable_Subscription ){
96
+ $product_id = $product->get_meta( '_min_price_variation_id', true );
97
+ }
98
+
99
+ $original_product_id = $this->woocommerce_wpml->products->get_original_product_id( $product_id );
100
 
101
  if ( get_post_meta( $original_product_id, '_wcml_custom_prices_status', true ) ) {
102
  $subscription_sign_up_fee = get_post_meta( $original_product_id, '_subscription_sign_up_fee_' . $currency, true );
109
  return $subscription_sign_up_fee;
110
  }
111
 
112
+ public function wcml_variation_term_taxonomy_ids( $get_variation_term_taxonomy_ids ) {
113
 
114
+ $get_variation_term_taxonomy_id = $this->wpdb->get_var( "SELECT tt.term_taxonomy_id FROM {$this->wpdb->terms} AS t LEFT JOIN {$this->wpdb->term_taxonomy} AS tt ON t.term_id = tt.term_id WHERE t.slug = 'variable-subscription'" );
115
 
116
+ if ( ! empty( $get_variation_term_taxonomy_id ) ) {
117
  $get_variation_term_taxonomy_ids[] = $get_variation_term_taxonomy_id;
118
  }
119
 
120
  return $get_variation_term_taxonomy_ids;
121
  }
122
 
123
+ public function woocommerce_subscription_lengths( $subscription_ranges, $subscription_period ) {
124
 
125
+ if ( is_array( $subscription_ranges ) ) {
126
+ foreach ( $subscription_ranges as $period => $ranges ) {
127
+ if ( is_array( $ranges ) ) {
128
+ foreach ( $ranges as $range ) {
129
+ if ( $range == '9 months' ) {
130
  $breakpoint = true;
131
  }
132
+ $new_subscription_ranges[ $period ][] = apply_filters( 'wpml_translate_single_string', $range, 'wc_subscription_ranges', $range );
133
  }
134
  }
135
  }
136
  }
137
 
138
+ return isset( $new_subscription_ranges ) ? $new_subscription_ranges : $subscription_ranges;
139
  }
140
 
141
+ public function set_prices_fields( $fields, $product_id ) {
142
+ if ( $this->is_subscriptions_product( $product_id ) || $this->new_subscription ) {
143
  $fields[] = '_subscription_sign_up_fee';
144
  }
145
 
147
 
148
  }
149
 
150
+ public function set_labels_for_prices_fields( $labels, $product_id ) {
151
 
152
+ if ( $this->is_subscriptions_product( $product_id ) || $this->new_subscription ) {
153
+ $labels['_regular_price'] = __( 'Subscription Price', 'woocommerce-multilingual' );
154
+ $labels['_subscription_sign_up_fee'] = __( 'Sign-up Fee', 'woocommerce-multilingual' );
155
  }
156
 
157
  return $labels;
158
 
159
  }
160
 
161
+ public function update_custom_prices_values( $prices, $code, $variation_id = false ) {
162
 
163
+ if ( isset( $_POST['_custom_subscription_sign_up_fee'][ $code ] ) ) {
164
+ $prices['_subscription_sign_up_fee'] = wc_format_decimal( $_POST['_custom_subscription_sign_up_fee'][ $code ] );
165
  }
166
 
167
+ if ( $variation_id && isset( $_POST['_custom_variation_subscription_sign_up_fee'][ $code ][ $variation_id ] ) ) {
168
+ $prices['_subscription_sign_up_fee'] = wc_format_decimal( $_POST['_custom_variation_subscription_sign_up_fee'][ $code ][ $variation_id ] );
169
  }
170
 
171
  return $prices;
172
 
173
  }
174
 
175
+ public function is_subscriptions_product( $product_id ) {
176
 
177
+ $get_variation_term_taxonomy_ids = $this->wpdb->get_col( "SELECT tt.term_taxonomy_id FROM {$this->wpdb->terms} AS t LEFT JOIN {$this->wpdb->term_taxonomy} AS tt ON t.term_id = tt.term_id WHERE t.slug IN ( 'subscription', 'variable-subscription' ) AND tt.taxonomy = 'product_type'" );
178
 
179
+ if ( get_post_type( $product_id ) == 'product_variation' ) {
180
  $product_id = wp_get_post_parent_id( $product_id );
181
  }
182
 
183
  $is_subscriptions_product = $this->wpdb->get_var(
184
  $this->wpdb->prepare(
185
  "SELECT count(object_id) FROM {$this->wpdb->term_relationships}
186
+ WHERE object_id = %d AND term_taxonomy_id IN (" . wpml_prepare_in( $get_variation_term_taxonomy_ids, '%d' ) . ')',
187
+ $product_id
188
+ )
189
  );
190
  return $is_subscriptions_product;
191
  }
192
 
193
+ public function new_subscription_prices_block( $product_id ) {
194
 
195
+ if ( $product_id == 'new' ) {
196
  $this->new_subscription = true;
197
  echo '<div class="wcml_prices_if_subscription" style="display: none">';
198
  $custom_prices_ui = new WCML_Custom_Prices_UI( $this->woocommerce_wpml, 'new' );
199
  $custom_prices_ui->show();
200
  echo '</div>';
201
  ?>
202
+ <script>
203
+ jQuery(document).ready(function($) {
204
+ jQuery('.wcml_prices_if_subscription .wcml_custom_prices_input').attr('name', '_wcml_custom_prices[new_subscription]').attr( 'id', '_wcml_custom_prices[new_subscription]');
205
+ jQuery('.wcml_prices_if_subscription .wcml_custom_prices_options_block>label').attr('for', '_wcml_custom_prices[new_subscription]');
206
+ jQuery('.wcml_prices_if_subscription .wcml_schedule_input').each( function(){
207
+ jQuery(this).attr('name', jQuery(this).attr('name')+'_subscription');
208
+ });
209
+
210
+ jQuery('.options_group>.wcml_custom_prices_block .wcml_custom_prices_input:first-child').click();
211
+ jQuery('.options_group>.wcml_custom_prices_block .wcml_schedule_options .wcml_schedule_input:first-child').click();
212
+
213
+ jQuery(document).on('change', 'select#product-type', function () {
214
+ if (jQuery(this).val() == 'subscription') {
215
+ jQuery('.wcml_prices_if_subscription').show();
216
+ jQuery('.options_group>.wcml_custom_prices_block').hide();
217
+ } else if (jQuery(this).val() != 'variable-subscription') {
218
+ jQuery('.wcml_prices_if_subscription').hide();
219
+ jQuery('.options_group>.wcml_custom_prices_block').show();
220
+ }
221
+ });
222
+
223
+ jQuery(document).on('click', '#publish', function () {
224
+ if ( jQuery('.wcml_prices_if_subscription').is( ':visible' ) ) {
225
+ jQuery('.options_group>.wcml_custom_prices_block').remove();
226
+ jQuery('.wcml_prices_if_subscription .wcml_custom_prices_input').attr('name', '_wcml_custom_prices[new]');
227
+ jQuery('.wcml_prices_if_subscription .wcml_schedule_input').each( function(){
228
+ jQuery(this).attr('name', jQuery(this).attr('name').replace('_subscription','') );
229
+ });
230
+ }else{
231
+ jQuery('.wcml_prices_if_subscription').remove();
232
+ }
233
+ });
234
+ });
235
+ </script>
236
  <?php
237
  }
238
  }
239
 
240
+ public function register_endpoint( $query_vars, $wc_vars, $obj ) {
241
 
242
+ $query_vars['view-subscription'] = $obj->get_endpoint_translation( 'view-subscription', isset( $wc_vars['view-subscription'] ) ? $wc_vars['view-subscription'] : 'view-subscription' );
243
+ $query_vars['subscriptions'] = $obj->get_endpoint_translation( 'subscriptions', isset( $wc_vars['subscriptions'] ) ? $wc_vars['subscriptions'] : 'subscriptions' );
244
  return $query_vars;
245
  }
246
 
247
+ public function endpoint_permalink_filter( $endpoint, $key ) {
248
 
249
+ if ( $key == 'view-subscription' ) {
250
  return 'view-subscription';
251
  }
252
 
253
  return $endpoint;
254
  }
255
 
256
+ public function show_pointer_info() {
257
 
258
  $pointer_ui = new WCML_Pointer_UI(
259
+ sprintf( __( 'You can translate strings related to subscription products on the %1$sWPML String Translation page%2$s. Use the search on the top of that page to find the strings.', 'woocommerce-multilingual' ), '<a href="' . admin_url( 'admin.php?page=' . WPML_ST_FOLDER . '/menu/string-translation.php&context=woocommerce_subscriptions' ) . '">', '</a>' ),
260
  'https://wpml.org/documentation/woocommerce-extensions-compatibility/translating-woocommerce-subscriptions-woocommerce-multilingual/',
261
  'general_product_data .subscription_pricing',
262
  'prepend'
268
  /**
269
  * @param WC_Cart $cart
270
  */
271
+ public function maybe_backup_recurring_carts( $cart ) {
272
+ if ( ! empty( $cart->recurring_carts ) ) {
273
  $this->recurring_carts = $cart->recurring_carts;
274
  }
275
  }
277
  /**
278
  * @param WC_Cart $cart
279
  */
280
+ public function maybe_restore_recurring_carts( $cart ) {
281
+ if ( ! empty( $this->recurring_carts ) ) {
282
  $cart->recurring_carts = $this->recurring_carts;
283
  $this->recurring_carts = null;
284
  }
285
  }
286
 
287
+ /**
288
+ * @param string $price
289
+ * @param WC_Product|WC_Product_Subscription_Variation $product
290
+ *
291
+ * @return string
292
+ */
293
+ public function woocommerce_subscription_price_from( $price, $product ) {
294
 
295
+ if ( $product && $product instanceof WC_Product_Subscription_Variation ) {
296
 
297
+ $custom_prices_on = get_post_meta( $product->get_id(), '_wcml_custom_prices_status', true );
298
+ if ( $custom_prices_on ) {
299
  $client_currency = $this->woocommerce_wpml->multi_currency->get_client_currency();
300
 
301
+ $price = get_post_meta( $product->get_id(), '_price_' . $client_currency, true );
302
+ } else {
303
  $price = apply_filters( 'wcml_raw_price_amount', $price );
304
  }
 
305
  }
306
 
307
  return $price;
309
 
310
  /**
311
  * Force client currency for resubscribe subscription
 
312
  */
313
+ public function maybe_force_client_currency_for_subscription() {
314
 
315
+ if ( wcml_is_multi_currency_on() ) {
 
316
 
317
+ $subscription_id = false;
318
+ $getData = wpml_collect( $_GET );
319
 
320
+ if ( $getData->has( 'resubscribe' ) ) {
321
+ $subscription_id = (int) $getData->get( 'resubscribe' );
322
+ } elseif ( $getData->has( 'subscription_renewal_early' ) ) {
323
+ $subscription_id = (int) $getData->get( 'subscription_renewal_early' );
324
+ } elseif ( is_cart() || is_checkout() ) {
325
+ $resubscribe_cart_item = wcs_cart_contains_resubscribe();
326
+ if ( $resubscribe_cart_item ) {
327
+ $subscription_id = $resubscribe_cart_item['subscription_resubscribe']['subscription_id'];
328
+ } else {
329
+ $early_renewal_cart_item = wcs_cart_contains_early_renewal();
330
+ if ( $early_renewal_cart_item ) {
331
+ $subscription_id = $early_renewal_cart_item['subscription_renewal']['subscription_renewal_early'];
332
+ }
333
+ }
334
+ }
335
+
336
+ if ( $subscription_id ) {
337
+ $subscription_currency = get_post_meta( $subscription_id, '_order_currency', true );
338
+ if ( $subscription_currency && $this->woocommerce_wpml->multi_currency->get_client_currency() !== $subscription_currency ) {
339
+ $this->woocommerce_wpml->multi_currency->set_client_currency( $subscription_currency );
340
+ }
341
+ }
342
  }
343
  }
344
 
347
  *
348
  * @return array
349
  */
350
+ public function set_allowed_variations_types_in_xliff( $allowed_types ) {
351
 
352
  $allowed_types[] = 'variable-subscription';
353
  $allowed_types[] = 'subscription_variation';
354
 
355
+ return $allowed_types;
356
+ }
357
 
358
  /**
359
  * Translate strings of renewal notifications
360
+ *
361
  * @param integer $order_id Order ID
362
  */
363
  public function translate_renewal_notification( $order_id ) {
364
+
365
  if ( isset( WC()->mailer()->emails['WCS_Email_Customer_Renewal_Invoice'] ) ) {
366
  $this->woocommerce_wpml->emails->refresh_email_lang( $order_id );
367
+
368
  $WCS_Email_Customer_Renewal_Invoice = WC()->mailer()->emails['WCS_Email_Customer_Renewal_Invoice'];
369
  $WCS_Email_Customer_Renewal_Invoice->heading = __( $WCS_Email_Customer_Renewal_Invoice->heading, 'woocommerce-subscriptions' );
370
  $WCS_Email_Customer_Renewal_Invoice->subject = __( $WCS_Email_Customer_Renewal_Invoice->subject, 'woocommerce-subscriptions' );
371
 
372
+ add_filter( 'woocommerce_email_get_option', [ $this, 'translate_heading_subject' ], 10, 4 );
373
+ }
374
  }
375
+
376
  /**
377
  * Translate custom heading and subject for renewal notification
378
+ *
379
+ * @param string $return_value original string
380
  * @param WCS_Email_Customer_Renewal_Invoice $obj Object of email class
381
+ * @param string $value Original value from setting
382
+ * @param string $key Name of the key
383
  * @return string Translated value or original value incase of not translated
384
  */
385
  public function translate_heading_subject( $return_value, $obj, $value, $key ) {
386
 
387
+ if ( $obj instanceof WCS_Email_Customer_Renewal_Invoice ) {
388
+ if ( $key == 'subject' || $key == 'heading' ) {
389
+ $translated_admin_string = $this->woocommerce_wpml->emails->wcml_get_translated_email_string( 'admin_texts_woocommerce_customer_renewal_invoice_settings', '[woocommerce_customer_renewal_invoice_settings]' . $key );
390
+ return empty( $translated_admin_string ) ? $return_value : $translated_admin_string;
391
+ }
392
  }
393
+
394
+ return $return_value;
 
395
  }
396
+
397
  /**
398
  * Add customer renewal invoice option to translate
399
+ *
400
  * @param array $emails_options list of option to translate
401
  * @return array $emails_options
402
  */
403
  public function translate_email_options( $emails_options ) {
404
+
405
+ if ( is_array( $emails_options ) ) {
406
+ $emails_options[] = 'woocommerce_customer_renewal_invoice_settings';
407
+ }
408
+
409
+ return $emails_options;
410
  }
411
+
412
  /**
413
  * Change section name prefix to add language links
414
+ *
415
  * @param string $section_prefix section prefix
416
  * @param string $emails_option current option name
417
  * @return string $section_prefix
418
  */
419
  public function email_option_section_prefix( $section_prefix, $emails_option ) {
420
+
421
+ if ( $emails_option === 'woocommerce_customer_renewal_invoice_settings' ) {
422
+ return 'wcs_email_';
423
+ }
424
+
425
+ return $section_prefix;
426
  }
427
 
428
  /**
430
  *
431
  * @return WC_Subscription
432
  */
433
+ public function filter_subscription_items( $subscription ) {
434
 
435
  $this->woocommerce_wpml->orders->adjust_order_item_in_language( $subscription->get_items() );
436
 
compatibility/class-wcml-wcexporter.php CHANGED
@@ -17,12 +17,12 @@ class WCML_wcExporter {
17
  * @param SitePress $sitepress
18
  * @param woocommerce_wpml $woocommerce_wpml
19
  */
20
- function __construct( SitePress $sitepress, woocommerce_wpml $woocommerce_wpml ) {
21
  $this->sitepress = $sitepress;
22
  $this->woocommerce_wpml = $woocommerce_wpml;
23
  }
24
 
25
- function add_hooks() {
26
 
27
  add_filter( 'woo_ce_product_fields', array( $this, 'woo_ce_fields' ) );
28
  add_filter( 'woo_ce_category_fields', array( $this, 'woo_ce_fields' ) );
@@ -34,7 +34,7 @@ class WCML_wcExporter {
34
 
35
  }
36
 
37
- function woo_ce_fields( $fields ) {
38
  $fields[] = array(
39
  'name' => 'language',
40
  'label' => __( 'Language', 'woo_ce' ),
@@ -49,7 +49,7 @@ class WCML_wcExporter {
49
  return $fields;
50
  }
51
 
52
- function woo_ce_order_fields( $fields ) {
53
  $fields[] = array(
54
  'name' => 'language',
55
  'label' => __( 'Language', 'woo_ce' ),
@@ -59,7 +59,7 @@ class WCML_wcExporter {
59
  return $fields;
60
  }
61
 
62
- function woo_ce_product_item( $data, $product_id ) {
63
 
64
  $data->language = $this->sitepress->get_language_for_element( $product_id, 'post_' . get_post_type( $product_id ) );
65
  $data->translation_of = $this->woocommerce_wpml->products->get_original_product_id( $product_id );
@@ -67,7 +67,7 @@ class WCML_wcExporter {
67
  return $data;
68
  }
69
 
70
- function woo_ce_category_item( $data ) {
71
 
72
  $data->language = $this->sitepress->get_language_for_element( $data->term_taxonomy_id, 'tax_product_cat' );
73
  $data->translation_of = apply_filters( 'translate_object_id', $data->term_taxonomy_id, 'tax_product_cat', true, $this->sitepress->get_default_language() );
@@ -75,7 +75,7 @@ class WCML_wcExporter {
75
  return $data;
76
  }
77
 
78
- function woo_ce_tags( $tags ) {
79
 
80
  foreach ( $tags as $key => $tag ) {
81
  $tags[ $key ]->language = $this->sitepress->get_language_for_element( $tag->term_taxonomy_id, 'tax_product_tag' );
17
  * @param SitePress $sitepress
18
  * @param woocommerce_wpml $woocommerce_wpml
19
  */
20
+ public function __construct( SitePress $sitepress, woocommerce_wpml $woocommerce_wpml ) {
21
  $this->sitepress = $sitepress;
22
  $this->woocommerce_wpml = $woocommerce_wpml;
23
  }
24
 
25
+ public function add_hooks() {
26
 
27
  add_filter( 'woo_ce_product_fields', array( $this, 'woo_ce_fields' ) );
28
  add_filter( 'woo_ce_category_fields', array( $this, 'woo_ce_fields' ) );
34
 
35
  }
36
 
37
+ public function woo_ce_fields( $fields ) {
38
  $fields[] = array(
39
  'name' => 'language',
40
  'label' => __( 'Language', 'woo_ce' ),
49
  return $fields;
50
  }
51
 
52
+ public function woo_ce_order_fields( $fields ) {
53
  $fields[] = array(
54
  'name' => 'language',
55
  'label' => __( 'Language', 'woo_ce' ),
59
  return $fields;
60
  }
61
 
62
+ public function woo_ce_product_item( $data, $product_id ) {
63
 
64
  $data->language = $this->sitepress->get_language_for_element( $product_id, 'post_' . get_post_type( $product_id ) );
65
  $data->translation_of = $this->woocommerce_wpml->products->get_original_product_id( $product_id );
67
  return $data;
68
  }
69
 
70
+ public function woo_ce_category_item( $data ) {
71
 
72
  $data->language = $this->sitepress->get_language_for_element( $data->term_taxonomy_id, 'tax_product_cat' );
73
  $data->translation_of = apply_filters( 'translate_object_id', $data->term_taxonomy_id, 'tax_product_cat', true, $this->sitepress->get_default_language() );
75
  return $data;
76
  }
77
 
78
+ public function woo_ce_tags( $tags ) {
79
 
80
  foreach ( $tags as $key => $tag ) {
81
  $tags[ $key ]->language = $this->sitepress->get_language_for_element( $tag->term_taxonomy_id, 'tax_product_tag' );
compatibility/class-wcml-woo-var-table.php CHANGED
@@ -13,16 +13,16 @@ class WCML_Woo_Var_Table {
13
  /**
14
  * @param string $current_language
15
  */
16
- function __construct( $current_language ){
17
  $this->current_language = $current_language;
18
  }
19
 
20
- function add_hooks() {
21
 
22
- add_filter( 'vartable_add_to_cart_product_id', array( $this, 'filter_add_to_cart_product_id' ) );
23
  }
24
 
25
- function filter_add_to_cart_product_id( $product_id ) {
26
 
27
  $product_id = apply_filters( 'translate_object_id', $product_id, get_post_type( $product_id ), true, $this->current_language );
28
 
13
  /**
14
  * @param string $current_language
15
  */
16
+ public function __construct( $current_language ) {
17
  $this->current_language = $current_language;
18
  }
19
 
20
+ public function add_hooks() {
21
 
22
+ add_filter( 'vartable_add_to_cart_product_id', [ $this, 'filter_add_to_cart_product_id' ] );
23
  }
24
 
25
+ public function filter_add_to_cart_product_id( $product_id ) {
26
 
27
  $product_id = apply_filters( 'translate_object_id', $product_id, get_post_type( $product_id ), true, $this->current_language );
28
 
compatibility/class-wcml-woobe.php CHANGED
@@ -16,16 +16,16 @@ class WCML_Woobe {
16
  /**
17
  * WCML_Woobe constructor.
18
  *
19
- * @param SitePress $sitepress
20
  * @param WPML_Post_Translation $post_translations
21
  */
22
- function __construct( SitePress $sitepress, WPML_Post_Translation $post_translations ) {
23
- $this->sitepress = $sitepress;
24
  $this->post_translations = $post_translations;
25
  }
26
 
27
  public function add_hooks() {
28
- add_action( 'woobe_after_update_page_field', array( $this, 'replace_price_in_translations' ), 10, 5 );
29
  }
30
 
31
  /**
@@ -62,13 +62,13 @@ class WCML_Woobe {
62
  */
63
  private function is_price_updated( $product_id, $field_key, $value ) {
64
  return is_numeric( $product_id )
65
- && 'regular_price' === $field_key
66
- && is_numeric( $value );
67
  }
68
 
69
  private function is_field_set_to_copy( $field_key ) {
70
- $settings = $this->sitepress->get_settings();
71
- $field_translation_setting = isset( $settings['translation-management']['custom_fields_translation']['_' . $field_key] ) ? $settings['translation-management']['custom_fields_translation']['_' . $field_key] : null;
72
  return $field_translation_setting === $this->sitepress->get_wp_api()->constant( 'WPML_COPY_CUSTOM_FIELD' );
73
  }
74
  }
16
  /**
17
  * WCML_Woobe constructor.
18
  *
19
+ * @param SitePress $sitepress
20
  * @param WPML_Post_Translation $post_translations
21
  */
22
+ public function __construct( SitePress $sitepress, WPML_Post_Translation $post_translations ) {
23
+ $this->sitepress = $sitepress;
24
  $this->post_translations = $post_translations;
25
  }
26
 
27
  public function add_hooks() {
28
+ add_action( 'woobe_after_update_page_field', [ $this, 'replace_price_in_translations' ], 10, 5 );
29
  }
30
 
31
  /**
62
  */
63
  private function is_price_updated( $product_id, $field_key, $value ) {
64
  return is_numeric( $product_id )
65
+ && 'regular_price' === $field_key
66
+ && is_numeric( $value );
67
  }
68
 
69
  private function is_field_set_to_copy( $field_key ) {
70
+ $settings = $this->sitepress->get_settings();
71
+ $field_translation_setting = isset( $settings['translation-management']['custom_fields_translation'][ '_' . $field_key ] ) ? $settings['translation-management']['custom_fields_translation'][ '_' . $field_key ] : null;
72
  return $field_translation_setting === $this->sitepress->get_wp_api()->constant( 'WPML_COPY_CUSTOM_FIELD' );
73
  }
74
  }
compatibility/class-wcml-wpb-vc.php CHANGED
@@ -5,12 +5,12 @@
5
 
6
  class WCML_Wpb_Vc {
7
 
8
- function add_hooks() {
9
 
10
- add_filter( 'wcml_is_localize_woocommerce_on_ajax', array( $this, 'is_localize_woocommerce_on_ajax' ), 10, 2 );
11
  }
12
 
13
- function is_localize_woocommerce_on_ajax( $localize, $action ) {
14
 
15
  if ( 'vc_edit_form' === $action ) {
16
  $localize = false;
5
 
6
  class WCML_Wpb_Vc {
7
 
8
+ public function add_hooks() {
9
 
10
+ add_filter( 'wcml_is_localize_woocommerce_on_ajax', [ $this, 'is_localize_woocommerce_on_ajax' ], 10, 2 );
11
  }
12
 
13
+ public function is_localize_woocommerce_on_ajax( $localize, $action ) {
14
 
15
  if ( 'vc_edit_form' === $action ) {
16
  $localize = false;
compatibility/class-wcml-wpfastest-cache.php CHANGED
@@ -3,10 +3,13 @@
3
  class WCML_WpFastest_Cache {
4
 
5
  public function add_hooks() {
6
- add_filter( 'wcml_is_cache_enabled_for_switching_currency', array(
7
- $this,
8
- 'is_cache_enabled_for_switching_currency'
9
- ) );
 
 
 
10
  }
11
 
12
  /**
3
  class WCML_WpFastest_Cache {
4
 
5
  public function add_hooks() {
6
+ add_filter(
7
+ 'wcml_is_cache_enabled_for_switching_currency',
8
+ [
9
+ $this,
10
+ 'is_cache_enabled_for_switching_currency',
11
+ ]
12
+ );
13
  }
14
 
15
  /**
compatibility/class-wcml-wpseo.php CHANGED
@@ -1,57 +1,57 @@
1
  <?php
2
 
3
- class WCML_WPSEO{
4
 
5
- private $updated_post_id;
6
 
7
- function __construct(){
8
 
9
- add_filter( 'wcml_product_content_label', array( $this, 'wpseo_custom_field_label' ), 10, 2 );
10
 
11
- if( defined( 'WPSEO_VERSION') && defined( 'WPSEO_PATH' ) && isset( $_GET[ 'page' ] ) && $_GET[ 'page' ] == 'wpml-wcml' && isset( $_GET[ 'tab' ] ) && $_GET[ 'tab' ] == 'products' ){
12
- if( version_compare( WPSEO_VERSION, '3', '<' ) ) {
13
- require_once WPSEO_PATH . 'admin/class-metabox.php';
14
- } elseif( file_exists( WPSEO_PATH . 'admin/metabox/class-metabox.php' ) ) {
15
- require_once WPSEO_PATH . 'admin/metabox/class-metabox.php';
16
- }
17
- }
18
 
19
- add_action( 'post_updated', array( $this, 'set_updated_post_id' ) );
20
- add_action( 'wpseo_premium_post_redirect_slug_change', array( $this, 'wpseo_premium_post_redirect_slug_change' ) );
21
- }
22
 
23
- function wpseo_custom_field_label( $field, $product_id ){
24
- global $woocommerce_wpml, $wpseo_metabox;
25
 
26
- $yoast_seo_fields = array( '_yoast_wpseo_focuskw', '_yoast_wpseo_title', '_yoast_wpseo_metadesc' );
27
 
28
- if ( !is_array( maybe_unserialize( get_post_meta( $product_id, $field, true ) ) ) ) {
29
 
30
- if ( !is_null( $wpseo_metabox ) && in_array( $field, $yoast_seo_fields ) ) {
31
 
32
- $wpseo_metabox_values = $wpseo_metabox->get_meta_boxes( 'product' );
33
 
34
- $label = $wpseo_metabox_values[ str_replace( '_yoast_wpseo_', '', $field ) ][ 'title' ];
35
 
36
- return $label;
37
- }
38
- }
39
 
40
- return $field;
41
- }
42
 
43
- function set_updated_post_id( $post_id ){
44
- $this->updated_post_id = $post_id;
45
- }
46
 
47
- function wpseo_premium_post_redirect_slug_change( $slug_changed_flag ){
48
 
49
- if( null !== $this->updated_post_id && get_post_type( $this->updated_post_id ) === 'product_variation' ){
50
- return true;
51
- }
52
 
53
- return $slug_changed_flag;
54
- }
55
 
56
  }
57
 
1
  <?php
2
 
3
+ class WCML_WPSEO {
4
 
5
+ private $updated_post_id;
6
 
7
+ public function __construct() {
8
 
9
+ add_filter( 'wcml_product_content_label', [ $this, 'wpseo_custom_field_label' ], 10, 2 );
10
 
11
+ if ( defined( 'WPSEO_VERSION' ) && defined( 'WPSEO_PATH' ) && isset( $_GET['page'] ) && $_GET['page'] == 'wpml-wcml' && isset( $_GET['tab'] ) && $_GET['tab'] == 'products' ) {
12
+ if ( version_compare( WPSEO_VERSION, '3', '<' ) ) {
13
+ require_once WPSEO_PATH . 'admin/class-metabox.php';
14
+ } elseif ( file_exists( WPSEO_PATH . 'admin/metabox/class-metabox.php' ) ) {
15
+ require_once WPSEO_PATH . 'admin/metabox/class-metabox.php';
16
+ }
17
+ }
18
 
19
+ add_action( 'post_updated', [ $this, 'set_updated_post_id' ] );
20
+ add_action( 'wpseo_premium_post_redirect_slug_change', [ $this, 'wpseo_premium_post_redirect_slug_change' ] );
21
+ }
22
 
23
+ public function wpseo_custom_field_label( $field, $product_id ) {
24
+ global $woocommerce_wpml, $wpseo_metabox;
25
 
26
+ $yoast_seo_fields = [ '_yoast_wpseo_focuskw', '_yoast_wpseo_title', '_yoast_wpseo_metadesc' ];
27
 
28
+ if ( ! is_array( maybe_unserialize( get_post_meta( $product_id, $field, true ) ) ) ) {
29
 
30
+ if ( ! is_null( $wpseo_metabox ) && in_array( $field, $yoast_seo_fields ) ) {
31
 
32
+ $wpseo_metabox_values = $wpseo_metabox->get_meta_boxes( 'product' );
33
 
34
+ $label = $wpseo_metabox_values[ str_replace( '_yoast_wpseo_', '', $field ) ]['title'];
35
 
36
+ return $label;
37
+ }
38
+ }
39
 
40
+ return $field;
41
+ }
42
 
43
+ public function set_updated_post_id( $post_id ) {
44
+ $this->updated_post_id = $post_id;
45
+ }
46
 
47
+ public function wpseo_premium_post_redirect_slug_change( $slug_changed_flag ) {
48
 
49
+ if ( null !== $this->updated_post_id && get_post_type( $this->updated_post_id ) === 'product_variation' ) {
50
+ return true;
51
+ }
52
 
53
+ return $slug_changed_flag;
54
+ }
55
 
56
  }
57
 
compatibility/class-wcml-yikes-custom-product-tabs.php CHANGED
@@ -25,11 +25,11 @@ class WCML_YIKES_Custom_Product_Tabs {
25
  /**
26
  * WCML_Tab_Manager constructor.
27
  *
28
- * @param woocommerce_wpml $woocommerce_wpml
29
- * @param SitePress $sitepress
30
  * @param WPML_Element_Translation_Package $tp
31
  */
32
- function __construct( woocommerce_wpml $woocommerce_wpml, SitePress $sitepress, WPML_Element_Translation_Package $tp ) {
33
  $this->sitepress = $sitepress;
34
  $this->woocommerce_wpml = $woocommerce_wpml;
35
  $this->tp = $tp;
@@ -37,28 +37,26 @@ class WCML_YIKES_Custom_Product_Tabs {
37
 
38
  public function add_hooks() {
39
 
40
- if ( is_admin() ) {
41
- add_action( 'wcml_gui_additional_box_html', array( $this, 'custom_box_html' ), 10, 3 );
42
- add_filter( 'wcml_gui_additional_box_data', array( $this, 'custom_box_html_data' ), 10, 4 );
43
- add_action( 'wcml_update_extra_fields', array( $this, 'sync_tabs' ), 10, 4 );
44
- add_filter( 'wpml_duplicate_custom_fields_exceptions', array( $this, 'custom_fields_exceptions' ) );
45
- add_filter( 'wcml_do_not_display_custom_fields_for_product', array( $this, 'custom_fields_exceptions' ) );
46
-
47
- add_filter( 'wpml_tm_translation_job_data', array( $this, 'append_custom_tabs_to_translation_package' ), 10, 2 );
48
- add_action( 'wpml_translation_job_saved', array( $this, 'save_custom_tabs_translation' ), 10, 3 );
49
 
50
- add_action( 'woocommerce_product_data_panels', array( $this, 'show_pointer_info' ) );
51
- add_action( 'init', array( $this, 'maybe_remove_admin_language_switcher' ) );
 
 
 
 
 
 
 
52
  }
53
  }
54
 
55
  /**
56
  * @param object $obj
57
- * @param int $product_id
58
- * @param array $data
59
- *
60
  */
61
- function custom_box_html( $obj, $product_id, $data ) {
62
 
63
  $orig_prod_tabs = $this->get_product_tabs( $product_id );
64
 
@@ -87,23 +85,23 @@ class WCML_YIKES_Custom_Product_Tabs {
87
 
88
 
89
  /**
90
- * @param array $data
91
- * @param int $product_id
92
  * @param object $translation
93
  * @param string $lang
94
  *
95
  * @return array
96
  */
97
- function custom_box_html_data( $data, $product_id, $translation, $lang ) {
98
 
99
  $orig_prod_tabs = $this->get_product_tabs( $product_id );
100
  if ( $orig_prod_tabs ) {
101
  foreach ( $orig_prod_tabs as $key => $prod_tab ) {
102
  if ( isset( $prod_tab['title'] ) ) {
103
- $data[ 'tab_' . $key . '_title' ] = array( 'original' => $prod_tab['title'] );
104
  }
105
  if ( isset( $prod_tab['content'] ) ) {
106
- $data[ 'tab_' . $key . '_content' ] = array( 'original' => $prod_tab['content'] );
107
  }
108
  }
109
 
@@ -126,20 +124,19 @@ class WCML_YIKES_Custom_Product_Tabs {
126
  }
127
 
128
  /**
129
- * @param int $original_product_id
130
- * @param int $trnsl_product_id
131
- * @param array $data
132
  * @param string $lang
133
- *
134
  */
135
- function sync_tabs( $original_product_id, $trnsl_product_id, $data, $lang ) {
136
 
137
  $orig_prod_tabs = $this->get_product_tabs( $original_product_id );
138
 
139
  if ( ( isset( $_POST['icl_ajx_action'] ) && ( 'make_duplicates' === $_POST['icl_ajx_action'] ) ) || ( get_post_meta( $trnsl_product_id, '_icl_lang_duplicate_of', true ) ) ) {
140
  update_post_meta( $trnsl_product_id, self::CUSTOM_TABS_FIELD, $orig_prod_tabs );
141
  } elseif ( $orig_prod_tabs ) {
142
- $trnsl_product_tabs = array();
143
  foreach ( $orig_prod_tabs as $key => $orig_prod_tab ) {
144
  $title_key = md5( 'tab_' . $key . '_title' );
145
  $content_key = md5( 'tab_' . $key . '_content' );
@@ -172,7 +169,7 @@ class WCML_YIKES_Custom_Product_Tabs {
172
  }
173
 
174
  /**
175
- * @param array $package
176
  * @param object $post
177
  *
178
  * @return array
@@ -185,19 +182,19 @@ class WCML_YIKES_Custom_Product_Tabs {
185
  if ( $orig_prod_tabs ) {
186
  foreach ( $orig_prod_tabs as $key => $prod_tab ) {
187
  if ( isset( $prod_tab['title'] ) ) {
188
- $package['contents'][ self::CUSTOM_TABS_FIELD . ':product_tab:' . $key . ':title' ] = array(
189
  'translate' => 1,
190
  'data' => $this->tp->encode_field_data( $prod_tab['title'], 'base64' ),
191
  'format' => 'base64',
192
- );
193
  }
194
 
195
  if ( isset( $prod_tab['content'] ) ) {
196
- $package['contents'][ self::CUSTOM_TABS_FIELD . ':product_tab:' . $key . ':content' ] = array(
197
  'translate' => 1,
198
  'data' => $this->tp->encode_field_data( $prod_tab['content'], 'base64' ),
199
  'format' => 'base64',
200
- );
201
  }
202
  }
203
  }
@@ -207,8 +204,8 @@ class WCML_YIKES_Custom_Product_Tabs {
207
  }
208
 
209
  /**
210
- * @param int $post_id
211
- * @param array $data
212
  * @param object $job
213
  */
214
  public function save_custom_tabs_translation( $post_id, $data, $job ) {
@@ -219,13 +216,13 @@ class WCML_YIKES_Custom_Product_Tabs {
219
 
220
  $translated_product_tabs = $this->get_product_tabs( $post_id );
221
 
222
- if( !$translated_product_tabs ){
223
  $translated_product_tabs = $original_product_tabs;
224
  }
225
 
226
  foreach ( $data as $value ) {
227
 
228
- if ( preg_match( '/'.self::CUSTOM_TABS_FIELD.':product_tab:([0-9]+):(.+)/', $value['field_type'], $matches ) ) {
229
 
230
  $tab_key = $matches[1];
231
  $field = $matches[2];
@@ -254,10 +251,10 @@ class WCML_YIKES_Custom_Product_Tabs {
254
  $pointer_ui->show();
255
  }
256
 
257
- public function maybe_remove_admin_language_switcher( ) {
258
 
259
  if ( isset( $_GET['page'] ) && 'yikes-woo-settings' === $_GET['page'] ) {
260
- remove_action( 'wp_before_admin_bar_render', array( $this->sitepress, 'admin_language_switcher' ) );
261
  }
262
 
263
  }
25
  /**
26
  * WCML_Tab_Manager constructor.
27
  *
28
+ * @param woocommerce_wpml $woocommerce_wpml
29
+ * @param SitePress $sitepress
30
  * @param WPML_Element_Translation_Package $tp
31
  */
32
+ public function __construct( woocommerce_wpml $woocommerce_wpml, SitePress $sitepress, WPML_Element_Translation_Package $tp ) {
33
  $this->sitepress = $sitepress;
34
  $this->woocommerce_wpml = $woocommerce_wpml;
35
  $this->tp = $tp;
37
 
38
  public function add_hooks() {
39
 
40
+ add_action( 'wpml_translation_job_saved', [ $this, 'save_custom_tabs_translation' ], 10, 3 );
 
 
 
 
 
 
 
 
41
 
42
+ if ( is_admin() ) {
43
+ add_action( 'wcml_gui_additional_box_html', [ $this, 'custom_box_html' ], 10, 3 );
44
+ add_filter( 'wcml_gui_additional_box_data', [ $this, 'custom_box_html_data' ], 10, 4 );
45
+ add_action( 'wcml_update_extra_fields', [ $this, 'sync_tabs' ], 10, 4 );
46
+ add_filter( 'wpml_duplicate_custom_fields_exceptions', [ $this, 'custom_fields_exceptions' ] );
47
+ add_filter( 'wcml_do_not_display_custom_fields_for_product', [ $this, 'custom_fields_exceptions' ] );
48
+ add_filter( 'wpml_tm_translation_job_data', [ $this, 'append_custom_tabs_to_translation_package' ], 10, 2 );
49
+ add_action( 'woocommerce_product_data_panels', [ $this, 'show_pointer_info' ] );
50
+ add_action( 'init', [ $this, 'maybe_remove_admin_language_switcher' ] );
51
  }
52
  }
53
 
54
  /**
55
  * @param object $obj
56
+ * @param int $product_id
57
+ * @param array $data
 
58
  */
59
+ public function custom_box_html( $obj, $product_id, $data ) {
60
 
61
  $orig_prod_tabs = $this->get_product_tabs( $product_id );
62
 
85
 
86
 
87
  /**
88
+ * @param array $data
89
+ * @param int $product_id
90
  * @param object $translation
91
  * @param string $lang
92
  *
93
  * @return array
94
  */
95
+ public function custom_box_html_data( $data, $product_id, $translation, $lang ) {
96
 
97
  $orig_prod_tabs = $this->get_product_tabs( $product_id );
98
  if ( $orig_prod_tabs ) {
99
  foreach ( $orig_prod_tabs as $key => $prod_tab ) {
100
  if ( isset( $prod_tab['title'] ) ) {
101
+ $data[ 'tab_' . $key . '_title' ] = [ 'original' => $prod_tab['title'] ];
102
  }
103
  if ( isset( $prod_tab['content'] ) ) {
104
+ $data[ 'tab_' . $key . '_content' ] = [ 'original' => $prod_tab['content'] ];
105
  }
106
  }
107
 
124
  }
125
 
126
  /**
127
+ * @param int $original_product_id
128
+ * @param int $trnsl_product_id
129
+ * @param array $data
130
  * @param string $lang
 
131
  */
132
+ public function sync_tabs( $original_product_id, $trnsl_product_id, $data, $lang ) {
133
 
134
  $orig_prod_tabs = $this->get_product_tabs( $original_product_id );
135
 
136
  if ( ( isset( $_POST['icl_ajx_action'] ) && ( 'make_duplicates' === $_POST['icl_ajx_action'] ) ) || ( get_post_meta( $trnsl_product_id, '_icl_lang_duplicate_of', true ) ) ) {
137
  update_post_meta( $trnsl_product_id, self::CUSTOM_TABS_FIELD, $orig_prod_tabs );
138
  } elseif ( $orig_prod_tabs ) {
139
+ $trnsl_product_tabs = [];
140
  foreach ( $orig_prod_tabs as $key => $orig_prod_tab ) {
141
  $title_key = md5( 'tab_' . $key . '_title' );
142
  $content_key = md5( 'tab_' . $key . '_content' );
169
  }
170
 
171
  /**
172
+ * @param array $package
173
  * @param object $post
174
  *
175
  * @return array
182
  if ( $orig_prod_tabs ) {
183
  foreach ( $orig_prod_tabs as $key => $prod_tab ) {
184
  if ( isset( $prod_tab['title'] ) ) {
185
+ $package['contents'][ self::CUSTOM_TABS_FIELD . ':product_tab:' . $key . ':title' ] = [
186
  'translate' => 1,
187
  'data' => $this->tp->encode_field_data( $prod_tab['title'], 'base64' ),
188
  'format' => 'base64',
189
+ ];
190
  }
191
 
192
  if ( isset( $prod_tab['content'] ) ) {
193
+ $package['contents'][ self::CUSTOM_TABS_FIELD . ':product_tab:' . $key . ':content' ] = [
194
  'translate' => 1,
195
  'data' => $this->tp->encode_field_data( $prod_tab['content'], 'base64' ),
196
  'format' => 'base64',
197
+ ];
198
  }
199
  }
200
  }
204
  }
205
 
206
  /**
207
+ * @param int $post_id
208
+ * @param array $data
209
  * @param object $job
210
  */
211
  public function save_custom_tabs_translation( $post_id, $data, $job ) {
216
 
217
  $translated_product_tabs = $this->get_product_tabs( $post_id );
218
 
219
+ if ( ! $translated_product_tabs ) {
220
  $translated_product_tabs = $original_product_tabs;
221
  }
222
 
223
  foreach ( $data as $value ) {
224
 
225
+ if ( preg_match( '/' . self::CUSTOM_TABS_FIELD . ':product_tab:([0-9]+):(.+)/', $value['field_type'], $matches ) ) {
226
 
227
  $tab_key = $matches[1];
228
  $field = $matches[2];
251
  $pointer_ui->show();
252
  }
253
 
254
+ public function maybe_remove_admin_language_switcher() {
255
 
256
  if ( isset( $_GET['page'] ) && 'yikes-woo-settings' === $_GET['page'] ) {
257
+ remove_action( 'wp_before_admin_bar_render', [ $this->sitepress, 'admin_language_switcher' ] );
258
  }
259
 
260
  }
compatibility/class-wcml-yith-wcqv.php CHANGED
@@ -1,18 +1,18 @@
1
  <?php
2
 
3
- class WCML_YITH_WCQV{
4
 
5
- public function add_hooks(){
6
 
7
- add_filter( 'wcml_multi_currency_ajax_actions', array( $this, 'ajax_action_needs_multi_currency' ) );
8
 
9
- }
10
 
11
- function ajax_action_needs_multi_currency( $actions ){
12
 
13
- $actions[] = 'yith_load_product_quick_view';
14
 
15
- return $actions;
16
- }
17
 
18
  }
1
  <?php
2
 
3
+ class WCML_YITH_WCQV {
4
 
5
+ public function add_hooks() {
6
 
7
+ add_filter( 'wcml_multi_currency_ajax_actions', [ $this, 'ajax_action_needs_multi_currency' ] );
8
 
9
+ }
10
 
11
+ public function ajax_action_needs_multi_currency( $actions ) {
12
 
13
+ $actions[] = 'yith_load_product_quick_view';
14
 
15
+ return $actions;
16
+ }
17
 
18
  }
compatibility/includes/class-wcml-wc-product-bundles-items.php CHANGED
@@ -1,17 +1,17 @@
1
  <?php
2
 
3
- class WCML_WC_Product_Bundles_Items{
4
 
5
  /**
6
  * @param int
7
  *
8
  * @return array
9
  */
10
- public function get_items( $product_id ){
11
 
12
- $items = array();
13
  $product_bundle = new WC_Product_Bundle( $product_id );
14
- if( $product_bundle ){
15
  $items = $product_bundle->get_bundled_items();
16
  }
17
  return $items;
@@ -23,7 +23,7 @@ class WCML_WC_Product_Bundles_Items{
23
  *
24
  * @return array
25
  */
26
- function get_item_data( $bundled_item ){
27
  $item_data = $bundled_item->get_data();
28
  // #wcml-1927 - Insufficient Stock issue
29
  if ( $item_data['max_stock'] === null ) {
@@ -32,14 +32,14 @@ class WCML_WC_Product_Bundles_Items{
32
  return $item_data;
33
  }
34
 
35
- function copy_item_data( $item_id_1, $item_id_2 ){
36
 
37
  $item_1_data = $this->get_item_data_object( $item_id_1 );
38
  $item_2_data = $this->get_item_data_object( $item_id_2 );
39
 
40
  $meta_data = $item_1_data->get_meta_data();
41
 
42
- foreach( $meta_data as $key => $value ){
43
  $item_2_data->update_meta( $key, $value );
44
  }
45
 
@@ -51,7 +51,7 @@ class WCML_WC_Product_Bundles_Items{
51
  *
52
  * @return WC_Bundled_Item_Data
53
  */
54
- function get_item_data_object( $item_id ){
55
  return new WC_Bundled_Item_Data( $item_id );
56
  }
57
 
@@ -59,17 +59,15 @@ class WCML_WC_Product_Bundles_Items{
59
  * @param WC_Bundled_Item_Data
60
  * @param string
61
  * @param mixed
62
- *
63
  */
64
- public function update_item_meta( $bundled_item_data, $key, $value ){
65
- $bundled_item_data->update_meta($key, $value );
66
  }
67
 
68
  /**
69
  * @param WC_Bundled_Item_Data
70
- *
71
  */
72
- public function save_item_meta( $bundled_item_data ){
73
  $bundled_item_data->save();
74
  }
75
 
1
  <?php
2
 
3
+ class WCML_WC_Product_Bundles_Items {
4
 
5
  /**
6
  * @param int
7
  *
8
  * @return array
9
  */
10
+ public function get_items( $product_id ) {
11
 
12
+ $items = [];
13
  $product_bundle = new WC_Product_Bundle( $product_id );
14
+ if ( $product_bundle ) {
15
  $items = $product_bundle->get_bundled_items();
16
  }
17
  return $items;
23
  *
24
  * @return array
25
  */
26
+ public function get_item_data( $bundled_item ) {
27
  $item_data = $bundled_item->get_data();
28
  // #wcml-1927 - Insufficient Stock issue
29
  if ( $item_data['max_stock'] === null ) {
32
  return $item_data;
33
  }
34
 
35
+ public function copy_item_data( $item_id_1, $item_id_2 ) {
36
 
37
  $item_1_data = $this->get_item_data_object( $item_id_1 );
38
  $item_2_data = $this->get_item_data_object( $item_id_2 );
39
 
40
  $meta_data = $item_1_data->get_meta_data();
41
 
42
+ foreach ( $meta_data as $key => $value ) {
43
  $item_2_data->update_meta( $key, $value );
44
  }
45
 
51
  *
52
  * @return WC_Bundled_Item_Data
53
  */
54
+ public function get_item_data_object( $item_id ) {
55
  return new WC_Bundled_Item_Data( $item_id );
56
  }
57
 
59
  * @param WC_Bundled_Item_Data
60
  * @param string
61
  * @param mixed
 
62
  */
63
+ public function update_item_meta( $bundled_item_data, $key, $value ) {
64
+ $bundled_item_data->update_meta( $key, $value );
65
  }
66
 
67
  /**
68
  * @param WC_Bundled_Item_Data
 
69
  */
70
+ public function save_item_meta( $bundled_item_data ) {
71
  $bundled_item_data->save();
72
  }
73
 
inc/admin-menus/class-wcml-admin-menus.php CHANGED
@@ -35,21 +35,21 @@ class WCML_Admin_Menus {
35
  add_filter( 'wpml_menu_page', [ __CLASS__, 'wpml_menu_page' ] );
36
  }
37
 
38
- add_action( 'admin_menu', array( __CLASS__, 'register_menus' ), 80 );
39
 
40
  if ( self::is_page_without_admin_language_switcher() ) {
41
  self::remove_wpml_admin_language_switcher();
42
  }
43
 
44
  if ( is_admin() && ! is_null( $sitepress ) && self::$woocommerce_wpml->dependencies_are_ok ) {
45
- add_action( 'admin_footer', array( __CLASS__, 'documentation_links' ) );
46
- add_action( 'admin_head', array( __CLASS__, 'hide_multilingual_content_setup_box' ) );
47
- add_action( 'admin_init', array( __CLASS__, 'restrict_admin_with_redirect' ) );
48
  }
49
 
50
- add_filter( 'woocommerce_prevent_admin_access', array( __CLASS__, 'check_user_admin_access' ) );
51
 
52
- add_action( 'admin_head', array( __CLASS__, 'add_menu_warning' ) );
53
  }
54
 
55
  /**
@@ -63,11 +63,11 @@ class WCML_Admin_Menus {
63
  $get_page = isset( $_GET['page'] ) ? $_GET['page'] : false;
64
 
65
  $is_page_wpml_wcml = isset( $_GET['page'] ) && 'wpml-wcml' === $_GET['page'];
66
- $is_new_order_or_coupon = in_array( $pagenow, array( 'edit.php', 'post-new.php' ), true ) &&
67
- $get_post_type &&
68
- in_array( $get_post_type, array( 'shop_coupon', 'shop_order' ), true );
69
  $is_edit_order_or_coupon = 'post.php' === $pagenow && $get_post &&
70
- in_array( get_post_type( $get_post ), array( 'shop_coupon', 'shop_order' ), true );
71
  $is_shipping_zones = 'shipping_zones' === $get_page;
72
  $is_attributes_page = apply_filters( 'wcml_is_attributes_page', 'product_attributes' === $get_page );
73
 
@@ -81,7 +81,7 @@ class WCML_Admin_Menus {
81
  }
82
 
83
  public static function remove_wpml_admin_language_switcher() {
84
- remove_action( 'wp_before_admin_bar_render', array( self::$sitepress, 'admin_language_switcher' ) );
85
  }
86
 
87
  /**
@@ -105,7 +105,7 @@ class WCML_Admin_Menus {
105
  __( 'WooCommerce Multilingual', 'woocommerce-multilingual' ),
106
  'wpml_operate_woocommerce_multilingual',
107
  'wpml-wcml',
108
- array( __CLASS__, 'render_menus' )
109
  );
110
  } else {
111
  add_menu_page(
@@ -113,7 +113,7 @@ class WCML_Admin_Menus {
113
  __( 'WooCommerce Multilingual', 'woocommerce-multilingual' ),
114
  'wpml_manage_woocommerce_multilingual',
115
  'wpml-wcml',
116
- array( __CLASS__, 'render_menus' ),
117
  WCML_PLUGIN_URL . '/res/images/icon16.png'
118
  );
119
 
@@ -151,7 +151,7 @@ class WCML_Admin_Menus {
151
 
152
  $quick_edit_notice .= sprintf(
153
  /* translators: 1: WooCommerce Multilingual products editor, 2: Edit this product translation */
154
- __( "Quick edit is disabled for product translations. It\'s recommended to use the %s for editing products translations. %s", 'woocommerce-multilingual' ),
155
  '<a href="' . admin_url( 'admin.php?page=wpml-wcml&tab=products' ) . '" >' . __( 'WooCommerce Multilingual products editor', 'woocommerce-multilingual' ) . '</a>',
156
  '<a href="" class="quick_product_trnsl_link" >' . __( 'Edit this product translation', 'woocommerce-multilingual' ) . '</a>'
157
  );
@@ -250,7 +250,7 @@ class WCML_Admin_Menus {
250
  exit;
251
  }
252
  } elseif ( 'post.php' === $pagenow && self::is_post_product_translation_screen() ) {
253
- add_action( 'admin_notices', array( __CLASS__, 'inf_editing_product_in_non_default_lang' ) );
254
  }
255
  }
256
 
@@ -266,13 +266,13 @@ class WCML_Admin_Menus {
266
  */
267
  private static function is_post_action_needs_redirect() {
268
  return ! isset( $_GET['action'] ) ||
269
- ( isset( $_GET['action'] ) &&
270
- ! in_array(
271
- $_GET['action'],
272
- array( 'trash', 'delete', 'untrash' ),
273
- true
274
- )
275
- );
276
  }
277
 
278
  /**
@@ -293,7 +293,7 @@ class WCML_Admin_Menus {
293
  $message .= sprintf(
294
  /* translators: 1: open <a> tag, 2: close <a> tag */
295
  __(
296
- 'The recommended way to translate WooCommerce products is using the %sWooCommerce Multilingual products translation%s page.
297
  Please use this page only for translating elements that are not available in the WooCommerce Multilingual products translation table.',
298
  'woocommerce-multilingual'
299
  ),
35
  add_filter( 'wpml_menu_page', [ __CLASS__, 'wpml_menu_page' ] );
36
  }
37
 
38
+ add_action( 'admin_menu', [ __CLASS__, 'register_menus' ], 80 );
39
 
40
  if ( self::is_page_without_admin_language_switcher() ) {
41
  self::remove_wpml_admin_language_switcher();
42
  }
43
 
44
  if ( is_admin() && ! is_null( $sitepress ) && self::$woocommerce_wpml->dependencies_are_ok ) {
45
+ add_action( 'admin_footer', [ __CLASS__, 'documentation_links' ] );
46
+ add_action( 'admin_head', [ __CLASS__, 'hide_multilingual_content_setup_box' ] );
47
+ add_action( 'admin_init', [ __CLASS__, 'restrict_admin_with_redirect' ] );
48
  }
49
 
50
+ add_filter( 'woocommerce_prevent_admin_access', [ __CLASS__, 'check_user_admin_access' ] );
51
 
52
+ add_action( 'admin_head', [ __CLASS__, 'add_menu_warning' ] );
53
  }
54
 
55
  /**
63
  $get_page = isset( $_GET['page'] ) ? $_GET['page'] : false;
64
 
65
  $is_page_wpml_wcml = isset( $_GET['page'] ) && 'wpml-wcml' === $_GET['page'];
66
+ $is_new_order_or_coupon = in_array( $pagenow, [ 'edit.php', 'post-new.php' ], true ) &&
67
+ $get_post_type &&
68
+ in_array( $get_post_type, [ 'shop_coupon', 'shop_order' ], true );
69
  $is_edit_order_or_coupon = 'post.php' === $pagenow && $get_post &&
70
+ in_array( get_post_type( $get_post ), [ 'shop_coupon', 'shop_order' ], true );
71
  $is_shipping_zones = 'shipping_zones' === $get_page;
72
  $is_attributes_page = apply_filters( 'wcml_is_attributes_page', 'product_attributes' === $get_page );
73
 
81
  }
82
 
83
  public static function remove_wpml_admin_language_switcher() {
84
+ remove_action( 'wp_before_admin_bar_render', [ self::$sitepress, 'admin_language_switcher' ] );
85
  }
86
 
87
  /**
105
  __( 'WooCommerce Multilingual', 'woocommerce-multilingual' ),
106
  'wpml_operate_woocommerce_multilingual',
107
  'wpml-wcml',
108
+ [ __CLASS__, 'render_menus' ]
109
  );
110
  } else {
111
  add_menu_page(
113
  __( 'WooCommerce Multilingual', 'woocommerce-multilingual' ),
114
  'wpml_manage_woocommerce_multilingual',
115
  'wpml-wcml',
116
+ [ __CLASS__, 'render_menus' ],
117
  WCML_PLUGIN_URL . '/res/images/icon16.png'
118
  );
119
 
151
 
152
  $quick_edit_notice .= sprintf(
153
  /* translators: 1: WooCommerce Multilingual products editor, 2: Edit this product translation */
154
+ __( 'Quick edit is disabled for product translations. It\'s recommended to use the %1$s for editing products translations. %2$s', 'woocommerce-multilingual' ),
155
  '<a href="' . admin_url( 'admin.php?page=wpml-wcml&tab=products' ) . '" >' . __( 'WooCommerce Multilingual products editor', 'woocommerce-multilingual' ) . '</a>',
156
  '<a href="" class="quick_product_trnsl_link" >' . __( 'Edit this product translation', 'woocommerce-multilingual' ) . '</a>'
157
  );
250
  exit;
251
  }
252
  } elseif ( 'post.php' === $pagenow && self::is_post_product_translation_screen() ) {
253
+ add_action( 'admin_notices', [ __CLASS__, 'inf_editing_product_in_non_default_lang' ] );
254
  }
255
  }
256
 
266
  */
267
  private static function is_post_action_needs_redirect() {
268
  return ! isset( $_GET['action'] ) ||
269
+ ( isset( $_GET['action'] ) &&
270
+ ! in_array(
271
+ $_GET['action'],
272
+ [ 'trash', 'delete', 'untrash' ],
273
+ true
274
+ )
275
+ );
276
  }
277
 
278
  /**
293
  $message .= sprintf(
294
  /* translators: 1: open <a> tag, 2: close <a> tag */
295
  __(
296
+ 'The recommended way to translate WooCommerce products is using the %1$sWooCommerce Multilingual products translation%2$s page.
297
  Please use this page only for translating elements that are not available in the WooCommerce Multilingual products translation table.',
298
  'woocommerce-multilingual'
299
  ),
inc/class-wcml-ajax-setup.php CHANGED
@@ -19,15 +19,15 @@ class WCML_Ajax_Setup {
19
  }
20
 
21
  public function init() {
22
- add_filter( 'woocommerce_get_script_data', array( $this, 'add_language_parameter_to_ajax_url' ) );
23
- add_action( 'woocommerce_checkout_order_review', array( $this, 'add_hidden_language_field' ) );
24
  }
25
 
26
- function add_hidden_language_field() {
27
  do_action( 'wpml_add_language_form_field' );
28
  }
29
 
30
- function add_language_parameter_to_ajax_url( $woocommerce_params ) {
31
 
32
  if ( isset( $woocommerce_params['ajax_url'] ) && $this->sitepress->get_current_language() !== $this->sitepress->get_default_language() ) {
33
  $woocommerce_params['ajax_url'] = add_query_arg( 'lang', $this->sitepress->get_wp_api()->constant( 'ICL_LANGUAGE_CODE' ), $woocommerce_params['ajax_url'] );
19
  }
20
 
21
  public function init() {
22
+ add_filter( 'woocommerce_get_script_data', [ $this, 'add_language_parameter_to_ajax_url' ] );
23
+ add_action( 'woocommerce_checkout_order_review', [ $this, 'add_hidden_language_field' ] );
24
  }
25
 
26
+ public function add_hidden_language_field() {
27
  do_action( 'wpml_add_language_form_field' );
28
  }
29
 
30
+ public function add_language_parameter_to_ajax_url( $woocommerce_params ) {
31
 
32
  if ( isset( $woocommerce_params['ajax_url'] ) && $this->sitepress->get_current_language() !== $this->sitepress->get_default_language() ) {
33
  $woocommerce_params['ajax_url'] = add_query_arg( 'lang', $this->sitepress->get_wp_api()->constant( 'ICL_LANGUAGE_CODE' ), $woocommerce_params['ajax_url'] );
inc/class-wcml-attributes.php CHANGED
@@ -18,11 +18,11 @@ class WCML_Attributes {
18
  /**
19
  * WCML_Attributes constructor.
20
  *
21
- * @param woocommerce_wpml $woocommerce_wpml
22
- * @param SitePress $sitepress
23
  * @param WPML_Post_Translation $post_translations
24
  * @param WPML_Term_Translation $term_translations
25
- * @param wpdb $wpdb
26
  */
27
  public function __construct( woocommerce_wpml $woocommerce_wpml, SitePress $sitepress, WPML_Post_Translation $post_translations, WPML_Term_Translation $term_translations, wpdb $wpdb ) {
28
  $this->woocommerce_wpml = $woocommerce_wpml;
@@ -42,59 +42,91 @@ class WCML_Attributes {
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
 
84
  $is_attr_page = isset( $_GET['page'], $_GET['post_type'] )
85
- && 'product_attributes' === $_GET['page']
86
- && 'product' === $_GET['post_type'];
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
  }
@@ -108,15 +140,20 @@ class WCML_Attributes {
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
 
@@ -133,7 +170,7 @@ class WCML_Attributes {
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 );
@@ -154,8 +191,8 @@ class WCML_Attributes {
154
  private function fix_attribute_slug_in_translations_table( $old_attribute_name, $new_attribute_name ) {
155
  $this->wpdb->update(
156
  $this->wpdb->prefix . 'icl_translations',
157
- array( 'element_type' => 'tax_' . $new_attribute_name ),
158
- array( 'element_type' => 'tax_' . $old_attribute_name )
159
  );
160
  }
161
 
@@ -167,14 +204,14 @@ class WCML_Attributes {
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 );
@@ -199,7 +236,7 @@ class WCML_Attributes {
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'] );
@@ -215,18 +252,18 @@ class WCML_Attributes {
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
 
@@ -262,7 +299,7 @@ class WCML_Attributes {
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;
@@ -284,7 +321,7 @@ class WCML_Attributes {
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
 
@@ -302,14 +339,14 @@ class WCML_Attributes {
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'] ) {
@@ -319,21 +356,21 @@ class WCML_Attributes {
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;
@@ -343,7 +380,7 @@ class WCML_Attributes {
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 ] ) ) {
@@ -357,11 +394,11 @@ class WCML_Attributes {
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 );
@@ -375,7 +412,7 @@ class WCML_Attributes {
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
 
@@ -406,12 +443,15 @@ class WCML_Attributes {
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'] ) ) {
@@ -427,7 +467,7 @@ class WCML_Attributes {
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 );
@@ -469,7 +509,7 @@ class WCML_Attributes {
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
  }
@@ -566,13 +606,13 @@ class WCML_Attributes {
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() );
@@ -592,15 +632,15 @@ class WCML_Attributes {
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
 
@@ -627,7 +667,6 @@ class WCML_Attributes {
627
  foreach ( $attributes as $key => $attribute ) {
628
  $attributes[ $key ]['name'] = $this->filter_attribute_name( $attributes[ $key ]['name'], $product_id );
629
  }
630
-
631
  }
632
 
633
  return $attributes;
@@ -668,10 +707,10 @@ class WCML_Attributes {
668
  }
669
 
670
  /**
671
- * @param null $value
672
- * @param int $object_id
673
  * @param string $meta_key
674
- * @param bool $single
675
  *
676
  * @return array
677
  */
@@ -687,17 +726,26 @@ class WCML_Attributes {
687
  return $cached_value;
688
  }
689
 
690
- remove_filter( 'get_post_metadata', array(
691
- $this,
692
- 'filter_product_variation_post_meta_attribute_values_in_current_language'
693
- ), 10 );
 
 
 
 
694
 
695
  $all_meta = get_post_meta( $object_id );
696
 
697
- add_filter( 'get_post_metadata', array(
698
- $this,
699
- 'filter_product_variation_post_meta_attribute_values_in_current_language'
700
- ), 10, 4 );
 
 
 
 
 
701
 
702
  if ( $all_meta ) {
703
  foreach ( $all_meta as $meta_key => $meta_value ) {
@@ -712,7 +760,6 @@ class WCML_Attributes {
712
 
713
  return $all_meta;
714
  }
715
-
716
  }
717
 
718
  return $value;
@@ -734,7 +781,6 @@ class WCML_Attributes {
734
  $default_attributes[ $attribute_key ] = $this->get_attribute_term_translation_in_current_language( $attribute_key, $attribute_value );
735
 
736
  }
737
-
738
  }
739
 
740
  return $default_attributes;
@@ -760,8 +806,8 @@ class WCML_Attributes {
760
  }
761
 
762
  /**
763
- * @param int $meta_id
764
- * @param int $object_id
765
  * @param string $meta_key
766
  */
767
  public function set_translation_status_as_needs_update( $meta_id, $object_id, $meta_key ) {
@@ -797,4 +843,4 @@ class WCML_Attributes {
797
  }
798
  }
799
 
800
- }
18
  /**
19
  * WCML_Attributes constructor.
20
  *
21
+ * @param woocommerce_wpml $woocommerce_wpml
22
+ * @param SitePress $sitepress
23
  * @param WPML_Post_Translation $post_translations
24
  * @param WPML_Term_Translation $term_translations
25
+ * @param wpdb $wpdb
26
  */
27
  public function __construct( woocommerce_wpml $woocommerce_wpml, SitePress $sitepress, WPML_Post_Translation $post_translations, WPML_Term_Translation $term_translations, wpdb $wpdb ) {
28
  $this->woocommerce_wpml = $woocommerce_wpml;
42
 
43
  public function add_hooks() {
44
 
45
+ add_action( 'init', [ $this, 'init' ] );
46
 
47
+ add_filter(
48
+ 'wpml_translation_job_post_meta_value_translated',
49
+ [
50
+ $this,
51
+ 'filter_product_attributes_for_translation',
52
+ ],
53
+ 10,
54
+ 2
55
+ );
56
+ add_filter(
57
+ 'woocommerce_dropdown_variation_attribute_options_args',
58
+ [
59
+ $this,
60
+ 'filter_dropdown_variation_attribute_options_args',
61
+ ]
62
+ );
63
 
64
  if ( isset( $_POST['icl_ajx_action'] ) && $_POST['icl_ajx_action'] == 'icl_custom_tax_sync_options' ) {
65
  $this->icl_custom_tax_sync_options();
66
  }
67
+ add_filter(
68
+ 'woocommerce_product_get_attributes',
69
+ [
70
+ $this,
71
+ 'filter_adding_to_cart_product_attributes_names',
72
+ ]
73
+ );
74
 
75
  if ( $this->get_wcml_products_instance()->is_product_display_as_translated_post_type() ) {
76
+ add_filter(
77
+ 'woocommerce_available_variation',
78
+ [
79
+ $this,
80
+ 'filter_available_variation_attribute_values_in_current_language',
81
+ ]
82
+ );
83
+ add_filter(
84
+ 'get_post_metadata',
85
+ [
86
+ $this,
87
+ 'filter_product_variation_post_meta_attribute_values_in_current_language',
88
+ ],
89
+ 10,
90
+ 4
91
+ );
92
+ add_filter(
93
+ 'woocommerce_product_get_default_attributes',
94
+ [
95
+ $this,
96
+ 'filter_product_variation_default_attributes',
97
+ ]
98
+ );
99
+ }
100
+ add_action( 'update_post_meta', [ $this, 'set_translation_status_as_needs_update' ], 10, 3 );
101
+ add_action( 'wc_ajax_get_variation', [ $this, 'maybe_filter_get_variation' ], 9 );
102
  }
103
 
104
  public function init() {
105
 
106
  $is_attr_page = isset( $_GET['page'], $_GET['post_type'] )
107
+ && 'product_attributes' === $_GET['page']
108
+ && 'product' === $_GET['post_type'];
109
 
110
  if ( apply_filters( 'wcml_is_attributes_page', $is_attr_page ) ) {
111
+ add_action( 'admin_init', [ $this, 'not_translatable_html' ] );
112
+ add_action(
113
+ 'woocommerce_attribute_added',
114
+ [
115
+ $this,
116
+ 'set_attribute_readonly_config',
117
+ ],
118
+ self::PRIORITY_AFTER_WC_INIT,
119
+ 2
120
+ );
121
+ add_action(
122
+ 'woocommerce_attribute_updated',
123
+ [
124
+ $this,
125
+ 'set_attribute_readonly_config',
126
+ ],
127
+ self::PRIORITY_AFTER_WC_INIT,
128
+ 3
129
+ );
130
  }
131
 
132
  }
140
 
141
  public function get_attribute_terms( $attribute ) {
142
 
143
+ return $this->wpdb->get_results(
144
+ $this->wpdb->prepare(
145
+ "
146
+ SELECT * FROM {$this->wpdb->term_taxonomy} x JOIN {$this->wpdb->terms} t ON x.term_id = t.term_id WHERE x.taxonomy = %s",
147
+ $attribute
148
+ )
149
+ );
150
 
151
  }
152
 
153
  /**
154
+ * @param int $id
155
  * @param array $data
156
+ * @param bool $old_slug
157
  */
158
  public function set_attribute_readonly_config( $id, $data, $old_slug = false ) {
159
 
170
  $attribute_name = wc_attribute_taxonomy_name( $attribute_name );
171
 
172
  if ( $is_translatable === 0 ) {
173
+ // delete all translated attributes terms if "Translatable?" option un-checked.
174
  $this->delete_translated_attribute_terms( $attribute_name );
175
  $this->set_variations_to_use_original_attributes( $attribute_name );
176
  $this->set_original_attributes_for_products( $attribute_name );
191
  private function fix_attribute_slug_in_translations_table( $old_attribute_name, $new_attribute_name ) {
192
  $this->wpdb->update(
193
  $this->wpdb->prefix . 'icl_translations',
194
+ [ 'element_type' => 'tax_' . $new_attribute_name ],
195
+ [ 'element_type' => 'tax_' . $old_attribute_name ]
196
  );
197
  }
198
 
204
  }
205
 
206
  public function set_attribute_config_in_wcml_settings( $attribute_name, $is_translatable ) {
207
+ $wcml_settings = $this->woocommerce_wpml->get_settings();
208
  $wcml_settings['attributes_settings'][ $attribute_name ] = $is_translatable;
209
  $this->woocommerce_wpml->update_settings( $wcml_settings );
210
  }
211
 
212
  public function set_attribute_config_in_wpml_settings( $attribute_name, $is_translatable ) {
213
 
214
+ $sync_settings = $this->sitepress->get_setting( 'taxonomies_sync_option', [] );
215
  $sync_settings[ $attribute_name ] = $is_translatable;
216
  $this->sitepress->set_setting( 'taxonomies_sync_option', $sync_settings, true );
217
  $this->sitepress->verify_taxonomy_translations( $attribute_name );
236
  $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 ) );
237
 
238
  foreach ( $variations as $variation ) {
239
+ // update taxonomy in translation of variation.
240
  foreach ( $this->sitepress->get_active_languages() as $language ) {
241
 
242
  $trnsl_variation_id = apply_filters( 'translate_object_id', $variation->post_id, 'product_variation', false, $language['code'] );
252
  public function set_original_attributes_for_products( $attribute ) {
253
 
254
  $terms = $this->get_attribute_terms( $attribute );
255
+ $cleared_products = [];
256
  foreach ( $terms as $term ) {
257
  if ( is_null( $this->term_translations->get_source_lang_code( $term->term_id ) ) ) {
258
+ $args = [
259
+ 'tax_query' => [
260
+ [
261
  'taxonomy' => $attribute,
262
  'field' => 'slug',
263
+ 'terms' => $term->slug,
264
+ ],
265
+ ],
266
+ ];
267
 
268
  $products = get_posts( $args );
269
 
299
  public function get_translatable_attributes() {
300
  $attributes = wc_get_attribute_taxonomies();
301
 
302
+ $translatable_attributes = [];
303
  foreach ( $attributes as $attribute ) {
304
  if ( $this->is_translatable_attribute( wc_attribute_taxonomy_name( $attribute->attribute_name ) ) ) {
305
  $translatable_attributes[] = $attribute;
321
 
322
  public function sync_product_attr( $original_product_id, $tr_product_id, $language = false, $data = false ) {
323
 
324
+ // get "_product_attributes" from original product.
325
  $orig_product_attrs = $this->get_product_attributes( $original_product_id );
326
  $trnsl_product_attrs = $this->get_product_attributes( $tr_product_id );
327
 
339
  }
340
  if ( $data ) {
341
  if ( isset( $data[ md5( $key ) ] ) && ! empty( $data[ md5( $key ) ] ) && ! is_array( $data[ md5( $key ) ] ) ) {
342
+ // get translation values from $data.
343
  $orig_product_attrs[ $key_to_save ]['value'] = $data[ md5( $key ) ];
344
  } else {
345
  $orig_product_attrs[ $key_to_save ]['value'] = '';
346
  }
347
 
348
  if ( isset( $data[ md5( $key . '_name' ) ] ) && ! empty( $data[ md5( $key . '_name' ) ] ) && ! is_array( $data[ md5( $key . '_name' ) ] ) ) {
349
+ // get translation values from $data.
350
  $translated_labels[ $language ][ $key_to_save ] = stripslashes( $data[ md5( $key . '_name' ) ] );
351
  }
352
  } elseif ( ! $orig_product_attr['is_taxonomy'] ) {
356
  if ( isset( $trnsl_product_attrs[ $key ] ) ) {
357
  $orig_product_attrs[ $key_to_save ]['value'] = $trnsl_product_attrs[ $key ]['value'];
358
  } elseif ( ! empty( $trnsl_product_attrs ) ) {
359
+ unset( $orig_product_attrs[ $key_to_save ] );
360
  }
361
  }
362
  }
363
  }
364
 
365
  update_post_meta( $tr_product_id, 'attr_label_translations', $translated_labels );
366
+ // update "_product_attributes".
367
  update_post_meta( $tr_product_id, '_product_attributes', $orig_product_attrs );
368
  }
369
 
370
  public function get_product_attributes( $product_id ) {
371
  $attributes = get_post_meta( $product_id, '_product_attributes', true );
372
  if ( ! is_array( $attributes ) ) {
373
+ $attributes = [];
374
  }
375
 
376
  return $attributes;
380
  $trnsl_labels = get_post_meta( $product_id, 'attr_label_translations', true );
381
 
382
  if ( ! is_array( $trnsl_labels ) ) {
383
+ $trnsl_labels = [];
384
  }
385
 
386
  if ( isset( $trnsl_labels[ $lang ] ) ) {
394
  $original_default_attributes = get_post_meta( $orig_post_id, '_default_attributes', true );
395
 
396
  if ( ! empty( $original_default_attributes ) ) {
397
+ $unserialized_default_attributes = [];
398
  foreach ( maybe_unserialize( $original_default_attributes ) as $attribute => $default_term_slug ) {
399
+ // get the correct language.
400
  if ( substr( $attribute, 0, 3 ) == 'pa_' ) {
401
+ // attr is taxonomy.
402
  if ( $this->is_translatable_attribute( $attribute ) ) {
403
  $sanitized_attribute_name = wc_sanitize_taxonomy_name( $attribute );
404
  $default_term_id = $this->get_wcml_terms_instance()->wcml_get_term_id_by_slug( $sanitized_attribute_name, $default_term_slug );
412
  $unserialized_default_attributes[ $attribute ] = $default_term_slug;
413
  }
414
  } else {
415
+ // custom attr.
416
  $orig_product_attributes = get_post_meta( $orig_post_id, '_product_attributes', true );
417
  $unserialized_orig_product_attributes = maybe_unserialize( $orig_product_attributes );
418
 
443
  }
444
  }
445
 
446
+ $data = [ 'meta_value' => maybe_serialize( $unserialized_default_attributes ) ];
447
  } else {
448
+ $data = [ 'meta_value' => maybe_serialize( [] ) ];
449
  }
450
 
451
+ $where = [
452
+ 'post_id' => $transl_post_id,
453
+ 'meta_key' => '_default_attributes',
454
+ ];
455
 
456
  $translated_product_meta = get_post_meta( $transl_post_id );
457
  if ( isset( $translated_product_meta['_default_attributes'] ) ) {
467
  */
468
  public function get_custom_attribute_translation( $product_id, $attribute_key, $attribute, $lang_code ) {
469
  $tr_post_id = apply_filters( 'translate_object_id', $product_id, 'product', false, $lang_code );
470
+ $transl = [];
471
  if ( $tr_post_id ) {
472
  if ( ! $attribute['is_taxonomy'] ) {
473
  $tr_attrs = get_post_meta( $tr_post_id, '_product_attributes', true );
509
  $values = explode( '|', $orig_product_attribute['value'] );
510
 
511
  foreach ( $values as $key_id => $value ) {
512
+ if ( trim( $value, ' ' ) == $attribute ) {
513
  $attr_key_id = $key_id;
514
  }
515
  }
606
  $meta_key = 'attribute_' . $tax;
607
  }
608
 
609
+ return [
610
  'meta_value' => $meta_value,
611
+ 'meta_key' => $meta_key,
612
+ ];
613
  }
614
 
615
+ public function filter_dropdown_variation_attribute_options_args( $args ) {
616
 
617
  if ( isset( $args['attribute'] ) && isset( $args['product'] ) ) {
618
  $args['attribute'] = $this->filter_attribute_name( $args['attribute'], $args['product']->get_id() );
632
  * needs handle special chars accordingly
633
  * https://onthegosystems.myjetbrains.com/youtrack/issue/wcml-1785
634
  */
635
+ public function filter_attribute_name( $attribute_name, $product_id, $return_sanitized = false ) {
636
 
637
  if ( $product_id ) {
638
  $orig_lang = $this->get_wcml_products_instance()->get_original_product_language( $product_id );
639
  $current_language = $this->sitepress->get_current_language();
640
 
641
+ if ( in_array( $orig_lang, [ 'de', 'da' ] ) && $current_language !== $orig_lang ) {
642
  $attribute_name = $this->sitepress->locale_utils->filter_sanitize_title( remove_accents( $attribute_name ), $attribute_name );
643
+ remove_filter( 'sanitize_title', [ $this->sitepress->locale_utils, 'filter_sanitize_title' ], 10 );
644
  }
645
  }
646
 
667
  foreach ( $attributes as $key => $attribute ) {
668
  $attributes[ $key ]['name'] = $this->filter_attribute_name( $attributes[ $key ]['name'], $product_id );
669
  }
 
670
  }
671
 
672
  return $attributes;
707
  }
708
 
709
  /**
710
+ * @param null $value
711
+ * @param int $object_id
712
  * @param string $meta_key
713
+ * @param bool $single
714
  *
715
  * @return array
716
  */
726
  return $cached_value;
727
  }
728
 
729
+ remove_filter(
730
+ 'get_post_metadata',
731
+ [
732
+ $this,
733
+ 'filter_product_variation_post_meta_attribute_values_in_current_language',
734
+ ],
735
+ 10
736
+ );
737
 
738
  $all_meta = get_post_meta( $object_id );
739
 
740
+ add_filter(
741
+ 'get_post_metadata',
742
+ [
743
+ $this,
744
+ 'filter_product_variation_post_meta_attribute_values_in_current_language',
745
+ ],
746
+ 10,
747
+ 4
748
+ );
749
 
750
  if ( $all_meta ) {
751
  foreach ( $all_meta as $meta_key => $meta_value ) {
760
 
761
  return $all_meta;
762
  }
 
763
  }
764
 
765
  return $value;
781
  $default_attributes[ $attribute_key ] = $this->get_attribute_term_translation_in_current_language( $attribute_key, $attribute_value );
782
 
783
  }
 
784
  }
785
 
786
  return $default_attributes;
806
  }
807
 
808
  /**
809
+ * @param int $meta_id
810
+ * @param int $object_id
811
  * @param string $meta_key
812
  */
813
  public function set_translation_status_as_needs_update( $meta_id, $object_id, $meta_key ) {
843
  }
844
  }
845
 
846
+ }
inc/class-wcml-capabilities.php CHANGED
@@ -32,4 +32,4 @@ class WCML_Capabilities {
32
 
33
  }
34
 
35
- }
32
 
33
  }
34
 
35
+ }
inc/class-wcml-cart-switch-lang-functions.php CHANGED
@@ -1,92 +1,93 @@
1
  <?php
2
 
3
- class WCML_Cart_Switch_Lang_Functions{
4
 
5
- private $lang_from;
6
- private $lang_to;
7
 
8
- public function add_actions(){
9
- add_action( 'wp_footer', array( $this, 'wcml_language_switch_dialog' ) );
10
- add_action( 'wp_loaded', array( $this, 'wcml_language_force_switch' ) );
11
- add_action( 'wcml_user_switch_language', array( $this, 'language_has_switched' ), 10 , 2 );
12
 
13
- add_filter( 'woocommerce_product_add_to_cart_url', array( $this, 'remove_force_switch_from_add_to_cart_url' ) );
14
- }
15
 
16
- public function remove_force_switch_from_add_to_cart_url( $url ){
17
- $url = str_replace('force_switch=1&', '', $url );
18
- return $url;
19
- }
20
 
21
- public function language_has_switched( $lang_from, $lang_to ){
22
 
23
- $settings = get_option( '_wcml_settings' );
24
 
25
- if(
26
- !isset( $_GET[ 'force_switch' ] ) &&
27
- $lang_from != $lang_to &&
28
- !empty( $settings ) &&
29
- $settings[ 'cart_sync' ][ 'lang_switch' ] == WCML_CART_CLEAR
30
- ){
31
- $this->lang_from = $lang_from;
32
- $this->lang_to = $lang_to;
33
- }
34
- }
35
 
36
- public function wcml_language_force_switch(){
37
- global $woocommerce_wpml, $woocommerce;
38
 
39
- if( ! wpml_is_ajax() && isset( $_GET[ 'force_switch' ] ) && '1' === $_GET[ 'force_switch' ] ){
40
- $woocommerce_wpml->cart->empty_cart_if_needed( 'lang_switch' );
41
- $woocommerce->session->set( 'wcml_switched_type', 'lang_switch' );
42
- }
43
- }
44
 
45
- public function wcml_language_switch_dialog( ){
46
- global $woocommerce_wpml, $sitepress, $wp, $post;
47
 
48
- $dependencies = new WCML_Dependencies;
49
 
50
- if( $dependencies->check() ){
51
 
52
- $current_url = home_url( add_query_arg( array(), $wp->request ) );
53
 
54
- if( is_shop() ){
55
- $requested_page_id = apply_filters( 'translate_object_id', wc_get_page_id('shop'), 'post', true, $this->lang_from );
56
- }elseif( isset( $post->ID ) ){
57
- $requested_page_id = apply_filters( 'translate_object_id', $post->ID, get_post_type( $post->ID ), true, $this->lang_from );
58
- }
59
-
60
- if( isset( $requested_page_id ) ){
61
- $request_url = add_query_arg( 'force_switch', '0', $sitepress->convert_url( get_permalink( $requested_page_id ), $this->lang_from ) );
62
- }else{
63
- $request_url = $current_url;
64
- }
65
 
66
- $cart_for_session = false;
67
- if( isset( WC()->cart ) ){
68
- $cart_for_session = WC()->cart->get_cart_for_session();
69
- }
 
70
 
71
- if( $this->lang_from && $this->lang_to && $request_url && !empty( $cart_for_session ) ) {
 
 
 
72
 
73
- $force_cart_url = add_query_arg( 'force_switch', '1', $current_url );
74
- $active_languages = apply_filters( 'wpml_active_languages', null, null );
75
- $dialog_title = __( 'Switching language?', 'woocommerce-multilingual' );
76
 
77
- $confirmation_message = sprintf(
78
- __( "You've switched the language and there are items in the cart. If you keep the %s language, the cart will be emptied and you will have to add the items again to the cart.",
79
- 'woocommerce-multilingual' ),
80
- $active_languages[ $this->lang_to ]['translated_name']
81
- );
82
- $stay_in = sprintf( __( 'Keep %s', 'woocommerce-multilingual' ), $active_languages[ $this->lang_to ]['translated_name'] );
83
- $switch_to = sprintf( __( 'Switch back to %s', 'woocommerce-multilingual' ), $active_languages[ $this->lang_from ]['translated_name'] );
84
 
85
- $woocommerce_wpml->cart->cart_alert( $dialog_title, $confirmation_message, $stay_in, $switch_to, $force_cart_url, $request_url, true );
86
- }
 
 
 
 
 
 
 
87
 
88
- }
 
 
89
 
90
- }
91
 
92
- }
1
  <?php
2
 
3
+ class WCML_Cart_Switch_Lang_Functions {
4
 
5
+ private $lang_from;
6
+ private $lang_to;
7
 
8
+ public function add_actions() {
9
+ add_action( 'wp_footer', [ $this, 'wcml_language_switch_dialog' ] );
10
+ add_action( 'wp_loaded', [ $this, 'wcml_language_force_switch' ] );
11
+ add_action( 'wcml_user_switch_language', [ $this, 'language_has_switched' ], 10, 2 );
12
 
13
+ add_filter( 'woocommerce_product_add_to_cart_url', [ $this, 'remove_force_switch_from_add_to_cart_url' ] );
14
+ }
15
 
16
+ public function remove_force_switch_from_add_to_cart_url( $url ) {
17
+ $url = str_replace( 'force_switch=1&', '', $url );
18
+ return $url;
19
+ }
20
 
21
+ public function language_has_switched( $lang_from, $lang_to ) {
22
 
23
+ $settings = get_option( '_wcml_settings' );
24
 
25
+ if (
26
+ ! isset( $_GET['force_switch'] ) &&
27
+ $lang_from != $lang_to &&
28
+ ! empty( $settings ) &&
29
+ $settings['cart_sync']['lang_switch'] == WCML_CART_CLEAR
30
+ ) {
31
+ $this->lang_from = $lang_from;
32
+ $this->lang_to = $lang_to;
33
+ }
34
+ }
35
 
36
+ public function wcml_language_force_switch() {
37
+ global $woocommerce_wpml, $woocommerce;
38
 
39
+ if ( ! wpml_is_ajax() && isset( $_GET['force_switch'] ) && '1' === $_GET['force_switch'] ) {
40
+ $woocommerce_wpml->cart->empty_cart_if_needed( 'lang_switch' );
41
+ $woocommerce->session->set( 'wcml_switched_type', 'lang_switch' );
42
+ }
43
+ }
44
 
45
+ public function wcml_language_switch_dialog() {
46
+ global $woocommerce_wpml, $sitepress, $wp, $post;
47
 
48
+ $dependencies = new WCML_Dependencies();
49
 
50
+ if ( $dependencies->check() ) {
51
 
52
+ $current_url = home_url( add_query_arg( [], $wp->request ) );
53
 
54
+ if ( is_shop() ) {
55
+ $requested_page_id = apply_filters( 'translate_object_id', wc_get_page_id( 'shop' ), 'post', true, $this->lang_from );
56
+ } elseif ( isset( $post->ID ) ) {
57
+ $requested_page_id = apply_filters( 'translate_object_id', $post->ID, get_post_type( $post->ID ), true, $this->lang_from );
58
+ }
 
 
 
 
 
 
59
 
60
+ if ( isset( $requested_page_id ) ) {
61
+ $request_url = add_query_arg( 'force_switch', '0', $sitepress->convert_url( get_permalink( $requested_page_id ), $this->lang_from ) );
62
+ } else {
63
+ $request_url = $current_url;
64
+ }
65
 
66
+ $cart_for_session = false;
67
+ if ( isset( WC()->cart ) ) {
68
+ $cart_for_session = WC()->cart->get_cart_for_session();
69
+ }
70
 
71
+ if ( $this->lang_from && $this->lang_to && $request_url && ! empty( $cart_for_session ) ) {
 
 
72
 
73
+ $force_cart_url = add_query_arg( 'force_switch', '1', $current_url );
74
+ $active_languages = apply_filters( 'wpml_active_languages', null, null );
75
+ $dialog_title = __( 'Switching language?', 'woocommerce-multilingual' );
 
 
 
 
76
 
77
+ $confirmation_message = sprintf(
78
+ __(
79
+ "You've switched the language and there are items in the cart. If you keep the %s language, the cart will be emptied and you will have to add the items again to the cart.",
80
+ 'woocommerce-multilingual'
81
+ ),
82
+ $active_languages[ $this->lang_to ]['translated_name']
83
+ );
84
+ $stay_in = sprintf( __( 'Keep %s', 'woocommerce-multilingual' ), $active_languages[ $this->lang_to ]['translated_name'] );
85
+ $switch_to = sprintf( __( 'Switch back to %s', 'woocommerce-multilingual' ), $active_languages[ $this->lang_from ]['translated_name'] );
86
 
87
+ $woocommerce_wpml->cart->cart_alert( $dialog_title, $confirmation_message, $stay_in, $switch_to, $force_cart_url, $request_url, true );
88
+ }
89
+ }
90
 
91
+ }
92
 
93
+ }
inc/class-wcml-cart-sync-warnings.php CHANGED
@@ -1,6 +1,6 @@
1
  <?php
2
 
3
- class WCML_Cart_Sync_Warnings{
4
 
5
  /**
6
  * @var woocommerce_wpml
@@ -13,41 +13,41 @@ class WCML_Cart_Sync_Warnings{
13
  /**
14
  * @var array
15
  */
16
- private $extensions_list = array(
17
- 'WC_Subscriptions' => 'Woocommerce Subscriptions',
18
- 'WC_Product_Addons' => 'Woocommerce Product Addons',
19
- 'WC_Bookings' => 'Woocommerce Bookings',
20
  'WC_Accommodation_Bookings_Plugin' => 'Woocommerce Accommodation Bookings',
21
- 'WC_Product_Bundle' => 'Woocommerce Product Bundles',
22
- 'WC_Composite_Products' => 'Woocommerce Composite Products',
23
- 'WC_Dynamic_Pricing' => 'Woocommerce Dynamic Pricing',
24
- 'RP_WCDPD' => 'WooCommerce Dynamic Pricing & Discounts',
25
- );
26
 
27
- public function __construct( $woocommerce_wpml, $sitepress ){
28
  $this->woocommerce_wpml = $woocommerce_wpml;
29
- $this->sitepress = $sitepress;
30
  }
31
 
32
- public function add_hooks(){
33
 
34
- if( $this->check_if_show_notices_needed() ){
35
- add_action( 'admin_notices', array( $this, 'show_cart_notice' ) );
36
- add_action( 'admin_enqueue_scripts', array( $this, 'register_styles' ) );
37
  }
38
 
39
  }
40
 
41
- public function check_if_show_notices_needed(){
42
 
43
  $cart_sync_settings = $this->woocommerce_wpml->settings['cart_sync'];
44
 
45
- if(
46
  (
47
  $cart_sync_settings['lang_switch'] === $this->sitepress->get_wp_api()->constant( 'WCML_CART_SYNC' ) ||
48
  $cart_sync_settings['currency_switch'] === $this->sitepress->get_wp_api()->constant( 'WCML_CART_SYNC' )
49
  ) &&
50
- !$this->woocommerce_wpml->settings[ 'dismiss_cart_warning' ] &&
51
  $this->get_list_of_active_extensions()
52
  ) {
53
  return true;
@@ -57,16 +57,15 @@ class WCML_Cart_Sync_Warnings{
57
 
58
  }
59
 
60
- public function register_styles(){
61
  wp_enqueue_style( 'wcml-cart-warning', $this->sitepress->get_wp_api()->constant( 'WCML_PLUGIN_URL' ) . '/res/css/wcml-cart-warning.css' );
62
  }
63
 
64
- public function show_cart_notice(){
65
-
66
  $list_of_extensions = $this->get_list_of_active_extensions();
67
- $request_url = esc_url( $_SERVER['REQUEST_URI'] );
68
 
69
- $admin_settings_url = esc_url( admin_url('admin.php?page=wpml-wcml&tab=settings#cart') );
70
  $documentation_link = esc_url( 'https://wpml.org/documentation/related-projects/woocommerce-multilingual/clearing-cart-contents-when-language-or-currency-change/' );
71
 
72
  $reset_cart_strings[] = esc_html_x( 'Because of some elements in your site configuration, when the users switch the currency or the language on the front end, the cart content might not be synchronized correctly.', 'Reset cart option warning 1', 'woocommerce-multilingual' );
@@ -74,41 +73,42 @@ class WCML_Cart_Sync_Warnings{
74
 
75
  $reset_cart_configure_link = '<strong><a href="' . $admin_settings_url . '">' . esc_html__( 'configure WooCommerce Multilingual', 'woocommerce-multilingual' ) . '</a></strong>';
76
 
77
- $reset_cart_message = $reset_cart_strings[0];
78
  $reset_cart_message .= '</p>';
79
  $reset_cart_message .= $list_of_extensions;
80
  $reset_cart_message .= '<p>';
81
  $reset_cart_message .= $reset_cart_strings[1];
82
  $reset_cart_message .= '<strong><a href="' . $documentation_link . '" target="_blank">' . esc_html__( 'More details', 'woocommerce-multilingual' ) . '</a></strong>';
83
 
84
- $message = '<div class="message error otgs-is-dismissible">';
85
  $message .= '<p>';
86
  $message .= sprintf( $reset_cart_message, $reset_cart_configure_link );
87
  $message .= '</p>';
88
  $message .= '<a class="notice-dismiss" href="' . $request_url . '&wcml_action=dismiss_cart_warning"><span class="screen-reader-text">' . esc_html__( 'Dismiss', 'woocommerce-multilingual' ) . '</a>';
89
  $message .= '</div>';
90
 
 
91
  echo $message;
92
  }
93
 
94
- public function get_list_of_active_extensions (){
95
 
96
  $html = '';
97
 
98
- foreach( $this->extensions_list as $extension_class => $display_name ){
99
 
100
- if( class_exists( $extension_class ) ){
101
 
102
- if( empty( $html ) ){
103
  $html .= '<ul>';
104
  }
105
 
106
- $html .= '<li>'.$display_name.'</li>';
107
 
108
  }
109
  }
110
 
111
- if( !empty( $html ) ){
112
  $html .= '</ul>';
113
  }
114
 
@@ -116,4 +116,4 @@ class WCML_Cart_Sync_Warnings{
116
 
117
  }
118
 
119
- }
1
  <?php
2
 
3
+ class WCML_Cart_Sync_Warnings {
4
 
5
  /**
6
  * @var woocommerce_wpml
13
  /**
14
  * @var array
15
  */
16
+ private $extensions_list = [
17
+ 'WC_Subscriptions' => 'Woocommerce Subscriptions',
18
+ 'WC_Product_Addons' => 'Woocommerce Product Addons',
19
+ 'WC_Bookings' => 'Woocommerce Bookings',
20
  'WC_Accommodation_Bookings_Plugin' => 'Woocommerce Accommodation Bookings',
21
+ 'WC_Product_Bundle' => 'Woocommerce Product Bundles',
22
+ 'WC_Composite_Products' => 'Woocommerce Composite Products',
23
+ 'WC_Dynamic_Pricing' => 'Woocommerce Dynamic Pricing',
24
+ 'RP_WCDPD' => 'WooCommerce Dynamic Pricing & Discounts',
25
+ ];
26
 
27
+ public function __construct( $woocommerce_wpml, $sitepress ) {
28
  $this->woocommerce_wpml = $woocommerce_wpml;
29
+ $this->sitepress = $sitepress;
30
  }
31
 
32
+ public function add_hooks() {
33
 
34
+ if ( $this->check_if_show_notices_needed() ) {
35
+ add_action( 'admin_notices', [ $this, 'show_cart_notice' ] );
36
+ add_action( 'admin_enqueue_scripts', [ $this, 'register_styles' ] );
37
  }
38
 
39
  }
40
 
41
+ public function check_if_show_notices_needed() {
42
 
43
  $cart_sync_settings = $this->woocommerce_wpml->settings['cart_sync'];
44
 
45
+ if (
46
  (
47
  $cart_sync_settings['lang_switch'] === $this->sitepress->get_wp_api()->constant( 'WCML_CART_SYNC' ) ||
48
  $cart_sync_settings['currency_switch'] === $this->sitepress->get_wp_api()->constant( 'WCML_CART_SYNC' )
49
  ) &&
50
+ ! $this->woocommerce_wpml->settings['dismiss_cart_warning'] &&
51
  $this->get_list_of_active_extensions()
52
  ) {
53
  return true;
57
 
58
  }
59
 
60
+ public function register_styles() {
61
  wp_enqueue_style( 'wcml-cart-warning', $this->sitepress->get_wp_api()->constant( 'WCML_PLUGIN_URL' ) . '/res/css/wcml-cart-warning.css' );
62
  }
63
 
64
+ public function show_cart_notice() {
 
65
  $list_of_extensions = $this->get_list_of_active_extensions();
66
+ $request_url = esc_url( $_SERVER['REQUEST_URI'] );
67
 
68
+ $admin_settings_url = esc_url( admin_url( 'admin.php?page=wpml-wcml&tab=settings#cart' ) );
69
  $documentation_link = esc_url( 'https://wpml.org/documentation/related-projects/woocommerce-multilingual/clearing-cart-contents-when-language-or-currency-change/' );
70
 
71
  $reset_cart_strings[] = esc_html_x( 'Because of some elements in your site configuration, when the users switch the currency or the language on the front end, the cart content might not be synchronized correctly.', 'Reset cart option warning 1', 'woocommerce-multilingual' );
73
 
74
  $reset_cart_configure_link = '<strong><a href="' . $admin_settings_url . '">' . esc_html__( 'configure WooCommerce Multilingual', 'woocommerce-multilingual' ) . '</a></strong>';
75
 
76
+ $reset_cart_message = $reset_cart_strings[0];
77
  $reset_cart_message .= '</p>';
78
  $reset_cart_message .= $list_of_extensions;
79
  $reset_cart_message .= '<p>';
80
  $reset_cart_message .= $reset_cart_strings[1];
81
  $reset_cart_message .= '<strong><a href="' . $documentation_link . '" target="_blank">' . esc_html__( 'More details', 'woocommerce-multilingual' ) . '</a></strong>';
82
 
83
+ $message = '<div class="message error otgs-is-dismissible">';
84
  $message .= '<p>';
85
  $message .= sprintf( $reset_cart_message, $reset_cart_configure_link );
86
  $message .= '</p>';
87
  $message .= '<a class="notice-dismiss" href="' . $request_url . '&wcml_action=dismiss_cart_warning"><span class="screen-reader-text">' . esc_html__( 'Dismiss', 'woocommerce-multilingual' ) . '</a>';
88
  $message .= '</div>';
89
 
90
+ // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
91
  echo $message;
92
  }
93
 
94
+ public function get_list_of_active_extensions() {
95
 
96
  $html = '';
97
 
98
+ foreach ( $this->extensions_list as $extension_class => $display_name ) {
99
 
100
+ if ( class_exists( $extension_class ) ) {
101
 
102
+ if ( empty( $html ) ) {
103
  $html .= '<ul>';
104
  }
105
 
106
+ $html .= '<li>' . $display_name . '</li>';
107
 
108
  }
109
  }
110
 
111
+ if ( ! empty( $html ) ) {
112
  $html .= '</ul>';
113
  }
114
 
116
 
117
  }
118
 
119
+ }
inc/class-wcml-cart.php CHANGED
@@ -12,8 +12,8 @@ class WCML_Cart {
12
  * WCML_Cart constructor.
13
  *
14
  * @param woocommerce_wpml $woocommerce_wpml
15
- * @param SitePress $sitepress
16
- * @param WooCommerce $woocommerce
17
  */
18
  public function __construct( woocommerce_wpml $woocommerce_wpml, SitePress $sitepress, WooCommerce $woocommerce ) {
19
  $this->woocommerce_wpml = $woocommerce_wpml;
@@ -27,43 +27,61 @@ class WCML_Cart {
27
 
28
  $this->enqueue_dialog_ui();
29
 
30
- add_action( 'wcml_removed_cart_items', array( $this, 'wcml_removed_cart_items_widget' ) );
31
- add_action( 'wp_ajax_wcml_cart_clear_removed_items', array( $this, 'wcml_cart_clear_removed_items' ) );
32
- add_action( 'wp_ajax_nopriv_wcml_cart_clear_removed_items', array(
33
- $this,
34
- 'wcml_cart_clear_removed_items'
35
- ) );
36
-
37
- if( $this->is_clean_cart_enabled_for_currency_switch() ){
38
- add_filter( 'wcml_switch_currency_exception', array( $this, 'cart_switching_currency' ), 10, 4 );
39
- add_action( 'wcml_before_switch_currency', array(
40
  $this,
41
- 'switching_currency_empty_cart_if_needed'
42
- ), 10, 2 );
43
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
44
  } else {
45
- //cart widget
46
- add_action( 'wp_ajax_woocommerce_get_refreshed_fragments', array( $this, 'wcml_refresh_fragments' ), 0 );
47
- add_action( 'wp_ajax_woocommerce_add_to_cart', array( $this, 'wcml_refresh_fragments' ), 0 );
48
- add_action( 'wp_ajax_nopriv_woocommerce_get_refreshed_fragments', array(
49
- $this,
50
- 'wcml_refresh_fragments'
51
- ), 0 );
52
- add_action( 'wp_ajax_nopriv_woocommerce_add_to_cart', array( $this, 'wcml_refresh_fragments' ), 0 );
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' ) );
63
- add_filter( 'woocommerce_add_to_cart_sold_individually_found_in_cart', array(
64
- $this,
65
- 'add_to_cart_sold_individually_exception'
66
- ), 10, 4 );
 
 
 
 
 
 
 
 
 
 
67
 
68
  $this->localize_flat_rates_shipping_classes();
69
  }
@@ -112,7 +130,7 @@ class WCML_Cart {
112
 
113
  }
114
 
115
- public function wcml_removed_cart_items_widget( $args = array() ) {
116
 
117
  if ( ! empty( $this->woocommerce->session ) ) {
118
  $removed_cart_items = new WCML_Removed_Cart_Items_UI( $args, $this->woocommerce_wpml, $this->sitepress, $this->woocommerce );
@@ -137,7 +155,7 @@ class WCML_Cart {
137
  public function empty_cart_if_needed( $switching_type ) {
138
 
139
  if ( $this->woocommerce_wpml->settings['cart_sync'][ $switching_type ] == $this->sitepress->get_wp_api()->constant( 'WCML_CART_CLEAR' ) ) {
140
- $removed_products = $this->woocommerce->session->get( 'wcml_removed_items' ) ? maybe_unserialize( $this->woocommerce->session->get( 'wcml_removed_items' ) ) : array();
141
 
142
  foreach ( WC()->cart->get_cart_for_session() as $item_key => $cart ) {
143
  if ( ! in_array( $cart['product_id'], $removed_products ) ) {
@@ -165,7 +183,7 @@ class WCML_Cart {
165
 
166
  public function cart_switching_currency( $exc, $current_currency, $new_currency, $return = false ) {
167
 
168
- $cart_for_session = !is_null( WC()->cart ) ? array_filter( WC()->cart->get_cart_contents() ) : false;
169
 
170
  if ( $this->woocommerce_wpml->settings['cart_sync']['currency_switch'] == WCML_CART_SYNC || empty( $cart_for_session ) ) {
171
  return $exc;
@@ -182,7 +200,7 @@ class WCML_Cart {
182
  ob_end_clean();
183
 
184
  if ( $return ) {
185
- return array( 'prevent_switching' => $html );
186
  } else {
187
  wp_send_json_success( [ 'prevent_switching' => $html ] );
188
  }
@@ -190,17 +208,17 @@ class WCML_Cart {
190
  return true;
191
  }
192
 
193
- public function cart_alert( $dialog_title, $confirmation_message, $switch_to, $stay_in, $switch_to_value, $stay_in_value = false, $language_switch = false ){
194
- if( apply_filters( 'wcml_hide_cart_alert_dialog', false ) ){
195
- $switching_type = $language_switch ? 'lang_switch' : 'currency_switch';
196
- $this->empty_cart_if_needed( $switching_type );
197
- return false;
198
- }?>
199
- <div id="wcml-cart-dialog-confirm" title="<?php echo esc_attr( $dialog_title ) ?>">
200
- <p><?php echo esc_html( $confirmation_message ); ?></p>
201
- </div>
202
 
203
- <script type="text/javascript">
204
  jQuery(document).ready(function () {
205
  var dialogBox = jQuery("#wcml-cart-dialog-confirm");
206
  dialogBox.dialog({
@@ -225,26 +243,26 @@ class WCML_Cart {
225
  buttons: {
226
  "<?php echo $switch_to; ?>": function () {
227
  jQuery(this).dialog("close");
228
- <?php if( $language_switch ): ?>
229
  window.location = '<?php echo esc_url( $switch_to_value, null, 'redirect' ); ?>';
230
- <?php else: ?>
231
  jQuery('.wcml_currency_switcher').parent().find('img').remove();
232
  wcml_load_currency("<?php echo esc_js( $switch_to_value ); ?>", true);
233
- <?php endif; ?>
234
 
235
  },
236
  "<?php echo $stay_in; ?>": function () {
237
  jQuery(this).dialog("close");
238
- <?php if( $language_switch ): ?>
239
  window.location = '<?php echo esc_url( $stay_in_value, null, 'redirect' ); ?>';
240
- <?php else: ?>
241
- jQuery('.wcml_currency_switcher').each( function(){
242
- jQuery(this).parent().find('img').remove();
243
- jQuery(this).removeAttr('disabled');
244
- jQuery(this).val('<?php echo esc_js( $stay_in_value ); ?>');
245
- });
246
- jQuery(document).on('click', '.wcml_currency_switcher a', wcml_switch_currency_handler );
247
- <?php endif; ?>
248
  }
249
  }
250
  });
@@ -267,7 +285,7 @@ class WCML_Cart {
267
 
268
 
269
  });
270
- </script>
271
  <?php
272
  }
273
 
@@ -281,13 +299,12 @@ class WCML_Cart {
281
  public function woocommerce_calculate_totals( $cart, $currency = false ) {
282
 
283
  $current_language = $this->sitepress->get_current_language();
284
- $new_cart_data = array();
285
 
286
  foreach ( $cart->cart_contents as $key => $cart_item ) {
287
  $tr_product_id = apply_filters( 'translate_object_id', $cart_item['product_id'], 'product', false, $current_language );
288
- //translate custom attr labels in cart object
289
-
290
- //translate custom attr value in cart object
291
  if ( isset( $cart_item['variation'] ) && is_array( $cart_item['variation'] ) ) {
292
  foreach ( $cart_item['variation'] as $attr_key => $attribute ) {
293
  $cart->cart_contents[ $key ]['variation'][ $attr_key ] = $this->get_cart_attribute_translation(
@@ -305,10 +322,10 @@ class WCML_Cart {
305
  $cart->cart_contents[ $key ]['data']->price = get_post_meta( $cart_item['product_id'], '_price', 1 );
306
  }
307
 
308
- $display_as_translated = apply_filters( 'wpml_is_display_as_translated_post_type', false, 'product' );
309
- if ( $cart_item['product_id'] == $tr_product_id || $display_as_translated ) {
310
- $new_cart_data[ $key ] = apply_filters( 'wcml_cart_contents_not_changed', $cart->cart_contents[ $key ], $key, $current_language );
311
- $new_cart_data[ $key ][ 'data_hash' ] = $this->get_data_cart_hash( $cart_item );
312
  continue;
313
  }
314
 
@@ -330,10 +347,10 @@ class WCML_Cart {
330
 
331
  if ( ! is_null( $tr_product_id ) ) {
332
 
333
- $new_key = $this->wcml_generate_cart_key( $cart->cart_contents, $key );
334
- $cart->cart_contents = apply_filters( 'wcml_update_cart_contents_lang_switch', $cart->cart_contents, $key, $new_key, $current_language );
335
- $new_cart_data[ $new_key ] = $cart->cart_contents[ $key ];
336
- $new_cart_data[ $new_key ][ 'data_hash' ] = $this->get_data_cart_hash( $new_cart_data[ $new_key ] );
337
 
338
  $new_cart_data = apply_filters( 'wcml_cart_contents', $new_cart_data, $cart->cart_contents, $key, $new_key );
339
  }
@@ -356,7 +373,7 @@ class WCML_Cart {
356
 
357
  if ( function_exists( 'wc_get_cart_item_data_hash' ) ) {
358
  $hash_product_object = wc_get_product( $cart_item['variation_id'] ? $cart_item['variation_id'] : $cart_item['product_id'] );
359
- if( $hash_product_object ){
360
  $data_hash = wc_get_cart_item_data_hash( $hash_product_object );
361
  }
362
  }
@@ -365,32 +382,31 @@ class WCML_Cart {
365
  }
366
 
367
  /**
368
- * @param array $item_data
369
  * @param WC_Product $product Product object
370
  *
371
  * @return array
372
  */
373
  public function validate_cart_item_data( array $item_data, $product ) {
374
 
375
- if( $item_data['attributes'] ){
376
 
377
- $product_id = $product->get_parent_id();
378
- $product_language = $this->sitepress->get_language_for_element( $product_id, 'post_'.$item_data['type']);
379
- $tr_product_id = apply_filters( 'translate_object_id', $product_id, 'product', false, $product_language );
380
 
381
- foreach ( $item_data['attributes'] as $key => $name ){
382
- $item_data['attributes'][$key] = $this->get_cart_attribute_translation( $key, $name, $product->get_id(), $product_language, $product_id, $tr_product_id );
383
- }
384
-
385
- }
386
 
387
  return $item_data;
388
  }
389
 
390
  public function wcml_check_on_duplicate_products_in_cart( $cart_contents ) {
391
 
392
- $exists_products = array();
393
- remove_action( 'woocommerce_before_calculate_totals', array( $this, 'woocommerce_calculate_totals' ), 100 );
394
 
395
  foreach ( $cart_contents as $key => $cart_content ) {
396
  $cart_contents = apply_filters( 'wcml_check_on_duplicated_products_in_cart', $cart_contents, $key, $cart_content );
@@ -410,7 +426,7 @@ class WCML_Cart {
410
  }
411
  }
412
 
413
- add_action( 'woocommerce_before_calculate_totals', array( $this, 'woocommerce_calculate_totals' ), 100 );
414
 
415
  return $cart_contents;
416
  }
@@ -430,7 +446,7 @@ class WCML_Cart {
430
  $term = $this->woocommerce_wpml->terms->wcml_get_term_by_id( $trnsl_term_id, $taxonomy );
431
  $attr_translation = $term->slug;
432
  }
433
- } elseif( $variation_id ) {
434
 
435
  $trnsl_attr = get_post_meta( $variation_id, $attr_key, true );
436
 
@@ -472,7 +488,7 @@ class WCML_Cart {
472
  );
473
  }
474
 
475
- //get cart_item_data from existing cart array ( from session )
476
  public function get_cart_item_data_from_cart( $cart_contents ) {
477
  unset( $cart_contents['product_id'] );
478
  unset( $cart_contents['variation_id'] );
@@ -489,25 +505,6 @@ class WCML_Cart {
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'] ) ) {
495
- //special case: check if attachment loading
496
- $attachments = array( 'png', 'jpg', 'jpeg', 'gif', 'js', 'css' );
497
-
498
- foreach ( $attachments as $attachment ) {
499
- $match = preg_match( '/\.' . $attachment . '$/', $_SERVER['REQUEST_URI'] );
500
- if ( ! empty( $match ) ) {
501
- return false;
502
- }
503
- }
504
- }
505
-
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
512
  public function wcml_refresh_cart_total() {
513
  WC()->cart->calculate_totals();
@@ -521,10 +518,9 @@ class WCML_Cart {
521
  $shipping_methods = $this->woocommerce->shipping->get_shipping_methods();
522
  foreach ( $shipping_methods as $method ) {
523
  if ( isset( $method->flat_rate_option ) ) {
524
- add_filter( 'option_' . $method->flat_rate_option, array( $this, 'translate_shipping_class' ) );
525
  }
526
  }
527
-
528
  }
529
  }
530
 
@@ -552,7 +548,7 @@ class WCML_Cart {
552
  public function filter_paypal_args( $args ) {
553
  $args['lc'] = $this->sitepress->get_current_language();
554
 
555
- //filter URL when default permalinks uses
556
  $wpml_settings = $this->sitepress->get_settings();
557
  if ( $wpml_settings['language_negotiation_type'] == 3 ) {
558
  $args['notify_url'] = str_replace( '%2F&', '&', $args['notify_url'] );
@@ -582,15 +578,15 @@ class WCML_Cart {
582
 
583
  $current_product_trid = $this->sitepress->get_element_trid( $post_id, 'post_' . get_post_type( $post_id ) );
584
 
585
- if ( !empty( $cart_item['variation_id'] ) ) {
586
  $cart_element_trid = $this->sitepress->get_element_trid( $cart_item['variation_id'], 'post_product_variation' );
587
  } else {
588
  $cart_element_trid = $this->sitepress->get_element_trid( $cart_item['product_id'], 'post_product' );
589
  }
590
 
591
  if ( apply_filters( 'wcml_add_to_cart_sold_individually', true, $cart_item_data, $post_id, $cart_item['quantity'] ) &&
592
- $current_product_trid == $cart_element_trid &&
593
- $cart_item['quantity'] > 0
594
  ) {
595
  return true;
596
  } else {
@@ -600,7 +596,7 @@ class WCML_Cart {
600
 
601
  /**
602
  * @param string $permalink
603
- * @param array $cart_item
604
  *
605
  * @return string
606
  */
@@ -618,16 +614,16 @@ class WCML_Cart {
618
  *
619
  * @return float
620
  */
621
- public function get_cart_total_in_currency( $currency ){
622
 
623
  $client_currency = $this->woocommerce_wpml->multi_currency->get_client_currency();
624
- $cart_total = 0;
625
- $cart_items = WC()->cart->get_cart_contents();
626
 
627
- //items total
628
  foreach ( $cart_items as $item ) {
629
  $item_product_id = $item['variation_id'] ?: $item['product_id'];
630
- $cart_total += $this->woocommerce_wpml->multi_currency->prices->get_product_price_in_currency( $item_product_id, $currency ) * $item['quantity'];
631
  }
632
 
633
  $cart_total += $this->get_cart_shipping_in_currency( $currency );
@@ -641,7 +637,7 @@ class WCML_Cart {
641
  * @param string $currency
642
  *
643
  * @return string
644
- */
645
  public function get_formatted_cart_total_in_currency( $currency ) {
646
  return $this->woocommerce_wpml->multi_currency->prices->format_price_in_currency( $this->get_cart_total_in_currency( $currency ), $currency );
647
  }
@@ -670,4 +666,13 @@ class WCML_Cart {
670
  return $product;
671
  }
672
 
673
- }
 
 
 
 
 
 
 
 
 
12
  * WCML_Cart constructor.
13
  *
14
  * @param woocommerce_wpml $woocommerce_wpml
15
+ * @param SitePress $sitepress
16
+ * @param WooCommerce $woocommerce
17
  */
18
  public function __construct( woocommerce_wpml $woocommerce_wpml, SitePress $sitepress, WooCommerce $woocommerce ) {
19
  $this->woocommerce_wpml = $woocommerce_wpml;
27
 
28
  $this->enqueue_dialog_ui();
29
 
30
+ add_action( 'wcml_removed_cart_items', [ $this, 'wcml_removed_cart_items_widget' ] );
31
+ add_action( 'wp_ajax_wcml_cart_clear_removed_items', [ $this, 'wcml_cart_clear_removed_items' ] );
32
+ add_action(
33
+ 'wp_ajax_nopriv_wcml_cart_clear_removed_items',
34
+ [
 
 
 
 
 
35
  $this,
36
+ 'wcml_cart_clear_removed_items',
37
+ ]
38
+ );
39
+
40
+ if ( $this->is_clean_cart_enabled_for_currency_switch() ) {
41
+ add_filter( 'wcml_switch_currency_exception', [ $this, 'cart_switching_currency' ], 10, 4 );
42
+ add_action(
43
+ 'wcml_before_switch_currency',
44
+ [
45
+ $this,
46
+ 'switching_currency_empty_cart_if_needed',
47
+ ],
48
+ 10,
49
+ 2
50
+ );
51
+ }
52
  } else {
53
+ // cart widget
54
+ add_action( 'wp_ajax_woocommerce_get_refreshed_fragments', [ $this, 'wcml_refresh_fragments' ], 0 );
55
+ add_action( 'wp_ajax_woocommerce_add_to_cart', [ $this, 'wcml_refresh_fragments' ], 0 );
56
+ add_action(
57
+ 'wp_ajax_nopriv_woocommerce_get_refreshed_fragments',
58
+ [
59
+ $this,
60
+ 'wcml_refresh_fragments',
61
+ ],
62
+ 0
63
+ );
64
+ add_action( 'wp_ajax_nopriv_woocommerce_add_to_cart', [ $this, 'wcml_refresh_fragments' ], 0 );
65
+
66
+ // cart
67
+ add_action( 'woocommerce_before_calculate_totals', [ $this, 'woocommerce_calculate_totals' ], 100 );
68
+ add_action( 'woocommerce_before_checkout_process', [ $this, 'wcml_refresh_cart_total' ] );
69
+ add_filter( 'woocommerce_cart_item_data_to_validate', [ $this, 'validate_cart_item_data' ], 10, 2 );
70
+ add_filter( 'woocommerce_cart_item_product', [ $this, 'adjust_cart_item_product_name' ] );
71
+
72
+ add_filter( 'woocommerce_cart_item_permalink', [ $this, 'cart_item_permalink' ], 10, 2 );
73
+ add_filter( 'woocommerce_paypal_args', [ $this, 'filter_paypal_args' ] );
74
+ add_filter(
75
+ 'woocommerce_add_to_cart_sold_individually_found_in_cart',
76
+ [
77
+ $this,
78
+ 'add_to_cart_sold_individually_exception',
79
+ ],
80
+ 10,
81
+ 4
82
+ );
83
+
84
+ add_filter( 'woocommerce_cart_hash_key', [ $this, 'add_language_to_cart_hash_key' ] );
85
 
86
  $this->localize_flat_rates_shipping_classes();
87
  }
130
 
131
  }
132
 
133
+ public function wcml_removed_cart_items_widget( $args = [] ) {
134
 
135
  if ( ! empty( $this->woocommerce->session ) ) {
136
  $removed_cart_items = new WCML_Removed_Cart_Items_UI( $args, $this->woocommerce_wpml, $this->sitepress, $this->woocommerce );
155
  public function empty_cart_if_needed( $switching_type ) {
156
 
157
  if ( $this->woocommerce_wpml->settings['cart_sync'][ $switching_type ] == $this->sitepress->get_wp_api()->constant( 'WCML_CART_CLEAR' ) ) {
158
+ $removed_products = $this->woocommerce->session->get( 'wcml_removed_items' ) ? maybe_unserialize( $this->woocommerce->session->get( 'wcml_removed_items' ) ) : [];
159
 
160
  foreach ( WC()->cart->get_cart_for_session() as $item_key => $cart ) {
161
  if ( ! in_array( $cart['product_id'], $removed_products ) ) {
183
 
184
  public function cart_switching_currency( $exc, $current_currency, $new_currency, $return = false ) {
185
 
186
+ $cart_for_session = ! is_null( WC()->cart ) ? array_filter( WC()->cart->get_cart_contents() ) : false;
187
 
188
  if ( $this->woocommerce_wpml->settings['cart_sync']['currency_switch'] == WCML_CART_SYNC || empty( $cart_for_session ) ) {
189
  return $exc;
200
  ob_end_clean();
201
 
202
  if ( $return ) {
203
+ return [ 'prevent_switching' => $html ];
204
  } else {
205
  wp_send_json_success( [ 'prevent_switching' => $html ] );
206
  }
208
  return true;
209
  }
210
 
211
+ public function cart_alert( $dialog_title, $confirmation_message, $switch_to, $stay_in, $switch_to_value, $stay_in_value = false, $language_switch = false ) {
212
+ if ( apply_filters( 'wcml_hide_cart_alert_dialog', false ) ) {
213
+ $switching_type = $language_switch ? 'lang_switch' : 'currency_switch';
214
+ $this->empty_cart_if_needed( $switching_type );
215
+ return false;
216
+ }?>
217
+ <div id="wcml-cart-dialog-confirm" title="<?php echo esc_attr( $dialog_title ); ?>">
218
+ <p><?php echo esc_html( $confirmation_message ); ?></p>
219
+ </div>
220
 
221
+ <script type="text/javascript">
222
  jQuery(document).ready(function () {
223
  var dialogBox = jQuery("#wcml-cart-dialog-confirm");
224
  dialogBox.dialog({
243
  buttons: {
244
  "<?php echo $switch_to; ?>": function () {
245
  jQuery(this).dialog("close");
246
+ <?php if ( $language_switch ) : ?>
247
  window.location = '<?php echo esc_url( $switch_to_value, null, 'redirect' ); ?>';
248
+ <?php else : ?>
249
  jQuery('.wcml_currency_switcher').parent().find('img').remove();
250
  wcml_load_currency("<?php echo esc_js( $switch_to_value ); ?>", true);
251
+ <?php endif; ?>
252
 
253
  },
254
  "<?php echo $stay_in; ?>": function () {
255
  jQuery(this).dialog("close");
256
+ <?php if ( $language_switch ) : ?>
257
  window.location = '<?php echo esc_url( $stay_in_value, null, 'redirect' ); ?>';
258
+ <?php else : ?>
259
+ jQuery('.wcml_currency_switcher').each( function(){
260
+ jQuery(this).parent().find('img').remove();
261
+ jQuery(this).removeAttr('disabled');
262
+ jQuery(this).val('<?php echo esc_js( $stay_in_value ); ?>');
263
+ });
264
+ jQuery(document).on('click', '.wcml_currency_switcher a', wcml_switch_currency_handler );
265
+ <?php endif; ?>
266
  }
267
  }
268
  });
285
 
286
 
287
  });
288
+ </script>
289
  <?php
290
  }
291
 
299
  public function woocommerce_calculate_totals( $cart, $currency = false ) {
300
 
301
  $current_language = $this->sitepress->get_current_language();
302
+ $new_cart_data = [];
303
 
304
  foreach ( $cart->cart_contents as $key => $cart_item ) {
305
  $tr_product_id = apply_filters( 'translate_object_id', $cart_item['product_id'], 'product', false, $current_language );
306
+ // translate custom attr labels in cart object
307
+ // translate custom attr value in cart object
 
308
  if ( isset( $cart_item['variation'] ) && is_array( $cart_item['variation'] ) ) {
309
  foreach ( $cart_item['variation'] as $attr_key => $attribute ) {
310
  $cart->cart_contents[ $key ]['variation'][ $attr_key ] = $this->get_cart_attribute_translation(
322
  $cart->cart_contents[ $key ]['data']->price = get_post_meta( $cart_item['product_id'], '_price', 1 );
323
  }
324
 
325
+ $display_as_translated = apply_filters( 'wpml_is_display_as_translated_post_type', false, 'product' );
326
+ if ( $cart_item['product_id'] == $tr_product_id || ( $display_as_translated && !$tr_product_id ) ) {
327
+ $new_cart_data[ $key ] = apply_filters( 'wcml_cart_contents_not_changed', $cart->cart_contents[ $key ], $key, $current_language );
328
+ $new_cart_data[ $key ]['data_hash'] = $this->get_data_cart_hash( $cart_item );
329
  continue;
330
  }
331
 
347
 
348
  if ( ! is_null( $tr_product_id ) ) {
349
 
350
+ $new_key = $this->wcml_generate_cart_key( $cart->cart_contents, $key );
351
+ $cart->cart_contents = apply_filters( 'wcml_update_cart_contents_lang_switch', $cart->cart_contents, $key, $new_key, $current_language );
352
+ $new_cart_data[ $new_key ] = $cart->cart_contents[ $key ];
353
+ $new_cart_data[ $new_key ]['data_hash'] = $this->get_data_cart_hash( $new_cart_data[ $new_key ] );
354
 
355
  $new_cart_data = apply_filters( 'wcml_cart_contents', $new_cart_data, $cart->cart_contents, $key, $new_key );
356
  }
373
 
374
  if ( function_exists( 'wc_get_cart_item_data_hash' ) ) {
375
  $hash_product_object = wc_get_product( $cart_item['variation_id'] ? $cart_item['variation_id'] : $cart_item['product_id'] );
376
+ if ( $hash_product_object ) {
377
  $data_hash = wc_get_cart_item_data_hash( $hash_product_object );
378
  }
379
  }
382
  }
383
 
384
  /**
385
+ * @param array $item_data
386
  * @param WC_Product $product Product object
387
  *
388
  * @return array
389
  */
390
  public function validate_cart_item_data( array $item_data, $product ) {
391
 
392
+ if ( $item_data['attributes'] ) {
393
 
394
+ $product_id = $product->get_parent_id();
395
+ $product_language = $this->sitepress->get_language_for_element( $product_id, 'post_' . $item_data['type'] );
396
+ $tr_product_id = apply_filters( 'translate_object_id', $product_id, 'product', false, $product_language );
397
 
398
+ foreach ( $item_data['attributes'] as $key => $name ) {
399
+ $item_data['attributes'][ $key ] = $this->get_cart_attribute_translation( $key, $name, $product->get_id(), $product_language, $product_id, $tr_product_id );
400
+ }
401
+ }
 
402
 
403
  return $item_data;
404
  }
405
 
406
  public function wcml_check_on_duplicate_products_in_cart( $cart_contents ) {
407
 
408
+ $exists_products = [];
409
+ remove_action( 'woocommerce_before_calculate_totals', [ $this, 'woocommerce_calculate_totals' ], 100 );
410
 
411
  foreach ( $cart_contents as $key => $cart_content ) {
412
  $cart_contents = apply_filters( 'wcml_check_on_duplicated_products_in_cart', $cart_contents, $key, $cart_content );
426
  }
427
  }
428
 
429
+ add_action( 'woocommerce_before_calculate_totals', [ $this, 'woocommerce_calculate_totals' ], 100 );
430
 
431
  return $cart_contents;
432
  }
446
  $term = $this->woocommerce_wpml->terms->wcml_get_term_by_id( $trnsl_term_id, $taxonomy );
447
  $attr_translation = $term->slug;
448
  }
449
+ } elseif ( $variation_id ) {
450
 
451
  $trnsl_attr = get_post_meta( $variation_id, $attr_key, true );
452
 
488
  );
489
  }
490
 
491
+ // get cart_item_data from existing cart array ( from session )
492
  public function get_cart_item_data_from_cart( $cart_contents ) {
493
  unset( $cart_contents['product_id'] );
494
  unset( $cart_contents['variation_id'] );
505
  return apply_filters( 'wcml_filter_cart_item_data', $cart_contents );
506
  }
507
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
508
  // refresh cart total to return correct price from WC object
509
  public function wcml_refresh_cart_total() {
510
  WC()->cart->calculate_totals();
518
  $shipping_methods = $this->woocommerce->shipping->get_shipping_methods();
519
  foreach ( $shipping_methods as $method ) {
520
  if ( isset( $method->flat_rate_option ) ) {
521
+ add_filter( 'option_' . $method->flat_rate_option, [ $this, 'translate_shipping_class' ] );
522
  }
523
  }
 
524
  }
525
  }
526
 
548
  public function filter_paypal_args( $args ) {
549
  $args['lc'] = $this->sitepress->get_current_language();
550
 
551
+ // filter URL when default permalinks uses
552
  $wpml_settings = $this->sitepress->get_settings();
553
  if ( $wpml_settings['language_negotiation_type'] == 3 ) {
554
  $args['notify_url'] = str_replace( '%2F&', '&', $args['notify_url'] );
578
 
579
  $current_product_trid = $this->sitepress->get_element_trid( $post_id, 'post_' . get_post_type( $post_id ) );
580
 
581
+ if ( ! empty( $cart_item['variation_id'] ) ) {
582
  $cart_element_trid = $this->sitepress->get_element_trid( $cart_item['variation_id'], 'post_product_variation' );
583
  } else {
584
  $cart_element_trid = $this->sitepress->get_element_trid( $cart_item['product_id'], 'post_product' );
585
  }
586
 
587
  if ( apply_filters( 'wcml_add_to_cart_sold_individually', true, $cart_item_data, $post_id, $cart_item['quantity'] ) &&
588
+ $current_product_trid == $cart_element_trid &&
589
+ $cart_item['quantity'] > 0
590
  ) {
591
  return true;
592
  } else {
596
 
597
  /**
598
  * @param string $permalink
599
+ * @param array $cart_item
600
  *
601
  * @return string
602
  */
614
  *
615
  * @return float
616
  */
617
+ public function get_cart_total_in_currency( $currency ) {
618
 
619
  $client_currency = $this->woocommerce_wpml->multi_currency->get_client_currency();
620
+ $cart_total = 0;
621
+ $cart_items = WC()->cart->get_cart_contents();
622
 
623
+ // items total
624
  foreach ( $cart_items as $item ) {
625
  $item_product_id = $item['variation_id'] ?: $item['product_id'];
626
+ $cart_total += $this->woocommerce_wpml->multi_currency->prices->get_product_price_in_currency( $item_product_id, $currency ) * $item['quantity'];
627
  }
628
 
629
  $cart_total += $this->get_cart_shipping_in_currency( $currency );
637
  * @param string $currency
638
  *
639
  * @return string
640
+ */
641
  public function get_formatted_cart_total_in_currency( $currency ) {
642
  return $this->woocommerce_wpml->multi_currency->prices->format_price_in_currency( $this->get_cart_total_in_currency( $currency ), $currency );
643
  }
666
  return $product;
667
  }
668
 
669
+ /**
670
+ * @param string $cart_hash_key
671
+ *
672
+ * @return string
673
+ */
674
+ public function add_language_to_cart_hash_key( $cart_hash_key ) {
675
+ return $cart_hash_key . '-' . $this->sitepress->get_current_language();
676
+ }
677
+
678
+ }
inc/class-wcml-comments.php CHANGED
@@ -3,8 +3,8 @@
3
  class WCML_Comments {
4
 
5
  const WCML_AVERAGE_RATING_KEY = '_wcml_average_rating';
6
- const WCML_REVIEW_COUNT_KEY = '_wcml_review_count';
7
- const WC_REVIEW_COUNT_KEY = '_wc_review_count';
8
 
9
  /** @var woocommerce_wpml */
10
  private $woocommerce_wpml;
@@ -12,33 +12,42 @@ class WCML_Comments {
12
  private $sitepress;
13
  /** @var WPML_Post_Translation */
14
  private $post_translations;
 
 
15
 
16
  /**
17
  * WCML_Comments constructor.
18
  *
19
- * @param woocommerce_wpml $woocommerce_wpml
20
- * @param SitePress $sitepress
21
  * @param WPML_Post_Translation $post_translations
 
22
  */
23
- public function __construct( woocommerce_wpml $woocommerce_wpml, SitePress $sitepress, WPML_Post_Translation $post_translations ) {
24
  $this->woocommerce_wpml = $woocommerce_wpml;
25
  $this->sitepress = $sitepress;
26
  $this->post_translations = $post_translations;
 
27
  }
28
 
29
  public function add_hooks() {
30
 
31
- add_action( 'comment_post', array( $this, 'add_comment_rating' ) );
32
- add_action( 'woocommerce_review_before_comment_meta', array( $this, 'add_comment_flag' ), 9 );
33
 
34
- add_filter( 'get_post_metadata', array( $this, 'filter_average_rating' ), 10, 4 );
35
- add_filter( 'comments_clauses', array( $this, 'comments_clauses' ), 10, 2 );
36
- add_action( 'comment_form_before', array( $this, 'comments_link' ) );
37
 
38
- add_filter( 'wpml_is_comment_query_filtered', array( $this, 'is_comment_query_filtered' ), 10, 2 );
39
- add_action( 'trashed_comment', array( $this, 'recalculate_average_rating_on_comment_hook' ), 10, 2 );
40
- add_action( 'deleted_comment', array( $this, 'recalculate_average_rating_on_comment_hook' ), 10, 2 );
41
- add_action( 'untrashed_comment', array( $this, 'recalculate_average_rating_on_comment_hook' ), 10, 2 );
 
 
 
 
 
42
  }
43
 
44
  /**
@@ -64,7 +73,7 @@ class WCML_Comments {
64
  *
65
  * @param int $product_id
66
  */
67
- public function recalculate_comment_rating( $product_id ){
68
 
69
  $translations = $this->post_translations->get_element_translations( $product_id );
70
  $average_ratings_sum = 0;
@@ -72,21 +81,21 @@ class WCML_Comments {
72
  $reviews_count = 0;
73
 
74
  foreach ( $translations as $translation ) {
75
- $product = wc_get_product( $translation );
76
 
77
  $ratings = WC_Comments::get_rating_counts_for_product( $product );
78
  $review_count = WC_Comments::get_review_count_for_product( $product );
79
 
80
  if ( is_array( $ratings ) ) {
81
  foreach ( $ratings as $rating => $count ) {
82
- $average_ratings_sum += $rating * $count;
83
  $average_ratings_count += $count;
84
  }
85
  }
86
 
87
- if( $review_count ){
88
  $reviews_count += $review_count;
89
- }else{
90
  update_post_meta( $translation, self::WCML_AVERAGE_RATING_KEY, null );
91
  update_post_meta( $translation, self::WCML_REVIEW_COUNT_KEY, null );
92
  }
@@ -117,9 +126,9 @@ class WCML_Comments {
117
 
118
  $filtered_value = $value;
119
 
120
- if ( in_array( $meta_key, array( '_wc_average_rating', self::WC_REVIEW_COUNT_KEY ) ) && 'product' === get_post_type( $object_id ) ) {
121
 
122
- switch ( $meta_key ){
123
  case '_wc_average_rating':
124
  $filtered_value = get_post_meta( $object_id, self::WCML_AVERAGE_RATING_KEY, $single );
125
  break;
@@ -131,13 +140,13 @@ class WCML_Comments {
131
  }
132
  }
133
 
134
- return !empty( $filtered_value ) ? $filtered_value : $value;
135
  }
136
 
137
  /**
138
  * Filters comment queries to display in all languages if needed
139
  *
140
- * @param string[] $clauses
141
  * @param WP_Comment_Query $obj
142
  *
143
  * @return string[]
@@ -146,7 +155,7 @@ class WCML_Comments {
146
 
147
  if ( $this->is_reviews_in_all_languages( $obj->query_vars['post_id'] ) ) {
148
 
149
- $ids = $this->get_translations_ids_list( $obj->query_vars['post_id'] );
150
 
151
  $clauses['where'] = str_replace( 'comment_post_ID = ' . $obj->query_vars['post_id'], 'comment_post_ID IN (' . $ids . ')', $clauses['where'] );
152
  }
@@ -161,7 +170,7 @@ class WCML_Comments {
161
  *
162
  * @return string list of ids
163
  */
164
- private function get_translations_ids_list( $product_id ){
165
 
166
  $translations = $this->post_translations->get_element_translations( $product_id );
167
 
@@ -172,29 +181,29 @@ class WCML_Comments {
172
  /**
173
  * Display link to show rating in all/current language
174
  */
175
- public function comments_link( ) {
176
 
177
- if( is_product() ){
178
- $current_url = ( is_ssl() ? 'https://' : 'http://' ) . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
179
  $current_language = $this->sitepress->get_current_language();
180
 
181
  if ( ! isset( $_GET['clang'] ) || $current_language === $_GET['clang'] ) {
182
- $comments_link = add_query_arg( array( 'clang' => 'all' ), $current_url );
183
- $all_languages_reviews_count = $this->get_reviews_count( 'all' );
184
  $current_language_reviews_count = $this->get_reviews_count();
185
 
186
- if( $all_languages_reviews_count > $current_language_reviews_count ){
187
- $comments_link_text = sprintf( __( 'Show reviews in all languages (%s)', 'woocommerce-multilingual'), $all_languages_reviews_count);
188
  }
189
  } elseif ( 'all' === $_GET['clang'] ) {
190
 
191
  $current_language_reviews_count = $this->get_reviews_count();
192
- $comments_link = add_query_arg( array( 'clang' => $current_language ), $current_url );
193
- $language_details = $this->sitepress->get_language_details( $current_language );
194
- $comments_link_text = sprintf( __( 'Show only reviews in %s (%s)', 'woocommerce-multilingual'), $language_details['display_name'], $current_language_reviews_count );
195
  }
196
 
197
- if( isset( $comments_link_text ) && $comments_link_text ){
198
  echo '<p><a id="lang-comments-link" href="' . $comments_link . '">' . $comments_link_text . '</a></p>';
199
  }
200
  }
@@ -204,7 +213,7 @@ class WCML_Comments {
204
  * Checks if comments needs filtering by language.
205
  *
206
  * @param bool $filtered
207
- * @param int $post_id
208
  * @return bool
209
  */
210
  public function is_comment_query_filtered( $filtered, $post_id ) {
@@ -226,7 +235,7 @@ class WCML_Comments {
226
  if ( $this->is_reviews_in_all_languages( $comment->comment_post_ID ) ) {
227
  $comment_language = $this->post_translations->get_element_lang_code( $comment->comment_post_ID );
228
 
229
- $html = '<div style="float: left; padding-right: 5px;">';
230
  $html .= '<img src="' . $this->sitepress->get_flag_url( $comment_language ) . '" width=18" height="12">';
231
  $html .= '</div>';
232
 
@@ -253,36 +262,67 @@ class WCML_Comments {
253
  */
254
  public function get_reviews_count( $language = false ) {
255
 
256
- remove_filter( 'get_post_metadata', array( $this, 'filter_average_rating' ), 10, 4 );
257
 
258
  if ( ! metadata_exists( 'post', get_the_ID(), self::WCML_REVIEW_COUNT_KEY ) ) {
259
  $this->recalculate_comment_rating( get_the_ID() );
260
  }
261
 
262
- if( 'all' === $language ){
263
  $reviews_count = get_post_meta( get_the_ID(), self::WCML_REVIEW_COUNT_KEY, true );
264
- }else{
265
  $reviews_count = get_post_meta( get_the_ID(), self::WC_REVIEW_COUNT_KEY, true );
266
  }
267
 
268
- add_filter( 'get_post_metadata', array( $this, 'filter_average_rating' ), 10, 4 );
269
 
270
  return $reviews_count;
271
  }
272
 
273
  /**
274
- * @param int $comment_id
275
  * @param WP_Comment|null $comment
276
  */
277
- public function recalculate_average_rating_on_comment_hook( $comment_id, $comment ){
278
 
279
- if( !$comment ){
280
  $comment = get_comment( $comment_id );
281
  }
282
 
283
- if( in_array( get_post_type( $comment->comment_post_ID ), array( 'product', 'product_variation' ) ) ){
284
- $this->recalculate_comment_rating( (int)$comment->comment_post_ID );
285
  }
286
  }
287
 
288
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3
  class WCML_Comments {
4
 
5
  const WCML_AVERAGE_RATING_KEY = '_wcml_average_rating';
6
+ const WCML_REVIEW_COUNT_KEY = '_wcml_review_count';
7
+ const WC_REVIEW_COUNT_KEY = '_wc_review_count';
8
 
9
  /** @var woocommerce_wpml */
10
  private $woocommerce_wpml;
12
  private $sitepress;
13
  /** @var WPML_Post_Translation */
14
  private $post_translations;
15
+ /** @var wpdb */
16
+ private $wpdb;
17
 
18
  /**
19
  * WCML_Comments constructor.
20
  *
21
+ * @param woocommerce_wpml $woocommerce_wpml
22
+ * @param SitePress $sitepress
23
  * @param WPML_Post_Translation $post_translations
24
+ * @param wpdb $wpdb
25
  */
26
+ public function __construct( woocommerce_wpml $woocommerce_wpml, SitePress $sitepress, WPML_Post_Translation $post_translations, wpdb $wpdb ) {
27
  $this->woocommerce_wpml = $woocommerce_wpml;
28
  $this->sitepress = $sitepress;
29
  $this->post_translations = $post_translations;
30
+ $this->wpdb = $wpdb;
31
  }
32
 
33
  public function add_hooks() {
34
 
35
+ add_action( 'comment_post', [ $this, 'add_comment_rating' ] );
36
+ add_action( 'woocommerce_review_before_comment_meta', [ $this, 'add_comment_flag' ], 9 );
37
 
38
+ add_filter( 'get_post_metadata', [ $this, 'filter_average_rating' ], 10, 4 );
39
+ add_filter( 'comments_clauses', [ $this, 'comments_clauses' ], 10, 2 );
40
+ add_action( 'comment_form_before', [ $this, 'comments_link' ] );
41
 
42
+ add_filter( 'wpml_is_comment_query_filtered', [ $this, 'is_comment_query_filtered' ], 10, 2 );
43
+ add_action( 'trashed_comment', [ $this, 'recalculate_average_rating_on_comment_hook' ], 10, 2 );
44
+ add_action( 'deleted_comment', [ $this, 'recalculate_average_rating_on_comment_hook' ], 10, 2 );
45
+ add_action( 'untrashed_comment', [ $this, 'recalculate_average_rating_on_comment_hook' ], 10, 2 );
46
+ //before WCML_Synchronize_Product_Data::sync_product_translations_visibility hook
47
+ add_action( 'woocommerce_product_set_visibility', [ $this, 'recalculate_comment_rating' ], 9 );
48
+
49
+ add_filter( 'woocommerce_top_rated_products_widget_args', [ $this, 'top_rated_products_widget_args' ] );
50
+ add_filter( 'woocommerce_rating_filter_count', [ $this, 'woocommerce_rating_filter_count' ], 10, 3 );
51
  }
52
 
53
  /**
73
  *
74
  * @param int $product_id
75
  */
76
+ public function recalculate_comment_rating( $product_id ) {
77
 
78
  $translations = $this->post_translations->get_element_translations( $product_id );
79
  $average_ratings_sum = 0;
81
  $reviews_count = 0;
82
 
83
  foreach ( $translations as $translation ) {
84
+ $product = wc_get_product( $translation );
85
 
86
  $ratings = WC_Comments::get_rating_counts_for_product( $product );
87
  $review_count = WC_Comments::get_review_count_for_product( $product );
88
 
89
  if ( is_array( $ratings ) ) {
90
  foreach ( $ratings as $rating => $count ) {
91
+ $average_ratings_sum += $rating * $count;
92
  $average_ratings_count += $count;
93
  }
94
  }
95
 
96
+ if ( $review_count ) {
97
  $reviews_count += $review_count;
98
+ } else {
99
  update_post_meta( $translation, self::WCML_AVERAGE_RATING_KEY, null );
100
  update_post_meta( $translation, self::WCML_REVIEW_COUNT_KEY, null );
101
  }
126
 
127
  $filtered_value = $value;
128
 
129
+ if ( in_array( $meta_key, [ '_wc_average_rating', self::WC_REVIEW_COUNT_KEY ] ) && 'product' === get_post_type( $object_id ) ) {
130
 
131
+ switch ( $meta_key ) {
132
  case '_wc_average_rating':
133
  $filtered_value = get_post_meta( $object_id, self::WCML_AVERAGE_RATING_KEY, $single );
134
  break;
140
  }
141
  }
142
 
143
+ return ! empty( $filtered_value ) ? $filtered_value : $value;
144
  }
145
 
146
  /**
147
  * Filters comment queries to display in all languages if needed
148
  *
149
+ * @param string[] $clauses
150
  * @param WP_Comment_Query $obj
151
  *
152
  * @return string[]
155
 
156
  if ( $this->is_reviews_in_all_languages( $obj->query_vars['post_id'] ) ) {
157
 
158
+ $ids = $this->get_translations_ids_list( $obj->query_vars['post_id'] );
159
 
160
  $clauses['where'] = str_replace( 'comment_post_ID = ' . $obj->query_vars['post_id'], 'comment_post_ID IN (' . $ids . ')', $clauses['where'] );
161
  }
170
  *
171
  * @return string list of ids
172
  */
173
+ private function get_translations_ids_list( $product_id ) {
174
 
175
  $translations = $this->post_translations->get_element_translations( $product_id );
176
 
181
  /**
182
  * Display link to show rating in all/current language
183
  */
184
+ public function comments_link() {
185
 
186
+ if ( is_product() ) {
187
+ $current_url = ( is_ssl() ? 'https://' : 'http://' ) . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
188
  $current_language = $this->sitepress->get_current_language();
189
 
190
  if ( ! isset( $_GET['clang'] ) || $current_language === $_GET['clang'] ) {
191
+ $comments_link = add_query_arg( [ 'clang' => 'all' ], $current_url );
192
+ $all_languages_reviews_count = $this->get_reviews_count( 'all' );
193
  $current_language_reviews_count = $this->get_reviews_count();
194
 
195
+ if ( $all_languages_reviews_count > $current_language_reviews_count ) {
196
+ $comments_link_text = sprintf( __( 'Show reviews in all languages (%s)', 'woocommerce-multilingual' ), $all_languages_reviews_count );
197
  }
198
  } elseif ( 'all' === $_GET['clang'] ) {
199
 
200
  $current_language_reviews_count = $this->get_reviews_count();
201
+ $comments_link = add_query_arg( [ 'clang' => $current_language ], $current_url );
202
+ $language_details = $this->sitepress->get_language_details( $current_language );
203
+ $comments_link_text = sprintf( __( 'Show only reviews in %1$s (%2$s)', 'woocommerce-multilingual' ), $language_details['display_name'], $current_language_reviews_count );
204
  }
205
 
206
+ if ( isset( $comments_link_text ) && $comments_link_text ) {
207
  echo '<p><a id="lang-comments-link" href="' . $comments_link . '">' . $comments_link_text . '</a></p>';
208
  }
209
  }
213
  * Checks if comments needs filtering by language.
214
  *
215
  * @param bool $filtered
216
+ * @param int $post_id
217
  * @return bool
218
  */
219
  public function is_comment_query_filtered( $filtered, $post_id ) {
235
  if ( $this->is_reviews_in_all_languages( $comment->comment_post_ID ) ) {
236
  $comment_language = $this->post_translations->get_element_lang_code( $comment->comment_post_ID );
237
 
238
+ $html = '<div style="float: left; padding-right: 5px;">';
239
  $html .= '<img src="' . $this->sitepress->get_flag_url( $comment_language ) . '" width=18" height="12">';
240
  $html .= '</div>';
241
 
262
  */
263
  public function get_reviews_count( $language = false ) {
264
 
265
+ remove_filter( 'get_post_metadata', [ $this, 'filter_average_rating' ], 10, 4 );
266
 
267
  if ( ! metadata_exists( 'post', get_the_ID(), self::WCML_REVIEW_COUNT_KEY ) ) {
268
  $this->recalculate_comment_rating( get_the_ID() );
269
  }
270
 
271
+ if ( 'all' === $language ) {
272
  $reviews_count = get_post_meta( get_the_ID(), self::WCML_REVIEW_COUNT_KEY, true );
273
+ } else {
274
  $reviews_count = get_post_meta( get_the_ID(), self::WC_REVIEW_COUNT_KEY, true );
275
  }
276
 
277
+ add_filter( 'get_post_metadata', [ $this, 'filter_average_rating' ], 10, 4 );
278
 
279
  return $reviews_count;
280
  }
281
 
282
  /**
283
+ * @param int $comment_id
284
  * @param WP_Comment|null $comment
285
  */
286
+ public function recalculate_average_rating_on_comment_hook( $comment_id, $comment ) {
287
 
288
+ if ( ! $comment ) {
289
  $comment = get_comment( $comment_id );
290
  }
291
 
292
+ if ( in_array( get_post_type( $comment->comment_post_ID ), [ 'product', 'product_variation' ] ) ) {
293
+ $this->recalculate_comment_rating( (int) $comment->comment_post_ID );
294
  }
295
  }
296
 
297
+ /**
298
+ * @param array $args
299
+ *
300
+ * @return array
301
+ */
302
+ public function top_rated_products_widget_args( $args ) {
303
+ $args['meta_key'] = self::WCML_AVERAGE_RATING_KEY;
304
+
305
+ return $args;
306
+ }
307
+
308
+ /**
309
+ * @param string $label
310
+ * @param int $count
311
+ * @param int $rating
312
+ *
313
+ * @return array
314
+ */
315
+ public function woocommerce_rating_filter_count( $label, $count, $rating ) {
316
+
317
+ $ratingTerm = get_term_by( 'name', 'rated-' . $rating, 'product_visibility' );
318
+
319
+ $productsCountInCurrentLanguage = $this->wpdb->get_var( $this->wpdb->prepare( "
320
+ SELECT COUNT( DISTINCT tr.object_id )
321
+ FROM {$this->wpdb->term_relationships} tr
322
+ LEFT JOIN {$this->wpdb->prefix}icl_translations t ON t.element_id = tr.object_id
323
+ WHERE tr.term_taxonomy_id = %d AND t.element_type='post_product' AND t.language_code = %s
324
+ ", $ratingTerm->term_taxonomy_id, $this->sitepress->get_current_language() ) );
325
+
326
+ return "({$productsCountInCurrentLanguage})";
327
+ }
328
+ }
inc/class-wcml-compatibility.php CHANGED
@@ -39,7 +39,7 @@ class WCML_Compatibility {
39
  * @param wpdb $wpdb Database object.
40
  * @param WPML_Element_Translation_Package $tp Element Translation Package.
41
  */
42
- function __construct( SitePress $sitepress, woocommerce_wpml $woocommerce_wpml, wpdb $wpdb, WPML_Element_Translation_Package $tp, WPML_Post_Translation $wpml_post_translations ) {
43
  $this->sitepress = $sitepress;
44
  $this->woocommerce_wpml = $woocommerce_wpml;
45
  $this->wpdb = $wpdb;
@@ -145,13 +145,13 @@ class WCML_Compatibility {
145
  }
146
  }
147
 
148
- // WOOBE WooCommerce Bulk Editor
149
  if ( defined( 'WOOBE_PATH' ) ) {
150
  $this->woobe = new WCML_Woobe( $this->sitepress, $this->wpml_post_translations );
151
  $this->woobe->add_hooks();
152
  }
153
 
154
- // WooCommerce Checkout Field Editor
155
  if ( function_exists( 'woocommerce_init_checkout_field_editor' ) ) {
156
  $this->checkout_field_editor = new WCML_Checkout_Field_Editor();
157
  $this->checkout_field_editor->add_hooks();
@@ -167,10 +167,6 @@ class WCML_Compatibility {
167
  $this->wc_ajax_layered_nav_widget = new WCML_Ajax_Layered_Nav_Widget();
168
  }
169
 
170
- if ( is_plugin_active( 'woocommerce-ajax-cart/wooajaxcart.php' ) ) {
171
- $this->wc_ajax_cart = new WCML_WC_Ajax_Cart();
172
- }
173
-
174
  // woocommerce composite products.
175
  if ( isset( $GLOBALS['woocommerce_composite_products'] ) ) {
176
  $this->wc_composite_products = new WCML_Composite_Products( $this->sitepress, $this->woocommerce_wpml, $this->tp );
@@ -206,11 +202,6 @@ class WCML_Compatibility {
206
  new WCML_Aurum();
207
  }
208
 
209
- // Visual Products Configurator.
210
- if ( class_exists( 'Vpc' ) ) {
211
- $this->vpc = new WCML_Vpc();
212
- }
213
-
214
  // WooCommerce Show Single Variations.
215
  if ( defined( 'JCK_WSSV_PATH' ) ) {
216
  new WCML_JCK_WSSV();
@@ -250,12 +241,6 @@ class WCML_Compatibility {
250
  $this->maxstore->add_hooks();
251
  }
252
 
253
- // MaxStore-Pro Theme.
254
- if ( defined( 'ETHEME_THEME_NAME' ) && 'Blanco' === ETHEME_THEME_NAME ) {
255
- $this->etheme_blanco = new WCML_Etheme_Blanco();
256
- $this->etheme_blanco->add_hooks();
257
- }
258
-
259
  // WPBakery Page Builder.
260
  if ( defined( 'WPB_VC_VERSION' ) ) {
261
  $this->wpb_vc = new WCML_Wpb_Vc();
39
  * @param wpdb $wpdb Database object.
40
  * @param WPML_Element_Translation_Package $tp Element Translation Package.
41
  */
42
+ public function __construct( SitePress $sitepress, woocommerce_wpml $woocommerce_wpml, wpdb $wpdb, WPML_Element_Translation_Package $tp, WPML_Post_Translation $wpml_post_translations ) {
43
  $this->sitepress = $sitepress;
44
  $this->woocommerce_wpml = $woocommerce_wpml;
45
  $this->wpdb = $wpdb;
145
  }
146
  }
147
 
148
+ // WOOBE WooCommerce Bulk Editor.
149
  if ( defined( 'WOOBE_PATH' ) ) {
150
  $this->woobe = new WCML_Woobe( $this->sitepress, $this->wpml_post_translations );
151
  $this->woobe->add_hooks();
152
  }
153
 
154
+ // WooCommerce Checkout Field Editor.
155
  if ( function_exists( 'woocommerce_init_checkout_field_editor' ) ) {
156
  $this->checkout_field_editor = new WCML_Checkout_Field_Editor();
157
  $this->checkout_field_editor->add_hooks();
167
  $this->wc_ajax_layered_nav_widget = new WCML_Ajax_Layered_Nav_Widget();
168
  }
169
 
 
 
 
 
170
  // woocommerce composite products.
171
  if ( isset( $GLOBALS['woocommerce_composite_products'] ) ) {
172
  $this->wc_composite_products = new WCML_Composite_Products( $this->sitepress, $this->woocommerce_wpml, $this->tp );
202
  new WCML_Aurum();
203
  }
204
 
 
 
 
 
 
205
  // WooCommerce Show Single Variations.
206
  if ( defined( 'JCK_WSSV_PATH' ) ) {
207
  new WCML_JCK_WSSV();
241
  $this->maxstore->add_hooks();
242
  }
243
 
 
 
 
 
 
 
244
  // WPBakery Page Builder.
245
  if ( defined( 'WPB_VC_VERSION' ) ) {
246
  $this->wpb_vc = new WCML_Wpb_Vc();
inc/class-wcml-dependencies.php CHANGED
@@ -2,41 +2,41 @@
2
 
3
  class WCML_Dependencies {
4
 
5
- const MIN_WPML = '4.3.5';
6
- const MIN_WPML_TM = '2.9.1';
7
- const MIN_WPML_ST = '3.0.5';
8
  const MIN_WOOCOMMERCE = '3.3.0';
9
 
10
- private $missing = array();
11
  private $err_message = '';
12
- private $allok = true;
13
 
14
  /**
15
  * @var WCML_Tracking_Link
16
  */
17
  private $tracking_link;
18
 
19
- function __construct() {
20
 
21
  if ( is_admin() ) {
22
- add_action( 'init', array( $this, 'check_wpml_config' ), 100 );
23
  }
24
 
25
  $this->tracking_link = new WCML_Tracking_Link();
26
  }
27
 
28
- function check() {
29
  global $sitepress, $woocommerce;
30
 
31
  if ( ! defined( 'ICL_SITEPRESS_VERSION' ) || ICL_PLUGIN_INACTIVE || is_null( $sitepress ) || ! class_exists( 'SitePress' ) ) {
32
  $this->missing['WPML'] = $this->tracking_link->generate( 'https://wpml.org/' );
33
  $this->allok = false;
34
  } elseif ( version_compare( ICL_SITEPRESS_VERSION, self::MIN_WPML, '<' ) ) {
35
- add_action( 'admin_notices', array( $this, '_old_wpml_warning' ) );
36
  $this->allok = false;
37
  } elseif ( ! $sitepress->setup() ) {
38
  if ( ! ( isset( $_GET['page'] ) && ICL_PLUGIN_FOLDER . '/menu/languages.php' === $_GET['page'] ) ) {
39
- add_action( 'admin_notices', array( $this, '_wpml_not_installed_warning' ) );
40
  }
41
  $this->allok = false;
42
  }
@@ -48,7 +48,7 @@ class WCML_Dependencies {
48
  defined( 'WC_VERSION' ) && version_compare( WC_VERSION, self::MIN_WOOCOMMERCE, '<' ) ||
49
  isset( $woocommerce->version ) && version_compare( $woocommerce->version, self::MIN_WOOCOMMERCE, '<' )
50
  ) {
51
- add_action( 'admin_notices', array( $this, '_old_wc_warning' ) );
52
  $this->allok = false;
53
  }
54
 
@@ -56,25 +56,25 @@ class WCML_Dependencies {
56
  $this->missing['WPML Translation Management'] = $this->tracking_link->generate( 'https://wpml.org/' );
57
  $this->allok = false;
58
  } elseif ( version_compare( WPML_TM_VERSION, self::MIN_WPML_TM, '<' ) ) {
59
- add_action( 'admin_notices', array( $this, '_old_wpml_tm_warning' ) );
60
  $this->allok = false;
61
  }
62
 
63
- if ( ! defined( 'WPML_ST_VERSION' ) || !function_exists( 'icl_get_string_id' ) ) {
64
  $this->missing['WPML String Translation'] = $this->tracking_link->generate( 'https://wpml.org/' );
65
  $this->allok = false;
66
  } elseif ( version_compare( WPML_ST_VERSION, self::MIN_WPML_ST, '<' ) ) {
67
- add_action( 'admin_notices', array( $this, '_old_wpml_st_warning' ) );
68
  $this->allok = false;
69
  }
70
 
71
  if ( $this->missing ) {
72
- add_action( 'admin_notices', array( $this, '_missing_plugins_warning' ) );
73
  }
74
 
75
  if ( $this->allok ) {
76
  $this->check_for_incompatible_permalinks();
77
- $this->check_for_transaltable_default_taxonomies();
78
  }
79
 
80
  if ( isset( $sitepress ) ) {
@@ -91,12 +91,23 @@ class WCML_Dependencies {
91
  public function _old_wpml_warning() {
92
  ?>
93
  <div class="message error">
94
- <p><?php printf( __( 'WooCommerce Multilingual is enabled but not effective. It is not compatible with <a href="%s">WPML</a> versions prior %s.',
95
- 'woocommerce-multilingual' ), $this->tracking_link->generate( 'https://wpml.org/' ), self::MIN_WPML ); ?></p>
 
 
 
 
 
 
 
 
 
 
96
  </div>
97
- <?php }
 
98
 
99
- function _wpml_not_installed_warning() {
100
  ?>
101
  <div class="message error">
102
  <p><?php printf( __( 'WooCommerce Multilingual is enabled but not effective. Please finish the installation of WPML first.', 'woocommerce-multilingual' ) ); ?></p>
@@ -104,36 +115,69 @@ class WCML_Dependencies {
104
  <?php
105
  }
106
 
107
- function _old_wc_warning() {
108
  ?>
109
  <div class="message error">
110
- <p><?php printf( __( 'WooCommerce Multilingual is enabled but not effective. It is not compatible with <a href="%s">Woocommerce</a> versions prior %s.',
111
- 'woocommerce-multilingual' ), 'http://www.woothemes.com/woocommerce/', self::MIN_WOOCOMMERCE ); ?></p>
 
 
 
 
 
 
 
 
 
 
112
  </div>
113
- <?php }
 
114
 
115
  public function _old_wpml_tm_warning() {
116
  ?>
117
  <div class="message error">
118
- <p><?php printf( __( 'WooCommerce Multilingual is enabled but not effective. It is not compatible with <a href="%s">WPML Translation Management</a> versions prior %s.',
119
- 'woocommerce-multilingual' ), $this->tracking_link->generate( 'https://wpml.org/' ), self::MIN_WPML_TM ); ?></p>
 
 
 
 
 
 
 
 
 
 
120
  </div>
121
- <?php }
 
122
 
123
  public function _old_wpml_st_warning() {
124
  ?>
125
  <div class="message error">
126
- <p><?php printf( __( 'WooCommerce Multilingual is enabled but not effective. It is not compatible with <a href="%s">WPML String Translation</a> versions prior %s.',
127
- 'woocommerce-multilingual' ), $this->tracking_link->generate( 'https://wpml.org/' ), self::MIN_WPML_ST ); ?></p>
 
 
 
 
 
 
 
 
 
 
128
  </div>
129
- <?php }
 
130
 
131
  /**
132
  * Adds default taxonomies notice.
133
  */
134
- public function check_for_transaltable_default_taxonomies() {
135
 
136
- $default_taxonomies = array( 'product_cat', 'product_tag', 'product_shipping_class' );
137
  $show_error = false;
138
 
139
  foreach ( $default_taxonomies as $taxonomy ) {
@@ -160,7 +204,7 @@ class WCML_Dependencies {
160
  $sentences[] = sprintf( _x( "It's best to contact %s, tell that you're getting this message and offer to send a Duplicator copy of the site. We will work with the theme/plugin author and fix the problem for good. In the meanwhile, we'll give you a temporary solution, so you're not stuck.", 'Default taxonomies must be translatable: 6/6', 'woocommerce-multilingual' ), $support_link );
161
 
162
  $this->err_message = '<div class="message error"><p>' . implode( '</p><p>', $sentences ) . '</p></div>';
163
- add_action( 'admin_notices', array( $this, 'plugin_notice_message' ) );
164
  }
165
  }
166
 
@@ -181,7 +225,8 @@ class WCML_Dependencies {
181
  $sep = ', ';
182
  }
183
  $missing .= '<a href="' . $url . '">' . $title . '</a>' . $sep;
184
- } ?>
 
185
 
186
  <div class="message error">
187
  <p><?php printf( __( 'WooCommerce Multilingual is enabled but not effective. It requires %s in order to work.', 'woocommerce-multilingual' ), $missing ); ?></p>
@@ -200,12 +245,12 @@ class WCML_Dependencies {
200
  global $sitepress, $sitepress_settings, $pagenow;
201
 
202
  // WooCommerce 2.x specific checks
203
- $permalinks = get_option( 'woocommerce_permalinks', array( 'product_base' => '' ) );
204
  if ( empty( $permalinks['product_base'] ) ) {
205
  return;
206
  }
207
 
208
- $message = __( 'Because this site uses the default permalink structure, you cannot use slug translation for product permalinks.', 'woocommerce-multilingual' );
209
  $message .= '<br /><br />';
210
  $message .= __( 'Please choose a different permalink structure or disable slug translation.', 'woocommerce-multilingual' );
211
  $message .= '<br /><br />';
@@ -217,16 +262,15 @@ class WCML_Dependencies {
217
  $compatible = true;
218
  $permalink_structure = get_option( 'permalink_structure' );
219
  if ( empty( $permalink_structure )
220
- && ! empty( $sitepress_settings['posts_slug_translation']['on'] )
221
- && ! empty( $sitepress_settings['posts_slug_translation']['types'] )
222
- && $sitepress_settings['posts_slug_translation']['types']['product'] ) {
223
  $compatible = false;
224
  }
225
 
226
-
227
  if ( ! $compatible && ( $pagenow == 'options-permalink.php' || ( isset( $_GET['page'] ) && $_GET['page'] == 'wpml-wcml' ) ) ) {
228
  $this->err_message = '<div class="message error"><p>' . $message . ' </p></div>';
229
- add_action( 'admin_notices', array( $this, 'plugin_notice_message' ) );
230
  }
231
  }
232
 
@@ -249,9 +293,9 @@ class WCML_Dependencies {
249
 
250
  if ( isset( $config['wpml-config'] ) ) {
251
 
252
- //custom-fields
253
  if ( isset( $config['wpml-config']['custom-fields'] ) ) {
254
- if ( isset( $config['wpml-config']['custom-fields']['custom-field']['value'] ) ) { //single
255
  $cfs[] = $config['wpml-config']['custom-fields']['custom-field'];
256
  } else {
257
  foreach ( $config['wpml-config']['custom-fields']['custom-field'] as $cf ) {
@@ -273,12 +317,11 @@ class WCML_Dependencies {
273
  }
274
  }
275
  }
276
-
277
  }
278
 
279
- //custom-types
280
  if ( isset( $config['wpml-config']['custom-types'] ) ) {
281
- if ( isset( $config['wpml-config']['custom-types']['custom-type']['value'] ) ) { //single
282
  $cts[] = $config['wpml-config']['custom-types']['custom-type'];
283
  } else {
284
  foreach ( $config['wpml-config']['custom-types']['custom-type'] as $cf ) {
@@ -294,12 +337,10 @@ class WCML_Dependencies {
294
  $effective_config_value = $sitepress_settings['custom_posts_sync_option'][ $ct['value'] ];
295
  $correct_config_value = $ct['attr']['translate'];
296
 
297
-
298
  if ( 'product' === $ct['value'] && $woocommerce_wpml->products->is_product_display_as_translated_post_type() ) {
299
  $correct_config_value = WPML_CONTENT_TYPE_DISPLAY_AS_IF_TRANSLATED;
300
  }
301
 
302
-
303
  if ( $effective_config_value != $correct_config_value ) {
304
  $this->xml_config_errors[] = sprintf( __( 'Custom type %s configuration from wpml-config.xml file was altered!', 'woocommerce-multilingual' ), '<i>' . $ct['value'] . '</i>' );
305
  }
@@ -307,9 +348,9 @@ class WCML_Dependencies {
307
  }
308
  }
309
 
310
- //taxonomies
311
  if ( isset( $config['wpml-config']['taxonomies'] ) ) {
312
- if ( isset( $config['wpml-config']['taxonomies']['taxonomy']['value'] ) ) { //single
313
  $txs[] = $config['wpml-config']['taxonomies']['taxonomy'];
314
  } else {
315
  foreach ( $config['wpml-config']['taxonomies']['taxonomy'] as $cf ) {
@@ -334,7 +375,6 @@ class WCML_Dependencies {
334
  }
335
  }
336
  }
337
-
338
  }
339
  }
340
  }
2
 
3
  class WCML_Dependencies {
4
 
5
+ const MIN_WPML = '4.3.5';
6
+ const MIN_WPML_TM = '2.9.1';
7
+ const MIN_WPML_ST = '3.0.5';
8
  const MIN_WOOCOMMERCE = '3.3.0';
9
 
10
+ private $missing = [];
11
  private $err_message = '';
12
+ private $allok = true;
13
 
14
  /**
15
  * @var WCML_Tracking_Link
16
  */
17
  private $tracking_link;
18
 
19
+ public function __construct() {
20
 
21
  if ( is_admin() ) {
22
+ add_action( 'init', [ $this, 'check_wpml_config' ], 100 );
23
  }
24
 
25
  $this->tracking_link = new WCML_Tracking_Link();
26
  }
27
 
28
+ public function check() {
29
  global $sitepress, $woocommerce;
30
 
31
  if ( ! defined( 'ICL_SITEPRESS_VERSION' ) || ICL_PLUGIN_INACTIVE || is_null( $sitepress ) || ! class_exists( 'SitePress' ) ) {
32
  $this->missing['WPML'] = $this->tracking_link->generate( 'https://wpml.org/' );
33
  $this->allok = false;
34
  } elseif ( version_compare( ICL_SITEPRESS_VERSION, self::MIN_WPML, '<' ) ) {
35
+ add_action( 'admin_notices', [ $this, '_old_wpml_warning' ] );
36
  $this->allok = false;
37
  } elseif ( ! $sitepress->setup() ) {
38
  if ( ! ( isset( $_GET['page'] ) && ICL_PLUGIN_FOLDER . '/menu/languages.php' === $_GET['page'] ) ) {
39
+ add_action( 'admin_notices', [ $this, '_wpml_not_installed_warning' ] );
40
  }
41
  $this->allok = false;
42
  }
48
  defined( 'WC_VERSION' ) && version_compare( WC_VERSION, self::MIN_WOOCOMMERCE, '<' ) ||
49
  isset( $woocommerce->version ) && version_compare( $woocommerce->version, self::MIN_WOOCOMMERCE, '<' )
50
  ) {
51
+ add_action( 'admin_notices', [ $this, '_old_wc_warning' ] );
52
  $this->allok = false;
53
  }
54
 
56
  $this->missing['WPML Translation Management'] = $this->tracking_link->generate( 'https://wpml.org/' );
57
  $this->allok = false;
58
  } elseif ( version_compare( WPML_TM_VERSION, self::MIN_WPML_TM, '<' ) ) {
59
+ add_action( 'admin_notices', [ $this, '_old_wpml_tm_warning' ] );
60
  $this->allok = false;
61
  }
62
 
63
+ if ( ! defined( 'WPML_ST_VERSION' ) || ! function_exists( 'icl_get_string_id' ) ) {
64
  $this->missing['WPML String Translation'] = $this->tracking_link->generate( 'https://wpml.org/' );
65
  $this->allok = false;
66
  } elseif ( version_compare( WPML_ST_VERSION, self::MIN_WPML_ST, '<' ) ) {
67
+ add_action( 'admin_notices', [ $this, '_old_wpml_st_warning' ] );
68
  $this->allok = false;
69
  }
70
 
71
  if ( $this->missing ) {
72
+ add_action( 'admin_notices', [ $this, '_missing_plugins_warning' ] );
73
  }
74
 
75
  if ( $this->allok ) {
76
  $this->check_for_incompatible_permalinks();
77
+ add_action( 'init', [ $this, 'check_for_translatable_default_taxonomies' ] );
78
  }
79
 
80
  if ( isset( $sitepress ) ) {
91
  public function _old_wpml_warning() {
92
  ?>
93
  <div class="message error">
94
+ <p>
95
+ <?php
96
+ printf(
97
+ __(
98
+ 'WooCommerce Multilingual is enabled but not effective. It is not compatible with <a href="%1$s">WPML</a> versions prior %2$s.',
99
+ 'woocommerce-multilingual'
100
+ ),
101
+ $this->tracking_link->generate( 'https://wpml.org/' ),
102
+ self::MIN_WPML
103
+ );
104
+ ?>
105
+ </p>
106
  </div>
107
+ <?php
108
+ }
109
 
110
+ public function _wpml_not_installed_warning() {
111
  ?>
112
  <div class="message error">
113
  <p><?php printf( __( 'WooCommerce Multilingual is enabled but not effective. Please finish the installation of WPML first.', 'woocommerce-multilingual' ) ); ?></p>
115
  <?php
116
  }
117
 
118
+ public function _old_wc_warning() {
119
  ?>
120
  <div class="message error">
121
+ <p>
122
+ <?php
123
+ printf(
124
+ __(
125
+ 'WooCommerce Multilingual is enabled but not effective. It is not compatible with <a href="%1$s">Woocommerce</a> versions prior %2$s.',
126
+ 'woocommerce-multilingual'
127
+ ),
128
+ 'http://www.woothemes.com/woocommerce/',
129
+ self::MIN_WOOCOMMERCE
130
+ );
131
+ ?>
132
+ </p>
133
  </div>
134
+ <?php
135
+ }
136
 
137
  public function _old_wpml_tm_warning() {
138
  ?>
139
  <div class="message error">
140
+ <p>
141
+ <?php
142
+ printf(
143
+ __(
144
+ 'WooCommerce Multilingual is enabled but not effective. It is not compatible with <a href="%1$s">WPML Translation Management</a> versions prior %2$s.',
145
+ 'woocommerce-multilingual'
146
+ ),
147
+ $this->tracking_link->generate( 'https://wpml.org/' ),
148
+ self::MIN_WPML_TM
149
+ );
150
+ ?>
151
+ </p>
152
  </div>
153
+ <?php
154
+ }
155
 
156
  public function _old_wpml_st_warning() {
157
  ?>
158
  <div class="message error">
159
+ <p>
160
+ <?php
161
+ printf(
162
+ __(
163
+ 'WooCommerce Multilingual is enabled but not effective. It is not compatible with <a href="%1$s">WPML String Translation</a> versions prior %2$s.',
164
+ 'woocommerce-multilingual'
165
+ ),
166
+ $this->tracking_link->generate( 'https://wpml.org/' ),
167
+ self::MIN_WPML_ST
168
+ );
169
+ ?>
170
+ </p>
171
  </div>
172
+ <?php
173
+ }
174
 
175
  /**
176
  * Adds default taxonomies notice.
177
  */
178
+ public function check_for_translatable_default_taxonomies() {
179
 
180
+ $default_taxonomies = [ 'product_cat', 'product_tag', 'product_shipping_class' ];
181
  $show_error = false;
182
 
183
  foreach ( $default_taxonomies as $taxonomy ) {
204
  $sentences[] = sprintf( _x( "It's best to contact %s, tell that you're getting this message and offer to send a Duplicator copy of the site. We will work with the theme/plugin author and fix the problem for good. In the meanwhile, we'll give you a temporary solution, so you're not stuck.", 'Default taxonomies must be translatable: 6/6', 'woocommerce-multilingual' ), $support_link );
205
 
206
  $this->err_message = '<div class="message error"><p>' . implode( '</p><p>', $sentences ) . '</p></div>';
207
+ add_action( 'admin_notices', [ $this, 'plugin_notice_message' ] );
208
  }
209
  }
210
 
225
  $sep = ', ';
226
  }
227
  $missing .= '<a href="' . $url . '">' . $title . '</a>' . $sep;
228
+ }
229
+ ?>
230
 
231
  <div class="message error">
232
  <p><?php printf( __( 'WooCommerce Multilingual is enabled but not effective. It requires %s in order to work.', 'woocommerce-multilingual' ), $missing ); ?></p>
245
  global $sitepress, $sitepress_settings, $pagenow;
246
 
247
  // WooCommerce 2.x specific checks
248
+ $permalinks = get_option( 'woocommerce_permalinks', [ 'product_base' => '' ] );
249
  if ( empty( $permalinks['product_base'] ) ) {
250
  return;
251
  }
252
 
253
+ $message = __( 'Because this site uses the default permalink structure, you cannot use slug translation for product permalinks.', 'woocommerce-multilingual' );
254
  $message .= '<br /><br />';
255
  $message .= __( 'Please choose a different permalink structure or disable slug translation.', 'woocommerce-multilingual' );
256
  $message .= '<br /><br />';
262
  $compatible = true;
263
  $permalink_structure = get_option( 'permalink_structure' );
264
  if ( empty( $permalink_structure )
265
+ && ! empty( $sitepress_settings['posts_slug_translation']['on'] )
266
+ && ! empty( $sitepress_settings['posts_slug_translation']['types'] )
267
+ && $sitepress_settings['posts_slug_translation']['types']['product'] ) {
268
  $compatible = false;
269
  }
270
 
 
271
  if ( ! $compatible && ( $pagenow == 'options-permalink.php' || ( isset( $_GET['page'] ) && $_GET['page'] == 'wpml-wcml' ) ) ) {
272
  $this->err_message = '<div class="message error"><p>' . $message . ' </p></div>';
273
+ add_action( 'admin_notices', [ $this, 'plugin_notice_message' ] );
274
  }
275
  }
276
 
293
 
294
  if ( isset( $config['wpml-config'] ) ) {
295
 
296
+ // custom-fields
297
  if ( isset( $config['wpml-config']['custom-fields'] ) ) {
298
+ if ( isset( $config['wpml-config']['custom-fields']['custom-field']['value'] ) ) { // single
299
  $cfs[] = $config['wpml-config']['custom-fields']['custom-field'];
300
  } else {
301
  foreach ( $config['wpml-config']['custom-fields']['custom-field'] as $cf ) {
317
  }
318
  }
319
  }
 
320
  }
321
 
322
+ // custom-types
323
  if ( isset( $config['wpml-config']['custom-types'] ) ) {
324
+ if ( isset( $config['wpml-config']['custom-types']['custom-type']['value'] ) ) { // single
325
  $cts[] = $config['wpml-config']['custom-types']['custom-type'];
326
  } else {
327
  foreach ( $config['wpml-config']['custom-types']['custom-type'] as $cf ) {
337
  $effective_config_value = $sitepress_settings['custom_posts_sync_option'][ $ct['value'] ];
338
  $correct_config_value = $ct['attr']['translate'];
339
 
 
340
  if ( 'product' === $ct['value'] && $woocommerce_wpml->products->is_product_display_as_translated_post_type() ) {
341
  $correct_config_value = WPML_CONTENT_TYPE_DISPLAY_AS_IF_TRANSLATED;
342
  }
343
 
 
344
  if ( $effective_config_value != $correct_config_value ) {
345
  $this->xml_config_errors[] = sprintf( __( 'Custom type %s configuration from wpml-config.xml file was altered!', 'woocommerce-multilingual' ), '<i>' . $ct['value'] . '</i>' );
346
  }
348
  }
349
  }
350
 
351
+ // taxonomies
352
  if ( isset( $config['wpml-config']['taxonomies'] ) ) {
353
+ if ( isset( $config['wpml-config']['taxonomies']['taxonomy']['value'] ) ) { // single
354
  $txs[] = $config['wpml-config']['taxonomies']['taxonomy'];
355
  } else {
356
  foreach ( $config['wpml-config']['taxonomies']['taxonomy'] as $cf ) {
375
  }
376
  }
377
  }
 
378
  }
379
  }
380
  }
inc/class-wcml-emails.php CHANGED
@@ -2,8 +2,11 @@
2
 
3
  class WCML_Emails {
4
 
5
- private $order_id = false;
6
- private $locale = false;
 
 
 
7
  private $admin_language = false;
8
  /** @var WCML_WC_Strings */
9
  private $wcmlStrings;
@@ -14,115 +17,171 @@ class WCML_Emails {
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
 
24
- function add_hooks() {
25
- //wrappers for email's header
26
  if ( is_admin() && ! defined( 'DOING_AJAX' ) ) {
27
- add_action( 'woocommerce_order_status_completed_notification', array(
28
- $this,
29
- 'email_heading_completed'
30
- ), 9 );
31
- add_action( 'woocommerce_order_status_changed', array( $this, 'comments_language' ), 10 );
 
 
 
 
 
 
32
  }
33
 
34
- add_action( 'woocommerce_new_customer_note_notification', array( $this, 'email_heading_note' ), 9 );
35
 
36
- add_action( 'wp_ajax_woocommerce_mark_order_status', array( $this, 'email_refresh_in_ajax' ), 9 );
37
 
38
- foreach ( array( 'pending', 'failed', 'cancelled', 'on-hold' ) as $state ) {
39
- add_action( 'woocommerce_order_status_' . $state . '_to_processing_notification', array(
40
- $this,
41
- 'email_heading_processing'
42
- ), 9 );
 
 
 
 
43
 
44
- add_action( 'woocommerce_order_status_' . $state . '_to_processing_notification', array(
45
- $this,
46
- 'refresh_email_lang'
47
- ), 9 );
 
 
 
 
48
  }
49
 
50
- foreach ( array( 'pending', 'failed', 'cancelled' ) as $state ) {
51
- add_action( 'woocommerce_order_status_' . $state . '_to_on-hold_notification', array(
52
- $this,
53
- 'email_heading_on_hold'
54
- ), 9 );
 
 
 
 
55
  }
56
 
57
- //wrappers for email's body
58
- add_action( 'woocommerce_before_resend_order_emails', array( $this, 'email_header' ) );
59
- add_action( 'woocommerce_after_resend_order_email', array( $this, 'email_footer' ) );
60
-
61
- //filter string language before for emails
62
- add_filter( 'icl_current_string_language', array( $this, 'icl_current_string_language' ), 10, 2 );
63
 
64
- //change order status
65
- add_action( 'woocommerce_order_status_completed', array( $this, 'refresh_email_lang_complete' ), 9 );
66
 
67
- add_action( 'woocommerce_order_status_pending_to_on-hold_notification', array(
68
- $this,
69
- 'refresh_email_lang'
70
- ), 9 );
71
- add_action( 'woocommerce_new_customer_note', array( $this, 'refresh_email_lang' ), 9 );
72
 
73
- foreach ( array( 'pending', 'failed' ) as $from_state ) {
74
- foreach ( array( 'processing', 'completed', 'on-hold' ) as $to_state ) {
75
- add_action( 'woocommerce_order_status_' . $from_state . '_to_' . $to_state . '_notification', array(
76
- $this,
77
- 'new_order_admin_email'
78
- ), 9 );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
79
  }
80
  }
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
 
87
- add_filter( 'woocommerce_allow_send_queued_transactional_email', array(
88
- $this,
89
- 'send_queued_transactional_email'
90
- ), 10, 3 );
 
 
 
 
 
91
 
92
- add_action( 'woocommerce_order_partially_refunded_notification', array( $this, 'refresh_email_lang' ), 9 );
93
- add_action( 'woocommerce_order_fully_refunded_notification', array( $this, 'refresh_email_lang' ), 9 );
94
- add_filter( 'woocommerce_email_get_option', array( $this, 'filter_refund_emails_strings' ), 10, 4 );
95
 
96
  add_filter( 'woocommerce_email_setup_locale', '__return_false' );
97
  add_filter( 'woocommerce_email_restore_locale', '__return_false' );
98
 
 
 
99
 
100
- add_filter( 'woocommerce_email_heading_new_order', array( $this, 'new_order_email_heading' ) );
101
- add_filter( 'woocommerce_email_subject_new_order', array( $this, 'new_order_email_subject' ) );
 
 
 
 
 
 
 
 
 
 
 
 
102
 
103
- add_filter( 'woocommerce_email_heading_customer_on_hold_order', array(
104
- $this,
105
- 'customer_on_hold_order_heading'
106
- ) );
107
- add_filter( 'woocommerce_email_subject_customer_on_hold_order', array(
108
- $this,
109
- 'customer_on_hold_order_subject'
110
- ) );
 
 
 
 
 
 
111
 
112
- add_filter( 'woocommerce_email_heading_customer_processing_order', array(
113
- $this,
114
- 'customer_processing_order_heading'
115
- ) );
116
- add_filter( 'woocommerce_email_subject_customer_processing_order', array(
117
- $this,
118
- 'customer_processing_order_subject'
119
- ) );
120
 
121
- add_action( 'woocommerce_low_stock_notification', array( $this, 'low_stock_admin_notification' ), 9 );
122
- add_action( 'woocommerce_no_stock_notification', array( $this, 'no_stock_admin_notification' ), 9 );
 
 
 
 
 
 
 
 
 
 
123
  }
124
 
125
- function email_refresh_in_ajax() {
126
  if ( isset( $_GET['order_id'] ) ) {
127
  $this->refresh_email_lang( $_GET['order_id'] );
128
 
@@ -134,7 +193,7 @@ class WCML_Emails {
134
  }
135
  }
136
 
137
- function refresh_email_lang_complete( $order_id ) {
138
 
139
  $this->order_id = $order_id;
140
  $this->refresh_email_lang( $order_id );
@@ -148,7 +207,7 @@ class WCML_Emails {
148
  * @global type $order_id
149
  * @return type
150
  */
151
- function email_header( $order ) {
152
 
153
  if ( is_array( $order ) ) {
154
  $order = $order['order_id'];
@@ -160,7 +219,7 @@ class WCML_Emails {
160
  }
161
 
162
 
163
- function refresh_email_lang( $order_id ) {
164
 
165
  if ( is_array( $order_id ) ) {
166
  if ( isset( $order_id['order_id'] ) ) {
@@ -179,7 +238,7 @@ class WCML_Emails {
179
  /**
180
  * After email translation switch language to default.
181
  */
182
- function email_footer() {
183
  $this->sitepress->switch_lang( $this->sitepress->get_default_language() );
184
  }
185
 
@@ -193,7 +252,7 @@ class WCML_Emails {
193
  }
194
 
195
 
196
- function email_heading_completed( $order_id, $no_checking = false ) {
197
  $email = $this->getEmailObject( 'WC_Email_Customer_Completed_Order', $no_checking );
198
 
199
  if ( $email ) {
@@ -210,11 +269,11 @@ class WCML_Emails {
210
  $original_enabled_state = $email->enabled;
211
  $email->enabled = false;
212
  $email->trigger( $order_id );
213
- $email->enabled = $original_enabled_state;
214
  }
215
  }
216
 
217
- function email_heading_processing( $order_id ) {
218
  $this->translate_email_headings( $order_id, 'WC_Email_Customer_Processing_Order', 'woocommerce_customer_processing_order_settings' );
219
  }
220
 
@@ -233,8 +292,8 @@ class WCML_Emails {
233
 
234
  /**
235
  * @param int|string $order_id
236
- * @param string $class_name
237
- * @param string $string_name
238
  */
239
  private function translate_email_headings( $order_id, $class_name, $string_name ) {
240
  $email = $this->getEmailObject( $class_name );
@@ -263,7 +322,7 @@ class WCML_Emails {
263
  return $this->get_translated_order_strings( 'subject', $subject, 'WC_Email_Customer_On_Hold_Order' );
264
  }
265
 
266
- function email_heading_note( $args ) {
267
  $email = $this->getEmailObject( 'WC_Email_Customer_Note' );
268
 
269
  if ( $email ) {
@@ -281,28 +340,58 @@ class WCML_Emails {
281
  }
282
  }
283
 
284
- public function filter_refund_emails_strings( $value, $object, $old_value, $key ) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
285
 
286
- if ( in_array( $key, array(
287
- 'subject_partial',
288
- 'subject_full',
289
- 'heading_partial',
290
- 'heading_full'
291
- ) ) && $object->object ) {
292
- $translated_value = $this->get_refund_email_translated_string( $key, $object );
293
  }
294
 
295
- return ! empty( $translated_value ) ? $translated_value : $value;
296
  }
297
 
298
- public function get_refund_email_translated_string( $key, $object ) {
 
 
 
 
 
 
 
 
 
299
 
300
- return $this->wcml_get_translated_email_string( 'admin_texts_woocommerce_customer_refunded_order_settings',
301
- '[woocommerce_customer_refunded_order_settings]' . $key, $object->object->get_id() );
302
 
 
303
  }
304
 
305
- function new_order_admin_email( $order_id ) {
306
  $email = $this->getEmailObject( 'WC_Email_New_Order', true );
307
 
308
  if ( $email ) {
@@ -317,7 +406,7 @@ class WCML_Emails {
317
  * @param string $recipient Admin email
318
  * @param int $order_id Order ID
319
  */
320
- $admin_language = apply_filters( 'wcml_new_order_admin_email_language', $this->get_admin_language_by_email( $recipient ), $recipient, $order_id );
321
 
322
  $this->change_email_language( $admin_language );
323
 
@@ -341,16 +430,19 @@ class WCML_Emails {
341
 
342
  /**
343
  * @param string $recipient
 
344
  *
345
  * @return string
346
  */
347
- private function get_admin_language_by_email( $recipient ){
348
  $user = get_user_by( 'email', $recipient );
349
  if ( $user ) {
350
- return $this->sitepress->get_user_admin_language( $user->ID, true );
351
  } else {
352
- return $this->sitepress->get_default_language();
353
  }
 
 
354
  }
355
 
356
  public function new_order_email_heading( $heading ) {
@@ -383,15 +475,18 @@ class WCML_Emails {
383
  }
384
 
385
  public function backend_new_order_admin_email( $order_id ) {
386
- if ( isset( $_POST['wc_order_action'] ) && in_array( $_POST['wc_order_action'], array(
 
 
387
  'send_email_new_order',
388
- 'send_order_details_admin'
389
- ) ) ) {
 
390
  $this->new_order_admin_email( $order_id );
391
  }
392
  }
393
 
394
- function change_email_language( $lang ) {
395
  if ( ! $this->admin_language ) {
396
  $this->admin_language = $this->sitepress->get_user_admin_language( get_current_user_id(), true );
397
  }
@@ -400,7 +495,7 @@ class WCML_Emails {
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 ) {
406
  $order_language = get_post_meta( $order_id, 'wpml_language', true );
@@ -412,7 +507,7 @@ class WCML_Emails {
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 ) {
416
  $order_id = false;
417
 
418
  if ( isset( $_POST['action'] ) && $_POST['action'] == 'editpost' && isset( $_POST['post_type'] ) && $_POST['post_type'] == 'shop_order' && isset( $_POST['wc_order_action'] ) && $_POST['wc_order_action'] != 'send_email_new_order' ) {
@@ -450,7 +545,7 @@ class WCML_Emails {
450
  }
451
 
452
  // set correct locale code for emails
453
- function set_locale_for_emails( $locale, $domain ) {
454
 
455
  if ( $domain == 'woocommerce' && $this->locale ) {
456
  $locale = $this->locale;
@@ -459,12 +554,12 @@ class WCML_Emails {
459
  return $locale;
460
  }
461
 
462
- function translate_woocommerce_countries( $countries ) {
463
 
464
  if ( isset( $_POST['wc_order_action'] ) && $_POST['wc_order_action'] !== 'send_email_new_order' && isset( $_POST['post_ID'] ) ) {
465
  $current_language = $this->sitepress->get_current_language();
466
  $this->refresh_email_lang( $_POST['post_ID'] );
467
- $countries = include( WC()->plugin_path() . '/i18n/countries.php' );
468
  $this->change_email_language( $current_language );
469
  }
470
 
@@ -472,7 +567,7 @@ class WCML_Emails {
472
  }
473
 
474
 
475
- function send_queued_transactional_email( $allow, $filter, $args ) {
476
  $this->order_id = $args[0];
477
 
478
  return $allow;
@@ -527,12 +622,12 @@ class WCML_Emails {
527
 
528
  /**
529
  * @param WC_Product $product
530
- * @param string $action
531
- * @param string $method
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 ) {
@@ -549,4 +644,4 @@ class WCML_Emails {
549
  $this->sitepress->switch_lang();
550
  }
551
  }
552
- }
2
 
3
  class WCML_Emails {
4
 
5
+ const PRIORITY_AFTER_STATUS_CHANGE_EMAIL = 11;
6
+ const PRIORITY_BEFORE_EMAIL_SET_LANGUAGE = 9;
7
+
8
+ private $order_id = false;
9
+ private $locale = false;
10
  private $admin_language = false;
11
  /** @var WCML_WC_Strings */
12
  private $wcmlStrings;
17
  /** @var wpdb */
18
  private $wpdb;
19
 
20
+ public function __construct( WCML_WC_Strings $wcmlStrings, SitePress $sitepress, woocommerce $woocommerce, wpdb $wpdb ) {
21
  $this->wcmlStrings = $wcmlStrings;
22
  $this->sitepress = $sitepress;
23
  $this->woocommerce = $woocommerce;
24
  $this->wpdb = $wpdb;
25
  }
26
 
27
+ public function add_hooks() {
28
+ // wrappers for email's header
29
  if ( is_admin() && ! defined( 'DOING_AJAX' ) ) {
30
+ add_action(
31
+ 'woocommerce_order_status_completed_notification',
32
+ [
33
+ $this,
34
+ 'email_heading_completed',
35
+ ],
36
+ self::PRIORITY_BEFORE_EMAIL_SET_LANGUAGE
37
+ );
38
+ add_action( 'woocommerce_order_status_changed', [ $this, 'comments_language' ], 10 );
39
+
40
+ $this->add_hooks_to_restore_language_for_admin_notes();
41
  }
42
 
43
+ add_action( 'woocommerce_new_customer_note_notification', [ $this, 'email_heading_note' ], self::PRIORITY_BEFORE_EMAIL_SET_LANGUAGE );
44
 
45
+ add_action( 'wp_ajax_woocommerce_mark_order_status', [ $this, 'email_refresh_in_ajax' ], self::PRIORITY_BEFORE_EMAIL_SET_LANGUAGE );
46
 
47
+ foreach ( [ 'pending', 'failed', 'cancelled', 'on-hold' ] as $state ) {
48
+ add_action(
49
+ 'woocommerce_order_status_' . $state . '_to_processing_notification',
50
+ [
51
+ $this,
52
+ 'email_heading_processing',
53
+ ],
54
+ self::PRIORITY_BEFORE_EMAIL_SET_LANGUAGE
55
+ );
56
 
57
+ add_action(
58
+ 'woocommerce_order_status_' . $state . '_to_processing_notification',
59
+ [
60
+ $this,
61
+ 'refresh_email_lang',
62
+ ],
63
+ self::PRIORITY_BEFORE_EMAIL_SET_LANGUAGE
64
+ );
65
  }
66
 
67
+ foreach ( [ 'pending', 'failed', 'cancelled' ] as $state ) {
68
+ add_action(
69
+ 'woocommerce_order_status_' . $state . '_to_on-hold_notification',
70
+ [
71
+ $this,
72
+ 'email_heading_on_hold',
73
+ ],
74
+ self::PRIORITY_BEFORE_EMAIL_SET_LANGUAGE
75
+ );
76
  }
77
 
78
+ // wrappers for email's body
79
+ add_action( 'woocommerce_before_resend_order_emails', [ $this, 'email_header' ] );
80
+ add_action( 'woocommerce_after_resend_order_email', [ $this, 'email_footer' ] );
 
 
 
81
 
82
+ // filter string language before for emails
83
+ add_filter( 'icl_current_string_language', [ $this, 'icl_current_string_language' ], 10, 2 );
84
 
85
+ // change order status
86
+ add_action( 'woocommerce_order_status_completed', [ $this, 'refresh_email_lang_complete' ], self::PRIORITY_BEFORE_EMAIL_SET_LANGUAGE );
 
 
 
87
 
88
+ add_action(
89
+ 'woocommerce_order_status_pending_to_on-hold_notification',
90
+ [
91
+ $this,
92
+ 'refresh_email_lang',
93
+ ],
94
+ self::PRIORITY_BEFORE_EMAIL_SET_LANGUAGE
95
+ );
96
+ add_action( 'woocommerce_new_customer_note', [ $this, 'refresh_email_lang' ], self::PRIORITY_BEFORE_EMAIL_SET_LANGUAGE );
97
+
98
+ foreach ( [ 'pending', 'failed' ] as $from_state ) {
99
+ foreach ( [ 'processing', 'completed', 'on-hold' ] as $to_state ) {
100
+ add_action(
101
+ 'woocommerce_order_status_' . $from_state . '_to_' . $to_state . '_notification',
102
+ [
103
+ $this,
104
+ 'new_order_admin_email',
105
+ ],
106
+ self::PRIORITY_BEFORE_EMAIL_SET_LANGUAGE
107
+ );
108
  }
109
  }
110
 
111
+ add_action( 'woocommerce_before_resend_order_emails', [ $this, 'backend_new_order_admin_email' ], self::PRIORITY_BEFORE_EMAIL_SET_LANGUAGE );
112
 
113
+ add_filter( 'plugin_locale', [ $this, 'set_locale_for_emails' ], 10, 2 );
114
+ add_filter( 'woocommerce_countries', [ $this, 'translate_woocommerce_countries' ] );
115
 
116
+ add_filter(
117
+ 'woocommerce_allow_send_queued_transactional_email',
118
+ [
119
+ $this,
120
+ 'send_queued_transactional_email',
121
+ ],
122
+ 10,
123
+ 3
124
+ );
125
 
126
+ add_action( 'woocommerce_order_partially_refunded_notification', [ $this, 'refresh_email_lang' ], self::PRIORITY_BEFORE_EMAIL_SET_LANGUAGE );
127
+ add_action( 'woocommerce_order_fully_refunded_notification', [ $this, 'refresh_email_lang' ], self::PRIORITY_BEFORE_EMAIL_SET_LANGUAGE );
128
+ add_filter( 'woocommerce_email_get_option', [ $this, 'filter_emails_strings' ], 10, 4 );
129
 
130
  add_filter( 'woocommerce_email_setup_locale', '__return_false' );
131
  add_filter( 'woocommerce_email_restore_locale', '__return_false' );
132
 
133
+ add_filter( 'woocommerce_email_heading_new_order', [ $this, 'new_order_email_heading' ] );
134
+ add_filter( 'woocommerce_email_subject_new_order', [ $this, 'new_order_email_subject' ] );
135
 
136
+ add_filter(
137
+ 'woocommerce_email_heading_customer_on_hold_order',
138
+ [
139
+ $this,
140
+ 'customer_on_hold_order_heading',
141
+ ]
142
+ );
143
+ add_filter(
144
+ 'woocommerce_email_subject_customer_on_hold_order',
145
+ [
146
+ $this,
147
+ 'customer_on_hold_order_subject',
148
+ ]
149
+ );
150
 
151
+ add_filter(
152
+ 'woocommerce_email_heading_customer_processing_order',
153
+ [
154
+ $this,
155
+ 'customer_processing_order_heading',
156
+ ]
157
+ );
158
+ add_filter(
159
+ 'woocommerce_email_subject_customer_processing_order',
160
+ [
161
+ $this,
162
+ 'customer_processing_order_subject',
163
+ ]
164
+ );
165
 
166
+ add_action( 'woocommerce_low_stock_notification', [ $this, 'low_stock_admin_notification' ], self::PRIORITY_BEFORE_EMAIL_SET_LANGUAGE );
167
+ add_action( 'woocommerce_no_stock_notification', [ $this, 'no_stock_admin_notification' ], self::PRIORITY_BEFORE_EMAIL_SET_LANGUAGE );
168
+ }
 
 
 
 
 
169
 
170
+ private function add_hooks_to_restore_language_for_admin_notes(){
171
+ wpml_collect( [
172
+ 'pending',
173
+ 'processing',
174
+ 'on-hold',
175
+ 'completed',
176
+ 'cancelled',
177
+ 'refunded',
178
+ 'failed',
179
+ ] )->each( function ( $status ) {
180
+ add_action( 'woocommerce_order_status_' . $status, [ $this, 'comments_language' ], self::PRIORITY_AFTER_STATUS_CHANGE_EMAIL );
181
+ } );
182
  }
183
 
184
+ public function email_refresh_in_ajax() {
185
  if ( isset( $_GET['order_id'] ) ) {
186
  $this->refresh_email_lang( $_GET['order_id'] );
187
 
193
  }
194
  }
195
 
196
+ public function refresh_email_lang_complete( $order_id ) {
197
 
198
  $this->order_id = $order_id;
199
  $this->refresh_email_lang( $order_id );
207
  * @global type $order_id
208
  * @return type
209
  */
210
+ public function email_header( $order ) {
211
 
212
  if ( is_array( $order ) ) {
213
  $order = $order['order_id'];
219
  }
220
 
221
 
222
+ public function refresh_email_lang( $order_id ) {
223
 
224
  if ( is_array( $order_id ) ) {
225
  if ( isset( $order_id['order_id'] ) ) {
238
  /**
239
  * After email translation switch language to default.
240
  */
241
+ public function email_footer() {
242
  $this->sitepress->switch_lang( $this->sitepress->get_default_language() );
243
  }
244
 
252
  }
253
 
254
 
255
+ public function email_heading_completed( $order_id, $no_checking = false ) {
256
  $email = $this->getEmailObject( 'WC_Email_Customer_Completed_Order', $no_checking );
257
 
258
  if ( $email ) {
269
  $original_enabled_state = $email->enabled;
270
  $email->enabled = false;
271
  $email->trigger( $order_id );
272
+ $email->enabled = $original_enabled_state;
273
  }
274
  }
275
 
276
+ public function email_heading_processing( $order_id ) {
277
  $this->translate_email_headings( $order_id, 'WC_Email_Customer_Processing_Order', 'woocommerce_customer_processing_order_settings' );
278
  }
279
 
292
 
293
  /**
294
  * @param int|string $order_id
295
+ * @param string $class_name
296
+ * @param string $string_name
297
  */
298
  private function translate_email_headings( $order_id, $class_name, $string_name ) {
299
  $email = $this->getEmailObject( $class_name );
322
  return $this->get_translated_order_strings( 'subject', $subject, 'WC_Email_Customer_On_Hold_Order' );
323
  }
324
 
325
+ public function email_heading_note( $args ) {
326
  $email = $this->getEmailObject( 'WC_Email_Customer_Note' );
327
 
328
  if ( $email ) {
340
  }
341
  }
342
 
343
+ public function filter_emails_strings( $value, $object, $old_value, $key ) {
344
+
345
+ $translated_value = false;
346
+ $emailStrings = wpml_collect( [
347
+ 'subject_partial',
348
+ 'subject_full',
349
+ 'heading_partial',
350
+ 'heading_full',
351
+ 'additional_content'
352
+ ] );
353
+
354
+ if (
355
+ isset( $object->object ) &&
356
+ $emailStrings->contains( $key )
357
+ ) {
358
+
359
+ $language = null;
360
+
361
+ $adminEmails = wpml_collect([
362
+ 'new_order',
363
+ 'cancelled_order',
364
+ 'failed_order',
365
+ ]);
366
 
367
+ if ( $adminEmails->contains( $object->id ) ) {
368
+ $language = $this->get_admin_language_by_email( $object->recipient, $object->object->get_id() );
369
+ }
370
+
371
+ $translated_value = $this->get_email_translated_string( $key, $object, $language );
 
 
372
  }
373
 
374
+ return $translated_value ?: $value;
375
  }
376
 
377
+ /**
378
+ * @param string $key
379
+ * @param WC_Email $object
380
+ * @param string $language
381
+ *
382
+ * @return string
383
+ */
384
+ public function get_email_translated_string( $key,
385
+ $object, $language)
386
+ {
387
 
388
+ $context = 'admin_texts_woocommerce_' . $object->id . '_settings';
389
+ $name = '[woocommerce_' . $object->id . '_settings]' . $key;
390
 
391
+ return $this->wcml_get_translated_email_string( $context, $name, $object->object->get_id(), $language );
392
  }
393
 
394
+ public function new_order_admin_email( $order_id ) {
395
  $email = $this->getEmailObject( 'WC_Email_New_Order', true );
396
 
397
  if ( $email ) {
406
  * @param string $recipient Admin email
407
  * @param int $order_id Order ID
408
  */
409
+ $admin_language = $this->get_admin_language_by_email( $recipient, $order_id );
410
 
411
  $this->change_email_language( $admin_language );
412
 
430
 
431
  /**
432
  * @param string $recipient
433
+ * @param integer|bool $order_id
434
  *
435
  * @return string
436
  */
437
+ private function get_admin_language_by_email( $recipient, $order_id = false ) {
438
  $user = get_user_by( 'email', $recipient );
439
  if ( $user ) {
440
+ $language = $this->sitepress->get_user_admin_language( $user->ID, true );
441
  } else {
442
+ $language = $this->sitepress->get_default_language();
443
  }
444
+
445
+ return apply_filters( 'wcml_new_order_admin_email_language', $language, $recipient, $order_id );
446
  }
447
 
448
  public function new_order_email_heading( $heading ) {
475
  }
476
 
477
  public function backend_new_order_admin_email( $order_id ) {
478
+ if ( isset( $_POST['wc_order_action'] ) && in_array(
479
+ $_POST['wc_order_action'],
480
+ [
481
  'send_email_new_order',
482
+ 'send_order_details_admin',
483
+ ]
484
+ ) ) {
485
  $this->new_order_admin_email( $order_id );
486
  }
487
  }
488
 
489
+ public function change_email_language( $lang ) {
490
  if ( ! $this->admin_language ) {
491
  $this->admin_language = $this->sitepress->get_user_admin_language( get_current_user_id(), true );
492
  }
495
  $this->locale = $this->sitepress->get_locale( $lang );
496
  }
497
 
498
+ public function wcml_get_translated_email_string( $context, $name, $order_id = false, $language_code = null ) {
499
 
500
  if ( $order_id && ! $language_code ) {
501
  $order_language = get_post_meta( $order_id, 'wpml_language', true );
507
  return $this->wcmlStrings->get_translated_string_by_name_and_context( $context, $name, $language_code );
508
  }
509
 
510
+ public function icl_current_string_language( $current_language, $name ) {
511
  $order_id = false;
512
 
513
  if ( isset( $_POST['action'] ) && $_POST['action'] == 'editpost' && isset( $_POST['post_type'] ) && $_POST['post_type'] == 'shop_order' && isset( $_POST['wc_order_action'] ) && $_POST['wc_order_action'] != 'send_email_new_order' ) {
545
  }
546
 
547
  // set correct locale code for emails
548
+ public function set_locale_for_emails( $locale, $domain ) {
549
 
550
  if ( $domain == 'woocommerce' && $this->locale ) {
551
  $locale = $this->locale;
554
  return $locale;
555
  }
556
 
557
+ public function translate_woocommerce_countries( $countries ) {
558
 
559
  if ( isset( $_POST['wc_order_action'] ) && $_POST['wc_order_action'] !== 'send_email_new_order' && isset( $_POST['post_ID'] ) ) {
560
  $current_language = $this->sitepress->get_current_language();
561
  $this->refresh_email_lang( $_POST['post_ID'] );
562
+ $countries = include WC()->plugin_path() . '/i18n/countries.php';
563
  $this->change_email_language( $current_language );
564
  }
565
 
567
  }
568
 
569
 
570
+ public function send_queued_transactional_email( $allow, $filter, $args ) {
571
  $this->order_id = $args[0];
572
 
573
  return $allow;
622
 
623
  /**
624
  * @param WC_Product $product
625
+ * @param string $action
626
+ * @param string $method
627
  */
628
  private function admin_notification( $product, $action, $method ) {
629
 
630
+ $wcEmails = $this->woocommerce->mailer();
631
  $is_action_removed = remove_action( $action, [ $wcEmails, $method ] );
632
 
633
  if ( $is_action_removed ) {
644
  $this->sitepress->switch_lang();
645
  }
646
  }
647
+ }
inc/class-wcml-endpoints-legacy.php CHANGED
@@ -6,7 +6,7 @@ class WCML_Endpoints_Legacy {
6
  private $woocommerce_wpml;
7
  var $endpoints_strings = array();
8
 
9
- function __construct( $woocommerce_wpml ) {
10
  $this->woocommerce_wpml = $woocommerce_wpml;
11
  }
12
 
@@ -19,7 +19,7 @@ class WCML_Endpoints_Legacy {
19
  add_filter( 'option_rewrite_rules', array(
20
  $this,
21
  'translate_endpoints_in_rewrite_rules'
22
- ), 0, 1 ); // high priority
23
  add_filter( 'page_link', array( $this, 'endpoint_permalink_filter' ), 10, 2 ); //after WPML
24
 
25
  if ( ! is_admin() ) {
@@ -30,7 +30,7 @@ class WCML_Endpoints_Legacy {
30
  add_filter( 'woocommerce_settings_saved', array( $this, 'update_original_endpoints_strings' ) );
31
  }
32
 
33
- function register_endpoints_translations( $language = null ) {
34
 
35
  if ( ! class_exists( 'WooCommerce' ) || ! defined( 'ICL_SITEPRESS_VERSION' ) || ICL_PLUGIN_INACTIVE || version_compare( WOOCOMMERCE_VERSION, '2.2', '<' ) ) {
36
  return false;
@@ -40,11 +40,11 @@ class WCML_Endpoints_Legacy {
40
 
41
  if ( ! empty( $wc_vars ) ) {
42
  $query_vars = array(
43
- // Checkout actions
44
  'order-pay' => $this->get_endpoint_translation( 'order-pay', $wc_vars['order-pay'], $language ),
45
  'order-received' => $this->get_endpoint_translation( 'order-received', $wc_vars['order-received'], $language ),
46
 
47
- // My account actions
48
  'view-order' => $this->get_endpoint_translation( 'view-order', $wc_vars['view-order'], $language ),
49
  'edit-account' => $this->get_endpoint_translation( 'edit-account', $wc_vars['edit-account'], $language ),
50
  'edit-address' => $this->get_endpoint_translation( 'edit-address', $wc_vars['edit-address'], $language ),
@@ -79,7 +79,7 @@ class WCML_Endpoints_Legacy {
79
  return WC()->query->query_vars;
80
  }
81
 
82
- function get_endpoint_translation( $key, $endpoint, $language = null ) {
83
 
84
  $this->register_endpoint_string( $key, $endpoint );
85
 
@@ -108,19 +108,19 @@ class WCML_Endpoints_Legacy {
108
 
109
  }
110
 
111
- function rewrite_rule_endpoints( $call, $data ) {
112
 
113
- if ( $call == 'icl_st_save_translation' && in_array( $data['icl_st_string_id'], $this->endpoints_strings ) ) {
114
  $this->add_endpoints();
115
  $this->flush_rules_for_endpoints_translations();
116
  }
117
  }
118
 
119
- function flush_rules_for_endpoints_translations() {
120
  add_option( 'flush_rules_for_endpoints_translations', true );
121
  }
122
 
123
- function maybe_flush_rules() {
124
  if ( get_option( 'flush_rules_for_endpoints_translations' ) ) {
125
  delete_option( 'flush_rules_for_endpoints_translations' );
126
  WC()->query->init_query_vars();
@@ -142,14 +142,14 @@ class WCML_Endpoints_Legacy {
142
  }
143
  }
144
 
145
- function update_rewrite_rules( $value, $old_value ) {
146
  $this->add_endpoints();
147
  $this->flush_rules_for_endpoints_translations();
148
 
149
  return $value;
150
  }
151
 
152
- function add_endpoints() {
153
  if ( ! isset( $this->endpoints_strings ) ) {
154
  return;
155
  }
@@ -167,7 +167,7 @@ class WCML_Endpoints_Legacy {
167
 
168
  }
169
 
170
- function endpoint_permalink_filter( $p, $pid ) {
171
  global $post, $wp;
172
 
173
  if ( isset( $post->ID ) && ! is_admin() && version_compare( WOOCOMMERCE_VERSION, '2.2', '>=' ) && defined( 'ICL_SITEPRESS_VERSION' ) && ! ICL_PLUGIN_INACTIVE ) {
@@ -210,7 +210,7 @@ class WCML_Endpoints_Legacy {
210
  return $p;
211
  }
212
 
213
- function get_endpoint_url( $endpoint, $value = '', $permalink = '', $page_lang = false ) {
214
  global $sitepress;
215
 
216
  if ( $page_lang ) {
@@ -242,7 +242,7 @@ class WCML_Endpoints_Legacy {
242
  }
243
 
244
 
245
- function get_translated_edit_address_slug( $slug, $language = false ) {
246
 
247
  $strings_language = $this->woocommerce_wpml->strings->get_string_language( $slug, 'woocommerce', 'edit-address-slug: ' . $slug );
248
 
6
  private $woocommerce_wpml;
7
  var $endpoints_strings = array();
8
 
9
+ public function __construct( $woocommerce_wpml ) {
10
  $this->woocommerce_wpml = $woocommerce_wpml;
11
  }
12
 
19
  add_filter( 'option_rewrite_rules', array(
20
  $this,
21
  'translate_endpoints_in_rewrite_rules'
22
+ ), 0, 1 ); // high priority.
23
  add_filter( 'page_link', array( $this, 'endpoint_permalink_filter' ), 10, 2 ); //after WPML
24
 
25
  if ( ! is_admin() ) {
30
  add_filter( 'woocommerce_settings_saved', array( $this, 'update_original_endpoints_strings' ) );
31
  }
32
 
33
+ public function register_endpoints_translations( $language = null ) {
34
 
35
  if ( ! class_exists( 'WooCommerce' ) || ! defined( 'ICL_SITEPRESS_VERSION' ) || ICL_PLUGIN_INACTIVE || version_compare( WOOCOMMERCE_VERSION, '2.2', '<' ) ) {
36
  return false;
40
 
41
  if ( ! empty( $wc_vars ) ) {
42
  $query_vars = array(
43
+ // Checkout actions.
44
  'order-pay' => $this->get_endpoint_translation( 'order-pay', $wc_vars['order-pay'], $language ),
45
  'order-received' => $this->get_endpoint_translation( 'order-received', $wc_vars['order-received'], $language ),
46
 
47
+ // My account actions.
48
  'view-order' => $this->get_endpoint_translation( 'view-order', $wc_vars['view-order'], $language ),
49
  'edit-account' => $this->get_endpoint_translation( 'edit-account', $wc_vars['edit-account'], $language ),
50
  'edit-address' => $this->get_endpoint_translation( 'edit-address', $wc_vars['edit-address'], $language ),
79
  return WC()->query->query_vars;
80
  }
81
 
82
+ public function get_endpoint_translation( $key, $endpoint, $language = null ) {
83
 
84
  $this->register_endpoint_string( $key, $endpoint );
85
 
108
 
109
  }
110
 
111
+ public function rewrite_rule_endpoints( $call, $data ) {
112
 
113
+ if ( $call==='icl_st_save_translation' && in_array( $data['icl_st_string_id'], $this->endpoints_strings ) ) {
114
  $this->add_endpoints();
115
  $this->flush_rules_for_endpoints_translations();
116
  }
117
  }
118
 
119
+ public function flush_rules_for_endpoints_translations() {
120
  add_option( 'flush_rules_for_endpoints_translations', true );
121
  }
122
 
123
+ public function maybe_flush_rules() {
124
  if ( get_option( 'flush_rules_for_endpoints_translations' ) ) {
125
  delete_option( 'flush_rules_for_endpoints_translations' );
126
  WC()->query->init_query_vars();
142
  }
143
  }
144
 
145
+ public function update_rewrite_rules( $value, $old_value ) {
146
  $this->add_endpoints();
147
  $this->flush_rules_for_endpoints_translations();
148
 
149
  return $value;
150
  }
151
 
152
+ public function add_endpoints() {
153
  if ( ! isset( $this->endpoints_strings ) ) {
154
  return;
155
  }
167
 
168
  }
169
 
170
+ public function endpoint_permalink_filter( $p, $pid ) {
171
  global $post, $wp;
172
 
173
  if ( isset( $post->ID ) && ! is_admin() && version_compare( WOOCOMMERCE_VERSION, '2.2', '>=' ) && defined( 'ICL_SITEPRESS_VERSION' ) && ! ICL_PLUGIN_INACTIVE ) {
210
  return $p;
211
  }
212
 
213
+ public function get_endpoint_url( $endpoint, $value = '', $permalink = '', $page_lang = false ) {
214
  global $sitepress;
215
 
216
  if ( $page_lang ) {
242
  }
243
 
244
 
245
+ public function get_translated_edit_address_slug( $slug, $language = false ) {
246
 
247
  $strings_language = $this->woocommerce_wpml->strings->get_string_language( $slug, 'woocommerce', 'edit-address-slug: ' . $slug );
248
 
inc/class-wcml-endpoints.php CHANGED
@@ -15,7 +15,7 @@ class WCML_Endpoints {
15
 
16
  var $endpoints_strings = array();
17
 
18
- function __construct( woocommerce_wpml $woocommerce_wpml, SitePress $sitepress, wpdb $wpdb ) {
19
  $this->woocommerce_wpml = $woocommerce_wpml;
20
  $this->sitepress = $sitepress;
21
  $this->wpdb = $wpdb;
15
 
16
  var $endpoints_strings = array();
17
 
18
+ public function __construct( woocommerce_wpml $woocommerce_wpml, SitePress $sitepress, wpdb $wpdb ) {
19
  $this->woocommerce_wpml = $woocommerce_wpml;
20
  $this->sitepress = $sitepress;
21
  $this->wpdb = $wpdb;
inc/class-wcml-install.php CHANGED
@@ -1,6 +1,6 @@
1
  <?php
2
 
3
- class WCML_Install{
4
 
5
  /**
6
  * @param woocommerce_wpml $woocommerce_wpml
@@ -8,282 +8,299 @@ class WCML_Install{
8
  */
9
  public static function initialize( $woocommerce_wpml, $sitepress ) {
10
  // @todo Cover by tests, required for wcml-3037.
 
11
 
12
- if( is_admin() ) {
 
13
 
14
- // Install routine
15
- if ( empty( $woocommerce_wpml->settings['set_up'] ) ) { // from 3.2
 
 
16
 
17
- if ( $woocommerce_wpml->settings['is_term_order_synced'] !== 'yes' ) {
18
- //global term ordering resync when moving to >= 3.3.x
19
- add_action( 'init', array( $woocommerce_wpml->terms, 'sync_term_order_globally' ), 20 );
20
- }
21
 
22
- if ( ! isset( $woocommerce_wpml->settings['wc_admin_options_saved'] ) ) {
23
- self::handle_admin_texts();
24
- $woocommerce_wpml->settings['wc_admin_options_saved'] = 1;
25
- }
 
 
 
 
 
26
 
27
- if( $woocommerce_wpml->is_wpml_prior_4_2() ){
28
- if ( ! isset( $woocommerce_wpml->settings['trnsl_interface'] ) ) {
29
- $woocommerce_wpml->settings['trnsl_interface'] = 1;
30
- }
31
- }else{
32
- global $iclTranslationManagement;
33
- $iclTranslationManagement->settings[ WPML_TM_Post_Edit_TM_Editor_Mode::TM_KEY_FOR_POST_TYPE_USE_NATIVE ][ 'product' ] = false;
34
- $iclTranslationManagement->save_settings();
35
- }
36
 
 
 
 
37
 
38
- if ( ! isset( $woocommerce_wpml->settings['products_sync_date'] ) ) {
39
- $woocommerce_wpml->settings['products_sync_date'] = 1;
40
- }
41
 
42
- if ( ! isset( $woocommerce_wpml->settings['products_sync_order'] ) ) {
43
- $woocommerce_wpml->settings['products_sync_order'] = 1;
44
- }
 
45
 
46
- if ( ! isset( $woocommerce_wpml->settings['display_custom_prices'] ) ) {
47
- $woocommerce_wpml->settings['display_custom_prices'] = 0;
48
- }
49
 
50
- if ( ! isset( $woocommerce_wpml->settings['sync_taxonomies_checked'] ) ) {
51
- $woocommerce_wpml->terms->check_if_sync_terms_needed();
52
- $woocommerce_wpml->settings['sync_taxonomies_checked'] = 1;
53
- }
54
 
55
- WCML_Capabilities::set_up_capabilities();
56
 
57
- self:: set_language_information( $sitepress );
58
- self:: check_product_type_terms();
59
 
60
- set_transient( '_wcml_activation_redirect', 1, 30 );
61
 
62
- // Before the setup wizard redirects from plugins.php, allow WPML to scan the wpml-config.xml file
63
- WPML_Config::load_config_run();
64
-
65
- add_action( 'init', array( __CLASS__, 'insert_default_categories' ) );
66
-
67
- $woocommerce_wpml->settings['set_up'] = 1;
68
- $woocommerce_wpml->update_settings();
69
- }
70
-
71
- if ( empty( $woocommerce_wpml->settings['downloaded_translations_for_wc'] ) ) { //from 3.3.3
72
- $woocommerce_wpml->languages_upgrader->download_woocommerce_translations_for_active_languages();
73
- $woocommerce_wpml->settings['downloaded_translations_for_wc'] = 1;
74
- $woocommerce_wpml->update_settings();
75
- }
76
-
77
- if ( empty( $woocommerce_wpml->settings[ 'rewrite_rules_flashed' ] ) ) {
78
- flush_rewrite_rules();
79
- $woocommerce_wpml->settings['rewrite_rules_flashed'] = 1;
80
- }
81
 
82
- add_filter( 'wpml_tm_dashboard_translatable_types', array(
83
- __CLASS__,
84
- 'hide_variation_type_on_tm_dashboard'
85
- ) );
 
86
 
87
- $WCML_Setup_UI = new WCML_Setup_UI( $woocommerce_wpml );
88
- $WCML_Setup_UI->add_hooks();
89
- $WCML_Setup_Handlers = new WCML_Setup_Handlers( $woocommerce_wpml );
90
- $WCML_Setup = new WCML_Setup( $WCML_Setup_UI, $WCML_Setup_Handlers, $woocommerce_wpml, $sitepress );
91
- $WCML_Setup->setup_redirect();
92
- $WCML_Setup->add_hooks();
93
 
94
- if ( ! empty( $woocommerce_wpml->settings['set_up_wizard_run'] ) ) {
95
- add_action( 'admin_notices', array( __CLASS__, 'admin_notice_after_install' ) );
96
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
97
 
98
- $translated_product_type_terms = WCML_Install::translated_product_type_terms();
99
- if ( !empty( $translated_product_type_terms ) ) {
100
- add_action( 'admin_notices', array( __CLASS__, 'admin_translated_product_type_terms_notice' ) );
101
- }elseif( $sitepress->is_translated_taxonomy( 'product_type' ) ){
102
- add_action( 'admin_notices', array( __CLASS__, 'admin_translated_product_type_notice' ) );
103
- }
104
- }
105
 
106
- }
107
 
108
  /**
109
  * @param SitePress $sitepress
110
  */
111
  private static function set_language_information( $sitepress ) {
112
- global $wpdb;
113
-
114
- $def_lang = $sitepress->get_default_language();
115
- //set language info for products
116
- $products = $wpdb->get_results("SELECT ID FROM $wpdb->posts WHERE post_type = 'product' AND post_status <> 'auto-draft'");
117
- foreach($products as $product){
118
- $exist = $sitepress->get_language_for_element($product->ID,'post_product');
119
- if(!$exist){
120
- $sitepress->set_element_language_details($product->ID, 'post_product',false,$def_lang);
121
- }
122
- }
123
-
124
- //set language info for taxonomies
125
- $terms = $wpdb->get_results("SELECT term_taxonomy_id FROM $wpdb->term_taxonomy WHERE taxonomy = 'product_cat'");
126
- foreach($terms as $term){
127
- $exist = $sitepress->get_language_for_element($term->term_taxonomy_id, 'tax_product_cat');
128
- if(!$exist){
129
- $sitepress->set_element_language_details($term->term_taxonomy_id, 'tax_product_cat',false,$def_lang);
130
- }
131
- }
132
- $terms = $wpdb->get_results("SELECT term_taxonomy_id FROM $wpdb->term_taxonomy WHERE taxonomy = 'product_tag'");
133
- foreach($terms as $term){
134
- $exist = $sitepress->get_language_for_element($term->term_taxonomy_id, 'tax_product_tag');
135
- if(!$exist){
136
- $sitepress->set_element_language_details($term->term_taxonomy_id, 'tax_product_tag',false,$def_lang);
137
- }
138
- }
139
-
140
- $terms = $wpdb->get_results("SELECT term_taxonomy_id FROM $wpdb->term_taxonomy WHERE taxonomy = 'product_shipping_class'");
141
- foreach($terms as $term){
142
- $exist = $sitepress->get_language_for_element($term->term_taxonomy_id, 'tax_product_shipping_class');
143
- if(!$exist){
144
- $sitepress->set_element_language_details($term->term_taxonomy_id, 'tax_product_shipping_class',false,$def_lang);
145
- }
146
- }
147
- }
148
-
149
- //handle situation when product_type terms translated before activating WCML
150
- public static function check_product_type_terms(){
151
- global $wpdb;
152
- //check if terms were translated
153
- $translations = self::translated_product_type_terms();
154
-
155
- if( $translations ){
156
- foreach( $translations as $translation ){
157
- if( !is_null( $translation->source_language_code ) ){
158
- //check relationships
159
- $term_relationships = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM {$wpdb->term_relationships} WHERE term_taxonomy_id = %d", $translation->element_id ) );
160
- if( $term_relationships ){
161
- $orig_term = $wpdb->get_var( $wpdb->prepare( "SELECT element_id FROM {$wpdb->prefix}icl_translations WHERE element_type = 'tax_product_type' AND trid = %d AND source_language_code IS NULL", $translation->trid ) );
162
- if( $orig_term ){
163
- foreach( $term_relationships as $term_relationship ){
164
- $wpdb->update(
165
- $wpdb->term_relationships,
166
- array(
167
- 'term_taxonomy_id' => $orig_term
168
- ),
169
- array(
170
- 'object_id' => $term_relationship->object_id,
171
- 'term_taxonomy_id' => $translation->element_id
172
- )
173
- );
174
- }
175
- }
176
- }
177
- $term_id = $wpdb->get_var( $wpdb->prepare( "SELECT term_id FROM {$wpdb->term_taxonomy} WHERE term_taxonomy_id = %d", $translation->element_id ) );
178
-
179
- if( $term_id ){
180
- $wpdb->delete(
181
- $wpdb->terms,
182
- array(
183
- 'term_id' => $term_id
184
- )
185
- );
186
-
187
- $wpdb->delete(
188
- $wpdb->term_taxonomy,
189
- array(
190
- 'term_taxonomy_id' => $translation->element_id
191
- )
192
- );
193
- }
194
- }
195
- }
196
-
197
- foreach( $translations as $translation ){
198
- $wpdb->delete(
199
- $wpdb->prefix . 'icl_translations',
200
- array(
201
- 'translation_id' => $translation->translation_id
202
- )
203
- );
204
- }
205
- }
206
- }
207
-
208
- public static function translated_product_type_terms(){
209
- global $wpdb;
210
- //check if terms were translated
211
- $translations = $wpdb->get_results( "SELECT * FROM {$wpdb->prefix}icl_translations WHERE element_type = 'tax_product_type'" );
212
-
213
- return $translations;
214
- }
215
-
216
- private static function handle_admin_texts(){
217
- if(class_exists('WooCommerce')){
218
- //emails texts
219
- $emails = new WC_Emails();
220
- foreach($emails->emails as $email){
221
- $option_name = $email->plugin_id.$email->id.'_settings';
222
- if(!get_option($option_name)){
223
- add_option($option_name,$email->settings);
224
- }
225
- }
226
- }
227
- }
228
-
229
- public static function admin_notice_after_install(){
230
- global $woocommerce_wpml;
231
-
232
- $tracking_link = new WCML_Tracking_Link();
233
- if( !$woocommerce_wpml->settings['dismiss_doc_main'] ){
234
-
235
- $url = $_SERVER['REQUEST_URI'];
236
- $pos = strpos($url, '?');
237
-
238
- if($pos !== false){
239
- $url .= '&wcml_action=dismiss';
240
- } else {
241
- $url .= '?wcml_action=dismiss';
242
- }
243
- ?>
244
- <div id="message" class="updated message fade otgs-is-dismissible">
245
- <p>
246
- <?php printf( esc_html__( "You've successfully installed %sWooCommerce Multilingual%s. Would you like to see a quick overview?", 'woocommerce-multilingual' ),
247
- '<strong>', '</strong>' ); ?>
248
- </p>
249
- <p>
250
- <a class="button-primary align-right" href="<?php echo esc_url( $tracking_link->generate(
251
- 'https://wpml.org/documentation/related-projects/woocommerce-multilingual/','woocommerce-multilingual','documentation') ); ?>" target="_blank">
252
- <?php _e('Learn how to turn your e-commerce site multilingual', 'woocommerce-multilingual') ?>
253
- </a>
254
- </p>
255
- <a class="notice-dismiss" href="<?php echo $url; ?>"><span class="screen-reader-text"><?php _e('Dismiss', 'woocommerce-multilingual') ?></span></a>
256
- </div>
257
- <?php
258
- }
259
- }
260
-
261
- public static function admin_translated_product_type_notice(){ ?>
262
-
263
- <div id="message" class="updated error">
264
- <p>
265
- <?php printf(__("We detected a problem in your WPML configuration: the %sproduct_type%s taxonomy is set as translatable and this would cause problems with translated products. You can fix this in the %sMultilingual Content Setup page%s.", 'woocommerce-multilingual'), '<i>', '</i>','<a href="' . admin_url( 'admin.php?page=' . WPML_TM_FOLDER . '/menu/main.php&sm=mcsetup#ml-content-setup-sec-8' ) . '">','</a>'); ?>
266
- </p>
267
- </div>
268
-
269
- <?php
270
- }
271
-
272
- public static function admin_translated_product_type_terms_notice(){ ?>
273
-
274
- <div id="message" class="updated error">
275
- <p>
276
- <?php printf(__("We detected that the %sproduct_type%s field was set incorrectly for some product translations. This happened because the product_type taxonomy was translated. You can fix this in the WooCommerce Multilingual %stroubleshooting page%s.", 'woocommerce-multilingual'), '<i>', '</i>','<a href="' . admin_url( 'admin.php?page=wpml-wcml&tab=troubleshooting' ) . '">','</a>'); ?>
277
- </p>
278
- </div>
279
-
280
- <?php
281
- }
282
-
283
- public static function hide_variation_type_on_tm_dashboard( $types ){
284
- unset( $types['product_variation'] );
285
- return $types;
286
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
287
 
288
  public static function insert_default_categories() {
289
  global $sitepress, $woocommerce_wpml;
@@ -291,7 +308,7 @@ class WCML_Install{
291
  $settings = $woocommerce_wpml->get_settings();
292
 
293
  $default_language = $sitepress->get_default_language();
294
- $default_categories = isset( $settings['default_categories'] ) ? $settings['default_categories'] : array() ;
295
 
296
  foreach ( $sitepress->get_active_languages() as $language ) {
297
  if ( isset( $default_categories[ $language['code'] ] ) ) {
@@ -299,21 +316,21 @@ class WCML_Install{
299
  }
300
 
301
  $sitepress->switch_locale( $language['code'] );
302
- $translated_cat_name = __( 'Uncategorized', 'sitepress' );
303
- $translated_cat_name = $translated_cat_name === 'Uncategorized' && $language['code'] !== 'en' ? 'Uncategorized @' . $language['code'] : $translated_cat_name;
304
- $translated_term = get_term_by( 'name', $translated_cat_name, 'product_cat', ARRAY_A );
305
  $sitepress->switch_locale();
306
 
307
- // check if the term already exists
308
- if ( !$translated_term ) {
309
  $translated_term = wp_insert_term( $translated_cat_name, 'product_cat' );
310
  }
311
 
312
  if ( $translated_term && ! is_wp_error( $translated_term ) ) {
313
- // add it to settings
314
  $settings['default_categories'][ $language['code'] ] = $translated_term['term_taxonomy_id'];
315
 
316
- //update translations table
317
  $default_category_trid = $sitepress->get_element_trid(
318
  get_option( 'default_product_cat' ),
319
  'tax_product_cat'
@@ -326,10 +343,9 @@ class WCML_Install{
326
  $default_language
327
  );
328
  }
329
-
330
  }
331
 
332
  $woocommerce_wpml->update_settings( $settings );
333
  }
334
 
335
- }
1
  <?php
2
 
3
+ class WCML_Install {
4
 
5
  /**
6
  * @param woocommerce_wpml $woocommerce_wpml
8
  */
9
  public static function initialize( $woocommerce_wpml, $sitepress ) {
10
  // @todo Cover by tests, required for wcml-3037.
11
+ if ( is_admin() ) {
12
 
13
+ // Install routine.
14
+ if ( empty( $woocommerce_wpml->settings['set_up'] ) ) { // from 3.2.
15
 
16
+ if ( $woocommerce_wpml->settings['is_term_order_synced'] !== 'yes' ) {
17
+ // global term ordering resync when moving to >= 3.3.x.
18
+ add_action( 'init', [ $woocommerce_wpml->terms, 'sync_term_order_globally' ], 20 );
19
+ }
20
 
21
+ if ( ! isset( $woocommerce_wpml->settings['wc_admin_options_saved'] ) ) {
22
+ self::handle_admin_texts();
23
+ $woocommerce_wpml->settings['wc_admin_options_saved'] = 1;
24
+ }
25
 
26
+ if ( $woocommerce_wpml->is_wpml_prior_4_2() ) {
27
+ if ( ! isset( $woocommerce_wpml->settings['trnsl_interface'] ) ) {
28
+ $woocommerce_wpml->settings['trnsl_interface'] = 1;
29
+ }
30
+ } else {
31
+ global $iclTranslationManagement;
32
+ $iclTranslationManagement->settings[ WPML_TM_Post_Edit_TM_Editor_Mode::TM_KEY_FOR_POST_TYPE_USE_NATIVE ]['product'] = false;
33
+ $iclTranslationManagement->save_settings();
34
+ }
35
 
36
+ if ( ! isset( $woocommerce_wpml->settings['products_sync_date'] ) ) {
37
+ $woocommerce_wpml->settings['products_sync_date'] = 1;
38
+ }
 
 
 
 
 
 
39
 
40
+ if ( ! isset( $woocommerce_wpml->settings['products_sync_order'] ) ) {
41
+ $woocommerce_wpml->settings['products_sync_order'] = 1;
42
+ }
43
 
44
+ if ( ! isset( $woocommerce_wpml->settings['display_custom_prices'] ) ) {
45
+ $woocommerce_wpml->settings['display_custom_prices'] = 0;
46
+ }
47
 
48
+ if ( ! isset( $woocommerce_wpml->settings['sync_taxonomies_checked'] ) ) {
49
+ $woocommerce_wpml->terms->check_if_sync_terms_needed();
50
+ $woocommerce_wpml->settings['sync_taxonomies_checked'] = 1;
51
+ }
52
 
53
+ WCML_Capabilities::set_up_capabilities();
 
 
54
 
55
+ self::set_language_information( $sitepress );
56
+ self::check_product_type_terms();
 
 
57
 
58
+ set_transient( '_wcml_activation_redirect', 1, 30 );
59
 
60
+ // Before the setup wizard redirects from plugins.php, allow WPML to scan the wpml-config.xml file.
61
+ WPML_Config::load_config_run();
62
 
63
+ add_action( 'init', [ __CLASS__, 'insert_default_categories' ] );
64
 
65
+ $woocommerce_wpml->settings['set_up'] = 1;
66
+ $woocommerce_wpml->update_settings();
67
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
68
 
69
+ if ( empty( $woocommerce_wpml->settings['downloaded_translations_for_wc'] ) ) { // from 3.3.3.
70
+ $woocommerce_wpml->languages_upgrader->download_woocommerce_translations_for_active_languages();
71
+ $woocommerce_wpml->settings['downloaded_translations_for_wc'] = 1;
72
+ $woocommerce_wpml->update_settings();
73
+ }
74
 
75
+ if ( empty( $woocommerce_wpml->settings['rewrite_rules_flashed'] ) ) {
76
+ flush_rewrite_rules();
77
+ $woocommerce_wpml->settings['rewrite_rules_flashed'] = 1;
78
+ }
 
 
79
 
80
+ add_filter(
81
+ 'wpml_tm_dashboard_translatable_types',
82
+ [
83
+ __CLASS__,
84
+ 'hide_variation_type_on_tm_dashboard',
85
+ ]
86
+ );
87
+
88
+ $WCML_Setup_UI = new WCML_Setup_UI( $woocommerce_wpml );
89
+ $WCML_Setup_UI->add_hooks();
90
+ $WCML_Setup_Handlers = new WCML_Setup_Handlers( $woocommerce_wpml );
91
+ $WCML_Setup = new WCML_Setup( $WCML_Setup_UI, $WCML_Setup_Handlers, $woocommerce_wpml, $sitepress );
92
+ $WCML_Setup->setup_redirect();
93
+ $WCML_Setup->add_hooks();
94
+
95
+ if ( ! empty( $woocommerce_wpml->settings['set_up_wizard_run'] ) ) {
96
+ add_action( 'admin_notices', [ __CLASS__, 'admin_notice_after_install' ] );
97
+ }
98
 
99
+ $translated_product_type_terms = self::translated_product_type_terms();
100
+ if ( ! empty( $translated_product_type_terms ) ) {
101
+ add_action( 'admin_notices', [ __CLASS__, 'admin_translated_product_type_terms_notice' ] );
102
+ } elseif ( $sitepress->is_translated_taxonomy( 'product_type' ) ) {
103
+ add_action( 'admin_notices', [ __CLASS__, 'admin_translated_product_type_notice' ] );
104
+ }
105
+ }
106
 
107
+ }
108
 
109
  /**
110
  * @param SitePress $sitepress
111
  */
112
  private static function set_language_information( $sitepress ) {
113
+ global $wpdb;
114
+
115
+ $def_lang = $sitepress->get_default_language();
116
+ // set language info for products.
117
+ $products = $wpdb->get_results( "SELECT ID FROM $wpdb->posts WHERE post_type = 'product' AND post_status <> 'auto-draft'" );
118
+ foreach ( $products as $product ) {
119
+ $exist = $sitepress->get_language_for_element( $product->ID, 'post_product' );
120
+ if ( ! $exist ) {
121
+ $sitepress->set_element_language_details( $product->ID, 'post_product', false, $def_lang );
122
+ }
123
+ }
124
+
125
+ // set language info for taxonomies.
126
+ $terms = $wpdb->get_results( "SELECT term_taxonomy_id FROM $wpdb->term_taxonomy WHERE taxonomy = 'product_cat'" );
127
+ foreach ( $terms as $term ) {
128
+ $exist = $sitepress->get_language_for_element( $term->term_taxonomy_id, 'tax_product_cat' );
129
+ if ( ! $exist ) {
130
+ $sitepress->set_element_language_details( $term->term_taxonomy_id, 'tax_product_cat', false, $def_lang );
131
+ }
132
+ }
133
+ $terms = $wpdb->get_results( "SELECT term_taxonomy_id FROM $wpdb->term_taxonomy WHERE taxonomy = 'product_tag'" );
134
+ foreach ( $terms as $term ) {
135
+ $exist = $sitepress->get_language_for_element( $term->term_taxonomy_id, 'tax_product_tag' );
136
+ if ( ! $exist ) {
137
+ $sitepress->set_element_language_details( $term->term_taxonomy_id, 'tax_product_tag', false, $def_lang );
138
+ }
139
+ }
140
+
141
+ $terms = $wpdb->get_results( "SELECT term_taxonomy_id FROM $wpdb->term_taxonomy WHERE taxonomy = 'product_shipping_class'" );
142
+ foreach ( $terms as $term ) {
143
+ $exist = $sitepress->get_language_for_element( $term->term_taxonomy_id, 'tax_product_shipping_class' );
144
+ if ( ! $exist ) {
145
+ $sitepress->set_element_language_details( $term->term_taxonomy_id, 'tax_product_shipping_class', false, $def_lang );
146
+ }
147
+ }
148
+ }
149
+
150
+ // handle situation when product_type terms translated before activating WCML.
151
+ public static function check_product_type_terms() {
152
+ global $wpdb;
153
+ // check if terms were translated.
154
+ $translations = self::translated_product_type_terms();
155
+
156
+ if ( $translations ) {
157
+ foreach ( $translations as $translation ) {
158
+ if ( ! is_null( $translation->source_language_code ) ) {
159
+ // check relationships.
160
+ $term_relationships = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM {$wpdb->term_relationships} WHERE term_taxonomy_id = %d", $translation->element_id ) );
161
+ if ( $term_relationships ) {
162
+ $orig_term = $wpdb->get_var( $wpdb->prepare( "SELECT element_id FROM {$wpdb->prefix}icl_translations WHERE element_type = 'tax_product_type' AND trid = %d AND source_language_code IS NULL", $translation->trid ) );
163
+ if ( $orig_term ) {
164
+ foreach ( $term_relationships as $term_relationship ) {
165
+ $wpdb->update(
166
+ $wpdb->term_relationships,
167
+ [
168
+ 'term_taxonomy_id' => $orig_term,
169
+ ],
170
+ [
171
+ 'object_id' => $term_relationship->object_id,
172
+ 'term_taxonomy_id' => $translation->element_id,
173
+ ]
174
+ );
175
+ }
176
+ }
177
+ }
178
+ $term_id = $wpdb->get_var( $wpdb->prepare( "SELECT term_id FROM {$wpdb->term_taxonomy} WHERE term_taxonomy_id = %d", $translation->element_id ) );
179
+
180
+ if ( $term_id ) {
181
+ $wpdb->delete(
182
+ $wpdb->terms,
183
+ [
184
+ 'term_id' => $term_id,
185
+ ]
186
+ );
187
+
188
+ $wpdb->delete(
189
+ $wpdb->term_taxonomy,
190
+ [
191
+ 'term_taxonomy_id' => $translation->element_id,
192
+ ]
193
+ );
194
+ }
195
+ }
196
+ }
197
+
198
+ foreach ( $translations as $translation ) {
199
+ $wpdb->delete(
200
+ $wpdb->prefix . 'icl_translations',
201
+ [
202
+ 'translation_id' => $translation->translation_id,
203
+ ]
204
+ );
205
+ }
206
+ }
207
+ }
208
+
209
+ public static function translated_product_type_terms() {
210
+ global $wpdb;
211
+ // check if terms were translated.
212
+ $translations = $wpdb->get_results( "SELECT * FROM {$wpdb->prefix}icl_translations WHERE element_type = 'tax_product_type'" );
213
+
214
+ return $translations;
215
+ }
216
+
217
+ private static function handle_admin_texts() {
218
+ if ( class_exists( 'WooCommerce' ) ) {
219
+ // emails texts.
220
+ $emails = new WC_Emails();
221
+ foreach ( $emails->emails as $email ) {
222
+ $option_name = $email->plugin_id . $email->id . '_settings';
223
+ if ( ! get_option( $option_name ) ) {
224
+ add_option( $option_name, $email->settings );
225
+ }
226
+ }
227
+ }
228
+ }
229
+
230
+ public static function admin_notice_after_install() {
231
+ global $woocommerce_wpml;
232
+
233
+ $tracking_link = new WCML_Tracking_Link();
234
+ if ( ! $woocommerce_wpml->settings['dismiss_doc_main'] ) {
235
+
236
+ $url = $_SERVER['REQUEST_URI'];
237
+ $pos = strpos( $url, '?' );
238
+
239
+ if ( $pos !== false ) {
240
+ $url .= '&wcml_action=dismiss';
241
+ } else {
242
+ $url .= '?wcml_action=dismiss';
243
+ }
244
+ ?>
245
+ <div id="message" class="updated message fade otgs-is-dismissible">
246
+ <p>
247
+ <?php
248
+ printf(
249
+ esc_html__( "You've successfully installed %1\$sWooCommerce Multilingual%2\$s. Would you like to see a quick overview?", 'woocommerce-multilingual' ),
250
+ '<strong>',
251
+ '</strong>'
252
+ );
253
+ ?>
254
+ </p>
255
+ <p>
256
+ <a class="button-primary align-right" href="
257
+ <?php
258
+ echo esc_url(
259
+ $tracking_link->generate(
260
+ 'https://wpml.org/documentation/related-projects/woocommerce-multilingual/',
261
+ 'woocommerce-multilingual',
262
+ 'documentation'
263
+ )
264
+ );
265
+ ?>
266
+ " target="_blank">
267
+ <?php _e( 'Learn how to turn your e-commerce site multilingual', 'woocommerce-multilingual' ); ?>
268
+ </a>
269
+ </p>
270
+ <a class="notice-dismiss" href="<?php echo $url; ?>"><span class="screen-reader-text"><?php _e( 'Dismiss', 'woocommerce-multilingual' ); ?></span></a>
271
+ </div>
272
+ <?php
273
+ }
274
+ }
275
+
276
+ public static function admin_translated_product_type_notice() {
277
+ ?>
278
+
279
+ <div id="message" class="updated error">
280
+ <p>
281
+ <?php printf( __( 'We detected a problem in your WPML configuration: the %1$sproduct_type%2$s taxonomy is set as translatable and this would cause problems with translated products. You can fix this in the %3$sMultilingual Content Setup page%4$s.', 'woocommerce-multilingual' ), '<i>', '</i>', '<a href="' . admin_url( 'admin.php?page=' . WPML_TM_FOLDER . '/menu/main.php&sm=mcsetup#ml-content-setup-sec-8' ) . '">', '</a>' ); ?>
282
+ </p>
283
+ </div>
284
+
285
+ <?php
286
+ }
287
+
288
+ public static function admin_translated_product_type_terms_notice() {
289
+ ?>
290
+
291
+ <div id="message" class="updated error">
292
+ <p>
293
+ <?php printf( __( 'We detected that the %1$sproduct_type%2$s field was set incorrectly for some product translations. This happened because the product_type taxonomy was translated. You can fix this in the WooCommerce Multilingual %3$stroubleshooting page%4$s.', 'woocommerce-multilingual' ), '<i>', '</i>', '<a href="' . admin_url( 'admin.php?page=wpml-wcml&tab=troubleshooting' ) . '">', '</a>' ); ?>
294
+ </p>
295
+ </div>
296
+
297
+ <?php
298
+ }
299
+
300
+ public static function hide_variation_type_on_tm_dashboard( $types ) {
301
+ unset( $types['product_variation'] );
302
+ return $types;
303
+ }
304
 
305
  public static function insert_default_categories() {
306
  global $sitepress, $woocommerce_wpml;
308
  $settings = $woocommerce_wpml->get_settings();
309
 
310
  $default_language = $sitepress->get_default_language();
311
+ $default_categories = isset( $settings['default_categories'] ) ? $settings['default_categories'] : [];
312
 
313
  foreach ( $sitepress->get_active_languages() as $language ) {
314
  if ( isset( $default_categories[ $language['code'] ] ) ) {
316
  }
317
 
318
  $sitepress->switch_locale( $language['code'] );
319
+ $translated_cat_name = __( 'Uncategorized', 'sitepress' );
320
+ $translated_cat_name = $translated_cat_name === 'Uncategorized' && $language['code'] !== 'en' ? 'Uncategorized @' . $language['code'] : $translated_cat_name;
321
+ $translated_term = get_term_by( 'name', $translated_cat_name, 'product_cat', ARRAY_A );
322
  $sitepress->switch_locale();
323
 
324
+ // check if the term already exists.
325
+ if ( ! $translated_term ) {
326
  $translated_term = wp_insert_term( $translated_cat_name, 'product_cat' );
327
  }
328
 
329
  if ( $translated_term && ! is_wp_error( $translated_term ) ) {
330
+ // add it to settings.
331
  $settings['default_categories'][ $language['code'] ] = $translated_term['term_taxonomy_id'];
332
 
333
+ // update translations table.
334
  $default_category_trid = $sitepress->get_element_trid(
335
  get_option( 'default_product_cat' ),
336
  'tax_product_cat'
343
  $default_language
344
  );
345
  }
 
346
  }
347
 
348
  $woocommerce_wpml->update_settings( $settings );
349
  }
350
 
351
+ }
inc/class-wcml-languages-upgrader.php CHANGED
@@ -1,253 +1,254 @@
1
  <?php
2
 
3
- class WCML_Languages_Upgrader{
4
 
5
 
6
 
7
- function __construct(){
8
 
9
- add_action( 'icl_update_active_languages', array( $this, 'download_woocommerce_translations_for_active_languages' ) );
10
- add_filter( 'upgrader_pre_download', array( $this, 'version_update' ), 10, 2 );
11
- add_action( 'admin_notices', array( $this, 'translation_upgrade_notice' ) );
12
- add_action( 'wp_ajax_hide_wcml_translations_message', array($this, 'hide_wcml_translations_message') );
13
 
14
- $this->load_js();
15
- }
16
 
17
- /**
18
- * Automatically download translations for WC ( when user install WCML ( from 3.3.3) / add new language in WPML )
19
- *
20
- * @param string $lang_code Language code
21
- *
22
- */
23
- function download_woocommerce_translations( $lang_code, $wc_version ){
24
- global $sitepress;
25
 
26
- $locale = $sitepress->get_locale( $lang_code );
27
 
28
- if( $locale != 'en_US' && $this->has_available_update( $locale, $wc_version ) ){
29
 
30
- $wc_version = $wc_version ? $wc_version : WC_VERSION;
31
 
32
- include_once( ABSPATH . 'wp-admin/includes/class-wp-upgrader.php' );
33
- require_once( ABSPATH . 'wp-admin/includes/file.php' );
34
- require_once( ABSPATH . 'wp-admin/includes/plugin.php' );
35
- require_once( ABSPATH . 'wp-admin/includes/template.php' );
36
 
37
- $url = 'update-core.php?action=do-translation-upgrade';
38
- $nonce = 'upgrade-translations';
39
- $title = '';
40
- $context = WP_LANG_DIR;
41
 
42
- $upgrader = new Language_Pack_Upgrader( new Automatic_Upgrader_Skin( compact( 'url', 'nonce', 'title', 'context' ) ) ); // use Language_Pack_Upgrader_Skin instead of Automatic_Upgrader_Skin to display upgrade process
43
 
44
- $upgr_object = array();
45
- $upgr_object[0] = new stdClass();
46
- $upgr_object[0]->type = 'plugin';
47
- $upgr_object[0]->slug = 'woocommerce';
48
- $upgr_object[0]->language = $locale;
49
- $upgr_object[0]->version = $wc_version;
50
- $upgr_object[0]->updated = date('Y-m-d H:i:s');
51
- $upgr_object[0]->package = $this->get_language_pack_uri( $locale, $wc_version );
52
- $upgr_object[0]->autoupdate = 1;
53
 
54
- $ob_level_before = ob_get_level();
55
 
56
- $upgrader->bulk_upgrade( $upgr_object );
57
 
58
- // Close a potential unclosed output buffer
59
- $ob_level_after = ob_get_level();
60
- if( $ob_level_after > $ob_level_before ){
61
- ob_end_clean();
62
- }
63
 
 
 
64
 
65
- $this->save_translation_version( $locale, false, $wc_version );
66
- }
67
 
68
- }
69
 
 
 
 
 
 
 
70
 
71
- /*
72
- * Automatically download translations for WC for active languages
73
- *
74
- */
75
- function download_woocommerce_translations_for_active_languages( $wc_version = false ){
76
- global $sitepress, $woocommerce_wpml;
77
 
78
- $active_languages = $sitepress->get_active_languages();
79
 
80
- $current_language = $sitepress->get_current_language();
81
 
82
- foreach( $active_languages as $language ){
83
 
84
- $this->download_woocommerce_translations( $language['code'], $wc_version );
85
 
86
- }
87
 
88
- $sitepress->switch_lang( $current_language );
 
 
89
 
90
- if( isset( $woocommerce_wpml->url_translation ) ){
91
- $woocommerce_wpml->url_translation->register_product_and_taxonomy_bases();
92
- }
93
 
94
- }
95
 
96
- function get_language_pack_uri( $locale, $version = false ){
 
 
97
 
98
- if( !$version ){
99
- $version = WC_VERSION;
100
- }
101
 
102
- $repo = 'https://downloads.wordpress.org/translation/plugin/woocommerce/';
103
- return $repo . $version . '/' . $locale . '.zip';
104
- }
 
 
 
 
 
 
 
105
 
106
- /*
107
- * Update the WC language version in database
108
- *
109
- *
110
- * @param bool $reply Whether to bail without returning the package (default: false)
111
- * @param string $package Package URL
112
- *
113
- * @return bool
114
- */
115
- function version_update( $reply, $package ) {
116
 
117
- $notices = maybe_unserialize( get_option( 'wcml_translations_upgrade_notice' ) );
 
 
118
 
119
- if( !is_array( $notices ) ){
120
- return $reply;
121
- }
122
 
123
- foreach( $notices as $key => $locale){
124
- if( strstr( $package, 'woocommerce') && strstr( $package, $locale) ){
125
 
126
- $this->save_translation_version( $locale, $key );
 
127
 
128
- }
129
- }
130
 
131
- return $reply;
132
- }
133
 
 
134
 
135
- function save_translation_version( $locale, $key = false, $wc_version = false ){
136
 
137
- $notices = maybe_unserialize( get_option( 'wcml_translations_upgrade_notice' ) );
 
138
 
139
- // Update the language pack version
140
- update_option( 'woocommerce_language_pack_version_'.$locale, array( $wc_version ? $wc_version : WC_VERSION, $locale ) );
141
 
142
- if( is_array( $notices ) ){
 
 
143
 
144
- if( !$key )
145
- $key = array_search( $locale, $notices );
146
 
147
- // Remove the translation upgrade notice
148
- unset( $notices[ $key ] );
149
 
150
- update_option( 'wcml_translations_upgrade_notice', $notices );
151
 
152
- }
153
 
154
- }
 
 
 
 
 
 
 
 
155
 
156
- /*
157
- * Check if has available translation update
158
- *
159
- * @param string $locale Locale code
160
- *
161
- * @return bool
162
- */
163
- function has_available_update( $locale, $wc_version = false ) {
164
- $wc_version = $wc_version ? $wc_version : WC_VERSION;
165
 
166
- $version = get_option( 'woocommerce_language_pack_version_'.$locale, array( '0', $locale ) );
 
167
 
168
- $is_new_version = !is_array( $version ) || version_compare( $version[0], $wc_version, '<' ) || $version[1] !== $locale;
169
- $mo_file_absent = !file_exists( sprintf( WP_LANG_DIR . '/plugins/woocommerce-%s.mo', $locale ) );
170
 
171
- $notices = maybe_unserialize( get_option( 'wcml_translations_upgrade_notice' ) );
 
172
 
173
- if ( 'en_US' !== $locale && ( $is_new_version || $mo_file_absent ) ) {
174
- if ( $this->check_if_language_pack_exists( $locale, $wc_version ) ){
175
 
176
- if( !$notices || !in_array( $locale, $notices )){
177
- $notices[] = $locale;
 
178
 
179
- update_option( 'wcml_translations_upgrade_notice', $notices );
180
- update_option( 'hide_wcml_translations_message', 0 );
181
- }
 
 
 
182
 
183
- return true;
184
- } else {
185
- // Updated the woocommerce_language_pack_version to avoid searching translations for this release again
186
- update_option( 'woocommerce_language_pack_version_'.$locale, array( $wc_version, $locale ) );
187
- }
188
- }
189
 
190
- return false;
191
- }
192
 
 
 
 
 
 
 
193
 
194
- /**
195
- * Check if language pack exists
196
- *
197
- * @return bool
198
- */
199
- function check_if_language_pack_exists( $locale, $wc_version ) {
200
 
201
- $response = wp_safe_remote_get( $this->get_language_pack_uri( $locale, $wc_version ), array( 'timeout' => 60 ) );
 
 
 
 
 
202
 
203
- if ( ! is_wp_error( $response ) && $response['response']['code'] >= 200 && $response['response']['code'] < 300 && $response['body'] != '404 File not found' ) {
204
- return true;
205
- } else {
206
- return false;
207
- }
208
- }
209
 
 
 
 
 
 
210
 
211
- /*
212
- * Display Translations upgrade notice message
213
- */
214
- function translation_upgrade_notice(){
215
- global $woocommerce_wpml;
216
 
217
- $screen = get_current_screen();
218
- $notices = maybe_unserialize( get_option( 'wcml_translations_upgrade_notice' ) );
219
 
220
- if ( 'update-core' !== $screen->id && !empty ( $notices ) && !get_option( 'hide_wcml_translations_message' ) ) {
 
 
 
221
 
222
- $lang_notices = new WCML_Languages_Upgrade_Notice( $notices );
223
- $lang_notices->show();
224
- }
225
- }
 
 
 
 
 
226
 
227
- /*
228
- * Hide Translations upgrade notice message ( update option in DB )
229
- */
230
- function hide_wcml_translations_message(){
231
- $nonce = filter_input( INPUT_POST, 'wcml_nonce', FILTER_SANITIZE_FULL_SPECIAL_CHARS );
232
- if(!$nonce || !wp_verify_nonce($nonce, 'hide_wcml_translations_message' ) ){
233
- die('Invalid nonce');
234
- }
235
- update_option( 'hide_wcml_translations_message', true );
236
 
237
- die();
238
- }
239
 
240
- public function load_js(){
 
241
 
242
- wp_register_script( 'wcml-lang-notice', WCML_PLUGIN_URL . '/res/js/languages_notice' . WCML_JS_MIN . '.js', array( 'jquery' ), WCML_VERSION, true );
243
- wp_enqueue_script( 'wcml-lang-notice');
 
 
 
 
 
244
 
245
- wp_localize_script( 'wcml-lang-notice', 'wcml_language_upgrade_notices',
246
- array(
247
- 'dont_close' => esc_html__( "Downloading translations... Please don't close this page.", 'woocommerce-multilingual' )
248
- )
249
- );
250
-
251
- }
252
 
253
  }
1
  <?php
2
 
3
+ class WCML_Languages_Upgrader {
4
 
5
 
6
 
7
+ public function __construct() {
8
 
9
+ add_action( 'icl_update_active_languages', [ $this, 'download_woocommerce_translations_for_active_languages' ] );
10
+ add_filter( 'upgrader_pre_download', [ $this, 'version_update' ], 10, 2 );
11
+ add_action( 'admin_notices', [ $this, 'translation_upgrade_notice' ] );
12
+ add_action( 'wp_ajax_hide_wcml_translations_message', [ $this, 'hide_wcml_translations_message' ] );
13
 
14
+ $this->load_js();
15
+ }
16
 
17
+ /**
18
+ * Automatically download translations for WC ( when user install WCML ( from 3.3.3) / add new language in WPML )
19
+ *
20
+ * @param string $lang_code Language code
21
+ */
22
+ public function download_woocommerce_translations( $lang_code, $wc_version ) {
23
+ global $sitepress;
 
24
 
25
+ $locale = $sitepress->get_locale( $lang_code );
26
 
27
+ if ( $locale !== 'en_US' && $this->has_available_update( $locale, $wc_version ) ) {
28
 
29
+ $wc_version = $wc_version ? $wc_version : WC_VERSION;
30
 
31
+ include_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php';
32
+ require_once ABSPATH . 'wp-admin/includes/file.php';
33
+ require_once ABSPATH . 'wp-admin/includes/plugin.php';
34
+ require_once ABSPATH . 'wp-admin/includes/template.php';
35
 
36
+ $url = 'update-core.php?action=do-translation-upgrade';
37
+ $nonce = 'upgrade-translations';
38
+ $title = '';
39
+ $context = WP_LANG_DIR;
40
 
41
+ $upgrader = new Language_Pack_Upgrader( new Automatic_Upgrader_Skin( compact( 'url', 'nonce', 'title', 'context' ) ) ); // use Language_Pack_Upgrader_Skin instead of Automatic_Upgrader_Skin to display upgrade process.
42
 
43
+ $upgr_object = [];
44
+ $upgr_object[0] = new stdClass();
45
+ $upgr_object[0]->type = 'plugin';
46
+ $upgr_object[0]->slug = 'woocommerce';
47
+ $upgr_object[0]->language = $locale;
48
+ $upgr_object[0]->version = $wc_version;
49
+ $upgr_object[0]->updated = date( 'Y-m-d H:i:s' );
50
+ $upgr_object[0]->package = $this->get_language_pack_uri( $locale, $wc_version );
51
+ $upgr_object[0]->autoupdate = 1;
52
 
53
+ $ob_level_before = ob_get_level();
54
 
55
+ $upgrader->bulk_upgrade( $upgr_object );
56
 
57
+ // Close a potential unclosed output buffer.
58
+ $ob_level_after = ob_get_level();
59
+ if ( $ob_level_after > $ob_level_before ) {
60
+ ob_end_clean();
61
+ }
62
 
63
+ $this->save_translation_version( $locale, false, $wc_version );
64
+ }
65
 
66
+ }
 
67
 
 
68
 
69
+ /*
70
+ * Automatically download translations for WC for active languages
71
+ *
72
+ */
73
+ public function download_woocommerce_translations_for_active_languages( $wc_version = false ) {
74
+ global $sitepress, $woocommerce_wpml;
75
 
76
+ $active_languages = $sitepress->get_active_languages();
 
 
 
 
 
77
 
78
+ $current_language = $sitepress->get_current_language();
79
 
80
+ foreach ( $active_languages as $language ) {
81
 
82
+ $this->download_woocommerce_translations( $language['code'], $wc_version );
83
 
84
+ }
85
 
86
+ $sitepress->switch_lang( $current_language );
87
 
88
+ if ( isset( $woocommerce_wpml->url_translation ) ) {
89
+ $woocommerce_wpml->url_translation->register_product_and_taxonomy_bases();
90
+ }
91
 
92
+ }
 
 
93
 
94
+ public function get_language_pack_uri( $locale, $version = false ) {
95
 
96
+ if ( ! $version ) {
97
+ $version = WC_VERSION;
98
+ }
99
 
100
+ $repo = 'https://downloads.wordpress.org/translation/plugin/woocommerce/';
101
+ return $repo . $version . '/' . $locale . '.zip';
102
+ }
103
 
104
+ /*
105
+ * Update the WC language version in database
106
+ *
107
+ *
108
+ * @param bool $reply Whether to bail without returning the package (default: false)
109
+ * @param string $package Package URL
110
+ *
111
+ * @return bool
112
+ */
113
+ public function version_update( $reply, $package ) {
114
 
115
+ $notices = maybe_unserialize( get_option( 'wcml_translations_upgrade_notice' ) );
 
 
 
 
 
 
 
 
 
116
 
117
+ if ( ! is_array( $notices ) ) {
118
+ return $reply;
119
+ }
120
 
121
+ foreach ( $notices as $key => $locale ) {
122
+ if ( strstr( $package, 'woocommerce' ) && strstr( $package, $locale ) ) {
 
123
 
124
+ $this->save_translation_version( $locale, $key );
 
125
 
126
+ }
127
+ }
128
 
129
+ return $reply;
130
+ }
131
 
 
 
132
 
133
+ public function save_translation_version( $locale, $key = false, $wc_version = false ) {
134
 
135
+ $notices = maybe_unserialize( get_option( 'wcml_translations_upgrade_notice' ) );
136
 
137
+ // Update the language pack version.
138
+ update_option( 'woocommerce_language_pack_version_' . $locale, [ $wc_version ? $wc_version : WC_VERSION, $locale ] );
139
 
140
+ if ( is_array( $notices ) ) {
 
141
 
142
+ if ( ! $key ) {
143
+ $key = array_search( $locale, $notices );
144
+ }
145
 
146
+ // Remove the translation upgrade notice.
147
+ unset( $notices[ $key ] );
148
 
149
+ update_option( 'wcml_translations_upgrade_notice', $notices );
 
150
 
151
+ }
152
 
153
+ }
154
 
155
+ /*
156
+ * Check if has available translation update
157
+ *
158
+ * @param string $locale Locale code
159
+ *
160
+ * @return bool
161
+ */
162
+ public function has_available_update( $locale, $wc_version = false ) {
163
+ $wc_version = $wc_version ? $wc_version : WC_VERSION;
164
 
165
+ $version = get_option( 'woocommerce_language_pack_version_' . $locale, [ '0', $locale ] );
 
 
 
 
 
 
 
 
166
 
167
+ $is_new_version = ! is_array( $version ) || version_compare( $version[0], $wc_version, '<' ) || $version[1] !== $locale;
168
+ $mo_file_absent = ! file_exists( sprintf( WP_LANG_DIR . '/plugins/woocommerce-%s.mo', $locale ) );
169
 
170
+ $notices = maybe_unserialize( get_option( 'wcml_translations_upgrade_notice' ) );
 
171
 
172
+ if ( 'en_US' !== $locale && ( $is_new_version || $mo_file_absent ) ) {
173
+ if ( $this->check_if_language_pack_exists( $locale, $wc_version ) ) {
174
 
175
+ if ( ! $notices || ! in_array( $locale, $notices ) ) {
176
+ $notices[] = $locale;
177
 
178
+ update_option( 'wcml_translations_upgrade_notice', $notices );
179
+ update_option( 'hide_wcml_translations_message', 0 );
180
+ }
181
 
182
+ return true;
183
+ } else {
184
+ // Updated the woocommerce_language_pack_version to avoid searching translations for this release again.
185
+ update_option( 'woocommerce_language_pack_version_' . $locale, [ $wc_version, $locale ] );
186
+ }
187
+ }
188
 
189
+ return false;
190
+ }
 
 
 
 
191
 
 
 
192
 
193
+ /**
194
+ * Check if language pack exists
195
+ *
196
+ * @return bool
197
+ */
198
+ public function check_if_language_pack_exists( $locale, $wc_version ) {
199
 
200
+ $response = wp_safe_remote_get( $this->get_language_pack_uri( $locale, $wc_version ), [ 'timeout' => 60 ] );
 
 
 
 
 
201
 
202
+ if ( ! is_wp_error( $response ) && $response['response']['code'] >= 200 && $response['response']['code'] < 300 && $response['body'] !== '404 File not found' ) {
203
+ return true;
204
+ } else {
205
+ return false;
206
+ }
207
+ }
208
 
 
 
 
 
 
 
209
 
210
+ /*
211
+ * Display Translations upgrade notice message
212
+ */
213
+ public function translation_upgrade_notice() {
214
+ global $woocommerce_wpml;
215
 
216
+ $screen = get_current_screen();
217
+ $notices = maybe_unserialize( get_option( 'wcml_translations_upgrade_notice' ) );
 
 
 
218
 
219
+ if ( 'update-core' !== $screen->id && ! empty( $notices ) && ! get_option( 'hide_wcml_translations_message' ) ) {
 
220
 
221
+ $lang_notices = new WCML_Languages_Upgrade_Notice( $notices );
222
+ $lang_notices->show();
223
+ }
224
+ }
225
 
226
+ /*
227
+ * Hide Translations upgrade notice message ( update option in DB )
228
+ */
229
+ public function hide_wcml_translations_message() {
230
+ $nonce = filter_input( INPUT_POST, 'wcml_nonce', FILTER_SANITIZE_FULL_SPECIAL_CHARS );
231
+ if ( ! $nonce || ! wp_verify_nonce( $nonce, 'hide_wcml_translations_message' ) ) {
232
+ die( 'Invalid nonce' );
233
+ }
234
+ update_option( 'hide_wcml_translations_message', true );
235
 
236
+ die();
237
+ }
 
 
 
 
 
 
 
238
 
239
+ public function load_js() {
 
240
 
241
+ wp_register_script( 'wcml-lang-notice', WCML_PLUGIN_URL . '/res/js/languages_notice' . WCML_JS_MIN . '.js', [ 'jquery' ], WCML_VERSION, true );
242
+ wp_enqueue_script( 'wcml-lang-notice' );
243
 
244
+ wp_localize_script(
245
+ 'wcml-lang-notice',
246
+ 'wcml_language_upgrade_notices',
247
+ [
248
+ 'dont_close' => esc_html__( "Downloading translations... Please don't close this page.", 'woocommerce-multilingual' ),
249
+ ]
250
+ );
251
 
252
+ }
 
 
 
 
 
 
253
 
254
  }
inc/class-wcml-locale.php CHANGED
@@ -1,9 +1,9 @@
1
  <?php
2
 
3
- class WCML_Locale{
4
 
5
- private $woocommerce_wpml;
6
- private $sitepress;
7
 
8
  /**
9
  * WCML_Locale constructor.
@@ -20,37 +20,46 @@ class WCML_Locale{
20
  add_filter( 'locale', [ $this, 'update_product_action_locale_check' ] );
21
  }
22
 
23
- function load_locale() {
24
- return load_plugin_textdomain( 'woocommerce-multilingual', false, WCML_PLUGIN_FOLDER.'/locale' );
25
- }
26
-
27
- public function switch_locale( $lang_code = false ) {
28
- global $l10n, $st_gettext_hooks;
29
- static $original_l10n;
30
- if ( ! empty( $lang_code ) ) {
31
-
32
- if ( null !== $st_gettext_hooks ) {
33
- $st_gettext_hooks->switch_language_hook( $lang_code );
34
- }
35
-
36
- $original_l10n = isset( $l10n[ 'woocommerce-multilingual' ] ) ? $l10n[ 'woocommerce-multilingual' ] : null;
37
- if ( $original_l10n !== null ) {
38
- unset( $l10n[ 'woocommerce-multilingual' ] );
39
- }
40
-
41
- return load_textdomain( 'woocommerce-multilingual',
42
- WCML_LOCALE_PATH . '/woocommerce-multilingual-' . $this->sitepress->get_locale( $lang_code ) . '.mo' );
43
-
44
- } else { // switch back
45
- $l10n[ 'woocommerce-multilingual' ] = $original_l10n;
46
- }
47
- }
48
-
49
- /* Change locale to saving language - needs for sanitize_title exception wcml-390 */
50
- public function update_product_action_locale_check( $locale ){
51
- if( isset($_POST['action']) && $_POST['action'] == 'wpml_translation_dialog_save_job' ){
52
- return $this->sitepress->get_locale( $_POST[ 'job_details' ][ 'target' ] );
53
- }
54
- return $locale;
55
- }
56
- }
 
 
 
 
 
 
 
 
 
1
  <?php
2
 
3
+ class WCML_Locale {
4
 
5
+ private $woocommerce_wpml;
6
+ private $sitepress;
7
 
8
  /**
9
  * WCML_Locale constructor.
20
  add_filter( 'locale', [ $this, 'update_product_action_locale_check' ] );
21
  }
22
 
23
+ public function load_locale() {
24
+ return load_plugin_textdomain( 'woocommerce-multilingual', false, WCML_PLUGIN_FOLDER . '/locale' );
25
+ }
26
+
27
+ public function switch_locale( $lang_code = false ) {
28
+ global $l10n, $st_gettext_hooks;
29
+ static $original_l10n;
30
+
31
+ if ( ! empty( $lang_code ) ) {
32
+ if ( null !== $st_gettext_hooks ) {
33
+ $st_gettext_hooks->switch_language_hook( $lang_code );
34
+ }
35
+
36
+ $original_l10n = isset( $l10n['woocommerce-multilingual'] ) ? $l10n['woocommerce-multilingual'] : null;
37
+ if ( null !== $original_l10n ) {
38
+ unset( $l10n['woocommerce-multilingual'] );
39
+ }
40
+
41
+ return load_textdomain(
42
+ 'woocommerce-multilingual',
43
+ WCML_LOCALE_PATH . '/woocommerce-multilingual-' . $this->sitepress->get_locale( $lang_code ) . '.mo'
44
+ );
45
+
46
+ } else { // Switch back.
47
+ // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited
48
+ $l10n['woocommerce-multilingual'] = $original_l10n;
49
+ }
50
+ }
51
+
52
+ /**
53
+ * Change locale to saving language - needs for sanitize_title exception wcml-390
54
+ *
55
+ * @param string $locale
56
+ *
57
+ * @return false|string
58
+ */
59
+ public function update_product_action_locale_check( $locale ) {
60
+ if ( isset( $_POST['action'] ) && 'wpml_translation_dialog_save_job' === $_POST['action'] ) {
61
+ return $this->sitepress->get_locale( $_POST['job_details']['target'] );
62
+ }
63
+ return $locale;
64
+ }
65
+ }
inc/class-wcml-orders.php CHANGED
@@ -3,100 +3,57 @@
3
  class WCML_Orders {
4
 
5
  const DASHBOARD_COOKIE_NAME = '_wcml_dashboard_order_language';
6
- const COOKIE_TTL = 86400;
7
 
8
  private $woocommerce_wpml;
9
  private $sitepress;
10
 
11
- private $standard_order_notes = array(
12
- 'Order status changed from %s to %s.',
13
- 'Order item stock reduced successfully.',
14
- 'Item #%s stock reduced from %s to %s.',
15
- 'Item #%s stock increased from %s to %s.',
16
- 'Awaiting BACS payment',
17
- 'Awaiting cheque payment',
18
- 'Payment to be made upon delivery.',
19
- 'Validation error: PayPal amounts do not match (gross %s).',
20
- 'Validation error: PayPal IPN response from a different email address (%s).',
21
- 'Payment pending: %s',
22
- 'Payment %s via IPN.',
23
- 'Validation error: PayPal amounts do not match (amt %s).',
24
- 'IPN payment completed',
25
- 'PDT payment completed'
26
- );
27
-
28
  public function __construct( $woocommerce_wpml, $sitepress ) {
29
  $this->woocommerce_wpml = $woocommerce_wpml;
30
  $this->sitepress = $sitepress;
31
 
32
- add_action( 'init', array( $this, 'init' ) );
33
 
34
- //checkout page
35
- add_action( 'wp_ajax_woocommerce_checkout', array( $this, 'switch_to_current' ), 9 );
36
- add_action( 'wp_ajax_nopriv_woocommerce_checkout', array( $this, 'switch_to_current' ), 9 );
37
 
38
- add_action( 'wp_ajax_wcml_order_delete_items', array( $this, 'order_delete_items' ) );
39
  }
40
 
41
- function init() {
42
-
43
- add_action( 'woocommerce_checkout_update_order_meta', array( $this, 'set_order_language' ) );
44
-
45
- add_filter( 'icl_lang_sel_copy_parameters', array( $this, 'append_query_parameters' ) );
46
-
47
- add_filter( 'the_comments', array( $this, 'get_filtered_comments' ) );
48
-
49
- if ( $this->should_attach_new_order_note_data_filter() ) {
50
- add_filter( 'gettext', array( $this, 'filtered_woocommerce_new_order_note_data' ), 10, 3 );
51
- }
52
-
53
- add_filter( 'woocommerce_order_get_items', array( $this, 'woocommerce_order_get_items' ), 10, 2 );
54
-
55
- add_action( 'woocommerce_process_shop_order_meta', array( $this, 'set_order_language_backend' ), 10, 2 );
56
- add_action( 'woocommerce_order_actions_start', array(
57
- $this,
58
- 'order_language_dropdown'
59
- ), 11 ); //after order currency drop-down
60
-
61
- add_action( 'woocommerce_before_order_itemmeta', array( $this, 'backend_before_order_itemmeta' ), 100, 3 );
62
- add_action( 'woocommerce_after_order_itemmeta', array( $this, 'backend_after_order_itemmeta' ), 100, 3 );
63
 
64
- add_filter( 'woocommerce_get_item_downloads', array( $this, 'filter_downloadable_product_items' ), 10, 3 );
65
- add_filter( 'woocommerce_customer_get_downloadable_products', array(
66
- $this,
67
- 'filter_customer_get_downloadable_products'
68
- ), 10, 3 );
69
- }
70
-
71
- public function should_attach_new_order_note_data_filter() {
72
- $admin_language = $this->sitepress->get_user_admin_language( get_current_user_id(), true );
73
- $all_strings_in_english = get_option( 'wpml-st-all-strings-are-in-english' );
74
 
75
- return 'en' !== $admin_language || ! $all_strings_in_english;
76
- }
77
 
78
- function filtered_woocommerce_new_order_note_data( $translations, $text, $domain ) {
79
- if ( in_array( $text, $this->standard_order_notes ) ) {
80
 
81
- $language = $this->woocommerce_wpml->strings->get_string_language( $text, 'woocommerce' );
 
 
 
 
 
82
 
83
- if ( $this->sitepress->get_user_admin_language( get_current_user_id(), true ) != $language ) {
 
84
 
85
- $string_id = icl_get_string_id( $text, 'woocommerce' );
86
- $strings = icl_get_string_translations_by_id( $string_id );
87
- if ( $strings ) {
88
- $translations = $strings[ $this->sitepress->get_user_admin_language( get_current_user_id(), true ) ]['value'];
89
- }
 
 
90
 
91
- } else {
92
- return $text;
93
- }
94
  }
95
-
96
- return $translations;
97
  }
98
 
99
- function get_filtered_comments( $comments ) {
100
 
101
  $user_id = get_current_user_id();
102
 
@@ -114,7 +71,6 @@ class WCML_Orders {
114
  }
115
  }
116
  }
117
-
118
  }
119
 
120
  return $comments;
@@ -133,12 +89,12 @@ class WCML_Orders {
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
 
@@ -171,7 +127,7 @@ class WCML_Orders {
171
 
172
  /**
173
  * @param WC_Order_Item_Product $item
174
- * @param string $language_to_filter
175
  */
176
  private function adjust_product_item_if_translated( $item, $language_to_filter ) {
177
 
@@ -198,7 +154,7 @@ class WCML_Orders {
198
 
199
  /**
200
  * @param WC_Order_Item_Product $item
201
- * @param string $language_to_filter
202
  */
203
  private function adjust_variation_item_if_translated( $item, $language_to_filter ) {
204
  $translated_variation_id = apply_filters( 'translate_object_id', $item->get_variation_id(), 'product_variation', false, $language_to_filter );
@@ -239,16 +195,14 @@ class WCML_Orders {
239
  * @return bool
240
  */
241
  private function is_order_action_triggered_for_customer() {
242
- return isset( $_GET['action'] ) && wpml_collect( [
243
- 'woocommerce_mark_order_complete',
244
- 'woocommerce_mark_order_status',
245
- 'mark_processing'
246
- ] )->contains( $_GET['action'] );
247
  }
248
 
249
  /**
250
  * @param WC_Order_Item_Product $item
251
- * @param int $variation_id
252
  */
253
  private function update_attribute_item_meta_value( $item, $variation_id ) {
254
  foreach ( $item->get_meta_data() as $meta_data ) {
@@ -265,7 +219,7 @@ class WCML_Orders {
265
 
266
  if ( $this->get_order_language_by_item_id( $item_id ) != $sitepress->get_user_admin_language( get_current_user_id(), true ) ) {
267
  foreach ( $item['item_meta'] as $key => $item_meta ) {
268
- if ( taxonomy_exists( wc_attribute_taxonomy_name( $key ) ) || substr( $key, 0, 3 ) == 'pa_' ) {
269
  $item_meta = (array) $item_meta;
270
  foreach ( $item_meta as $value ) {
271
  $this->force_update_itemmeta( $item_id, $key, $value, $sitepress->get_user_admin_language( get_current_user_id(), true ) );
@@ -281,7 +235,7 @@ class WCML_Orders {
281
  $order_languge = $this->get_order_language_by_item_id( $item_id );
282
  if ( $order_languge != $sitepress->get_user_admin_language( get_current_user_id(), true ) ) {
283
  foreach ( $item['item_meta'] as $key => $item_meta ) {
284
- if ( taxonomy_exists( wc_attribute_taxonomy_name( $key ) ) || substr( $key, 0, 3 ) == 'pa_' ) {
285
  $item_meta = (array) $item_meta;
286
  foreach ( $item_meta as $value ) {
287
  $this->force_update_itemmeta( $item_id, $key, $value, $order_languge );
@@ -299,20 +253,24 @@ class WCML_Orders {
299
  return get_post_meta( $order_id, 'wpml_language', true );
300
  }
301
 
302
- //force update to display attribute in correct language on edit order page
303
  public function force_update_itemmeta( $item_id, $key, $value, $languge ) {
304
  global $wpdb, $woocommerce_wpml;
305
 
306
- $taxonomy = substr( $key, 0, 3 ) != 'pa_' ? wc_attribute_taxonomy_name( $key ) : $key;
307
  $term_id = $woocommerce_wpml->terms->wcml_get_term_id_by_slug( $taxonomy, $value );
308
  $translated_term = $woocommerce_wpml->terms->wcml_get_translated_term( $term_id, $taxonomy, $languge );
309
 
310
  if ( $translated_term ) {
311
  $value = $translated_term->slug;
312
- $wpdb->update( $wpdb->prefix . 'woocommerce_order_itemmeta', array( 'meta_value' => $value ), array(
313
- 'order_item_id' => $item_id,
314
- 'meta_key' => $key
315
- ) );
 
 
 
 
316
  }
317
  }
318
 
@@ -321,13 +279,13 @@ class WCML_Orders {
321
  *
322
  * @param type $order_id
323
  */
324
- function set_order_language( $order_id ) {
325
  if ( ! get_post_meta( $order_id, 'wpml_language' ) ) {
326
  update_post_meta( $order_id, 'wpml_language', ICL_LANGUAGE_CODE );
327
  }
328
  }
329
 
330
- function append_query_parameters( $parameters ) {
331
 
332
  if ( is_order_received_page() || is_checkout() ) {
333
  if ( ! in_array( 'order', $parameters ) ) {
@@ -341,40 +299,45 @@ class WCML_Orders {
341
  return $parameters;
342
  }
343
 
344
- function switch_to_current() {
345
  $this->woocommerce_wpml->emails->change_email_language( $this->sitepress->get_current_language() );
346
  }
347
 
348
- function order_language_dropdown( $order_id ) {
349
  if ( ! get_post_meta( $order_id, '_order_currency' ) ) {
350
- $languages = apply_filters( 'wpml_active_languages', array(), array(
351
- 'skip_missing' => 0,
352
- 'orderby' => 'code'
353
- ) );
 
 
 
 
354
  $selected_lang = isset( $_COOKIE [ self::DASHBOARD_COOKIE_NAME ] ) ? $_COOKIE [ self::DASHBOARD_COOKIE_NAME ] : $this->sitepress->get_default_language();
355
  ?>
356
- <li class="wide">
357
- <label><?php _e( 'Order language:' ); ?></label>
358
- <select id="dropdown_shop_order_language" name="wcml_shop_order_language">
359
- <?php if ( ! empty( $languages ) ): ?>
360
 
361
- <?php foreach ( $languages as $l ): ?>
362
 
363
- <option
364
- value="<?php echo $l['language_code'] ?>" <?php echo $selected_lang == $l['language_code'] ? 'selected="selected"' : ''; ?>><?php echo $l['translated_name']; ?></option>
365
 
366
  <?php endforeach; ?>
367
 
368
  <?php endif; ?>
369
- </select>
370
- </li>
371
  <?php
372
  $wcml_set_dashboard_order_language_nonce = wp_create_nonce( 'set_dashboard_order_language' );
373
- wc_enqueue_js( "
 
374
  var order_lang_current_value = jQuery('#dropdown_shop_order_language option:selected').val();
375
 
376
  jQuery('#dropdown_shop_order_language').on('change', function(){
377
- if(confirm('" . esc_js( __( "All the products will be removed from the current order in order to change the language", 'woocommerce-multilingual' ) ) . "')){
378
  var lang = jQuery(this).val();
379
 
380
  jQuery.ajax({
@@ -396,27 +359,43 @@ class WCML_Orders {
396
  }
397
  });
398
 
399
- " );
 
400
  } else {
401
  $this->remove_dashboard_order_language_cookie();
402
  }
403
  }
404
 
405
- function order_delete_items() {
406
  $nonce = filter_input( INPUT_POST, 'wcml_nonce', FILTER_SANITIZE_FULL_SPECIAL_CHARS );
407
  if ( ! $nonce || ! wp_verify_nonce( $nonce, 'set_dashboard_order_language' ) ) {
408
- echo json_encode( array( 'error' => __( 'Invalid nonce', 'woocommerce-multilingual' ) ) );
409
  die();
410
  }
411
 
412
- setcookie( self::DASHBOARD_COOKIE_NAME, filter_input( INPUT_POST, 'lang', FILTER_SANITIZE_FULL_SPECIAL_CHARS ), time() + self::COOKIE_TTL, COOKIEPATH, COOKIE_DOMAIN );
 
 
 
 
413
  }
414
 
415
  private function remove_dashboard_order_language_cookie() {
416
  setcookie( self::DASHBOARD_COOKIE_NAME, '', time() - self::COOKIE_TTL, COOKIEPATH, COOKIE_DOMAIN );
417
  }
418
 
419
- function set_order_language_backend( $post_id, $post ) {
 
 
 
 
 
 
 
 
 
 
 
420
 
421
  if ( isset( $_POST['wcml_shop_order_language'] ) ) {
422
  update_post_meta( $post_id, 'wpml_language', filter_input( INPUT_POST, 'wcml_shop_order_language', FILTER_SANITIZE_FULL_SPECIAL_CHARS ) );
@@ -430,21 +409,21 @@ class WCML_Orders {
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 );
444
 
445
  $files = $item->get_item_downloads();
446
 
447
- add_filter( 'woocommerce_get_item_downloads', array( $this, 'filter_downloadable_product_items' ), 10, 3 );
448
 
449
  return $files;
450
  }
@@ -458,7 +437,6 @@ class WCML_Orders {
458
  if ( $translated_id ) {
459
  $downloads[ $key ]['product_name'] = get_the_title( $translated_id );
460
  }
461
-
462
  }
463
 
464
  return $downloads;
3
  class WCML_Orders {
4
 
5
  const DASHBOARD_COOKIE_NAME = '_wcml_dashboard_order_language';
6
+ const COOKIE_TTL = 86400;
7
 
8
  private $woocommerce_wpml;
9
  private $sitepress;
10
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
11
  public function __construct( $woocommerce_wpml, $sitepress ) {
12
  $this->woocommerce_wpml = $woocommerce_wpml;
13
  $this->sitepress = $sitepress;
14
 
15
+ add_action( 'init', [ $this, 'init' ] );
16
 
17
+ // Checkout page.
18
+ add_action( 'wp_ajax_woocommerce_checkout', [ $this, 'switch_to_current' ], 9 );
19
+ add_action( 'wp_ajax_nopriv_woocommerce_checkout', [ $this, 'switch_to_current' ], 9 );
20
 
21
+ add_action( 'wp_ajax_wcml_order_delete_items', [ $this, 'order_delete_items' ] );
22
  }
23
 
24
+ public function init() {
25
+ add_action( 'woocommerce_checkout_update_order_meta', [ $this, 'set_order_language' ] );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
26
 
27
+ add_filter( 'icl_lang_sel_copy_parameters', [ $this, 'append_query_parameters' ] );
 
 
 
 
 
 
 
 
 
28
 
29
+ add_filter( 'the_comments', [ $this, 'get_filtered_comments' ] );
 
30
 
31
+ add_filter( 'woocommerce_order_get_items', [ $this, 'woocommerce_order_get_items' ], 10, 2 );
 
32
 
33
+ add_action( 'woocommerce_process_shop_order_meta', [ $this, 'set_order_language_backend' ], 10, 2 );
34
+ add_action(
35
+ 'woocommerce_order_actions_start',
36
+ [ $this, 'order_language_dropdown' ],
37
+ 11
38
+ ); // After order currency drop-down.
39
 
40
+ add_action( 'woocommerce_before_order_itemmeta', [ $this, 'backend_before_order_itemmeta' ], 100, 3 );
41
+ add_action( 'woocommerce_after_order_itemmeta', [ $this, 'backend_after_order_itemmeta' ], 100, 3 );
42
 
43
+ add_filter( 'woocommerce_get_item_downloads', [ $this, 'filter_downloadable_product_items' ], 10, 3 );
44
+ add_filter(
45
+ 'woocommerce_customer_get_downloadable_products',
46
+ [ $this, 'filter_customer_get_downloadable_products' ],
47
+ 10,
48
+ 3
49
+ );
50
 
51
+ if ( is_admin() ) {
52
+ $this->maybe_set_dashboard_cookie();
 
53
  }
 
 
54
  }
55
 
56
+ public function get_filtered_comments( $comments ) {
57
 
58
  $user_id = get_current_user_id();
59
 
71
  }
72
  }
73
  }
 
74
  }
75
 
76
  return $comments;
89
  }
90
 
91
  /**
92
+ * @param array $items
93
  * @param string|bool $language_to_filter
94
  */
95
  public function adjust_order_item_in_language( $items, $language_to_filter = false ) {
96
 
97
+ if ( ! $language_to_filter ) {
98
  $language_to_filter = $this->sitepress->get_current_language();
99
  }
100
 
127
 
128
  /**
129
  * @param WC_Order_Item_Product $item
130
+ * @param string $language_to_filter
131
  */
132
  private function adjust_product_item_if_translated( $item, $language_to_filter ) {
133
 
154
 
155
  /**
156
  * @param WC_Order_Item_Product $item
157
+ * @param string $language_to_filter
158
  */
159
  private function adjust_variation_item_if_translated( $item, $language_to_filter ) {
160
  $translated_variation_id = apply_filters( 'translate_object_id', $item->get_variation_id(), 'product_variation', false, $language_to_filter );
195
  * @return bool
196
  */
197
  private function is_order_action_triggered_for_customer() {
198
+ return isset( $_GET['action'] ) && wpml_collect(
199
+ [ 'woocommerce_mark_order_complete', 'woocommerce_mark_order_status', 'mark_processing' ]
200
+ )->contains( $_GET['action'] );
 
 
201
  }
202
 
203
  /**
204
  * @param WC_Order_Item_Product $item
205
+ * @param int $variation_id
206
  */
207
  private function update_attribute_item_meta_value( $item, $variation_id ) {
208
  foreach ( $item->get_meta_data() as $meta_data ) {
219
 
220
  if ( $this->get_order_language_by_item_id( $item_id ) != $sitepress->get_user_admin_language( get_current_user_id(), true ) ) {
221
  foreach ( $item['item_meta'] as $key => $item_meta ) {
222
+ if ( taxonomy_exists( wc_attribute_taxonomy_name( $key ) ) || substr( $key, 0, 3 ) === 'pa_' ) {
223
  $item_meta = (array) $item_meta;
224
  foreach ( $item_meta as $value ) {
225
  $this->force_update_itemmeta( $item_id, $key, $value, $sitepress->get_user_admin_language( get_current_user_id(), true ) );
235
  $order_languge = $this->get_order_language_by_item_id( $item_id );
236
  if ( $order_languge != $sitepress->get_user_admin_language( get_current_user_id(), true ) ) {
237
  foreach ( $item['item_meta'] as $key => $item_meta ) {
238
+ if ( taxonomy_exists( wc_attribute_taxonomy_name( $key ) ) || substr( $key, 0, 3 ) === 'pa_' ) {
239
  $item_meta = (array) $item_meta;
240
  foreach ( $item_meta as $value ) {
241
  $this->force_update_itemmeta( $item_id, $key, $value, $order_languge );
253
  return get_post_meta( $order_id, 'wpml_language', true );
254
  }
255
 
256
+ // force update to display attribute in correct language on edit order page.
257
  public function force_update_itemmeta( $item_id, $key, $value, $languge ) {
258
  global $wpdb, $woocommerce_wpml;
259
 
260
+ $taxonomy = substr( $key, 0, 3 ) !== 'pa_' ? wc_attribute_taxonomy_name( $key ) : $key;
261
  $term_id = $woocommerce_wpml->terms->wcml_get_term_id_by_slug( $taxonomy, $value );
262
  $translated_term = $woocommerce_wpml->terms->wcml_get_translated_term( $term_id, $taxonomy, $languge );
263
 
264
  if ( $translated_term ) {
265
  $value = $translated_term->slug;
266
+ $wpdb->update(
267
+ $wpdb->prefix . 'woocommerce_order_itemmeta',
268
+ [ 'meta_value' => $value ],
269
+ [
270
+ 'order_item_id' => $item_id,
271
+ 'meta_key' => $key,
272
+ ]
273
+ );
274
  }
275
  }
276
 
279
  *
280
  * @param type $order_id
281
  */
282
+ public function set_order_language( $order_id ) {
283
  if ( ! get_post_meta( $order_id, 'wpml_language' ) ) {
284
  update_post_meta( $order_id, 'wpml_language', ICL_LANGUAGE_CODE );
285
  }
286
  }
287
 
288
+ public function append_query_parameters( $parameters ) {
289
 
290
  if ( is_order_received_page() || is_checkout() ) {
291
  if ( ! in_array( 'order', $parameters ) ) {
299
  return $parameters;
300
  }
301
 
302
+ public function switch_to_current() {
303
  $this->woocommerce_wpml->emails->change_email_language( $this->sitepress->get_current_language() );
304
  }
305
 
306
+ public function order_language_dropdown( $order_id ) {
307
  if ( ! get_post_meta( $order_id, '_order_currency' ) ) {
308
+ $languages = apply_filters(
309
+ 'wpml_active_languages',
310
+ [],
311
+ [
312
+ 'skip_missing' => 0,
313
+ 'orderby' => 'code',
314
+ ]
315
+ );
316
  $selected_lang = isset( $_COOKIE [ self::DASHBOARD_COOKIE_NAME ] ) ? $_COOKIE [ self::DASHBOARD_COOKIE_NAME ] : $this->sitepress->get_default_language();
317
  ?>
318
+ <li class="wide">
319
+ <label><?php _e( 'Order language:' ); ?></label>
320
+ <select id="dropdown_shop_order_language" name="wcml_shop_order_language">
321
+ <?php if ( ! empty( $languages ) ) : ?>
322
 
323
+ <?php foreach ( $languages as $l ) : ?>
324
 
325
+ <option
326
+ value="<?php echo $l['language_code']; ?>" <?php echo $selected_lang == $l['language_code'] ? 'selected="selected"' : ''; ?>><?php echo $l['translated_name']; ?></option>
327
 
328
  <?php endforeach; ?>
329
 
330
  <?php endif; ?>
331
+ </select>
332
+ </li>
333
  <?php
334
  $wcml_set_dashboard_order_language_nonce = wp_create_nonce( 'set_dashboard_order_language' );
335
+ wc_enqueue_js(
336
+ "
337
  var order_lang_current_value = jQuery('#dropdown_shop_order_language option:selected').val();
338
 
339
  jQuery('#dropdown_shop_order_language').on('change', function(){
340
+ if(confirm('" . esc_js( __( 'All the products will be removed from the current order in order to change the language', 'woocommerce-multilingual' ) ) . "')){
341
  var lang = jQuery(this).val();
342
 
343
  jQuery.ajax({
359
  }
360
  });
361
 
362
+ "
363
+ );
364
  } else {
365
  $this->remove_dashboard_order_language_cookie();
366
  }
367
  }
368
 
369
+ public function order_delete_items() {
370
  $nonce = filter_input( INPUT_POST, 'wcml_nonce', FILTER_SANITIZE_FULL_SPECIAL_CHARS );
371
  if ( ! $nonce || ! wp_verify_nonce( $nonce, 'set_dashboard_order_language' ) ) {
372
+ echo json_encode( [ 'error' => __( 'Invalid nonce', 'woocommerce-multilingual' ) ] );
373
  die();
374
  }
375
 
376
+ $this->set_dashboard_order_language_cookie( filter_input( INPUT_POST, 'lang', FILTER_SANITIZE_FULL_SPECIAL_CHARS ) );
377
+ }
378
+
379
+ private function set_dashboard_order_language_cookie( $language ) {
380
+ setcookie( self::DASHBOARD_COOKIE_NAME, $language, time() + self::COOKIE_TTL, COOKIEPATH, COOKIE_DOMAIN );
381
  }
382
 
383
  private function remove_dashboard_order_language_cookie() {
384
  setcookie( self::DASHBOARD_COOKIE_NAME, '', time() - self::COOKIE_TTL, COOKIEPATH, COOKIE_DOMAIN );
385
  }
386
 
387
+ private function maybe_set_dashboard_cookie() {
388
+ global $pagenow;
389
+
390
+ if (
391
+ ! isset( $_COOKIE [ self::DASHBOARD_COOKIE_NAME ] ) &&
392
+ ( 'post-new.php' === $pagenow && isset( $_GET['post_type'] ) && 'shop_order' === $_GET['post_type'] )
393
+ ) {
394
+ $this->set_dashboard_order_language_cookie( $this->sitepress->get_default_language() );
395
+ }
396
+ }
397
+
398
+ public function set_order_language_backend( $post_id, $post ) {
399
 
400
  if ( isset( $_POST['wcml_shop_order_language'] ) ) {
401
  update_post_meta( $post_id, 'wpml_language', filter_input( INPUT_POST, 'wcml_shop_order_language', FILTER_SANITIZE_FULL_SPECIAL_CHARS ) );
409
 
410
  if ( $item->get_variation_id() > 0 ) {
411
  $translated_variation_id = apply_filters( 'translate_object_id', $item->get_variation_id(), 'product_variation', false, $order_language );
412
+ if ( ! is_null( $translated_variation_id ) ) {
413
  $item->set_variation_id( $translated_variation_id );
414
+ }
415
  } else {
416
+ $translated_product_id = apply_filters( 'translate_object_id', $item->get_product_id(), 'product', false, $order_language );
417
+ if ( ! is_null( $translated_product_id ) ) {
418
  $item->set_product_id( $translated_product_id );
419
  }
420
  }
421
 
422
+ remove_filter( 'woocommerce_get_item_downloads', [ $this, 'filter_downloadable_product_items' ], 10, 3 );
423
 
424
  $files = $item->get_item_downloads();
425
 
426
+ add_filter( 'woocommerce_get_item_downloads', [ $this, 'filter_downloadable_product_items' ], 10, 3 );
427
 
428
  return $files;
429
  }
437
  if ( $translated_id ) {
438
  $downloads[ $key ]['product_name'] = get_the_title( $translated_id );
439
  }
 
440
  }
441
 
442
  return $downloads;
inc/class-wcml-products-screen-options.php CHANGED
@@ -9,8 +9,8 @@ class WCML_Products_Screen_Options {
9
  * Setup hooks.
10
  */
11
  public function init() {
12
- add_filter( 'default_hidden_columns', array( $this, 'filter_screen_options' ), 10, 2 );
13
- add_filter( 'wpml_hide_management_column', array( $this, 'sitepress_screen_option_filter' ), 10, 2 );
14
  }
15
 
16
  /**
9
  * Setup hooks.
10
  */
11
  public function init() {
12
+ add_filter( 'default_hidden_columns', [ $this, 'filter_screen_options' ], 10, 2 );
13
+ add_filter( 'wpml_hide_management_column', [ $this, 'sitepress_screen_option_filter' ], 10, 2 );
14
  }
15
 
16
  /**
inc/class-wcml-products.php CHANGED
@@ -1,27 +1,27 @@
1
  <?php
2
 
3
- class WCML_Products{
4
 
5
- /** @var woocommerce_wpml */
6
- private $woocommerce_wpml;
7
- /** @var SitePress */
8
- private $sitepress;
9
  /** @var WPML_Post_Translation */
10
  private $post_translations;
11
- /** @var wpdb */
12
- private $wpdb;
13
- /** @var WPML_WP_Cache */
14
- private $wpml_cache;
15
-
16
- /**
17
- * WCML_Products constructor.
18
- *
19
- * @param woocommerce_wpml $woocommerce_wpml
20
- * @param SitePress $sitepress
21
- * @param WPML_Post_Translation $post_translations
22
- * @param wpdb $wpdb
23
- * @param WPML_WP_Cache $wpml_cache
24
- */
25
  public function __construct( woocommerce_wpml $woocommerce_wpml, SitePress $sitepress, WPML_Post_Translation $post_translations, wpdb $wpdb, WPML_WP_Cache $wpml_cache = null ) {
26
  $this->woocommerce_wpml = $woocommerce_wpml;
27
  $this->sitepress = $sitepress;
@@ -37,44 +37,50 @@ class WCML_Products{
37
 
38
  if ( is_admin() ) {
39
 
40
- add_filter( 'woocommerce_json_search_found_products', array( $this, 'filter_wc_searched_products_on_admin' ) );
41
- add_filter( 'post_row_actions', array( $this, 'filter_product_actions' ), 10, 2 );
42
 
43
- add_action( 'wp_ajax_wpml_switch_post_language', array( $this, 'switch_product_variations_language' ), 9 );
44
- add_filter( 'woocommerce_product_type_query', array( $this, 'override_product_type_query' ), 10, 2 );
45
  } else {
46
- add_filter( 'woocommerce_json_search_found_products', array( $this, 'filter_wc_searched_products_on_front' ) );
47
- add_filter( 'woocommerce_related_products_args', array( $this, 'filter_related_products_args' ) );
48
- add_filter( 'woocommerce_product_related_posts_query', array( $this, 'filter_related_products_query' ) );
49
- add_filter( 'woocommerce_shortcode_products_query', array(
50
- $this,
51
- 'add_lang_to_shortcode_products_query'
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(
59
- $this,
60
- 'filter_woocommerce_upsell_crosssell_posts_by_language'
61
- ) );
62
- //update menu_order fro translations after ordering original products
63
- add_action( 'woocommerce_after_product_ordering', array( $this, 'update_all_products_translations_ordering' ) );
64
- //filter to copy excerpt value
65
- add_filter( 'wpml_copy_from_original_custom_fields', array( $this, 'filter_excerpt_field_content_copy' ) );
 
 
 
66
 
67
- add_filter( 'wpml_override_is_translator', array( $this, 'wcml_override_is_translator' ), 10, 3 );
68
- add_filter( 'wpml_user_can_translate', array( $this, 'wcml_user_can_translate' ), 10, 2 );
69
- add_filter( 'wc_product_has_unique_sku', array( $this, 'check_product_sku' ), 10, 3 );
70
 
71
- add_filter( 'get_product_search_form', array( $this->sitepress, 'get_search_form_filter' ) );
72
 
73
- add_filter( 'woocommerce_pre_customer_bought_product', array( $this, 'is_customer_bought_product' ), 10, 4 );
74
 
75
  if ( $this->sitepress->get_wp_api()->version_compare( $this->sitepress->get_wp_api()->constant( 'WC_VERSION' ), '3.6.0', '>=' ) ) {
76
- add_filter( 'get_post_metadata', array( $this, 'filter_product_data' ), 10, 3 );
77
- add_filter( 'woocommerce_can_reduce_order_stock', array( $this, 'remove_post_meta_data_filter_on_checkout_stock_update' ) );
78
  }
79
  }
80
 
@@ -92,194 +98,175 @@ class WCML_Products{
92
  *
93
  * @return null|string
94
  */
95
- public function get_original_product_language( $product_id ){
96
 
97
- $original_product_id = $this->get_original_product_id( $product_id );
98
 
99
  return $this->post_translations->get_element_lang_code( $original_product_id );
100
- }
101
 
102
  /**
103
  * @param int|string $product_id
104
  *
105
  * @return int|string
106
  */
107
- public function get_original_product_id( $product_id ){
108
-
109
- $original_product_id = $this->post_translations->get_original_element( $product_id );
110
-
111
- return $original_product_id ? $original_product_id : $product_id;
112
- }
113
-
114
- public function is_variable_product( $product_id ){
115
- $cache_key = $product_id;
116
- $cache_group = 'is_variable_product';
117
- $temp_is_variable = wp_cache_get( $cache_key, $cache_group );
118
- if( $temp_is_variable ) return $temp_is_variable;
119
-
120
- $get_variation_term_taxonomy_ids = $this->wpdb->get_col( "SELECT tt.term_taxonomy_id FROM {$this->wpdb->terms} AS t LEFT JOIN {$this->wpdb->term_taxonomy} AS tt ON t.term_id = tt.term_id WHERE t.name = 'variable' AND tt.taxonomy = 'product_type'" );
121
- $get_variation_term_taxonomy_ids = apply_filters( 'wcml_variation_term_taxonomy_ids',(array)$get_variation_term_taxonomy_ids );
122
-
123
- $is_variable_product = $this->wpdb->get_var( $this->wpdb->prepare( "SELECT count(object_id) FROM {$this->wpdb->term_relationships} WHERE object_id = %d AND term_taxonomy_id IN (".join(',',$get_variation_term_taxonomy_ids).")",$product_id ) );
124
- $is_variable_product = apply_filters( 'wcml_is_variable_product', $is_variable_product, $product_id );
125
-
126
- wp_cache_set( $cache_key, $is_variable_product, $cache_group );
127
-
128
- return $is_variable_product;
129
- }
130
-
131
- public function is_downloadable_product( $product ) {
132
-
133
- $product_id = $product->get_id();
134
- $cache_key = 'is_downloadable_product_' . $product_id;
135
-
136
- $found = false;
137
- $is_downloadable = $this->wpml_cache->get( $cache_key, $found );
138
- if ( ! $found ) {
139
- if ( $product->is_downloadable() ) {
140
- $is_downloadable = true;
141
- } elseif ( $this->is_variable_product( $product_id ) ) {
142
- foreach( $product->get_available_variations() as $variation ){
143
- if( $variation['is_downloadable'] ){
144
- $is_downloadable = true;
145
- break;
146
- }
147
- }
148
- }
149
- $this->wpml_cache->set( $cache_key, $is_downloadable );
150
- }
151
-
152
- return $is_downloadable;
153
- }
154
-
155
- public function is_grouped_product($product_id){
156
- $get_variation_term_taxonomy_id = $this->wpdb->get_var( "SELECT tt.term_taxonomy_id FROM {$this->wpdb->terms} AS t LEFT JOIN {$this->wpdb->term_taxonomy} AS tt ON t.term_id = tt.term_id WHERE t.name = 'grouped'" );
157
- $is_grouped_product = $this->wpdb->get_var( $this->wpdb->prepare( "SELECT count(object_id) FROM {$this->wpdb->term_relationships} WHERE object_id = %d AND term_taxonomy_id = %d ",$product_id,$get_variation_term_taxonomy_id ) );
158
-
159
- return $is_grouped_product;
160
- }
161
-
162
- public function get_translation_flags( $active_languages, $slang = false, $job_language = false ){
163
- $available_languages = array();
164
-
165
- foreach( $active_languages as $key => $language ){
166
- if( $job_language && $language[ 'code' ] != $job_language ) {
167
- continue;
168
- }elseif ( !$slang ||
169
- (
170
- ( $slang != $language[ 'code' ] ) &&
171
- ( current_user_can( 'wpml_operate_woocommerce_multilingual' ) ||
172
- wpml_check_user_is_translator( $slang, $language[ 'code' ] ) ) &&
173
- ( !isset( $_POST[ 'translation_status_lang' ] ) ||
174
- ( isset( $_POST[ 'translation_status_lang' ] ) &&
175
- ( $_POST[ 'translation_status_lang' ] == $language[ 'code' ] ) ||
176
- $_POST[ 'translation_status_lang' ]=='' )
177
- )
178
- )
179
- ){
180
- $available_languages[ $key ][ 'name' ] = $language[ 'english_name' ];
181
- $available_languages[ $key ][ 'flag_url' ] = $this->sitepress->get_flag_url( $language[ 'code' ] );
182
- }
183
- }
184
-
185
- return $available_languages;
186
- }
187
-
188
- public function get_translation_statuses( $original_product_id, $product_translations, $active_languages, $slang = false, $trid = false, $job_language = false ){
189
- foreach ( $active_languages as $language ) {
190
- if( $job_language && $language['code'] != $job_language ) {
191
- continue;
192
- }elseif( isset( $product_translations[ $language[ 'code' ] ] ) && $product_translations[ $language[ 'code' ] ]->original ) { ?>
193
- <span title="<?php echo $language['english_name'] . ': ' . __('Original language', 'woocommerce-multilingual'); ?>">
194
- <i class="otgs-ico-original"></i>
195
- </span>
196
- <?php }elseif(
197
- $slang != $language[ 'code' ] &&
198
- ( !isset( $_POST[ 'translation_status_lang' ] ) ||
199
- ( isset( $_POST['translation_status_lang']) &&
200
- $_POST['translation_status_lang'] == $language['code'] ||
201
- $_POST['translation_status_lang'] == ''
202
- )
203
- )
204
- ) {
205
- if( isset( $product_translations[ $language[ 'code' ] ] ) ) {
206
- $job_id = $this->wpdb->get_var(
207
- $this->wpdb->prepare(
208
- "SELECT MAX(tj.job_id) FROM {$this->wpdb->prefix}icl_translate_job AS tj
 
 
 
 
 
209
  LEFT JOIN {$this->wpdb->prefix}icl_translation_status AS ts
210
  ON tj.rid = ts.rid WHERE ts.translation_id=%d",
211
- $product_translations[ $language[ 'code' ] ]->translation_id )
212
- );
213
- }else{
214
- $job_id = false;
215
- }
216
-
217
- if( !current_user_can( 'wpml_manage_woocommerce_multilingual' ) && isset( $product_translations[ $language[ 'code' ] ] ) ) {
218
- $tr_status = $this->wpdb->get_row(
219
- $this->wpdb->prepare(
220
- "SELECT status,translator_id FROM {$this->wpdb->prefix}icl_translation_status
 
221
  WHERE translation_id = %d",
222
- $product_translations[ $language[ 'code' ] ]->translation_id )
223
- );
224
-
225
- if( !is_null( $tr_status ) && get_current_user_id() != $tr_status->translator_id ){
226
- if( $tr_status->status == ICL_TM_IN_PROGRESS ) { ?>
227
- <a title="<?php _e( 'Translation in progress', 'woocommerce-multilingual' ); ?>"><i
228
- class="otgs-ico-in-progress"></i></a>
229
- <?php continue;
230
- }elseif( $tr_status->status == ICL_TM_WAITING_FOR_TRANSLATOR && !$job_id ){
231
- $tr_job_id = $this->wpdb->get_var(
232
- $this->wpdb->prepare(
233
- "SELECT j.job_id FROM {$this->wpdb->prefix}icl_translate_job j
 
 
 
234
  JOIN {$this->wpdb->prefix}icl_translation_status s ON j.rid = s.rid
235
  WHERE s.translation_id = %d",
236
- $product_translations[ $language[ 'code' ] ]->translation_id )
237
- );
238
- $translation_queue_page = admin_url( 'admin.php?page=' . WPML_TM_FOLDER . '/menu/translations-queue.php&job_id=' . $tr_job_id );
239
- $edit_url = apply_filters( 'icl_job_edit_url', $translation_queue_page, $tr_job_id );
240
- ?>
241
- <a href="<?php echo $edit_url ?>" title="<?php echo $language[ 'english_name' ] . ': ' . __( 'Take this and edit', 'woocommerce-multilingual' ); ?>">
242
- <i class="otgs-ico-add"></i>
243
- </a>
244
- <?php continue;
245
- }
246
- }
247
- wpml_tm_load_status_display_filter();
248
- } ?>
249
- <a href="<?php echo apply_filters( 'wpml_link_to_translation', '', $original_product_id, $language[ 'code' ], $trid ) ?>"
250
- class="js-wpml-translate-link"
251
- data-tm-job-id="<?php echo $job_id ?>"
252
- <?php if( isset( $product_translations[ $language[ 'code' ] ] ) ){
253
- $tr_status = $this->wpdb->get_row(
254
- $this->wpdb->prepare(
255
- "SELECT status,needs_update FROM {$this->wpdb->prefix}icl_translation_status
256
- WHERE translation_id = %d",
257
- $product_translations[ $language[ 'code' ] ]->translation_id )
258
- );
259
- if (!$tr_status ) { ?>
260
- title="<?php echo $language[ 'english_name' ] . ': ' . __( 'Add translation', 'woocommerce-multilingual' ); ?>">
261
- <i class="otgs-ico-add"></i>
262
- <?php }elseif( $tr_status->needs_update ){ ?>
263
- title="<?php echo $language[ 'english_name' ] . ': ' . __( 'Update translation', 'woocommerce-multilingual' ); ?>">
264
- <i class="otgs-ico-refresh"></i>
265
- <?php }elseif( $tr_status->status != ICL_TM_COMPLETE && $tr_status->status != ICL_TM_DUPLICATE ){ ?>
266
- title="<?php echo $language[ 'english_name' ] . ': ' . __( 'Finish translating', 'woocommerce-multilingual' ); ?>">
267
- <i class="otgs-ico-refresh"></i>
268
- <?php }elseif( $tr_status->status == ICL_TM_COMPLETE ){ ?>
269
- title="<?php echo $language[ 'english_name' ] . ': ' . __( 'Edit translation', 'woocommerce-multilingual' ); ?>">
270
- <i class="otgs-ico-edit"></i>
271
- <?php }elseif( $tr_status->status == ICL_TM_DUPLICATE ){ ?>
272
- title="<?php echo $language[ 'english_name' ] . ': ' . __( 'Edit translation', 'woocommerce-multilingual' ); ?>">
273
- <i class="otgs-ico-duplicate"></i>
274
- <?php }
275
- } else { ?>
276
- title="<?php echo $language[ 'english_name' ] . ': ' . __( 'Add translation', 'woocommerce-multilingual' ); ?>">
277
- <i class="otgs-ico-add"></i>
278
- <?php } ?>
279
- </a>
280
- <?php } ?>
281
- <?php }
282
- }
283
 
284
  /**
285
  * @param bool $is_translator
@@ -317,67 +304,68 @@ class WCML_Products{
317
  return $user_can_translate;
318
  }
319
 
320
- //product quickedit
321
- public function filter_product_actions( $actions, $post ){
322
- if(
323
- $post->post_type == 'product' &&
324
- !$this->is_original_product( $post->ID ) &&
325
- isset( $actions[ 'inline hide-if-no-js' ] ) )
326
- {
327
- $new_actions = array();
328
- foreach( $actions as $key => $action ) {
329
- if( $key == 'inline hide-if-no-js' ) {
330
- $new_actions[ 'quick_hide' ] = '<a href="#TB_inline?width=200&height=150&inlineId=quick_edit_notice" class="thickbox" title="' .
331
- __('Edit this item inline', 'woocommerce-multilingual') . '">' .
332
- __('Quick Edit', 'woocommerce-multilingual') . '</a>';
333
- } else {
334
- $new_actions[ $key ] = $action;
335
- }
336
- }
337
- return $new_actions;
338
- }
339
- return $actions;
340
- }
341
-
342
- /**
343
- * Takes off translated products from the Up-sells/Cross-sells tab.
344
- */
345
- public function filter_woocommerce_upsell_crosssell_posts_by_language( $posts ){
346
- foreach( $posts as $key => $post ){
347
- $post_id = $posts[ $key ]->ID;
348
- $post_data = $this->wpdb->get_row(
349
- $this->wpdb->prepare(
350
- "SELECT * FROM {$this->wpdb->prefix}icl_translations
351
- WHERE element_id = %d ", $post_id
352
- ),
353
- ARRAY_A );
354
-
355
- if( $post_data[ 'language_code' ] !== $this->sitepress->get_current_language() ){
356
- unset( $posts[ $key ] );
357
- }
358
- }
359
-
360
- return $posts;
361
- }
 
362
 
363
 
364
  /**
365
  * Filters products by language
366
  *
367
  * @param array $found_products
368
- * @param bool $language
369
  *
370
  * @return array
371
  */
372
- private function filter_found_products_by_language( $found_products, $language = false ){
373
 
374
- if( !$language ){
375
  $language = $this->sitepress->get_current_language();
376
  }
377
 
378
- foreach( $found_products as $product_id => $product_name ){
379
 
380
- if( $this->post_translations->get_element_lang_code( $product_id ) !== $language ){
381
  unset( $found_products[ $product_id ] );
382
  }
383
  }
@@ -390,107 +378,110 @@ class WCML_Products{
390
  *
391
  * @return array
392
  */
393
- public function filter_wc_searched_products_on_front( $found_products ){
394
- return $this->filter_found_products_by_language( $found_products );
395
- }
396
 
397
  /**
398
  * @param array $found_products
399
  *
400
  * @return array
401
  */
402
- public function filter_wc_searched_products_on_admin( $found_products ){
403
-
404
- if ( isset( $_COOKIE['_wcml_dashboard_order_language'] ) ) {
405
- $found_products = $this->filter_found_products_by_language( $found_products, $_COOKIE['_wcml_dashboard_order_language'] );
406
- }else{
407
- $found_products = $this->filter_found_products_by_language( $found_products );
408
- }
409
-
410
- return $found_products;
411
- }
412
-
413
- //update menu_order fro translations after ordering original products
414
- public function update_all_products_translations_ordering(){
415
- if( $this->woocommerce_wpml->settings[ 'products_sync_order' ] ) {
416
- $current_language = $this->sitepress->get_current_language();
417
- if( $current_language == $this->sitepress->get_default_language() ){
418
- $products = $this->wpdb->get_results(
419
- $this->wpdb->prepare(
420
- "SELECT p.ID FROM {$this->wpdb->posts} AS p
421
  LEFT JOIN {$this->wpdb->prefix}icl_translations AS icl
422
  ON icl.element_id = p.id
423
  WHERE p.post_type = 'product'
424
  AND p.post_status IN ( 'publish', 'future', 'draft', 'pending', 'private' )
425
  AND icl.element_type= 'post_product'
426
  AND icl.language_code = %s",
427
- $current_language )
428
- );
429
-
430
- foreach( $products as $product ){
431
- $this->update_order_for_product_translations( $product->ID );
432
- }
433
- }
434
- }
435
- }
436
-
437
- //update menu_order fro translations after ordering original products
438
- public function update_order_for_product_translations( $product_id ){
439
- if( isset( $this->woocommerce_wpml->settings[ 'products_sync_order' ] ) && $this->woocommerce_wpml->settings[ 'products_sync_order' ] ){
440
- $current_language = $this->sitepress->get_current_language();
441
-
442
- if ( $current_language == $this->sitepress->get_default_language() ) {
443
- $menu_order = $this->wpdb->get_var( $this->wpdb->prepare("SELECT menu_order FROM {$this->wpdb->posts} WHERE ID = %d", $product_id ) );
444
- $translations = $this->post_translations->get_element_translations( $product_id );
445
-
446
- foreach( $translations as $translation ){
447
- if( $translation !== $product_id ){
448
- $this->wpdb->update( $this->wpdb->posts, array( 'menu_order' => $menu_order ), array( 'ID' => $translation ) );
449
- }
450
- }
451
- }
452
- }
453
- }
454
-
455
- public function filter_excerpt_field_content_copy( $elements ) {
456
-
457
- if ( $elements[ 'post_type' ] == 'product' ) {
458
- $elements[ 'excerpt' ] ['editor_type'] = 'editor';
459
- }
460
- if ( function_exists( 'format_for_editor' ) ) {
461
- // WordPress 4.3 uses format_for_editor
462
- $elements[ 'excerpt' ][ 'value' ] = htmlspecialchars_decode( format_for_editor( $elements[ 'excerpt' ][ 'value' ], $_POST[ 'excerpt_type' ] ) );
463
- } else {
464
- // Backwards compatible for WordPress < 4.3
465
- if($_POST[ 'excerpt_type'] == 'rich'){
466
- $elements[ 'excerpt' ][ 'value' ] = htmlspecialchars_decode( wp_richedit_pre( $elements[ 'excerpt' ][ 'value' ] ) );
467
- }else{
468
- $elements[ 'excerpt' ][ 'value' ] = htmlspecialchars_decode( wp_htmledit_pre( $elements[ 'excerpt' ][ 'value' ] ) );
469
- }
470
- }
471
- return $elements;
472
  }
473
 
474
- public function filter_related_products_args( $args ){
475
- if( $this->woocommerce_wpml->settings[ 'enable_multi_currency' ] == WCML_MULTI_CURRENCIES_INDEPENDENT &&
476
- isset( $this->woocommerce_wpml->settings[ 'display_custom_prices' ] ) &&
477
- $this->woocommerce_wpml->settings[ 'display_custom_prices' ] )
478
- {
 
 
 
479
 
480
- $client_currency = $this->woocommerce_wpml->multi_currency->get_client_currency();
481
- $woocommerce_currency = wcml_get_woocommerce_currency_option();
 
482
 
483
- if( $client_currency != $woocommerce_currency ){
484
- $args['meta_query'][] = array(
485
- 'key' => '_wcml_custom_prices_status',
486
- 'value' => 1,
487
- 'compare' => '=',
488
- );
489
- }
 
490
 
491
- }
492
- return $args;
493
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
494
 
495
  /**
496
  * @param array $query
@@ -500,118 +491,122 @@ class WCML_Products{
500
  public function filter_related_products_query( $query ) {
501
 
502
  $query['join'] .= " LEFT JOIN {$this->wpdb->prefix}icl_translations AS icl ON icl.element_id = p.ID ";
503
- $query['where'] .= $this->wpdb->prepare( " AND icl.language_code = %s ", $this->sitepress->get_current_language() );
504
 
505
  return $query;
506
  }
507
 
508
- /*
509
- * get meta ids for multiple values post meta key
510
- */
511
- public function get_mid_ids_by_key( $post_id, $meta_key ) {
512
- $ids = $this->wpdb->get_col( $this->wpdb->prepare( "SELECT meta_id FROM {$this->wpdb->postmeta} WHERE post_id = %d AND meta_key = %s", $post_id, $meta_key ) );
513
- if( $ids )
514
- return $ids;
 
515
 
516
- return false;
517
- }
518
 
519
- // count "in progress" and "waiting on translation" as untranslated too
520
- public function get_untranslated_products_count( $language ){
521
 
522
- $count = 0;
523
 
524
- $products = $this->wpdb->get_results( "
 
525
  SELECT p.ID, t.trid, t.language_code
526
  FROM {$this->wpdb->posts} AS p
527
  LEFT JOIN {$this->wpdb->prefix}icl_translations AS t ON t.element_id = p.id
528
  WHERE p.post_type = 'product' AND t.element_type = 'post_product' AND t.source_language_code IS NULL
529
- " );
530
-
531
- foreach( $products as $product ){
532
- if( $product->language_code == $language ) continue;
533
-
534
- $translation_status = apply_filters( 'wpml_translation_status', null, $product->trid, $language );
535
 
536
- if( in_array( $translation_status, array( ICL_TM_NOT_TRANSLATED, ICL_TM_WAITING_FOR_TRANSLATOR, ICL_TM_IN_PROGRESS ) ) ){
537
- $count++;
538
- }
539
- }
540
 
541
- return $count;
542
- }
543
 
544
- public function is_hide_resign_button(){
545
- global $iclTranslationManagement;
 
 
546
 
547
- $hide_resign = false;
 
548
 
549
- if( isset( $_GET[ 'source_language_code' ] ) && isset( $_GET[ 'language_code' ] ) ){
 
550
 
551
- $from_lang = $_GET[ 'source_language_code' ];
552
- $to_lang = $_GET[ 'language_code' ];
553
 
554
- }elseif( isset( $_GET[ 'job_id' ] ) ){
555
 
556
- $job = $iclTranslationManagement->get_translation_job( $_GET[ 'job_id' ] );
557
- if( $job ){
558
- $from_lang = $job->source_language_code;
559
- $to_lang = $job->language_code;
560
- }
561
- }
562
 
563
- if( isset( $from_lang ) ){
564
 
565
- $translators = $iclTranslationManagement->get_blog_translators(
566
- array(
567
- 'from' => $from_lang,
568
- 'to' => $to_lang
569
- )
570
- );
571
 
572
- if( empty( $translators ) || ( sizeof( $translators ) == 1 && $translators[0]->ID == get_current_user_id() ) ){
573
- $hide_resign = true;
574
- }
575
 
576
- }
 
 
 
 
 
577
 
578
- return $hide_resign;
579
- }
 
 
580
 
581
- public function switch_product_variations_language(){
 
582
 
583
- $lang_to = false;
584
- $post_id = false;
585
 
586
- if ( isset( $_POST[ 'wpml_to' ] ) ) {
587
- $lang_to = $_POST[ 'wpml_to' ];
588
- }
589
- if ( isset( $_POST[ 'wpml_post_id' ] ) ) {
590
- $post_id = $_POST[ 'wpml_post_id' ];
591
- }
592
 
593
- if ( $post_id && $lang_to && get_post_type( $post_id ) == 'product' ) {
594
- $product_variations = $this->woocommerce_wpml->sync_variations_data->get_product_variations( $post_id );
595
- foreach( $product_variations as $product_variation ){
596
- $trid = $this->sitepress->get_element_trid( $product_variation->ID, 'post_product_variation' );
597
- $current_prod_variation_id = apply_filters( 'translate_object_id', $product_variation->ID, 'product_variation', false, $lang_to );
598
- if( is_null( $current_prod_variation_id ) ){
599
- $this->sitepress->set_element_language_details( $product_variation->ID, 'post_product_variation', $trid, $lang_to );
600
 
601
- foreach( get_post_custom( $product_variation->ID ) as $meta_key => $meta ) {
602
- foreach ( $meta as $meta_value ) {
603
- if ( substr( $meta_key, 0, 10 ) == 'attribute_' ) {
604
- $trn_post_meta = $this->woocommerce_wpml->attributes->get_translated_variation_attribute_post_meta( $meta_value, $meta_key, $product_variation->ID, $product_variation->ID, $lang_to );
605
- update_post_meta( $product_variation->ID, $trn_post_meta['meta_key'], $trn_post_meta['meta_value']);
606
- }
607
- }
608
- }
609
- }
610
- }
611
- }
612
- }
 
 
 
 
 
 
 
 
613
 
614
- function check_product_sku( $sku_found, $product_id, $sku ) {
615
 
616
  if ( $sku_found ) {
617
 
@@ -645,35 +640,35 @@ class WCML_Products{
645
  return $sku_found;
646
  }
647
 
648
- public function add_lang_to_shortcode_products_query( $query_args ){
649
 
650
- $query_args[ 'lang' ] = $this->sitepress->get_current_language();
651
 
652
- return $query_args;
653
- }
654
 
655
 
656
- /**
657
- * Get file download path in correct domain
658
- *
659
- * @param string $file_path file path URL
660
- * @return string
661
- */
662
- public function filter_file_download_path( $file_path ) {
663
 
664
- $is_per_domain = $this->sitepress->get_wp_api()->constant( 'WPML_LANGUAGE_NEGOTIATION_TYPE_DOMAIN' ) === (int) $this->sitepress->get_setting( 'language_negotiation_type' );
665
 
666
- if ( $is_per_domain ) {
667
- $wpml_url_helper = new WPML_URL_Converter_Url_Helper();
668
 
669
- if( strpos( trim( $file_path ), $wpml_url_helper->get_abs_home() ) === 0 ){
670
- $file_path = $this->sitepress->convert_url( $file_path );
671
- }
672
- }
673
 
674
- return $file_path;
675
 
676
- }
677
 
678
 
679
  /**
@@ -685,32 +680,42 @@ class WCML_Products{
685
  }
686
 
687
 
688
- public function is_customer_bought_product( $value, $customer_email, $user_id, $product_id ){
689
 
690
- if( $this->is_customer_bought_original( $customer_email, $user_id, $product_id ) ){
691
- return true;
692
- }
693
 
694
- return $value;
695
- }
696
 
697
  private function is_customer_bought_original( $customer_email, $user_id, $product_id ) {
698
 
699
  if ( ! $this->is_original_product( $product_id ) ) {
700
- remove_filter( 'woocommerce_pre_customer_bought_product', array(
701
- $this,
702
- 'is_customer_bought_product'
703
- ), 10, 4 );
 
 
 
 
 
704
 
705
  $bought_original = wc_customer_bought_product( $customer_email, $user_id, $this->get_original_product_id( $product_id ) );
706
 
707
- add_filter( 'woocommerce_pre_customer_bought_product', array(
708
- $this,
709
- 'is_customer_bought_product'
710
- ), 10, 4 );
 
 
 
 
 
711
 
712
  return (bool) $bought_original;
713
- }
714
 
715
  return false;
716
  }
@@ -721,13 +726,13 @@ class WCML_Products{
721
 
722
  $post_type = get_post_type( $product_id );
723
 
724
- if ( in_array( $post_type, array( 'product', 'product_variation' ), true ) ) {
725
 
726
- remove_filter( 'get_post_metadata', array( $this, 'filter_product_data' ), 10 );
727
 
728
  $data = get_post_meta( $product_id );
729
 
730
- $meta_keys_to_filter = array();
731
  $is_mc_enabled = (int) $this->woocommerce_wpml->settings['enable_multi_currency'] === (int) $this->sitepress->get_wp_api()->constant( 'WCML_MULTI_CURRENCIES_INDEPENDENT' );
732
 
733
  if ( $is_mc_enabled ) {
@@ -753,7 +758,7 @@ class WCML_Products{
753
  $data[ $meta_key ][0] = get_post_meta( $product_id, $meta_key, true );
754
  }
755
 
756
- add_filter( 'get_post_metadata', array( $this, 'filter_product_data' ), 10, 3 );
757
  }
758
  }
759
 
@@ -765,16 +770,16 @@ class WCML_Products{
765
  *
766
  * @return null|string
767
  */
768
- public function get_product_price_from_db( $product_id ){
769
 
770
- return $this->wpdb->get_var( $this->wpdb->prepare( "SELECT meta_value FROM {$this->wpdb->postmeta} WHERE `meta_key` = '_price' AND post_id = %d ", $product_id ) );
771
- }
772
 
773
  /**
774
  * return not cached value for product
775
  *
776
  * @param bool $product_type
777
- * @param int $product_id
778
  *
779
  * @return bool|string
780
  */
@@ -796,9 +801,9 @@ class WCML_Products{
796
  *
797
  * @return bool
798
  */
799
- public function remove_post_meta_data_filter_on_checkout_stock_update( $reduce_stock ){
800
- if( isset( $_GET['wc-ajax'] ) && 'checkout' === $_GET['wc-ajax'] ){
801
- remove_filter( 'get_post_metadata', array( $this, 'filter_product_data' ), 10, 3 );
802
  }
803
  return $reduce_stock;
804
  }
@@ -809,17 +814,17 @@ class WCML_Products{
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 ) {
@@ -827,7 +832,9 @@ class WCML_Products{
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
  }
1
  <?php
2
 
3
+ class WCML_Products {
4
 
5
+ /** @var woocommerce_wpml */
6
+ private $woocommerce_wpml;
7
+ /** @var SitePress */
8
+ private $sitepress;
9
  /** @var WPML_Post_Translation */
10
  private $post_translations;
11
+ /** @var wpdb */
12
+ private $wpdb;
13
+ /** @var WPML_WP_Cache */
14
+ private $wpml_cache;
15
+
16
+ /**
17
+ * WCML_Products constructor.
18
+ *
19
+ * @param woocommerce_wpml $woocommerce_wpml
20
+ * @param SitePress $sitepress
21
+ * @param WPML_Post_Translation $post_translations
22
+ * @param wpdb $wpdb
23
+ * @param WPML_WP_Cache $wpml_cache
24
+ */
25
  public function __construct( woocommerce_wpml $woocommerce_wpml, SitePress $sitepress, WPML_Post_Translation $post_translations, wpdb $wpdb, WPML_WP_Cache $wpml_cache = null ) {
26
  $this->woocommerce_wpml = $woocommerce_wpml;
27
  $this->sitepress = $sitepress;
37
 
38
  if ( is_admin() ) {
39
 
40
+ add_filter( 'woocommerce_json_search_found_products', [ $this, 'filter_wc_searched_products_on_admin' ] );
41
+ add_filter( 'post_row_actions', [ $this, 'filter_product_actions' ], 10, 2 );
42
 
43
+ add_action( 'wp_ajax_wpml_switch_post_language', [ $this, 'switch_product_variations_language' ], 9 );
44
+ add_filter( 'woocommerce_product_type_query', [ $this, 'override_product_type_query' ], 10, 2 );
45
  } else {
46
+ add_filter( 'woocommerce_json_search_found_products', [ $this, 'filter_wc_searched_products_on_front' ] );
47
+ add_filter( 'woocommerce_related_products_args', [ $this, 'filter_related_products_args' ] );
48
+ add_filter( 'woocommerce_product_related_posts_query', [ $this, 'filter_related_products_query' ] );
49
+ add_filter(
50
+ 'woocommerce_shortcode_products_query',
51
+ [
52
+ $this,
53
+ 'add_lang_to_shortcode_products_query',
54
+ ]
55
+ );
56
 
57
+ add_filter( 'woocommerce_product_file_download_path', [ $this, 'filter_file_download_path' ] );
58
+ add_filter( 'woocommerce_product_add_to_cart_url', [ $this, 'maybe_add_language_parameter' ] );
59
  }
60
 
61
+ add_filter(
62
+ 'woocommerce_upsell_crosssell_search_products',
63
+ [
64
+ $this,
65
+ 'filter_woocommerce_upsell_crosssell_posts_by_language',
66
+ ]
67
+ );
68
+ // update menu_order fro translations after ordering original products.
69
+ add_action( 'woocommerce_after_product_ordering', [ $this, 'update_all_products_translations_ordering' ] );
70
+ // filter to copy excerpt value.
71
+ add_filter( 'wpml_copy_from_original_custom_fields', [ $this, 'filter_excerpt_field_content_copy' ] );
72
 
73
+ add_filter( 'wpml_override_is_translator', [ $this, 'wcml_override_is_translator' ], 10, 3 );
74
+ add_filter( 'wpml_user_can_translate', [ $this, 'wcml_user_can_translate' ], 10, 2 );
75
+ add_filter( 'wc_product_has_unique_sku', [ $this, 'check_product_sku' ], 10, 3 );
76
 
77
+ add_filter( 'get_product_search_form', [ $this->sitepress, 'get_search_form_filter' ] );
78
 
79
+ add_filter( 'woocommerce_pre_customer_bought_product', [ $this, 'is_customer_bought_product' ], 10, 4 );
80
 
81
  if ( $this->sitepress->get_wp_api()->version_compare( $this->sitepress->get_wp_api()->constant( 'WC_VERSION' ), '3.6.0', '>=' ) ) {
82
+ add_filter( 'get_post_metadata', [ $this, 'filter_product_data' ], 10, 3 );
83
+ add_filter( 'woocommerce_can_reduce_order_stock', [ $this, 'remove_post_meta_data_filter_on_checkout_stock_update' ] );
84
  }
85
  }
86
 
98
  *
99
  * @return null|string
100
  */
101
+ public function get_original_product_language( $product_id ) {
102
 
103
+ $original_product_id = $this->get_original_product_id( $product_id );
104
 
105
  return $this->post_translations->get_element_lang_code( $original_product_id );
106
+ }
107
 
108
  /**
109
  * @param int|string $product_id
110
  *
111
  * @return int|string
112
  */
113
+ public function get_original_product_id( $product_id ) {
114
+
115
+ $original_product_id = $this->post_translations->get_original_element( $product_id );
116
+
117
+ return $original_product_id ? $original_product_id : $product_id;
118
+ }
119
+
120
+ public function is_variable_product( $product_id ) {
121
+ $cache_key = $product_id;
122
+ $cache_group = 'is_variable_product';
123
+ $temp_is_variable = wp_cache_get( $cache_key, $cache_group );
124
+ if ( $temp_is_variable ) {
125
+ return $temp_is_variable;
126
+ }
127
+
128
+ $get_variation_term_taxonomy_ids = $this->wpdb->get_col( "SELECT tt.term_taxonomy_id FROM {$this->wpdb->terms} AS t LEFT JOIN {$this->wpdb->term_taxonomy} AS tt ON t.term_id = tt.term_id WHERE t.name = 'variable' AND tt.taxonomy = 'product_type'" );
129
+ $get_variation_term_taxonomy_ids = apply_filters( 'wcml_variation_term_taxonomy_ids', (array) $get_variation_term_taxonomy_ids );
130
+
131
+ $is_variable_product = $this->wpdb->get_var( $this->wpdb->prepare( "SELECT count(object_id) FROM {$this->wpdb->term_relationships} WHERE object_id = %d AND term_taxonomy_id IN (" . join( ',', $get_variation_term_taxonomy_ids ) . ')', $product_id ) );
132
+ $is_variable_product = apply_filters( 'wcml_is_variable_product', $is_variable_product, $product_id );
133
+
134
+ wp_cache_set( $cache_key, $is_variable_product, $cache_group );
135
+
136
+ return $is_variable_product;
137
+ }
138
+
139
+ public function is_downloadable_product( $product ) {
140
+
141
+ $product_id = $product->get_id();
142
+ $cache_key = 'is_downloadable_product_' . $product_id;
143
+
144
+ $found = false;
145
+ $is_downloadable = $this->wpml_cache->get( $cache_key, $found );
146
+ if ( ! $found ) {
147
+ if ( $product->is_downloadable() ) {
148
+ $is_downloadable = true;
149
+ } elseif ( $this->is_variable_product( $product_id ) ) {
150
+ foreach ( $product->get_available_variations() as $variation ) {
151
+ if ( $variation['is_downloadable'] ) {
152
+ $is_downloadable = true;
153
+ break;
154
+ }
155
+ }
156
+ }
157
+ $this->wpml_cache->set( $cache_key, $is_downloadable );
158
+ }
159
+
160
+ return $is_downloadable;
161
+ }
162
+
163
+ public function is_grouped_product( $product_id ) {
164
+ $get_variation_term_taxonomy_id = $this->wpdb->get_var( "SELECT tt.term_taxonomy_id FROM {$this->wpdb->terms} AS t LEFT JOIN {$this->wpdb->term_taxonomy} AS tt ON t.term_id = tt.term_id WHERE t.name = 'grouped'" );
165
+ $is_grouped_product = $this->wpdb->get_var( $this->wpdb->prepare( "SELECT count(object_id) FROM {$this->wpdb->term_relationships} WHERE object_id = %d AND term_taxonomy_id = %d ", $product_id, $get_variation_term_taxonomy_id ) );
166
+
167
+ return $is_grouped_product;
168
+ }
169
+
170
+ public function get_translation_flags( $active_languages, $slang = false, $job_language = false ) {
171
+ $available_languages = [];
172
+
173
+ foreach ( $active_languages as $key => $language ) {
174
+ if ( $job_language && $language['code'] != $job_language ) {
175
+ continue;
176
+ } elseif ( ! $slang ||
177
+ (
178
+ ( $slang != $language['code'] ) &&
179
+ ( current_user_can( 'wpml_operate_woocommerce_multilingual' ) ||
180
+ wpml_check_user_is_translator( $slang, $language['code'] ) ) &&
181
+ ( ! isset( $_POST['translation_status_lang'] ) ||
182
+ ( isset( $_POST['translation_status_lang'] ) &&
183
+ ( $_POST['translation_status_lang'] == $language['code'] ) ||
184
+ $_POST['translation_status_lang'] == '' )
185
+ )
186
+ )
187
+ ) {
188
+ $available_languages[ $key ]['name'] = $language['english_name'];
189
+ $available_languages[ $key ]['flag_url'] = $this->sitepress->get_flag_url( $language['code'] );
190
+ }
191
+ }
192
+
193
+ return $available_languages;
194
+ }
195
+
196
+ public function get_translation_statuses( $original_product_id, $product_translations, $active_languages, $slang = false, $trid = false, $job_language = false ) {
197
+ $status_display_factory = new WPML_Post_Status_Display_Factory( $this->sitepress );
198
+ $status_display = $status_display_factory->create();
199
+ foreach ( $active_languages as $language ) {
200
+ if ( $job_language && $language['code'] != $job_language ) {
201
+ continue;
202
+ } elseif ( isset( $product_translations[ $language['code'] ] ) && $product_translations[ $language['code'] ]->original ) { ?>
203
+ <span title="<?php echo $language['english_name'] . ': ' . __( 'Original language', 'woocommerce-multilingual' ); ?>">
204
+ <i class="otgs-ico-original"></i>
205
+ </span>
206
+ <?php
207
+ } elseif (
208
+ $slang != $language['code'] &&
209
+ ( ! isset( $_POST['translation_status_lang'] ) ||
210
+ ( isset( $_POST['translation_status_lang'] ) &&
211
+ $_POST['translation_status_lang'] == $language['code'] ||
212
+ $_POST['translation_status_lang'] == ''
213
+ )
214
+ )
215
+ ) {
216
+ if ( isset( $product_translations[ $language['code'] ] ) ) {
217
+ $job_id = $this->wpdb->get_var(
218
+ $this->wpdb->prepare(
219
+ "SELECT MAX(tj.job_id) FROM {$this->wpdb->prefix}icl_translate_job AS tj
220
  LEFT JOIN {$this->wpdb->prefix}icl_translation_status AS ts
221
  ON tj.rid = ts.rid WHERE ts.translation_id=%d",
222
+ $product_translations[ $language['code'] ]->translation_id
223
+ )
224
+ );
225
+ } else {
226
+ $job_id = false;
227
+ }
228
+
229
+ if ( ! current_user_can( 'wpml_manage_woocommerce_multilingual' ) && isset( $product_translations[ $language['code'] ] ) ) {
230
+ $tr_status = $this->wpdb->get_row(
231
+ $this->wpdb->prepare(
232
+ "SELECT status,translator_id FROM {$this->wpdb->prefix}icl_translation_status
233
  WHERE translation_id = %d",
234
+ $product_translations[ $language['code'] ]->translation_id
235
+ )
236
+ );
237
+
238
+ if ( ! is_null( $tr_status ) && get_current_user_id() != $tr_status->translator_id ) {
239
+ if ( $tr_status->status == ICL_TM_IN_PROGRESS ) {
240
+ ?>
241
+ <a title="<?php _e( 'Translation in progress', 'woocommerce-multilingual' ); ?>"><i
242
+ class="otgs-ico-in-progress"></i></a>
243
+ <?php
244
+ continue;
245
+ } elseif ( $tr_status->status == ICL_TM_WAITING_FOR_TRANSLATOR && ! $job_id ) {
246
+ $tr_job_id = $this->wpdb->get_var(
247
+ $this->wpdb->prepare(
248
+ "SELECT j.job_id FROM {$this->wpdb->prefix}icl_translate_job j
249
  JOIN {$this->wpdb->prefix}icl_translation_status s ON j.rid = s.rid
250
  WHERE s.translation_id = %d",
251
+ $product_translations[ $language['code'] ]->translation_id
252
+ )
253
+ );
254
+ $translation_queue_page = admin_url( 'admin.php?page=' . WPML_TM_FOLDER . '/menu/translations-queue.php&job_id=' . $tr_job_id );
255
+ $edit_url = apply_filters( 'icl_job_edit_url', $translation_queue_page, $tr_job_id );
256
+ ?>
257
+ <a href="<?php echo $edit_url; ?>" title="<?php echo $language['english_name'] . ': ' . __( 'Take this and edit', 'woocommerce-multilingual' ); ?>">
258
+ <i class="otgs-ico-add"></i>
259
+ </a>
260
+ <?php
261
+ continue;
262
+ }
263
+ }
264
+ wpml_tm_load_status_display_filter();
265
+ }
266
+ echo $status_display->get_status_html( $original_product_id, $language['code'] );
267
+ }
268
+ }
269
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
270
 
271
  /**
272
  * @param bool $is_translator
304
  return $user_can_translate;
305
  }
306
 
307
+ // product quickedit.
308
+ public function filter_product_actions( $actions, $post ) {
309
+ if (
310
+ $post->post_type == 'product' &&
311
+ ! $this->is_original_product( $post->ID ) &&
312
+ isset( $actions['inline hide-if-no-js'] ) ) {
313
+ $new_actions = [];
314
+ foreach ( $actions as $key => $action ) {
315
+ if ( $key == 'inline hide-if-no-js' ) {
316
+ $new_actions['quick_hide'] = '<a href="#TB_inline?width=200&height=150&inlineId=quick_edit_notice" class="thickbox" title="' .
317
+ __( 'Edit this item inline', 'woocommerce-multilingual' ) . '">' .
318
+ __( 'Quick Edit', 'woocommerce-multilingual' ) . '</a>';
319
+ } else {
320
+ $new_actions[ $key ] = $action;
321
+ }
322
+ }
323
+ return $new_actions;
324
+ }
325
+ return $actions;
326
+ }
327
+
328
+ /**
329
+ * Takes off translated products from the Up-sells/Cross-sells tab.
330
+ */
331
+ public function filter_woocommerce_upsell_crosssell_posts_by_language( $posts ) {
332
+ foreach ( $posts as $key => $post ) {
333
+ $post_id = $posts[ $key ]->ID;
334
+ $post_data = $this->wpdb->get_row(
335
+ $this->wpdb->prepare(
336
+ "SELECT * FROM {$this->wpdb->prefix}icl_translations
337
+ WHERE element_id = %d ",
338
+ $post_id
339
+ ),
340
+ ARRAY_A
341
+ );
342
+
343
+ if ( $post_data['language_code'] !== $this->sitepress->get_current_language() ) {
344
+ unset( $posts[ $key ] );
345
+ }
346
+ }
347
+
348
+ return $posts;
349
+ }
350
 
351
 
352
  /**
353
  * Filters products by language
354
  *
355
  * @param array $found_products
356
+ * @param bool $language
357
  *
358
  * @return array
359
  */
360
+ private function filter_found_products_by_language( $found_products, $language = false ) {
361
 
362
+ if ( ! $language ) {
363
  $language = $this->sitepress->get_current_language();
364
  }
365
 
366
+ foreach ( $found_products as $product_id => $product_name ) {
367
 
368
+ if ( $this->post_translations->get_element_lang_code( $product_id ) !== $language ) {
369
  unset( $found_products[ $product_id ] );
370
  }
371
  }
378
  *
379
  * @return array
380
  */
381
+ public function filter_wc_searched_products_on_front( $found_products ) {
382
+ return $this->filter_found_products_by_language( $found_products );
383
+ }
384
 
385
  /**
386
  * @param array $found_products
387
  *
388
  * @return array
389
  */
390
+ public function filter_wc_searched_products_on_admin( $found_products ) {
391
+
392
+ if ( isset( $_COOKIE['_wcml_dashboard_order_language'] ) ) {
393
+ $found_products = $this->filter_found_products_by_language( $found_products, $_COOKIE['_wcml_dashboard_order_language'] );
394
+ } else {
395
+ $found_products = $this->filter_found_products_by_language( $found_products );
396
+ }
397
+
398
+ return $found_products;
399
+ }
400
+
401
+ // update menu_order fro translations after ordering original products.
402
+ public function update_all_products_translations_ordering() {
403
+ if ( $this->woocommerce_wpml->settings['products_sync_order'] ) {
404
+ $current_language = $this->sitepress->get_current_language();
405
+ if ( $current_language == $this->sitepress->get_default_language() ) {
406
+ $products = $this->wpdb->get_results(
407
+ $this->wpdb->prepare(
408
+ "SELECT p.ID FROM {$this->wpdb->posts} AS p
409
  LEFT JOIN {$this->wpdb->prefix}icl_translations AS icl
410
  ON icl.element_id = p.id
411
  WHERE p.post_type = 'product'
412
  AND p.post_status IN ( 'publish', 'future', 'draft', 'pending', 'private' )
413
  AND icl.element_type= 'post_product'
414
  AND icl.language_code = %s",
415
+ $current_language
416
+ )
417
+ );
418
+
419
+ foreach ( $products as $product ) {
420
+ $this->update_order_for_product_translations( (int)$product->ID );
421
+ }
422
+ }
423
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
424
  }
425
 
426
+ /**
427
+ * update menu_order fro translations after ordering original products
428
+ *
429
+ * @param int $product_id
430
+ */
431
+ public function update_order_for_product_translations( $product_id ) {
432
+ if ( isset( $this->woocommerce_wpml->settings['products_sync_order'] ) && $this->woocommerce_wpml->settings['products_sync_order'] ) {
433
+ $current_language = $this->sitepress->get_current_language();
434
 
435
+ if ( $current_language == $this->sitepress->get_default_language() ) {
436
+ $menu_order = $this->wpdb->get_var( $this->wpdb->prepare( "SELECT menu_order FROM {$this->wpdb->posts} WHERE ID = %d", $product_id ) );
437
+ $translations = $this->post_translations->get_element_translations( $product_id );
438
 
439
+ foreach ( $translations as $translation ) {
440
+ if ( (int)$translation !== $product_id ) {
441
+ $this->wpdb->update( $this->wpdb->posts, [ 'menu_order' => $menu_order ], [ 'ID' => $translation ] );
442
+ }
443
+ }
444
+ }
445
+ }
446
+ }
447
 
448
+ public function filter_excerpt_field_content_copy( $elements ) {
449
+
450
+ if ( $elements['post_type'] == 'product' ) {
451
+ $elements['excerpt'] ['editor_type'] = 'editor';
452
+ }
453
+ if ( function_exists( 'format_for_editor' ) ) {
454
+ // WordPress 4.3 uses format_for_editor
455
+ $elements['excerpt']['value'] = htmlspecialchars_decode( format_for_editor( $elements['excerpt']['value'], $_POST['excerpt_type'] ) );
456
+ } else {
457
+ // Backwards compatible for WordPress < 4.3
458
+ if ( $_POST['excerpt_type'] == 'rich' ) {
459
+ $elements['excerpt']['value'] = htmlspecialchars_decode( wp_richedit_pre( $elements['excerpt']['value'] ) );
460
+ } else {
461
+ $elements['excerpt']['value'] = htmlspecialchars_decode( wp_htmledit_pre( $elements['excerpt']['value'] ) );
462
+ }
463
+ }
464
+ return $elements;
465
+ }
466
+
467
+ public function filter_related_products_args( $args ) {
468
+ if ( $this->woocommerce_wpml->settings['enable_multi_currency'] == WCML_MULTI_CURRENCIES_INDEPENDENT &&
469
+ isset( $this->woocommerce_wpml->settings['display_custom_prices'] ) &&
470
+ $this->woocommerce_wpml->settings['display_custom_prices'] ) {
471
+
472
+ $client_currency = $this->woocommerce_wpml->multi_currency->get_client_currency();
473
+ $woocommerce_currency = wcml_get_woocommerce_currency_option();
474
+
475
+ if ( $client_currency != $woocommerce_currency ) {
476
+ $args['meta_query'][] = [
477
+ 'key' => '_wcml_custom_prices_status',
478
+ 'value' => 1,
479
+ 'compare' => '=',
480
+ ];
481
+ }
482
+ }
483
+ return $args;
484
+ }
485
 
486
  /**
487
  * @param array $query
491
  public function filter_related_products_query( $query ) {
492
 
493
  $query['join'] .= " LEFT JOIN {$this->wpdb->prefix}icl_translations AS icl ON icl.element_id = p.ID ";
494
+ $query['where'] .= $this->wpdb->prepare( ' AND icl.language_code = %s ', $this->sitepress->get_current_language() );
495
 
496
  return $query;
497
  }
498
 
499
+ /*
500
+ * get meta ids for multiple values post meta key
501
+ */
502
+ public function get_mid_ids_by_key( $post_id, $meta_key ) {
503
+ $ids = $this->wpdb->get_col( $this->wpdb->prepare( "SELECT meta_id FROM {$this->wpdb->postmeta} WHERE post_id = %d AND meta_key = %s", $post_id, $meta_key ) );
504
+ if ( $ids ) {
505
+ return $ids;
506
+ }
507
 
508
+ return false;
509
+ }
510
 
511
+ // count "in progress" and "waiting on translation" as untranslated too
512
+ public function get_untranslated_products_count( $language ) {
513
 
514
+ $count = 0;
515
 
516
+ $products = $this->wpdb->get_results(
517
+ "
518
  SELECT p.ID, t.trid, t.language_code
519
  FROM {$this->wpdb->posts} AS p
520
  LEFT JOIN {$this->wpdb->prefix}icl_translations AS t ON t.element_id = p.id
521
  WHERE p.post_type = 'product' AND t.element_type = 'post_product' AND t.source_language_code IS NULL
522
+ "
523
+ );
 
 
 
 
524
 
525
+ foreach ( $products as $product ) {
526
+ if ( $product->language_code == $language ) {
527
+ continue;
528
+ }
529
 
530
+ $translation_status = apply_filters( 'wpml_translation_status', null, $product->trid, $language );
 
531
 
532
+ if ( in_array( $translation_status, [ ICL_TM_NOT_TRANSLATED, ICL_TM_WAITING_FOR_TRANSLATOR, ICL_TM_IN_PROGRESS ] ) ) {
533
+ $count++;
534
+ }
535
+ }
536
 
537
+ return $count;
538
+ }
539
 
540
+ public function is_hide_resign_button() {
541
+ global $iclTranslationManagement;
542
 
543
+ $hide_resign = false;
 
544
 
545
+ if ( isset( $_GET['source_language_code'] ) && isset( $_GET['language_code'] ) ) {
546
 
547
+ $from_lang = $_GET['source_language_code'];
548
+ $to_lang = $_GET['language_code'];
 
 
 
 
549
 
550
+ } elseif ( isset( $_GET['job_id'] ) ) {
551
 
552
+ $job = $iclTranslationManagement->get_translation_job( $_GET['job_id'] );
553
+ if ( $job ) {
554
+ $from_lang = $job->source_language_code;
555
+ $to_lang = $job->language_code;
556
+ }
557
+ }
558
 
559
+ if ( isset( $from_lang ) ) {
 
 
560
 
561
+ $translators = $iclTranslationManagement->get_blog_translators(
562
+ [
563
+ 'from' => $from_lang,
564
+ 'to' => $to_lang,
565
+ ]
566
+ );
567
 
568
+ if ( empty( $translators ) || ( sizeof( $translators ) == 1 && $translators[0]->ID == get_current_user_id() ) ) {
569
+ $hide_resign = true;
570
+ }
571
+ }
572
 
573
+ return $hide_resign;
574
+ }
575
 
576
+ public function switch_product_variations_language() {
 
577
 
578
+ $lang_to = false;
579
+ $post_id = false;
 
 
 
 
580
 
581
+ if ( isset( $_POST['wpml_to'] ) ) {
582
+ $lang_to = $_POST['wpml_to'];
583
+ }
584
+ if ( isset( $_POST['wpml_post_id'] ) ) {
585
+ $post_id = $_POST['wpml_post_id'];
586
+ }
 
587
 
588
+ if ( $post_id && $lang_to && get_post_type( $post_id ) == 'product' ) {
589
+ $product_variations = $this->woocommerce_wpml->sync_variations_data->get_product_variations( $post_id );
590
+ foreach ( $product_variations as $product_variation ) {
591
+ $trid = $this->sitepress->get_element_trid( $product_variation->ID, 'post_product_variation' );
592
+ $current_prod_variation_id = apply_filters( 'translate_object_id', $product_variation->ID, 'product_variation', false, $lang_to );
593
+ if ( is_null( $current_prod_variation_id ) ) {
594
+ $this->sitepress->set_element_language_details( $product_variation->ID, 'post_product_variation', $trid, $lang_to );
595
+
596
+ foreach ( get_post_custom( $product_variation->ID ) as $meta_key => $meta ) {
597
+ foreach ( $meta as $meta_value ) {
598
+ if ( substr( $meta_key, 0, 10 ) == 'attribute_' ) {
599
+ $trn_post_meta = $this->woocommerce_wpml->attributes->get_translated_variation_attribute_post_meta( $meta_value, $meta_key, $product_variation->ID, $product_variation->ID, $lang_to );
600
+ update_post_meta( $product_variation->ID, $trn_post_meta['meta_key'], $trn_post_meta['meta_value'] );
601
+ }
602
+ }
603
+ }
604
+ }
605
+ }
606
+ }
607
+ }
608
 
609
+ public function check_product_sku( $sku_found, $product_id, $sku ) {
610
 
611
  if ( $sku_found ) {
612
 
640
  return $sku_found;
641
  }
642
 
643
+ public function add_lang_to_shortcode_products_query( $query_args ) {
644
 
645
+ $query_args['lang'] = $this->sitepress->get_current_language();
646
 
647
+ return $query_args;
648
+ }
649
 
650
 
651
+ /**
652
+ * Get file download path in correct domain
653
+ *
654
+ * @param string $file_path file path URL
655
+ * @return string
656
+ */
657
+ public function filter_file_download_path( $file_path ) {
658
 
659
+ $is_per_domain = $this->sitepress->get_wp_api()->constant( 'WPML_LANGUAGE_NEGOTIATION_TYPE_DOMAIN' ) === (int) $this->sitepress->get_setting( 'language_negotiation_type' );
660
 
661
+ if ( $is_per_domain ) {
662
+ $wpml_url_helper = new WPML_URL_Converter_Url_Helper();
663
 
664
+ if ( strpos( trim( $file_path ), $wpml_url_helper->get_abs_home() ) === 0 ) {
665
+ $file_path = $this->sitepress->convert_url( $file_path );
666
+ }
667
+ }
668
 
669
+ return $file_path;
670
 
671
+ }
672
 
673
 
674
  /**
680
  }
681
 
682
 
683
+ public function is_customer_bought_product( $value, $customer_email, $user_id, $product_id ) {
684
 
685
+ if ( $this->is_customer_bought_original( $customer_email, $user_id, $product_id ) ) {
686
+ return true;
687
+ }
688
 
689
+ return $value;
690
+ }
691
 
692
  private function is_customer_bought_original( $customer_email, $user_id, $product_id ) {
693
 
694
  if ( ! $this->is_original_product( $product_id ) ) {
695
+ remove_filter(
696
+ 'woocommerce_pre_customer_bought_product',
697
+ [
698
+ $this,
699
+ 'is_customer_bought_product',
700
+ ],
701
+ 10,
702
+ 4
703
+ );
704
 
705
  $bought_original = wc_customer_bought_product( $customer_email, $user_id, $this->get_original_product_id( $product_id ) );
706
 
707
+ add_filter(
708
+ 'woocommerce_pre_customer_bought_product',
709
+ [
710
+ $this,
711
+ 'is_customer_bought_product',
712
+ ],
713
+ 10,
714
+ 4
715
+ );
716
 
717
  return (bool) $bought_original;
718
+ }
719
 
720
  return false;
721
  }
726
 
727
  $post_type = get_post_type( $product_id );
728
 
729
+ if ( in_array( $post_type, [ 'product', 'product_variation' ], true ) ) {
730
 
731
+ remove_filter( 'get_post_metadata', [ $this, 'filter_product_data' ], 10 );
732
 
733
  $data = get_post_meta( $product_id );
734
 
735
+ $meta_keys_to_filter = [];
736
  $is_mc_enabled = (int) $this->woocommerce_wpml->settings['enable_multi_currency'] === (int) $this->sitepress->get_wp_api()->constant( 'WCML_MULTI_CURRENCIES_INDEPENDENT' );
737
 
738
  if ( $is_mc_enabled ) {
758
  $data[ $meta_key ][0] = get_post_meta( $product_id, $meta_key, true );
759
  }
760
 
761
+ add_filter( 'get_post_metadata', [ $this, 'filter_product_data' ], 10, 3 );
762
  }
763
  }
764
 
770
  *
771
  * @return null|string
772
  */
773
+ public function get_product_price_from_db( $product_id ) {
774
 
775
+ return $this->wpdb->get_var( $this->wpdb->prepare( "SELECT meta_value FROM {$this->wpdb->postmeta} WHERE `meta_key` = '_price' AND post_id = %d ", $product_id ) );
776
+ }
777
 
778
  /**
779
  * return not cached value for product
780
  *
781
  * @param bool $product_type
782
+ * @param int $product_id
783
  *
784
  * @return bool|string
785
  */
801
  *
802
  * @return bool
803
  */
804
+ public function remove_post_meta_data_filter_on_checkout_stock_update( $reduce_stock ) {
805
+ if ( isset( $_GET['wc-ajax'] ) && 'checkout' === $_GET['wc-ajax'] ) {
806
+ remove_filter( 'get_post_metadata', [ $this, 'filter_product_data' ], 10, 3 );
807
  }
808
  return $reduce_stock;
809
  }
814
  'no' === get_option( 'woocommerce_enable_ajax_add_to_cart' ) &&
815
  constant( 'WPML_LANGUAGE_NEGOTIATION_TYPE_PARAMETER' ) === (int) $this->sitepress->get_setting( 'language_negotiation_type' )
816
  ) {
817
+ $current_language = $this->sitepress->get_current_language();
818
+ if ( $current_language !== $this->sitepress->get_default_language() ) {
819
+ $url .= '&lang=' . $this->sitepress->get_current_language();
820
+ }
821
  }
822
 
823
  return $url;
824
  }
825
 
826
  /**
827
+ * @param int $product_id
828
  * @param string $status
829
  */
830
  public function update_stock_status( $product_id, $status ) {
832
  $this->wpdb->query(
833
  $this->wpdb->prepare(
834
  "UPDATE {$this->wpdb->wc_product_meta_lookup} SET stock_status = %s WHERE product_id = %d",
835
+ $status,
836
+ $product_id
837
+ )
838
  );
839
  }
840
  }
inc/class-wcml-reports.php CHANGED
@@ -14,17 +14,17 @@ class WCML_Reports{
14
 
15
  public function init(){
16
 
17
- if( isset($_GET['page']) && $_GET['page'] == 'wc-reports' ) {
18
 
19
  $this->tab = isset( $_GET['tab'] ) ? $_GET['tab'] : 'orders';
20
  $this->report = isset( $_GET['report'] ) ? $_GET['report'] : '';
21
 
22
  add_filter( 'woocommerce_reports_get_order_report_query', array( $this, 'filter_reports_query' ), 0 );
23
 
24
- if ( $this->tab == 'orders' && $this->report == 'sales_by_product' ) {
25
  add_filter( 'woocommerce_reports_get_order_report_data', array( $this, 'combine_report_by_languages' ) );
26
  }
27
- if ( $this->tab == 'orders' && $this->report == 'sales_by_category' ) {
28
  add_filter( 'woocommerce_report_sales_by_category_get_products_in_category', array(
29
  $this,
30
  'use_categories_in_all_languages'
@@ -44,14 +44,14 @@ class WCML_Reports{
44
  $current_language = $sitepress->get_current_language();
45
  $active_languages = $sitepress->get_active_languages();
46
 
47
- if($this->tab == 'orders' && $this->report == 'sales_by_product'){
48
 
49
  $sparkline_query = strpos( $query[ 'select'], 'sparkline_value' ) !== false;
50
 
51
  if(
52
 
53
  $sparkline_query ||
54
- isset( $query[ 'order_by' ] ) && ( $query[ 'order_by' ] == 'ORDER BY order_item_qty DESC' || $query[ 'order_by' ] == 'ORDER BY order_item_total DESC' )
55
 
56
  ){
57
 
@@ -85,13 +85,13 @@ class WCML_Reports{
85
 
86
  }
87
 
88
- $query[ 'select' ] .= ', translations.language_code AS language_code_' . esc_sql( str_replace('-', '_', $current_language) ); // user for per-language caching
89
 
90
  }elseif(
91
- $query[ 'select' ] == 'SELECT SUM( order_item_meta__line_total.meta_value) as order_item_amount' || //sales for the selected items
92
- $query[ 'select' ] == 'SELECT SUM( order_item_meta__qty.meta_value) as order_item_count' || //purchases for the selected items
93
- $query[ 'select' ] == 'SELECT SUM( order_item_meta__qty.meta_value) as order_item_count, posts.post_date as post_date, order_item_meta__product_id.meta_value as product_id' || //Get orders and dates in range - main chart: order_item_counts
94
- $query[ 'select' ] == 'SELECT SUM( order_item_meta__line_total.meta_value) as order_item_amount, posts.post_date as post_date, order_item_meta__product_id.meta_value as product_id' //Get orders and dates in range - main chart: order_item_amounts
95
 
96
  ){
97
  preg_match("#order_item_meta__product_id_array\.meta_value IN \(([^\)]+)\)#", $query[ 'where' ], $matches);
@@ -152,7 +152,7 @@ class WCML_Reports{
152
  break;
153
  }
154
 
155
- if($row->order_language == $current_language){
156
 
157
  $combined_results[$key] = $row;
158
 
14
 
15
  public function init(){
16
 
17
+ if( isset($_GET['page']) && $_GET['page']==='wc-reports' ) {
18
 
19
  $this->tab = isset( $_GET['tab'] ) ? $_GET['tab'] : 'orders';
20
  $this->report = isset( $_GET['report'] ) ? $_GET['report'] : '';
21
 
22
  add_filter( 'woocommerce_reports_get_order_report_query', array( $this, 'filter_reports_query' ), 0 );
23
 
24
+ if ( $this->tab==='orders' && $this->report==='sales_by_product' ) {
25
  add_filter( 'woocommerce_reports_get_order_report_data', array( $this, 'combine_report_by_languages' ) );
26
  }
27
+ if ( $this->tab==='orders' && $this->report==='sales_by_category' ) {
28
  add_filter( 'woocommerce_report_sales_by_category_get_products_in_category', array(
29
  $this,
30
  'use_categories_in_all_languages'
44
  $current_language = $sitepress->get_current_language();
45
  $active_languages = $sitepress->get_active_languages();
46
 
47
+ if($this->tab==='orders' && $this->report==='sales_by_product'){
48
 
49
  $sparkline_query = strpos( $query[ 'select'], 'sparkline_value' ) !== false;
50
 
51
  if(
52
 
53
  $sparkline_query ||
54
+ isset( $query[ 'order_by' ] ) && ( $query[ 'order_by' ]==='ORDER BY order_item_qty DESC' || $query[ 'order_by' ]==='ORDER BY order_item_total DESC' )
55
 
56
  ){
57
 
85
 
86
  }
87
 
88
+ $query[ 'select' ] .= ', translations.language_code AS language_code_' . esc_sql( str_replace('-', '_', $current_language) ); // user for per-language caching.
89
 
90
  }elseif(
91
+ $query[ 'select' ]==='SELECT SUM( order_item_meta__line_total.meta_value) as order_item_amount' || //sales for the selected items
92
+ $query[ 'select' ]==='SELECT SUM( order_item_meta__qty.meta_value) as order_item_count' || //purchases for the selected items
93
+ $query[ 'select' ]==='SELECT SUM( order_item_meta__qty.meta_value) as order_item_count, posts.post_date as post_date, order_item_meta__product_id.meta_value as product_id' || //Get orders and dates in range - main chart: order_item_counts
94
+ $query[ 'select' ]==='SELECT SUM( order_item_meta__line_total.meta_value) as order_item_amount, posts.post_date as post_date, order_item_meta__product_id.meta_value as product_id' //Get orders and dates in range - main chart: order_item_amounts
95
 
96
  ){
97
  preg_match("#order_item_meta__product_id_array\.meta_value IN \(([^\)]+)\)#", $query[ 'where' ], $matches);
152
  break;
153
  }
154
 
155
+ if($row->order_language===$current_language){
156
 
157
  $combined_results[$key] = $row;
158
 
inc/class-wcml-requests.php CHANGED
@@ -1,103 +1,103 @@
1
  <?php
2
- class WCML_Requests{
3
-
4
- function __construct(){
5
-
6
- add_action('init', array($this, 'run') );
7
-
8
- }
9
-
10
- function run(){
11
- global $woocommerce_wpml;
12
-
13
- $nonce = filter_input( INPUT_POST, 'wcml_nonce', FILTER_SANITIZE_FULL_SPECIAL_CHARS );
14
- $settings_needs_update = false;
15
-
16
- if( isset( $_GET[ 'wcml_action' ] ) ){
17
- $settings_needs_update = true;
18
-
19
- if( $_GET['wcml_action'] == 'dismiss' ){
20
- $woocommerce_wpml->settings['dismiss_doc_main'] = 1;
21
- }elseif( $_GET['wcml_action'] == 'dismiss_tm_warning' ){
22
- $woocommerce_wpml->settings['dismiss_tm_warning'] = 1;
23
- }elseif( $_GET['wcml_action'] == 'dismiss_cart_warning' ){
24
- $woocommerce_wpml->settings['dismiss_cart_warning'] = 1;
25
- }else{
26
- $settings_needs_update = false;
27
- }
28
- }
29
-
30
- if(isset($_POST['wcml_save_settings']) && wp_verify_nonce($nonce, 'wcml_save_settings_nonce')){
31
- global $sitepress,$sitepress_settings;
32
-
33
- if ( isset( $_POST['trnsl_interface'] ) ){
34
- $woocommerce_wpml->settings['trnsl_interface'] = filter_input( INPUT_POST, 'trnsl_interface', FILTER_SANITIZE_NUMBER_INT );
35
- }
36
-
37
- $woocommerce_wpml->settings['products_sync_date'] = empty($_POST['products_sync_date']) ? 0 : 1;
38
- $woocommerce_wpml->settings['products_sync_order'] = empty($_POST['products_sync_order']) ? 0 : 1;
39
-
40
- $wcml_sync_media = empty( $_POST['sync_media'] ) ? 0 : 1;
41
- $woocommerce_wpml->update_setting( 'sync_media', $wcml_sync_media, true );
42
-
43
- $wcml_file_path_sync = filter_input( INPUT_POST, 'wcml_file_path_sync', FILTER_SANITIZE_NUMBER_INT );
44
-
45
- $woocommerce_wpml->settings['file_path_sync'] = $wcml_file_path_sync;
46
-
47
- if ( isset( $_POST['cart_sync_lang'] ) && isset( $_POST['cart_sync_currencies'] ) ) {
48
- $woocommerce_wpml->settings['cart_sync']['lang_switch'] = (int) filter_input( INPUT_POST, 'cart_sync_lang', FILTER_SANITIZE_NUMBER_INT );
49
- $woocommerce_wpml->settings['cart_sync']['currency_switch'] = (int) filter_input( INPUT_POST, 'cart_sync_currencies', FILTER_SANITIZE_NUMBER_INT );
50
- }
51
-
52
- $new_value = $wcml_file_path_sync == 0 ? 2 :$wcml_file_path_sync;
53
- $sitepress_settings['translation-management']['custom_fields_translation']['_downloadable_files'] = $new_value;
54
- $sitepress_settings['translation-management']['custom_fields_translation']['_file_paths'] = $new_value;
55
-
56
- $sitepress->save_settings($sitepress_settings);
57
-
58
- $message = array(
59
- 'id' => 'wcml-settings-saved',
60
- 'text' => __('Your settings have been saved.', 'woocommerce-multilingual' ),
61
- 'group' => 'wcml-settings',
62
- 'admin_notice' => true,
63
- 'limit_to_page' => true,
64
- 'classes' => array('updated', 'notice', 'notice-success'),
65
- 'show_once' => true
66
- );
67
- ICL_AdminNotifier::add_message( $message );
68
-
69
- $settings_needs_update = true;
70
- }
71
-
72
- if( $settings_needs_update ){
73
- $woocommerce_wpml->update_settings();
74
- }
75
-
76
- add_action('wp_ajax_wcml_ignore_warning', array( $this, 'update_settings_from_warning') );
77
-
78
- // Override cached widget id
79
- add_filter( 'woocommerce_cached_widget_id', array( $this, 'override_cached_widget_id' ) );
80
- }
81
-
82
- function update_settings_from_warning(){
83
- $nonce = filter_input( INPUT_POST, 'wcml_nonce', FILTER_SANITIZE_FULL_SPECIAL_CHARS );
84
- if(!$nonce || !wp_verify_nonce($nonce, 'wcml_ignore_warning')){
85
- die('Invalid nonce');
86
- }
87
- global $woocommerce_wpml;
88
-
89
- $woocommerce_wpml->settings[$_POST['setting']] = 1;
90
- $woocommerce_wpml->update_settings();
91
-
92
- }
93
-
94
- public function override_cached_widget_id( $widget_id ){
95
-
96
- if( defined( 'ICL_LANGUAGE_CODE' ) ){
97
- $widget_id .= ':' . ICL_LANGUAGE_CODE;
98
- }
99
-
100
- return $widget_id;
101
- }
102
-
103
- }
1
  <?php
2
+ class WCML_Requests {
3
+
4
+ public function __construct() {
5
+
6
+ add_action( 'init', [ $this, 'run' ] );
7
+
8
+ }
9
+
10
+ public function run() {
11
+ global $woocommerce_wpml;
12
+
13
+ $nonce = filter_input( INPUT_POST, 'wcml_nonce', FILTER_SANITIZE_FULL_SPECIAL_CHARS );
14
+ $settings_needs_update = false;
15
+
16
+ if ( isset( $_GET['wcml_action'] ) ) {
17
+ $settings_needs_update = true;
18
+
19
+ if ( 'dismiss' === $_GET['wcml_action'] ) {
20
+ $woocommerce_wpml->settings['dismiss_doc_main'] = 1;
21
+ } elseif ( 'dismiss_tm_warning' === $_GET['wcml_action'] ) {
22
+ $woocommerce_wpml->settings['dismiss_tm_warning'] = 1;
23
+ } elseif ( 'dismiss_cart_warning' === $_GET['wcml_action'] ) {
24
+ $woocommerce_wpml->settings['dismiss_cart_warning'] = 1;
25
+ } else {
26
+ $settings_needs_update = false;
27
+ }
28
+ }
29
+
30
+ if ( isset( $_POST['wcml_save_settings'] ) && wp_verify_nonce( $nonce, 'wcml_save_settings_nonce' ) ) {
31
+ global $sitepress,$sitepress_settings;
32
+
33
+ if ( isset( $_POST['trnsl_interface'] ) ) {
34
+ $woocommerce_wpml->settings['trnsl_interface'] = filter_input( INPUT_POST, 'trnsl_interface', FILTER_SANITIZE_NUMBER_INT );
35
+ }
36
+
37
+ $woocommerce_wpml->settings['products_sync_date'] = empty( $_POST['products_sync_date'] ) ? 0 : 1;
38
+ $woocommerce_wpml->settings['products_sync_order'] = empty( $_POST['products_sync_order'] ) ? 0 : 1;
39
+
40
+ $wcml_sync_media = empty( $_POST['sync_media'] ) ? 0 : 1;
41
+ $woocommerce_wpml->update_setting( 'sync_media', $wcml_sync_media, true );
42
+
43
+ $wcml_file_path_sync = filter_input( INPUT_POST, 'wcml_file_path_sync', FILTER_SANITIZE_NUMBER_INT );
44
+
45
+ $woocommerce_wpml->settings['file_path_sync'] = $wcml_file_path_sync;
46
+
47
+ if ( isset( $_POST['cart_sync_lang'] ) && isset( $_POST['cart_sync_currencies'] ) ) {
48
+ $woocommerce_wpml->settings['cart_sync']['lang_switch'] = (int) filter_input( INPUT_POST, 'cart_sync_lang', FILTER_SANITIZE_NUMBER_INT );
49
+ $woocommerce_wpml->settings['cart_sync']['currency_switch'] = (int) filter_input( INPUT_POST, 'cart_sync_currencies', FILTER_SANITIZE_NUMBER_INT );
50
+ }
51
+
52
+ $new_value = $wcml_file_path_sync == 0 ? 2 : $wcml_file_path_sync;
53
+ $sitepress_settings['translation-management']['custom_fields_translation']['_downloadable_files'] = $new_value;
54
+ $sitepress_settings['translation-management']['custom_fields_translation']['_file_paths'] = $new_value;
55
+
56
+ $sitepress->save_settings( $sitepress_settings );
57
+
58
+ $message = [
59
+ 'id' => 'wcml-settings-saved',
60
+ 'text' => __( 'Your settings have been saved.', 'woocommerce-multilingual' ),
61
+ 'group' => 'wcml-settings',
62
+ 'admin_notice' => true,
63
+ 'limit_to_page' => true,
64
+ 'classes' => [ 'updated', 'notice', 'notice-success' ],
65
+ 'show_once' => true,
66
+ ];
67
+ ICL_AdminNotifier::add_message( $message );
68
+
69
+ $settings_needs_update = true;
70
+ }
71
+
72
+ if ( $settings_needs_update ) {
73
+ $woocommerce_wpml->update_settings();
74
+ }
75
+
76
+ add_action( 'wp_ajax_wcml_ignore_warning', [ $this, 'update_settings_from_warning' ] );
77
+
78
+ // Override cached widget id.
79
+ add_filter( 'woocommerce_cached_widget_id', [ $this, 'override_cached_widget_id' ] );
80
+ }
81
+
82
+ public function update_settings_from_warning() {
83
+ $nonce = filter_input( INPUT_POST, 'wcml_nonce', FILTER_SANITIZE_FULL_SPECIAL_CHARS );
84
+ if ( ! $nonce || ! wp_verify_nonce( $nonce, 'wcml_ignore_warning' ) ) {
85
+ die( 'Invalid nonce' );
86
+ }
87
+ global $woocommerce_wpml;
88
+
89
+ $woocommerce_wpml->settings[ $_POST['setting'] ] = 1;
90
+ $woocommerce_wpml->update_settings();
91
+
92
+ }
93
+
94
+ public function override_cached_widget_id( $widget_id ) {
95
+
96
+ if ( defined( 'ICL_LANGUAGE_CODE' ) ) {
97
+ $widget_id .= ':' . ICL_LANGUAGE_CODE;
98
+ }
99
+
100
+ return $widget_id;
101
+ }
102
+
103
+ }
inc/class-wcml-resources.php CHANGED
@@ -2,17 +2,17 @@
2
 
3
  class WCML_Resources {
4
 
5
- private static $page;
6
- private static $tab;
7
- private static $is_wpml_wcml_page;
8
- private static $pagenow;
9
 
10
- private static $woocommerce_wpml;
11
- private static $sitepress;
12
 
13
- public static function add_hooks(){
14
- add_action( 'admin_enqueue_scripts', array( __CLASS__, 'admin_scripts' ) );
15
- add_action( 'wp_enqueue_scripts', array( __CLASS__, 'front_scripts' ) );
16
  }
17
 
18
  /**
@@ -20,284 +20,306 @@ class WCML_Resources {
20
  * @param SitePress $sitepress
21
  */
22
  public static function set_up_resources( $woocommerce_wpml, $sitepress ) {
23
- global $pagenow;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
24
 
25
- self::$woocommerce_wpml = $woocommerce_wpml;
26
- self::$sitepress = $sitepress;
 
 
 
27
 
28
- self::$page = isset($_GET['page']) ? $_GET['page'] : null;
29
- self::$tab = isset($_GET['tab']) ? $_GET['tab'] : null;
30
- self::$is_wpml_wcml_page = self::$page == 'wpml-wcml';
31
- self::$pagenow = $pagenow;
32
 
33
- self::load_css();
34
 
35
- $is_edit_product = self::$pagenow == 'post.php' && isset($_GET['post']) && get_post_type( $_GET['post'] ) == 'product';
36
- $is_original_product = isset( $_GET['post'] ) && !is_array( $_GET['post'] ) && self::$woocommerce_wpml->products->is_original_product( $_GET['post'] );
37
- $is_new_product = self::$pagenow == 'post-new.php' && isset($_GET['source_lang']) && isset($_GET['post_type']) && $_GET['post_type'] == 'product';
38
 
39
- if( self::$woocommerce_wpml->is_wpml_prior_4_2() ){
40
- $is_using_native_editor = !self::$woocommerce_wpml->settings['trnsl_interface'];
41
- }else{
42
- $tm_settings = $sitepress->get_setting( 'translation-management', array() );
43
- if( $is_edit_product ){
44
- $is_using_native_editor = WPML_TM_Post_Edit_TM_Editor_Mode::is_using_tm_editor( self::$sitepress, filter_var( $_GET['post'], FILTER_SANITIZE_NUMBER_INT ) );
45
- }else{
46
- $is_using_native_editor = isset( $tm_settings[ WPML_TM_Post_Edit_TM_Editor_Mode::TM_KEY_FOR_POST_TYPE_USE_NATIVE ][ 'product' ]) ? $tm_settings[ WPML_TM_Post_Edit_TM_Editor_Mode::TM_KEY_FOR_POST_TYPE_USE_NATIVE ][ 'product' ] : false;
47
 
48
- if ( ! $is_using_native_editor ) {
49
- $is_using_native_editor = isset( $tm_settings[ WPML_TM_Post_Edit_TM_Editor_Mode::TM_KEY_GLOBAL_USE_NATIVE ] ) ? $tm_settings[ WPML_TM_Post_Edit_TM_Editor_Mode::TM_KEY_GLOBAL_USE_NATIVE ] : false;
50
- }
51
- }
52
- }
53
 
54
- if ( ($is_edit_product && !$is_original_product) || $is_new_product && $is_using_native_editor ) {
55
- add_action( 'init', array(__CLASS__, 'load_lock_fields_js') );
56
- add_action( 'admin_footer', array(__CLASS__, 'hidden_label') );
57
- }
58
- }
59
 
60
- private static function load_css() {
61
-
62
- if ( self::$is_wpml_wcml_page || self::$page == WPML_TM_FOLDER . '/menu/translations-queue.php' ) {
 
 
63
 
64
- self::load_management_css();
 
 
 
65
 
66
- if ( in_array( self::$tab, array('multi-currency', 'slugs') ) ) {
67
- wp_register_style( 'wcml-dialogs', WCML_PLUGIN_URL . '/res/css/dialogs.css', array('wpml-dialog'), WCML_VERSION );
68
- wp_enqueue_style( 'wcml-dialogs' );
69
- }
70
 
71
- wp_enqueue_style( 'wp-color-picker' );
72
- }
73
 
74
- if ( self::$pagenow == 'options-permalink.php' ) {
75
- wp_register_style( 'wcml_op', WCML_PLUGIN_URL . '/res/css/options-permalink.css', null, WCML_VERSION );
76
- wp_enqueue_style( 'wcml_op' );
77
- }
78
 
79
- if( is_admin() ){
80
- wp_register_style( 'wcml_admin', WCML_PLUGIN_URL . '/res/css/admin.css', array( 'wp-pointer' ), WCML_VERSION );
81
- wp_enqueue_style( 'wcml_admin' );
82
- }
83
- }
84
 
85
- public static function load_management_css() {
86
- wp_register_style( 'wpml-wcml', WCML_PLUGIN_URL . '/res/css/management.css', array(), WCML_VERSION );
87
- wp_enqueue_style( 'wpml-wcml' );
88
- }
89
 
90
- public static function load_taxonomy_translation_scripts(){
91
- wp_register_script( 'wcml-taxonomy-translation-scripts', WCML_PLUGIN_URL . '/res/js/taxonomy_translation' . WCML_JS_MIN . '.js', array( 'jquery' ), WCML_VERSION, true );
92
- wp_enqueue_script( 'wcml-taxonomy-translation-scripts' );
93
- }
94
 
95
- public static function admin_scripts() {
 
 
 
96
 
97
- if ( self::$is_wpml_wcml_page ) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
98
 
99
- wp_register_script( 'wcml-scripts', WCML_PLUGIN_URL . '/res/js/scripts' . WCML_JS_MIN . '.js', array( 'jquery', 'jquery-ui-core', 'jquery-ui-resizable' ), WCML_VERSION, true );
 
 
 
100
 
101
- self::load_taxonomy_translation_scripts();
 
 
 
102
 
103
- wp_register_script( 'jquery-cookie', WCML_PLUGIN_URL . '/res/js/jquery.cookie' . WCML_JS_MIN . '.js', array( 'jquery' ), WCML_VERSION, true );
104
- wp_register_script( 'wcml-dialogs', WCML_PLUGIN_URL . '/res/js/dialogs' . WCML_JS_MIN . '.js', array( 'jquery', 'jquery-ui-core', 'jquery-ui-dialog', 'underscore' ), WCML_VERSION, true );
105
- wp_register_script( 'wcml-troubleshooting', WCML_PLUGIN_URL . '/res/js/troubleshooting' . WCML_JS_MIN . '.js', array( 'jquery' ), WCML_VERSION, true );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
106
 
107
- if( self::$woocommerce_wpml->is_wpml_prior_4_2() ){
108
- wp_register_script( 'wcml-translation-interface-dialog-warning', WCML_PLUGIN_URL . '/res/js/trnsl_interface_dialog_warning' . WCML_JS_MIN . '.js', array( 'jquery' ), WCML_VERSION, true );
109
- wp_enqueue_script( 'wcml-translation-interface-dialog-warning' );
110
- }
111
 
 
 
 
 
112
 
113
- wp_enqueue_script( 'wcml-scripts' );
114
- wp_enqueue_script( 'wp-color-picker');
115
- wp_enqueue_script( 'wcml-dialogs' );
116
- wp_enqueue_script( 'jquery-cookie' );
117
- wp_enqueue_script( 'wcml-troubleshooting' );
118
-
119
- wp_localize_script( 'wcml-scripts', 'wcml_settings',
120
- array(
121
- 'nonce' => wp_create_nonce( 'woocommerce_multilingual' )
122
- )
123
- );
124
-
125
- self::load_tooltip_resources();
126
- }
127
-
128
- if ( self::$page == WPML_TM_FOLDER . '/menu/main.php' ) {
129
- wp_register_script( 'wpml_tm', WCML_PLUGIN_URL . '/res/js/wpml_tm' . WCML_JS_MIN . '.js', array( 'jquery' ), WCML_VERSION, true );
130
- wp_enqueue_script( 'wpml_tm' );
131
- }
132
-
133
- if ( self::$pagenow == 'widgets.php' ) {
134
- wp_register_script( 'wcml_widgets', WCML_PLUGIN_URL . '/res/js/widgets' . WCML_JS_MIN . '.js', array( 'jquery' ), WCML_VERSION, true );
135
- wp_enqueue_script( 'wcml_widgets' );
136
- }
137
-
138
- if ( self::$page == 'wpml-wcml' && self::$tab == 'multi-currency' ) {
139
- wp_register_script( 'multi-currency', WCML_PLUGIN_URL . '/res/js/multi-currency' . WCML_JS_MIN . '.js', array('jquery', 'jquery-ui-sortable'), WCML_VERSION, true );
140
- wp_enqueue_script( 'multi-currency' );
141
-
142
- wp_register_script( 'currency-switcher-settings', WCML_PLUGIN_URL . '/res/js/currency-switcher-settings' . WCML_JS_MIN . '.js', array( 'jquery', 'jquery-ui-sortable', 'underscore' ), WCML_VERSION, true );
143
- wp_enqueue_script( 'currency-switcher-settings' );
144
- wp_localize_script( 'currency-switcher-settings', 'settings', array(
145
- 'pre_selected_colors' => WCML_Currency_Switcher_Options_Dialog::currency_switcher_pre_selected_colors()
146
- ) );
147
-
148
- wp_register_script( 'exchange-rates', WCML_PLUGIN_URL . '/res/js/exchange-rates' . WCML_JS_MIN . '.js', array('jquery'), WCML_VERSION, true );
149
- wp_enqueue_script( 'exchange-rates' );
150
- }
151
-
152
- if ( self::$page == 'wpml-wcml' && self::$tab == 'product-attributes' ) {
153
- wp_register_script( 'product-attributes', WCML_PLUGIN_URL . '/res/js/product-attributes' . WCML_JS_MIN . '.js', array('jquery'), WCML_VERSION, true );
154
- wp_enqueue_script( 'product-attributes' );
155
- }
156
-
157
- if ( self::$page == 'wpml-wcml' && self::$tab == 'custom-taxonomies' ) {
158
- wp_register_script( 'custom-taxonomies', WCML_PLUGIN_URL . '/res/js/product-custom-taxonomies' . WCML_JS_MIN . '.js', array('jquery'), WCML_VERSION, true );
159
- wp_enqueue_script( 'custom-taxonomies' );
160
- }
161
-
162
- wp_enqueue_script(
163
- 'wcml-pointer',
164
- WCML_PLUGIN_URL . '/res/js/pointer' . WCML_JS_MIN . '.js',
165
- array( 'wp-pointer' ),
166
- WCML_VERSION,
167
- true
168
- );
169
-
170
- wp_register_script( 'wcml-messages', WCML_PLUGIN_URL . '/res/js/wcml-messages' . WCML_JS_MIN . '.js', array( 'jquery' ), WCML_VERSION, true );
171
- wp_enqueue_script( 'wcml-messages' );
172
-
173
- $is_attr_page = apply_filters( 'wcml_is_attributes_page', self::$page == 'product_attributes' && isset( $_GET[ 'post_type' ] ) && $_GET[ 'post_type' ] == 'product' );
174
-
175
- if( $is_attr_page ){
176
- wp_register_script( 'wcml-attributes', WCML_PLUGIN_URL . '/res/js/wcml-attributes' . WCML_JS_MIN . '.js', array( 'jquery' ), WCML_VERSION, true );
177
- wp_enqueue_script( 'wcml-attributes' );
178
- }
179
-
180
- if( self::$page == WPML_TM_FOLDER . '/menu/translations-queue.php' ) {
181
-
182
- self::load_tooltip_resources();
183
- wp_enqueue_media();
184
- wp_register_script( 'wcml-editor', WCML_PLUGIN_URL . '/res/js/wcml-translation-editor' . WCML_JS_MIN . '.js', array( 'jquery', 'jquery-ui-core' ), WCML_VERSION, true );
185
- wp_enqueue_script( 'wcml-editor' );
186
- wp_localize_script( 'wcml-editor', 'wcml_settings',
187
- array(
188
- 'strings' => array(
189
- 'choose' => __( 'Choose a file', 'woocommerce-multilingual' ),
190
- 'save_tooltip' => __( 'At least one of these fields is required: title, content or excerpt', 'woocommerce-multilingual' ),
191
- 'resign_tooltip'=> __( 'This translation job will no longer be assigned to you. Other translators will be able take it and continue the translation.', 'woocommerce-multilingual')
192
- ),
193
- 'hide_resign' => self::$woocommerce_wpml->products->is_hide_resign_button()
194
- )
195
- );
196
- }
197
-
198
- if ( isset( $_GET['post_type'] ) && 'product' === $_GET['post_type'] && 'edit.php' === self::$pagenow ) {
199
- self::load_tooltip_resources();
200
- wp_enqueue_script( 'products-screen-options', WCML_PLUGIN_URL . '/res/js/products-screen-option.js', array( 'jquery', 'wcml-tooltip-init' ), WCML_VERSION, true );
201
- wp_localize_script( 'products-screen-options', 'products_screen_option', array( 'nonce' => wp_create_nonce( 'products-screen-option-action' ) ) );
202
- }
203
- }
204
 
205
  public static function front_scripts() {
206
 
207
- if ( self::$pagenow != 'wp-login.php' ) {
208
 
209
- wp_register_script( 'wcml-front-scripts', WCML_PLUGIN_URL . '/res/js/front-scripts' . WCML_JS_MIN . '.js', array( 'jquery' ), WCML_VERSION, true );
210
  wp_enqueue_script( 'wcml-front-scripts' );
211
 
212
  $referer = isset( $_SERVER['HTTP_REFERER'] ) ? $_SERVER['HTTP_REFERER'] : '';
213
 
214
- wp_register_script( 'cart-widget', WCML_PLUGIN_URL . '/res/js/cart_widget' . WCML_JS_MIN . '.js', array( 'jquery' ), WCML_VERSION, true );
215
  wp_enqueue_script( 'cart-widget' );
216
- wp_localize_script( 'cart-widget', 'actions', array(
217
- 'is_lang_switched' => self::$sitepress->get_language_from_url( $referer ) != self::$sitepress->get_current_language() ? 1 : 0,
218
- 'force_reset' => apply_filters( 'wcml_force_reset_cart_fragments', 0 )
219
- ) );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
220
  }
221
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
222
  }
223
 
224
- public static function load_tooltip_resources() {
225
-
226
- if ( class_exists( 'WooCommerce' ) && function_exists( 'WC' ) ) {
227
- wp_register_script( 'jquery-tiptip', WC()->plugin_url() . '/assets/js/jquery-tiptip/jquery.tipTip.min.js', array('jquery'), WC_VERSION, true );
228
- wp_register_script( 'wcml-tooltip-init', WCML_PLUGIN_URL . '/res/js/tooltip_init' . WCML_JS_MIN . '.js', array( 'jquery' ), WCML_VERSION, true );
229
- wp_enqueue_script( 'jquery-tiptip' );
230
- wp_enqueue_script( 'wcml-tooltip-init' );
231
- wp_enqueue_style( 'woocommerce_admin_styles', WC()->plugin_url() . '/assets/css/admin.css', array(), WC_VERSION );
232
- }
233
-
234
- }
235
-
236
- public static function load_lock_fields_js() {
237
- global $pagenow;
238
-
239
- wp_register_script( 'wcml-lock-script', WCML_PLUGIN_URL . '/res/js/lock_fields' . WCML_JS_MIN . '.js', array( 'jquery' ), WCML_VERSION, true );
240
- wp_enqueue_script( 'wcml-lock-script' );
241
-
242
- $file_path_sync = self::$woocommerce_wpml->settings['file_path_sync'];
243
-
244
- $product_id = false;
245
- if( $pagenow === 'post.php' && isset( $_GET['post'] ) ){
246
- $product_id = $_GET['post'];
247
- }elseif( isset( $_POST['product_id'] ) ){
248
- $product_id = $_POST['product_id'];
249
- }
250
-
251
- if( $product_id ){
252
- $original_id = self::$woocommerce_wpml->products->get_original_product_id( $product_id );
253
- $custom_product_sync = get_post_meta( $original_id, 'wcml_sync_files', true );
254
- if( $custom_product_sync && $custom_product_sync == 'self' ) {
255
- $file_path_sync = false;
256
- }elseif( $custom_product_sync && $custom_product_sync == 'auto' ){
257
- $file_path_sync = true;
258
- }
259
- }
260
-
261
- wp_localize_script( 'wcml-lock-script', 'unlock_fields', array(
262
- 'menu_order' => self::$woocommerce_wpml->settings['products_sync_order'],
263
- 'file_paths' => $file_path_sync
264
- )
265
- );
266
- wp_localize_script( 'wcml-lock-script', 'non_standard_fields', array(
267
- 'ids' => apply_filters( 'wcml_js_lock_fields_ids', array() ),
268
- 'classes' => apply_filters( 'wcml_js_lock_fields_classes', array() ),
269
- 'input_names' => apply_filters( 'wcml_js_lock_fields_input_names', array() )
270
- ) );
271
-
272
- do_action( 'wcml_after_load_lock_fields_js' );
273
-
274
- }
275
-
276
- public static function hidden_label() {
277
- global $sitepress;
278
-
279
- echo '<img src="' . WCML_PLUGIN_URL . '/res/images/locked.png" class="wcml_lock_img wcml_lock_icon" alt="' .
280
- __( 'This field is locked for editing because WPML will copy its value from the original language.', 'woocommerce-multilingual' ) .
281
- '" title="' . __( 'This field is locked for editing because WPML will copy its value from the original language.', 'woocommerce-multilingual' ) .
282
- '" style="display: none;position:relative;left:2px;top:2px;">';
283
-
284
- if ( isset($_GET['post']) ) {
285
- $original_id = self::$woocommerce_wpml->products->get_original_product_id( sanitize_text_field( $_GET['post'] ) );
286
- } elseif ( isset($_GET['trid']) ) {
287
- $original_id = $sitepress->get_original_element_id_by_trid( sanitize_text_field( $_GET['trid'] ) );
288
- }
289
-
290
- if ( isset($_GET['lang']) ) {
291
- $language = $_GET['lang'];
292
- } else {
293
- return;
294
- }
295
-
296
- echo '<h3 class="wcml_prod_hidden_notice">' .
297
- sprintf( __( "This is a translation of %s. Some of the fields are not editable. It's recommended to use the %s for translating products.",
298
- 'woocommerce-multilingual' ),
299
- '<a href="' . get_edit_post_link( $original_id ) . '" >' . get_the_title( $original_id ) . '</a>',
300
- '<a data-action="product-translation-dialog" class="js-wcml-dialog-trigger" data-id="' . $original_id . '" data-job_id="" data-language="' . $language . '">' .
301
- __( 'WooCommerce Multilingual products translator', 'woocommerce-multilingual' ) . '</a>' ) . '</h3>';
302
- }
303
  }
2
 
3
  class WCML_Resources {
4
 
5
+ private static $page;
6
+ private static $tab;
7
+ private static $is_wpml_wcml_page;
8
+ private static $pagenow;
9
 
10
+ private static $woocommerce_wpml;
11
+ private static $sitepress;
12
 
13
+ public static function add_hooks() {
14
+ add_action( 'admin_enqueue_scripts', [ __CLASS__, 'admin_scripts' ] );
15
+ add_action( 'wp_enqueue_scripts', [ __CLASS__, 'front_scripts' ] );
16
  }
17
 
18
  /**
20
  * @param SitePress $sitepress
21
  */
22
  public static function set_up_resources( $woocommerce_wpml, $sitepress ) {
23
+ global $pagenow;
24
+
25
+ self::$woocommerce_wpml = $woocommerce_wpml;
26
+ self::$sitepress = $sitepress;
27
+
28
+ self::$page = isset( $_GET['page'] ) ? $_GET['page'] : null;
29
+ self::$tab = isset( $_GET['tab'] ) ? $_GET['tab'] : null;
30
+ self::$is_wpml_wcml_page = self::$page == 'wpml-wcml';
31
+ self::$pagenow = $pagenow;
32
+
33
+ self::load_css();
34
+
35
+ $is_edit_product = self::$pagenow == 'post.php' && isset( $_GET['post'] ) && get_post_type( $_GET['post'] ) == 'product';
36
+ $is_original_product = isset( $_GET['post'] ) && ! is_array( $_GET['post'] ) && self::$woocommerce_wpml->products->is_original_product( $_GET['post'] );
37
+ $is_new_product = self::$pagenow == 'post-new.php' && isset( $_GET['source_lang'] ) && isset( $_GET['post_type'] ) && $_GET['post_type'] == 'product';
38
+
39
+ if ( self::$woocommerce_wpml->is_wpml_prior_4_2() ) {
40
+ $is_using_native_editor = ! self::$woocommerce_wpml->settings['trnsl_interface'];
41
+ } else {
42
+ $tm_settings = $sitepress->get_setting( 'translation-management', [] );
43
+ if ( $is_edit_product ) {
44
+ $is_using_native_editor = WPML_TM_Post_Edit_TM_Editor_Mode::is_using_tm_editor( self::$sitepress, filter_var( $_GET['post'], FILTER_SANITIZE_NUMBER_INT ) );
45
+ } else {
46
+ $is_using_native_editor = isset( $tm_settings[ WPML_TM_Post_Edit_TM_Editor_Mode::TM_KEY_FOR_POST_TYPE_USE_NATIVE ]['product'] ) ? $tm_settings[ WPML_TM_Post_Edit_TM_Editor_Mode::TM_KEY_FOR_POST_TYPE_USE_NATIVE ]['product'] : false;
47
+
48
+ if ( ! $is_using_native_editor ) {
49
+ $is_using_native_editor = isset( $tm_settings[ WPML_TM_Post_Edit_TM_Editor_Mode::TM_KEY_GLOBAL_USE_NATIVE ] ) ? $tm_settings[ WPML_TM_Post_Edit_TM_Editor_Mode::TM_KEY_GLOBAL_USE_NATIVE ] : false;
50
+ }
51
+ }
52
+ }
53
 
54
+ if ( ( $is_edit_product && ! $is_original_product ) || $is_new_product && $is_using_native_editor ) {
55
+ add_action( 'init', [ __CLASS__, 'load_lock_fields_js' ] );
56
+ add_action( 'admin_footer', [ __CLASS__, 'hidden_label' ] );
57
+ }
58
+ }
59
 
60
+ private static function load_css() {
 
 
 
61
 
62
+ if ( self::$is_wpml_wcml_page || self::$page == WPML_TM_FOLDER . '/menu/translations-queue.php' ) {
63
 
64
+ self::load_management_css();
 
 
65
 
66
+ if ( in_array( self::$tab, [ 'multi-currency', 'slugs' ] ) ) {
67
+ wp_register_style( 'wcml-dialogs', WCML_PLUGIN_URL . '/res/css/dialogs.css', [ 'wpml-dialog' ], WCML_VERSION );
68
+ wp_enqueue_style( 'wcml-dialogs' );
69
+ }
 
 
 
 
70
 
71
+ wp_enqueue_style( 'wp-color-picker' );
72
+ }
 
 
 
73
 
74
+ if ( self::$pagenow == 'options-permalink.php' ) {
75
+ wp_register_style( 'wcml_op', WCML_PLUGIN_URL . '/res/css/options-permalink.css', null, WCML_VERSION );
76
+ wp_enqueue_style( 'wcml_op' );
77
+ }
 
78
 
79
+ if ( is_admin() ) {
80
+ wp_register_style( 'wcml_admin', WCML_PLUGIN_URL . '/res/css/admin.css', [ 'wp-pointer' ], WCML_VERSION );
81
+ wp_enqueue_style( 'wcml_admin' );
82
+ }
83
+ }
84
 
85
+ public static function load_management_css() {
86
+ wp_register_style( 'wpml-wcml', WCML_PLUGIN_URL . '/res/css/management.css', [], WCML_VERSION );
87
+ wp_enqueue_style( 'wpml-wcml' );
88
+ }
89
 
90
+ public static function load_taxonomy_translation_scripts() {
91
+ wp_register_script( 'wcml-taxonomy-translation-scripts', WCML_PLUGIN_URL . '/res/js/taxonomy_translation' . WCML_JS_MIN . '.js', [ 'jquery' ], WCML_VERSION, true );
92
+ wp_enqueue_script( 'wcml-taxonomy-translation-scripts' );
93
+ }
94
 
95
+ public static function admin_scripts() {
 
96
 
97
+ if ( self::$is_wpml_wcml_page ) {
 
 
 
98
 
99
+ wp_register_script( 'wcml-scripts', WCML_PLUGIN_URL . '/res/js/scripts' . WCML_JS_MIN . '.js', [ 'jquery', 'jquery-ui-core', 'jquery-ui-resizable' ], WCML_VERSION, true );
 
 
 
 
100
 
101
+ self::load_taxonomy_translation_scripts();
 
 
 
102
 
103
+ wp_register_script( 'jquery-cookie', WCML_PLUGIN_URL . '/res/js/jquery.cookie' . WCML_JS_MIN . '.js', [ 'jquery' ], WCML_VERSION, true );
104
+ wp_register_script( 'wcml-dialogs', WCML_PLUGIN_URL . '/res/js/dialogs' . WCML_JS_MIN . '.js', [ 'jquery', 'jquery-ui-core', 'jquery-ui-dialog', 'underscore' ], WCML_VERSION, true );
105
+ wp_register_script( 'wcml-troubleshooting', WCML_PLUGIN_URL . '/res/js/troubleshooting' . WCML_JS_MIN . '.js', [ 'jquery' ], WCML_VERSION, true );
 
106
 
107
+ if ( self::$woocommerce_wpml->is_wpml_prior_4_2() ) {
108
+ wp_register_script( 'wcml-translation-interface-dialog-warning', WCML_PLUGIN_URL . '/res/js/trnsl_interface_dialog_warning' . WCML_JS_MIN . '.js', [ 'jquery' ], WCML_VERSION, true );
109
+ wp_enqueue_script( 'wcml-translation-interface-dialog-warning' );
110
+ }
111
 
112
+ wp_enqueue_script( 'wcml-scripts' );
113
+ wp_enqueue_script( 'wp-color-picker' );
114
+ wp_enqueue_script( 'wcml-dialogs' );
115
+ wp_enqueue_script( 'jquery-cookie' );
116
+ wp_enqueue_script( 'wcml-troubleshooting' );
117
+
118
+ wp_localize_script(
119
+ 'wcml-scripts',
120
+ 'wcml_settings',
121
+ [
122
+ 'nonce' => wp_create_nonce( 'woocommerce_multilingual' ),
123
+ ]
124
+ );
125
+
126
+ self::load_tooltip_resources();
127
+ }
128
 
129
+ if ( self::$page == WPML_TM_FOLDER . '/menu/main.php' ) {
130
+ wp_register_script( 'wpml_tm', WCML_PLUGIN_URL . '/res/js/wpml_tm' . WCML_JS_MIN . '.js', [ 'jquery' ], WCML_VERSION, true );
131
+ wp_enqueue_script( 'wpml_tm' );
132
+ }
133
 
134
+ if ( self::$pagenow == 'widgets.php' ) {
135
+ wp_register_script( 'wcml_widgets', WCML_PLUGIN_URL . '/res/js/widgets' . WCML_JS_MIN . '.js', [ 'jquery' ], WCML_VERSION, true );
136
+ wp_enqueue_script( 'wcml_widgets' );
137
+ }
138
 
139
+ if ( self::$page == 'wpml-wcml' && self::$tab == 'multi-currency' ) {
140
+ wp_register_script( 'multi-currency', WCML_PLUGIN_URL . '/res/js/multi-currency' . WCML_JS_MIN . '.js', [ 'jquery', 'jquery-ui-sortable' ], WCML_VERSION, true );
141
+ wp_enqueue_script( 'multi-currency' );
142
+
143
+ wp_register_script( 'currency-switcher-settings', WCML_PLUGIN_URL . '/res/js/currency-switcher-settings' . WCML_JS_MIN . '.js', [ 'jquery', 'jquery-ui-sortable', 'underscore' ], WCML_VERSION, true );
144
+ wp_enqueue_script( 'currency-switcher-settings' );
145
+ wp_localize_script(
146
+ 'currency-switcher-settings',
147
+ 'settings',
148
+ [
149
+ 'pre_selected_colors' => WCML_Currency_Switcher_Options_Dialog::currency_switcher_pre_selected_colors(),
150
+ ]
151
+ );
152
+
153
+ wp_register_script( 'exchange-rates', WCML_PLUGIN_URL . '/res/js/exchange-rates' . WCML_JS_MIN . '.js', [ 'jquery' ], WCML_VERSION, true );
154
+ wp_enqueue_script( 'exchange-rates' );
155
+ }
156
 
157
+ if ( self::$page == 'wpml-wcml' && self::$tab == 'product-attributes' ) {
158
+ wp_register_script( 'product-attributes', WCML_PLUGIN_URL . '/res/js/product-attributes' . WCML_JS_MIN . '.js', [ 'jquery' ], WCML_VERSION, true );
159
+ wp_enqueue_script( 'product-attributes' );
160
+ }
161
 
162
+ if ( self::$page == 'wpml-wcml' && self::$tab == 'custom-taxonomies' ) {
163
+ wp_register_script( 'custom-taxonomies', WCML_PLUGIN_URL . '/res/js/product-custom-taxonomies' . WCML_JS_MIN . '.js', [ 'jquery' ], WCML_VERSION, true );
164
+ wp_enqueue_script( 'custom-taxonomies' );
165
+ }
166
 
167
+ wp_enqueue_script(
168
+ 'wcml-pointer',
169
+ WCML_PLUGIN_URL . '/res/js/pointer' . WCML_JS_MIN . '.js',
170
+ [ 'wp-pointer' ],
171
+ WCML_VERSION,
172
+ true
173
+ );
174
+
175
+ wp_register_script( 'wcml-messages', WCML_PLUGIN_URL . '/res/js/wcml-messages' . WCML_JS_MIN . '.js', [ 'jquery' ], WCML_VERSION, true );
176
+ wp_enqueue_script( 'wcml-messages' );
177
+
178
+ $is_attr_page = apply_filters( 'wcml_is_attributes_page', self::$page == 'product_attributes' && isset( $_GET['post_type'] ) && $_GET['post_type'] == 'product' );
179
+
180
+ if ( $is_attr_page ) {
181
+ wp_register_script( 'wcml-attributes', WCML_PLUGIN_URL . '/res/js/wcml-attributes' . WCML_JS_MIN . '.js', [ 'jquery' ], WCML_VERSION, true );
182
+ wp_enqueue_script( 'wcml-attributes' );
183
+ }
184
+
185
+ if ( self::$page == WPML_TM_FOLDER . '/menu/translations-queue.php' ) {
186
+
187
+ self::load_tooltip_resources();
188
+ wp_enqueue_media();
189
+ wp_register_script( 'wcml-editor', WCML_PLUGIN_URL . '/res/js/wcml-translation-editor' . WCML_JS_MIN . '.js', [ 'jquery', 'jquery-ui-core' ], WCML_VERSION, true );
190
+ wp_enqueue_script( 'wcml-editor' );
191
+ wp_localize_script(
192
+ 'wcml-editor',
193
+ 'wcml_settings',
194
+ [
195
+ 'strings' => [
196
+ 'choose' => __( 'Choose a file', 'woocommerce-multilingual' ),
197
+ 'save_tooltip' => __( 'At least one of these fields is required: title, content or excerpt', 'woocommerce-multilingual' ),
198
+ 'resign_tooltip' => __( 'This translation job will no longer be assigned to you. Other translators will be able take it and continue the translation.', 'woocommerce-multilingual' ),
199
+ ],
200
+ 'hide_resign' => self::$woocommerce_wpml->products->is_hide_resign_button(),
201
+ ]
202
+ );
203
+ }
204
+
205
+ if ( isset( $_GET['post_type'] ) && 'product' === $_GET['post_type'] && 'edit.php' === self::$pagenow ) {
206
+ self::load_tooltip_resources();
207
+ wp_enqueue_script( 'products-screen-options', WCML_PLUGIN_URL . '/res/js/products-screen-option.js', [ 'jquery', 'wcml-tooltip-init' ], WCML_VERSION, true );
208
+ wp_localize_script( 'products-screen-options', 'products_screen_option', [ 'nonce' => wp_create_nonce( 'products-screen-option-action' ) ] );
209
+ }
210
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
211
 
212
  public static function front_scripts() {
213
 
214
+ if ( self::$pagenow !== 'wp-login.php' ) {
215
 
216
+ wp_register_script( 'wcml-front-scripts', WCML_PLUGIN_URL . '/res/js/front-scripts' . WCML_JS_MIN . '.js', [ 'jquery' ], WCML_VERSION, true );
217
  wp_enqueue_script( 'wcml-front-scripts' );
218
 
219
  $referer = isset( $_SERVER['HTTP_REFERER'] ) ? $_SERVER['HTTP_REFERER'] : '';
220
 
221
+ wp_register_script( 'cart-widget', WCML_PLUGIN_URL . '/res/js/cart_widget' . WCML_JS_MIN . '.js', [ 'jquery' ], WCML_VERSION, true );
222
  wp_enqueue_script( 'cart-widget' );
223
+ wp_localize_script(
224
+ 'cart-widget',
225
+ 'actions',
226
+ [
227
+ 'is_lang_switched' => self::$sitepress->get_language_from_url( $referer ) != self::$sitepress->get_current_language() ? 1 : 0,
228
+ 'force_reset' => apply_filters( 'wcml_force_reset_cart_fragments', 0 ),
229
+ ]
230
+ );
231
+ }
232
+
233
+ }
234
+
235
+ public static function load_tooltip_resources() {
236
+
237
+ if ( class_exists( 'WooCommerce' ) && function_exists( 'WC' ) ) {
238
+ wp_register_script( 'jquery-tiptip', WC()->plugin_url() . '/assets/js/jquery-tiptip/jquery.tipTip.min.js', [ 'jquery' ], WC_VERSION, true );
239
+ wp_register_script( 'wcml-tooltip-init', WCML_PLUGIN_URL . '/res/js/tooltip_init' . WCML_JS_MIN . '.js', [ 'jquery' ], WCML_VERSION, true );
240
+ wp_enqueue_script( 'jquery-tiptip' );
241
+ wp_enqueue_script( 'wcml-tooltip-init' );
242
+ wp_enqueue_style( 'woocommerce_admin_styles', WC()->plugin_url() . '/assets/css/admin.css', [], WC_VERSION );
243
+ }
244
+
245
+ }
246
+
247
+ public static function load_lock_fields_js() {
248
+ global $pagenow;
249
+
250
+ wp_register_script( 'wcml-lock-script', WCML_PLUGIN_URL . '/res/js/lock_fields' . WCML_JS_MIN . '.js', [ 'jquery' ], WCML_VERSION, true );
251
+ wp_enqueue_script( 'wcml-lock-script' );
252
+
253
+ $file_path_sync = self::$woocommerce_wpml->settings['file_path_sync'];
254
+
255
+ $product_id = false;
256
+ if ( $pagenow === 'post.php' && isset( $_GET['post'] ) ) {
257
+ $product_id = $_GET['post'];
258
+ } elseif ( isset( $_POST['product_id'] ) ) {
259
+ $product_id = $_POST['product_id'];
260
  }
261
 
262
+ if ( $product_id ) {
263
+ $original_id = self::$woocommerce_wpml->products->get_original_product_id( $product_id );
264
+ $custom_product_sync = get_post_meta( $original_id, 'wcml_sync_files', true );
265
+ if ( $custom_product_sync && $custom_product_sync == 'self' ) {
266
+ $file_path_sync = false;
267
+ } elseif ( $custom_product_sync && $custom_product_sync == 'auto' ) {
268
+ $file_path_sync = true;
269
+ }
270
+ }
271
+
272
+ wp_localize_script(
273
+ 'wcml-lock-script',
274
+ 'unlock_fields',
275
+ [
276
+ 'menu_order' => self::$woocommerce_wpml->settings['products_sync_order'],
277
+ 'file_paths' => $file_path_sync,
278
+ ]
279
+ );
280
+ wp_localize_script(
281
+ 'wcml-lock-script',
282
+ 'non_standard_fields',
283
+ [
284
+ 'ids' => apply_filters( 'wcml_js_lock_fields_ids', [] ),
285
+ 'classes' => apply_filters( 'wcml_js_lock_fields_classes', [] ),
286
+ 'input_names' => apply_filters( 'wcml_js_lock_fields_input_names', [] ),
287
+ ]
288
+ );
289
+
290
+ do_action( 'wcml_after_load_lock_fields_js' );
291
+
292
  }
293
 
294
+ public static function hidden_label() {
295
+ global $sitepress;
296
+
297
+ echo '<img src="' . WCML_PLUGIN_URL . '/res/images/locked.png" class="wcml_lock_img wcml_lock_icon" alt="' .
298
+ __( 'This field is locked for editing because WPML will copy its value from the original language.', 'woocommerce-multilingual' ) .
299
+ '" title="' . __( 'This field is locked for editing because WPML will copy its value from the original language.', 'woocommerce-multilingual' ) .
300
+ '" style="display: none;position:relative;left:2px;top:2px;">';
301
+
302
+ if ( isset( $_GET['post'] ) ) {
303
+ $original_id = self::$woocommerce_wpml->products->get_original_product_id( sanitize_text_field( $_GET['post'] ) );
304
+ } elseif ( isset( $_GET['trid'] ) ) {
305
+ $original_id = $sitepress->get_original_element_id_by_trid( sanitize_text_field( $_GET['trid'] ) );
306
+ }
307
+
308
+ if ( isset( $_GET['lang'] ) ) {
309
+ $language = $_GET['lang'];
310
+ } else {
311
+ return;
312
+ }
313
+
314
+ echo '<h3 class="wcml_prod_hidden_notice">' .
315
+ sprintf(
316
+ __(
317
+ "This is a translation of %1\$s. Some of the fields are not editable. It's recommended to use the %2\$s for translating products.",
318
+ 'woocommerce-multilingual'
319
+ ),
320
+ '<a href="' . get_edit_post_link( $original_id ) . '" >' . get_the_title( $original_id ) . '</a>',
321
+ '<a data-action="product-translation-dialog" class="js-wcml-dialog-trigger" data-id="' . $original_id . '" data-job_id="" data-language="' . $language . '">' .
322
+ __( 'WooCommerce Multilingual products translator', 'woocommerce-multilingual' ) . '</a>'
323
+ ) . '</h3>';
324
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
325
  }
inc/class-wcml-store-pages.php CHANGED
@@ -11,7 +11,7 @@ class WCML_Store_Pages {
11
  */
12
  private $sitepress;
13
 
14
- function __construct( woocommerce_wpml $woocommerce_wpml, SitePress $sitepress ) {
15
 
16
  $this->woocommerce_wpml = $woocommerce_wpml;
17
  $this->sitepress = $sitepress;
@@ -21,18 +21,18 @@ class WCML_Store_Pages {
21
  public function add_hooks() {
22
  global $pagenow;
23
 
24
- add_action( 'init', array( $this, 'init' ) );
25
- add_filter( 'woocommerce_create_pages', array( $this, 'switch_pages_language' ), 9 );
26
- add_filter( 'woocommerce_create_pages', array( $this, 'install_pages_action' ), 11 );
27
- //update wc pages ids after change default language or create new if not exists
28
- add_action( 'icl_after_set_default_language', array( $this, 'after_set_default_language' ), 10, 2 );
29
 
30
- add_filter( 'template_include', array( $this, 'template_loader' ), 100 );
31
 
32
  $is_admin = is_admin();
33
 
34
  if ( $is_admin ) {
35
- add_action( 'icl_post_languages_options_before', array( $this, 'show_translate_shop_pages_notice' ) );
36
  }
37
 
38
  $getData = wpml_collect( $_GET );
@@ -45,17 +45,19 @@ class WCML_Store_Pages {
45
  $this->add_filter_to_get_shop_translated_page_id();
46
  }
47
 
48
- add_filter( 'post_type_archive_link', array( $this, 'filter_shop_archive_link' ), 10, 2 );
 
 
49
  }
50
 
51
- function init() {
52
 
53
  if ( ! is_admin() ) {
54
- add_filter( 'pre_get_posts', array( $this, 'shop_page_query' ), 9 );
55
- add_filter( 'icl_ls_languages', array( $this, 'translate_ls_shop_url' ) );
56
  }
57
 
58
- add_filter( 'woocommerce_create_page_id', array( $this, 'check_store_page_id' ), 10, 3 );
59
 
60
  $nonce = filter_input( INPUT_POST, 'wcml_nonce', FILTER_SANITIZE_FULL_SPECIAL_CHARS );
61
  if ( isset( $_POST['create_pages'] ) && wp_verify_nonce( $nonce, 'create_pages' ) ) {
@@ -67,7 +69,7 @@ class WCML_Store_Pages {
67
  $this->shop_page = get_post( $this->shop_page_id );
68
  }
69
 
70
- function switch_pages_language( $pages ) {
71
 
72
  $default_language = $this->sitepress->get_default_language();
73
 
@@ -93,7 +95,7 @@ class WCML_Store_Pages {
93
  break;
94
  }
95
 
96
- if ( $this->sitepress->get_default_language() != 'en' ) {
97
  $page['name'] = $this->woocommerce_wpml->strings->get_translation_from_woocommerce_mo_file( 'Page slug' . $page['name'], $default_language );
98
  $page['title'] = $this->woocommerce_wpml->strings->get_translation_from_woocommerce_mo_file( 'Page title' . $page['title'], $default_language );
99
  }
@@ -103,36 +105,47 @@ class WCML_Store_Pages {
103
  return $pages;
104
  }
105
 
106
- function install_pages_action( $pages ) {
107
  global $wpdb;
108
 
109
  foreach ( $pages as $key => $page ) {
110
 
111
  if ( strlen( $page['content'] ) > 0 ) {
112
  // Search for an existing page with the specified page content (typically a shortcode)
113
- $page_found = $wpdb->get_var( $wpdb->prepare( "
114
- SELECT ID FROM " . $wpdb->posts . " as p
 
 
115
  LEFT JOIN {$wpdb->prefix}icl_translations AS icl ON icl.element_id = p.id
116
  WHERE post_type='page'
117
  AND post_content LIKE %s
118
  AND icl.element_type = 'post_page'
119
  AND icl.language_code = %s LIMIT 1;
120
  ",
121
- "%{$page[ 'content' ]}%", $this->sitepress->get_default_language() ) );
 
 
 
122
  } else {
123
  // Search for an existing page with the specified page slug
124
- $page_found = $wpdb->get_var( $wpdb->prepare( "
125
- SELECT ID FROM " . $wpdb->posts . " as p
 
 
126
  LEFT JOIN {$wpdb->prefix}icl_translations AS icl ON icl.element_id = p.id
127
  WHERE post_type='page'
128
  AND post_name = %s
129
  AND icl.element_type = 'post_page'
130
  AND icl.language_code = %s LIMIT 1;
131
- ", $page['name'], $this->sitepress->get_default_language() ) );
 
 
 
 
132
  }
133
 
134
  if ( ! $page_found ) {
135
- $page_data = array(
136
  'post_status' => 'publish',
137
  'post_type' => 'page',
138
  'post_author' => 1,
@@ -140,8 +153,8 @@ class WCML_Store_Pages {
140
  'post_title' => $page['title'],
141
  'post_content' => $page['content'],
142
  'post_parent' => ! empty( $page['parent'] ) ? wc_get_page_id( $page['parent'] ) : '',
143
- 'comment_status' => 'closed'
144
- );
145
  $page_id = wp_insert_post( $page_data );
146
 
147
  if ( 'woocommerce_' . $key . '_page_id' ) {
@@ -155,9 +168,9 @@ class WCML_Store_Pages {
155
  return $pages;
156
  }
157
 
158
- function add_filter_to_get_shop_translated_page_id() {
159
 
160
- $woo_pages = array(
161
  'shop_page_id',
162
  'cart_page_id',
163
  'checkout_page_id',
@@ -170,27 +183,24 @@ class WCML_Store_Pages {
170
  'pay_page_id',
171
  'thanks_page_id',
172
  'terms_page_id',
173
- 'review_order_page_id'
174
- );
175
 
176
  foreach ( $woo_pages as $woo_page ) {
177
- add_filter( 'woocommerce_get_' . $woo_page, array( $this, 'translate_pages_in_settings' ) );
178
- //I think following filter not needed because "option_woocommerce_..." not used in Woo, but I need ask David to confirm this
179
- add_filter( 'option_woocommerce_' . $woo_page, array( $this, 'translate_pages_in_settings' ) );
180
  }
181
-
182
- add_filter( 'woocommerce_get_checkout_url', array( $this, 'get_checkout_page_url' ) );
183
  }
184
 
185
- function translate_pages_in_settings( $id ) {
186
  return apply_filters( 'translate_object_id', $id, 'page', true );
187
  }
188
 
189
  /**
190
  * Filters WooCommerce query for translated shop page
191
- *
192
  */
193
- function shop_page_query( $q ) {
194
  if ( ! $q->is_main_query() ) {
195
  return;
196
  }
@@ -200,11 +210,11 @@ class WCML_Store_Pages {
200
  ! empty( $this->shop_page ) &&
201
  $this->shop_page->post_status == 'publish' &&
202
  ! empty( $this->front_page_id ) &&
203
- $q->get( 'post_type' ) != 'product' &&
204
  $q->get( 'page_id' ) !== $this->front_page_id &&
205
  $this->shop_page_id == $q->get( 'page_id' )
206
  ) {
207
- //do not alter query_object and query_object_id (part 1 of 2)
208
  global $wp_query;
209
  $queried_object_original = isset( $wp_query->queried_object ) ? $wp_query->queried_object : null;
210
  $queried_object_id_original = isset( $wp_query->queried_object_id ) ? $wp_query->queried_object_id : null;
@@ -237,7 +247,7 @@ class WCML_Store_Pages {
237
 
238
  add_filter( 'post_type_archive_title', '__return_empty_string', 5 );
239
 
240
- //do not alter query_object and query_object_id (part 2 of 2)
241
  if ( is_null( $queried_object_original ) ) {
242
  unset( $wp_query->queried_object );
243
  } else {
@@ -255,7 +265,7 @@ class WCML_Store_Pages {
255
  /**
256
  * Translate shop url
257
  */
258
- function translate_ls_shop_url( $languages, $debug_mode = false ) {
259
 
260
  $shop_id = $this->shop_page_id;
261
  $front_id = apply_filters( 'translate_object_id', $this->front_page_id, 'page' );
@@ -277,12 +287,20 @@ class WCML_Store_Pages {
277
  }
278
 
279
  // copy get parameters?
280
- $gets_passed = array();
281
- $parameters_copied = apply_filters( 'icl_lang_sel_copy_parameters',
282
- array_map( 'trim',
283
- explode( ',',
284
- wpml_get_setting_filter( '',
285
- 'icl_lang_sel_copy_parameters' ) ) ) );
 
 
 
 
 
 
 
 
286
  if ( $parameters_copied ) {
287
  foreach ( $_GET as $k => $v ) {
288
  if ( in_array( $k, $parameters_copied ) ) {
@@ -295,11 +313,10 @@ class WCML_Store_Pages {
295
  }
296
  }
297
 
298
-
299
  return $languages;
300
  }
301
 
302
- function create_missing_store_pages_with_redirect() {
303
  $this->create_missing_store_pages();
304
 
305
  wp_redirect( admin_url( 'admin.php?page=wpml-wcml&tab=status' ) );
@@ -310,12 +327,12 @@ class WCML_Store_Pages {
310
  /**
311
  * create missing pages
312
  */
313
- function create_missing_store_pages() {
314
  global $wp_rewrite;
315
  $miss_lang = $this->get_missing_store_pages();
316
 
317
- //dummy array for names
318
- $names = array(
319
  __( 'Cart', 'woocommerce-multilingual' ),
320
  __( 'Checkout', 'woocommerce-multilingual' ),
321
  __( 'Checkout &rarr; Pay', 'woocommerce-multilingual' ),
@@ -326,8 +343,8 @@ class WCML_Store_Pages {
326
  __( 'Logout', 'woocommerce-multilingual' ),
327
  __( 'Lost Password', 'woocommerce-multilingual' ),
328
  __( 'View Order', 'woocommerce-multilingual' ),
329
- __( 'Shop', 'woocommerce-multilingual' )
330
- );
331
 
332
  if ( isset( $miss_lang['codes'] ) ) {
333
  $wp_rewrite = new WP_Rewrite();
@@ -335,11 +352,11 @@ class WCML_Store_Pages {
335
  $check_pages = $this->get_wc_pages();
336
  $default_language = $this->sitepress->get_default_language();
337
  if ( in_array( $default_language, $miss_lang['codes'] ) ) {
338
- $miss_lang['codes'] = array_merge( array( $default_language ), array_diff( $miss_lang['codes'], array( $default_language ) ) );
339
  }
340
 
341
  foreach ( $miss_lang['codes'] as $mis_lang ) {
342
- $args = array();
343
 
344
  $this->switch_lang( $mis_lang );
345
 
@@ -348,7 +365,7 @@ class WCML_Store_Pages {
348
  $trid = $this->sitepress->get_element_trid( $orig_id, 'post_page' );
349
  $translations = $this->sitepress->get_element_translations( $trid, 'post_page', true );
350
 
351
- if ( ! isset( $translations[ $mis_lang ] ) || ( ! is_null( $translations[ $mis_lang ]->element_id ) && get_post_status( $translations[ $mis_lang ]->element_id ) != 'publish' ) ) {
352
  $orig_page = get_post( $orig_id );
353
 
354
  switch ( $page ) {
@@ -373,7 +390,7 @@ class WCML_Store_Pages {
373
  $args['post_type'] = $orig_page->post_type;
374
  $args['post_content'] = $orig_page->post_content;
375
  $args['post_excerpt'] = $orig_page->post_excerpt;
376
- $args['post_status'] = ( isset( $translations[ $mis_lang ]->element_id ) && get_post_status( $translations[ $mis_lang ]->element_id ) != 'publish' ) ? 'publish' : $orig_page->post_status;
377
  $args['menu_order'] = $orig_page->menu_order;
378
  $args['ping_status'] = $orig_page->ping_status;
379
  $args['comment_status'] = $orig_page->comment_status;
@@ -413,24 +430,24 @@ class WCML_Store_Pages {
413
  * get missing pages
414
  * return array;
415
  */
416
- function get_missing_store_pages() {
417
 
418
  $check_pages = $this->get_wc_pages();
419
 
420
- $missing_lang = array();
421
- $pages_in_progress = array();
422
 
423
  foreach ( $check_pages as $page ) {
424
  $page_id = wc_get_page_id( $page );
425
  $page_obj = get_post( $page_id );
426
- if ( ! $page_id || ! $page_obj || $page_obj->post_status != 'publish' ) {
427
  return 'non_exist';
428
  }
429
  }
430
 
431
  $languages = $this->sitepress->get_active_languages();
432
 
433
- $missing_lang_codes = array();
434
 
435
  foreach ( $check_pages as $page ) {
436
  $store_page_id = wc_get_page_id( $page );
@@ -439,7 +456,7 @@ class WCML_Store_Pages {
439
  $pages_in_progress_miss_lang = '';
440
  foreach ( $languages as $language ) {
441
  if ( ! in_array( $language['code'], $missing_lang_codes ) &&
442
- ( ! isset( $translations[ $language['code'] ] ) || ( ! is_null( $translations[ $language['code'] ]->element_id ) && get_post_status( $translations[ $language['code'] ]->element_id ) != 'publish' ) ) ) {
443
 
444
  $missing_lang_codes[] = $language['code'];
445
 
@@ -456,14 +473,13 @@ class WCML_Store_Pages {
456
  }
457
  }
458
 
459
-
460
  foreach ( $pages_in_progress as $key => $page_in_progress ) {
461
  $pages_in_progress_notice[ $key ]['page'] = get_the_title( $key ) . ' :';
462
  $pages_in_progress_notice[ $key ]['lang'] = $page_in_progress;
463
 
464
  }
465
 
466
- $status = array();
467
 
468
  if ( ! empty( $missing_lang ) ) {
469
  $status['lang'] = $missing_lang;
@@ -484,26 +500,29 @@ class WCML_Store_Pages {
484
  /**
485
  * Filters WooCommerce checkout link.
486
  */
487
- function get_checkout_page_url() {
488
  return get_permalink( apply_filters( 'translate_object_id', wc_get_page_id( 'checkout' ), 'page', true ) );
489
  }
490
 
491
- function get_wc_pages() {
492
- $pages = apply_filters( 'wcml_wc_installed_pages', array(
493
- 'woocommerce_shop_page_id',
494
- 'woocommerce_cart_page_id',
495
- 'woocommerce_checkout_page_id',
496
- 'woocommerce_myaccount_page_id'
497
- ) );
 
 
 
498
 
499
  foreach ( $pages as &$page ) {
500
- $page = preg_replace( '/(woocommerce_)(.*)(_page_id)/', "$2", $page );
501
  }
502
 
503
  return $pages;
504
  }
505
 
506
- function after_set_default_language( $code, $previous_code ) {
507
  global $wpdb;
508
 
509
  $this->create_missing_store_pages();
@@ -513,10 +532,9 @@ class WCML_Store_Pages {
513
  if ( $page_id = wc_get_page_id( $page ) ) {
514
  $trnsl_id = apply_filters( 'translate_object_id', $page_id, 'page', false, $code );
515
  if ( ! is_null( $trnsl_id ) ) {
516
- $wpdb->update( $wpdb->options, array( 'option_value' => $trnsl_id ), array( 'option_name' => 'woocommerce_' . $page . '_page_id' ) );
517
  }
518
  }
519
-
520
  }
521
 
522
  // Clear any unwanted data
@@ -524,7 +542,7 @@ class WCML_Store_Pages {
524
  delete_transient( 'woocommerce_cache_excluded_uris' );
525
  }
526
 
527
- function template_loader( $template ) {
528
 
529
  if ( is_product_taxonomy() ) {
530
  global $sitepress, $woocommerce_wpml;
@@ -534,7 +552,7 @@ class WCML_Store_Pages {
534
 
535
  if ( $current_language != $default_language ) {
536
 
537
- $templates = array( 'woocommerce.php' );
538
 
539
  $term = get_queried_object();
540
 
@@ -551,13 +569,12 @@ class WCML_Store_Pages {
551
  $original_term_id = icl_object_id( $term->term_id, $taxonomy, true, $default_language );
552
  $original_term = $woocommerce_wpml->terms->wcml_get_term_by_id( $original_term_id, $taxonomy );
553
 
554
-
555
- $terms_to_check = array( $term->term_id => $term->slug );
556
  if ( $original_term ) {
557
  $terms_to_check[ $original_term_id ] = $original_term->slug;
558
  }
559
 
560
- $paths = array( '', WC()->template_path() );
561
 
562
  foreach ( $paths as $path ) {
563
 
@@ -582,9 +599,7 @@ class WCML_Store_Pages {
582
  $template = $loaded_template;
583
 
584
  }
585
-
586
  }
587
-
588
  }
589
 
590
  return $template;
@@ -622,18 +637,19 @@ class WCML_Store_Pages {
622
  }
623
 
624
  if ( ! $is_translated ) {
625
- $text = sprintf( __( 'To quickly translate this and other WooCommerce store pages, please run the %ssetup wizard%s.', 'woocommerce-multilingual' ),
626
- '<a href="' . admin_url( 'admin.php?page=wcml-setup' ) . '">', '</a>' );
 
 
 
627
 
628
  echo '<div class="notice notice-error inline">';
629
  echo '<p><i class="otgs-ico-warning"></i> ' . $text . '</p>';
630
  echo '</div>';
631
  }
632
  }
633
-
634
  }
635
 
636
-
637
  }
638
 
639
  public function filter_shop_archive_link( $link, $post_type ) {
11
  */
12
  private $sitepress;
13
 
14
+ public function __construct( woocommerce_wpml $woocommerce_wpml, SitePress $sitepress ) {
15
 
16
  $this->woocommerce_wpml = $woocommerce_wpml;
17
  $this->sitepress = $sitepress;
21
  public function add_hooks() {
22
  global $pagenow;
23
 
24
+ add_action( 'init', [ $this, 'init' ] );
25
+ add_filter( 'woocommerce_create_pages', [ $this, 'switch_pages_language' ], 9 );
26
+ add_filter( 'woocommerce_create_pages', [ $this, 'install_pages_action' ], 11 );
27
+ // update wc pages ids after change default language or create new if not exists
28
+ add_action( 'icl_after_set_default_language', [ $this, 'after_set_default_language' ], 10, 2 );
29
 
30
+ add_filter( 'template_include', [ $this, 'template_loader' ], 100 );
31
 
32
  $is_admin = is_admin();
33
 
34
  if ( $is_admin ) {
35
+ add_action( 'icl_post_languages_options_before', [ $this, 'show_translate_shop_pages_notice' ] );
36
  }
37
 
38
  $getData = wpml_collect( $_GET );
45
  $this->add_filter_to_get_shop_translated_page_id();
46
  }
47
 
48
+ add_filter( 'woocommerce_get_checkout_url', [ $this, 'get_checkout_page_url' ] );
49
+
50
+ add_filter( 'post_type_archive_link', [ $this, 'filter_shop_archive_link' ], 10, 2 );
51
  }
52
 
53
+ public function init() {
54
 
55
  if ( ! is_admin() ) {
56
+ add_filter( 'pre_get_posts', [ $this, 'shop_page_query' ], 9 );
57
+ add_filter( 'icl_ls_languages', [ $this, 'translate_ls_shop_url' ] );
58
  }
59
 
60
+ add_filter( 'woocommerce_create_page_id', [ $this, 'check_store_page_id' ], 10, 3 );
61
 
62
  $nonce = filter_input( INPUT_POST, 'wcml_nonce', FILTER_SANITIZE_FULL_SPECIAL_CHARS );
63
  if ( isset( $_POST['create_pages'] ) && wp_verify_nonce( $nonce, 'create_pages' ) ) {
69
  $this->shop_page = get_post( $this->shop_page_id );
70
  }
71
 
72
+ public function switch_pages_language( $pages ) {
73
 
74
  $default_language = $this->sitepress->get_default_language();
75
 
95
  break;
96
  }
97
 
98
+ if ( $this->sitepress->get_default_language() !== 'en' ) {
99
  $page['name'] = $this->woocommerce_wpml->strings->get_translation_from_woocommerce_mo_file( 'Page slug' . $page['name'], $default_language );
100
  $page['title'] = $this->woocommerce_wpml->strings->get_translation_from_woocommerce_mo_file( 'Page title' . $page['title'], $default_language );
101
  }
105
  return $pages;
106
  }
107
 
108
+ public function install_pages_action( $pages ) {
109
  global $wpdb;
110
 
111
  foreach ( $pages as $key => $page ) {
112
 
113
  if ( strlen( $page['content'] ) > 0 ) {
114
  // Search for an existing page with the specified page content (typically a shortcode)
115
+ $page_found = $wpdb->get_var(
116
+ $wpdb->prepare(
117
+ '
118
+ SELECT ID FROM ' . $wpdb->posts . " as p
119
  LEFT JOIN {$wpdb->prefix}icl_translations AS icl ON icl.element_id = p.id
120
  WHERE post_type='page'
121
  AND post_content LIKE %s
122
  AND icl.element_type = 'post_page'
123
  AND icl.language_code = %s LIMIT 1;
124
  ",
125
+ "%{$page[ 'content' ]}%",
126
+ $this->sitepress->get_default_language()
127
+ )
128
+ );
129
  } else {
130
  // Search for an existing page with the specified page slug
131
+ $page_found = $wpdb->get_var(
132
+ $wpdb->prepare(
133
+ '
134
+ SELECT ID FROM ' . $wpdb->posts . " as p
135
  LEFT JOIN {$wpdb->prefix}icl_translations AS icl ON icl.element_id = p.id
136
  WHERE post_type='page'
137
  AND post_name = %s
138
  AND icl.element_type = 'post_page'
139
  AND icl.language_code = %s LIMIT 1;
140
+ ",
141
+ $page['name'],
142
+ $this->sitepress->get_default_language()
143
+ )
144
+ );
145
  }
146
 
147
  if ( ! $page_found ) {
148
+ $page_data = [
149
  'post_status' => 'publish',
150
  'post_type' => 'page',
151
  'post_author' => 1,
153
  'post_title' => $page['title'],
154
  'post_content' => $page['content'],
155
  'post_parent' => ! empty( $page['parent'] ) ? wc_get_page_id( $page['parent'] ) : '',
156
+ 'comment_status' => 'closed',
157
+ ];
158
  $page_id = wp_insert_post( $page_data );
159
 
160
  if ( 'woocommerce_' . $key . '_page_id' ) {
168
  return $pages;
169
  }
170
 
171
+ public function add_filter_to_get_shop_translated_page_id() {
172
 
173
+ $woo_pages = [
174
  'shop_page_id',
175
  'cart_page_id',
176
  'checkout_page_id',
183
  'pay_page_id',
184
  'thanks_page_id',
185
  'terms_page_id',
186
+ 'review_order_page_id',
187
+ ];
188
 
189
  foreach ( $woo_pages as $woo_page ) {
190
+ add_filter( 'woocommerce_get_' . $woo_page, [ $this, 'translate_pages_in_settings' ] );
191
+ // I think following filter not needed because "option_woocommerce_..." not used in Woo, but I need ask David to confirm this
192
+ add_filter( 'option_woocommerce_' . $woo_page, [ $this, 'translate_pages_in_settings' ] );
193
  }
 
 
194
  }
195
 
196
+ public function translate_pages_in_settings( $id ) {
197
  return apply_filters( 'translate_object_id', $id, 'page', true );
198
  }
199
 
200
  /**
201
  * Filters WooCommerce query for translated shop page
 
202
  */
203
+ public function shop_page_query( $q ) {
204
  if ( ! $q->is_main_query() ) {
205
  return;
206
  }
210
  ! empty( $this->shop_page ) &&
211
  $this->shop_page->post_status == 'publish' &&
212
  ! empty( $this->front_page_id ) &&
213
+ $q->get( 'post_type' ) !== 'product' &&
214
  $q->get( 'page_id' ) !== $this->front_page_id &&
215
  $this->shop_page_id == $q->get( 'page_id' )
216
  ) {
217
+ // do not alter query_object and query_object_id (part 1 of 2)
218
  global $wp_query;
219
  $queried_object_original = isset( $wp_query->queried_object ) ? $wp_query->queried_object : null;
220
  $queried_object_id_original = isset( $wp_query->queried_object_id ) ? $wp_query->queried_object_id : null;
247
 
248
  add_filter( 'post_type_archive_title', '__return_empty_string', 5 );
249
 
250
+ // do not alter query_object and query_object_id (part 2 of 2)
251
  if ( is_null( $queried_object_original ) ) {
252
  unset( $wp_query->queried_object );
253
  } else {
265
  /**
266
  * Translate shop url
267
  */
268
+ public function translate_ls_shop_url( $languages, $debug_mode = false ) {
269
 
270
  $shop_id = $this->shop_page_id;
271
  $front_id = apply_filters( 'translate_object_id', $this->front_page_id, 'page' );
287
  }
288
 
289
  // copy get parameters?
290
+ $gets_passed = [];
291
+ $parameters_copied = apply_filters(
292
+ 'icl_lang_sel_copy_parameters',
293
+ array_map(
294
+ 'trim',
295
+ explode(
296
+ ',',
297
+ wpml_get_setting_filter(
298
+ '',
299
+ 'icl_lang_sel_copy_parameters'
300
+ )
301
+ )
302
+ )
303
+ );
304
  if ( $parameters_copied ) {
305
  foreach ( $_GET as $k => $v ) {
306
  if ( in_array( $k, $parameters_copied ) ) {
313
  }
314
  }
315
 
 
316
  return $languages;
317
  }
318
 
319
+ public function create_missing_store_pages_with_redirect() {
320
  $this->create_missing_store_pages();
321
 
322
  wp_redirect( admin_url( 'admin.php?page=wpml-wcml&tab=status' ) );
327
  /**
328
  * create missing pages
329
  */
330
+ public function create_missing_store_pages() {
331
  global $wp_rewrite;
332
  $miss_lang = $this->get_missing_store_pages();
333
 
334
+ // dummy array for names
335
+ $names = [
336
  __( 'Cart', 'woocommerce-multilingual' ),
337
  __( 'Checkout', 'woocommerce-multilingual' ),
338
  __( 'Checkout &rarr; Pay', 'woocommerce-multilingual' ),
343
  __( 'Logout', 'woocommerce-multilingual' ),
344
  __( 'Lost Password', 'woocommerce-multilingual' ),
345
  __( 'View Order', 'woocommerce-multilingual' ),
346
+ __( 'Shop', 'woocommerce-multilingual' ),
347
+ ];
348
 
349
  if ( isset( $miss_lang['codes'] ) ) {
350
  $wp_rewrite = new WP_Rewrite();
352
  $check_pages = $this->get_wc_pages();
353
  $default_language = $this->sitepress->get_default_language();
354
  if ( in_array( $default_language, $miss_lang['codes'] ) ) {
355
+ $miss_lang['codes'] = array_merge( [ $default_language ], array_diff( $miss_lang['codes'], [ $default_language ] ) );
356
  }
357
 
358
  foreach ( $miss_lang['codes'] as $mis_lang ) {
359
+ $args = [];
360
 
361
  $this->switch_lang( $mis_lang );
362
 
365
  $trid = $this->sitepress->get_element_trid( $orig_id, 'post_page' );
366
  $translations = $this->sitepress->get_element_translations( $trid, 'post_page', true );
367
 
368
+ if ( ! isset( $translations[ $mis_lang ] ) || ( ! is_null( $translations[ $mis_lang ]->element_id ) && get_post_status( $translations[ $mis_lang ]->element_id ) !== 'publish' ) ) {
369
  $orig_page = get_post( $orig_id );
370
 
371
  switch ( $page ) {
390
  $args['post_type'] = $orig_page->post_type;
391
  $args['post_content'] = $orig_page->post_content;
392
  $args['post_excerpt'] = $orig_page->post_excerpt;
393
+ $args['post_status'] = ( isset( $translations[ $mis_lang ]->element_id ) && get_post_status( $translations[ $mis_lang ]->element_id ) !== 'publish' ) ? 'publish' : $orig_page->post_status;
394
  $args['menu_order'] = $orig_page->menu_order;
395
  $args['ping_status'] = $orig_page->ping_status;
396
  $args['comment_status'] = $orig_page->comment_status;
430
  * get missing pages
431
  * return array;
432
  */
433
+ public function get_missing_store_pages() {
434
 
435
  $check_pages = $this->get_wc_pages();
436
 
437
+ $missing_lang = [];
438
+ $pages_in_progress = [];
439
 
440
  foreach ( $check_pages as $page ) {
441
  $page_id = wc_get_page_id( $page );
442
  $page_obj = get_post( $page_id );
443
+ if ( ! $page_id || ! $page_obj || $page_obj->post_status !== 'publish' ) {
444
  return 'non_exist';
445
  }
446
  }
447
 
448
  $languages = $this->sitepress->get_active_languages();
449
 
450
+ $missing_lang_codes = [];
451
 
452
  foreach ( $check_pages as $page ) {
453
  $store_page_id = wc_get_page_id( $page );
456
  $pages_in_progress_miss_lang = '';
457
  foreach ( $languages as $language ) {
458
  if ( ! in_array( $language['code'], $missing_lang_codes ) &&
459
+ ( ! isset( $translations[ $language['code'] ] ) || ( ! is_null( $translations[ $language['code'] ]->element_id ) && get_post_status( $translations[ $language['code'] ]->element_id ) !== 'publish' ) ) ) {
460
 
461
  $missing_lang_codes[] = $language['code'];
462
 
473
  }
474
  }
475
 
 
476
  foreach ( $pages_in_progress as $key => $page_in_progress ) {
477
  $pages_in_progress_notice[ $key ]['page'] = get_the_title( $key ) . ' :';
478
  $pages_in_progress_notice[ $key ]['lang'] = $page_in_progress;
479
 
480
  }
481
 
482
+ $status = [];
483
 
484
  if ( ! empty( $missing_lang ) ) {
485
  $status['lang'] = $missing_lang;
500
  /**
501
  * Filters WooCommerce checkout link.
502
  */
503
+ public function get_checkout_page_url() {
504
  return get_permalink( apply_filters( 'translate_object_id', wc_get_page_id( 'checkout' ), 'page', true ) );
505
  }
506
 
507
+ public function get_wc_pages() {
508
+ $pages = apply_filters(
509
+ 'wcml_wc_installed_pages',
510
+ [
511
+ 'woocommerce_shop_page_id',
512
+ 'woocommerce_cart_page_id',
513
+ 'woocommerce_checkout_page_id',
514
+ 'woocommerce_myaccount_page_id',
515
+ ]
516
+ );
517
 
518
  foreach ( $pages as &$page ) {
519
+ $page = preg_replace( '/(woocommerce_)(.*)(_page_id)/', '$2', $page );
520
  }
521
 
522
  return $pages;
523
  }
524
 
525
+ public function after_set_default_language( $code, $previous_code ) {
526
  global $wpdb;
527
 
528
  $this->create_missing_store_pages();
532
  if ( $page_id = wc_get_page_id( $page ) ) {
533
  $trnsl_id = apply_filters( 'translate_object_id', $page_id, 'page', false, $code );
534
  if ( ! is_null( $trnsl_id ) ) {
535
+ $wpdb->update( $wpdb->options, [ 'option_value' => $trnsl_id ], [ 'option_name' => 'woocommerce_' . $page . '_page_id' ] );
536
  }
537
  }
 
538
  }
539
 
540
  // Clear any unwanted data
542
  delete_transient( 'woocommerce_cache_excluded_uris' );
543
  }
544
 
545
+ public function template_loader( $template ) {
546
 
547
  if ( is_product_taxonomy() ) {
548
  global $sitepress, $woocommerce_wpml;
552
 
553
  if ( $current_language != $default_language ) {
554
 
555
+ $templates = [ 'woocommerce.php' ];
556
 
557
  $term = get_queried_object();
558
 
569
  $original_term_id = icl_object_id( $term->term_id, $taxonomy, true, $default_language );
570
  $original_term = $woocommerce_wpml->terms->wcml_get_term_by_id( $original_term_id, $taxonomy );
571
 
572
+ $terms_to_check = [ $term->term_id => $term->slug ];
 
573
  if ( $original_term ) {
574
  $terms_to_check[ $original_term_id ] = $original_term->slug;
575
  }
576
 
577
+ $paths = [ '', WC()->template_path() ];
578
 
579
  foreach ( $paths as $path ) {
580
 
599
  $template = $loaded_template;
600
 
601
  }
 
602
  }
 
603
  }
604
 
605
  return $template;
637
  }
638
 
639
  if ( ! $is_translated ) {
640
+ $text = sprintf(
641
+ __( 'To quickly translate this and other WooCommerce store pages, please run the %1$ssetup wizard%2$s.', 'woocommerce-multilingual' ),
642
+ '<a href="' . admin_url( 'admin.php?page=wcml-setup' ) . '">',
643
+ '</a>'
644
+ );
645
 
646
  echo '<div class="notice notice-error inline">';
647
  echo '<p><i class="otgs-ico-warning"></i> ' . $text . '</p>';
648
  echo '</div>';
649
  }
650
  }
 
651
  }
652
 
 
653
  }
654
 
655
  public function filter_shop_archive_link( $link, $post_type ) {
inc/class-wcml-terms.php CHANGED
@@ -1,727 +1,800 @@
1
  <?php
2
-
3
- class WCML_Terms{
4
-
5
- private $ALL_TAXONOMY_TERMS_TRANSLATED = 0;
6
- private $NEW_TAXONOMY_TERMS = 1;
7
- private $NEW_TAXONOMY_IGNORED = 2;
 
8
 
9
  /** @var woocommerce_wpml */
10
  private $woocommerce_wpml;
11
  /** @var SitePress */
12
  private $sitepress;
13
  /** @var wpdb */
14
- private $wpdb;
15
 
16
  /**
17
  * WCML_Terms constructor.
18
  *
19
  * @param woocommerce_wpml $woocommerce_wpml
20
- * @param SitePress $sitepress
21
- * @param wpdb $wpdb
22
  */
23
- function __construct( woocommerce_wpml $woocommerce_wpml, SitePress $sitepress, wpdb $wpdb ){
24
- $this->woocommerce_wpml = $woocommerce_wpml;
25
- $this->sitepress = $sitepress;
26
- $this->wpdb = $wpdb;
27
- }
28
 
29
  public function add_hooks() {
30
 
31
- add_action( 'updated_woocommerce_term_meta', array( $this, 'sync_term_order' ), 100, 4 );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
32
 
33
- add_filter( 'wp_get_object_terms', array( $this->sitepress, 'get_terms_filter' ) );
34
- add_action( 'created_term', array( $this, 'translated_terms_status_update' ), 10, 3 );
35
- add_action( 'edit_term', array( $this, 'translated_terms_status_update' ), 10, 3 );
36
- add_action( 'wp_ajax_wcml_update_term_translated_warnings', array(
37
- $this,
38
- 'wcml_update_term_translated_warnings'
39
- ) );
40
 
41
- add_action( 'created_term', array( $this, 'set_flag_for_variation_on_attribute_update' ), 10, 3 );
 
 
42
 
43
- add_filter( 'wpml_taxonomy_translation_bottom', array( $this, 'sync_taxonomy_translations' ), 10, 3 );
 
 
 
44
 
45
- add_action( 'wp_ajax_wcml_sync_product_variations', array( $this, 'wcml_sync_product_variations' ) );
46
- add_action( 'wp_ajax_wcml_tt_sync_taxonomies_in_content', array( $this, 'wcml_sync_taxonomies_in_content' ) );
47
- add_action( 'wp_ajax_wcml_tt_sync_taxonomies_in_content_preview', array(
48
- $this,
49
- 'wcml_sync_taxonomies_in_content_preview'
50
- ) );
51
 
52
- if ( is_admin() ) {
53
- add_action( 'admin_menu', array( $this, 'admin_menu_setup' ) );
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(){
71
- global $pagenow;
72
- if($pagenow == 'edit-tags.php' && isset($_GET['action']) && $_GET['action'] == 'edit'){
73
- add_action('admin_notices', array($this, 'show_term_translation_screen_notices'));
74
- }
75
-
76
- $page = isset( $_GET['page'] )? $_GET['page'] : '';
77
- if ( $page === ICL_PLUGIN_FOLDER . '/menu/taxonomy-translation.php' ) {
78
- WCML_Resources::load_management_css();
79
- WCML_Resources::load_taxonomy_translation_scripts();
80
- }
81
-
82
- }
83
-
84
- function show_term_translation_screen_notices(){
85
-
86
- $taxonomies = array_keys(get_taxonomies(array('object_type'=>array('product')),'objects'));
87
- $taxonomies = $taxonomies + array_keys(get_taxonomies(array('object_type'=>array('product_variations')),'objects'));
88
- $taxonomies = array_unique($taxonomies);
89
- $taxonomy = isset($_GET['taxonomy']) ? $_GET['taxonomy'] : false;
90
- if( $taxonomy && in_array( $taxonomy, $taxonomies ) ){
91
- $taxonomy_obj = get_taxonomy($taxonomy);
92
- $message = sprintf(__('To translate %s please use the %s translation%s page, inside the %sWooCommerce Multilingual admin%s.', 'woocommerce-multilingual'),
93
- $taxonomy_obj->labels->name,
94
- '<strong><a href="' . admin_url('admin.php?page=wpml-wcml&tab=' . $taxonomy ) . '">' . $taxonomy_obj->labels->singular_name, '</a></strong>',
95
- '<strong><a href="' . admin_url('admin.php?page=wpml-wcml">'), '</a></strong>');
96
-
97
- echo '<div class="updated"><p>' . $message . '</p></div>';
98
- }
99
-
100
- }
101
-
102
- function sync_term_order_globally() {
103
- //syncs the term order of any taxonomy in $this->wpdb->prefix.'woocommerce_attribute_taxonomies'
104
- //use it when term orderings have become unsynched, e.g. before WCML 3.3.
105
-
106
- if(!defined('WOOCOMMERCE_VERSION')){
107
- return;
108
- }
109
-
110
- $cur_lang = $this->sitepress->get_current_language();
111
- $lang = $this->sitepress->get_default_language();
112
- $this->sitepress->switch_lang($lang);
113
-
114
- $taxes = wc_get_attribute_taxonomies ();
115
-
116
- if ($taxes) foreach ($taxes as $woo_tax) {
117
- $tax = 'pa_'.$woo_tax->attribute_name;
118
- $meta_key = 'order_'.$tax;
119
- //if ($tax != 'pa_frame') continue;
120
- $terms = get_terms($tax);
121
- if ($terms)foreach ($terms as $term) {
122
- $term_order = get_term_meta( $term->term_id, $meta_key, true );
123
- $trid = $this->sitepress->get_element_trid($term->term_taxonomy_id,'tax_'.$tax);
124
- $translations = $this->sitepress->get_element_translations($trid,'tax_' . $tax);
125
- if ($translations) foreach ($translations as $trans) {
126
- if ($trans->language_code != $lang) {
127
- update_term_meta( $trans->term_id, $meta_key, $term_order );
128
- }
129
- }
130
- }
131
- }
132
-
133
- //sync product categories ordering
134
- $terms = get_terms('product_cat');
135
- if ($terms) foreach($terms as $term) {
136
- $term_order = get_term_meta( $term->term_id, 'order', true );
137
- $trid = $this->sitepress->get_element_trid($term->term_taxonomy_id,'tax_product_cat');
138
- $translations = $this->sitepress->get_element_translations($trid,'tax_product_cat');
139
- if ($translations) foreach ($translations as $trans) {
140
- if ($trans->language_code != $lang) {
141
- update_term_meta( $trans->term_id, 'order', $term_order );
142
- }
143
- }
144
- }
145
-
146
- $this->sitepress->switch_lang($cur_lang);
147
-
148
- $this->woocommerce_wpml->settings['is_term_order_synced'] = 'yes';
149
- $this->woocommerce_wpml->update_settings();
150
-
151
- }
152
-
153
- function sync_term_order($meta_id, $object_id, $meta_key, $meta_value) {
154
-
155
- // WooCommerce before termmeta table migration
156
- $wc_before_term_meta = get_option( 'db_version' ) < 34370;
157
-
158
- if (!isset($_POST['thetaxonomy']) || !taxonomy_exists($_POST['thetaxonomy']) || substr($meta_key,0,5) != 'order')
159
- return;
160
-
161
- $tax = filter_input( INPUT_POST, 'thetaxonomy', FILTER_SANITIZE_FULL_SPECIAL_CHARS );
162
-
163
- $term_taxonomy_id = $this->wpdb->get_var($this->wpdb->prepare("SELECT term_taxonomy_id FROM {$this->wpdb->term_taxonomy} WHERE term_id=%d AND taxonomy=%s", $object_id, $tax));
164
- $trid = $this->sitepress->get_element_trid($term_taxonomy_id, 'tax_' . $tax);
165
- $translations = $this->sitepress->get_element_translations($trid,'tax_' . $tax);
166
- if ($translations) foreach ($translations as $trans) {
167
- if ($trans->element_id != $term_taxonomy_id) {
168
-
169
- // Backwards compatibility - WooCommerce termmeta table
170
- if( $wc_before_term_meta ) {
171
- $this->wpdb->update( $this->wpdb->prefix . 'woocommerce_termmeta',
172
- array('meta_value' => $meta_value),
173
- array('woocommerce_term_id' => $trans->term_id, 'meta_key' => $meta_key) );
174
- // END Backwards compatibility - WooCommerce termmeta table
175
- } else{
176
- update_term_meta( $trans->term_id, $meta_key, $meta_value);
177
- }
178
 
179
- }
180
- }
181
-
182
- }
183
-
184
- function translated_terms_status_update($term_id, $tt_id, $taxonomy){
185
 
186
- if ( isset( $_POST['product_cat_thumbnail_id'] ) || isset( $_POST['display_type'] ) ){
187
- global $sitepress_settings;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
188
 
189
- if( $this->is_original_category($tt_id,'tax_'.$taxonomy) ){
190
- $trid = $this->sitepress->get_element_trid($tt_id,'tax_'.$taxonomy);
191
- $translations = $this->sitepress->get_element_translations($trid,'tax_'.$taxonomy);
192
-
193
- foreach($translations as $translation){
194
- if(!$translation->original){
195
- if(isset($_POST['display_type'])){
196
- update_term_meta( $translation->term_id, 'display_type', esc_attr( $_POST['display_type'] ) );
197
- }
198
- update_term_meta( $translation->term_id, 'thumbnail_id', apply_filters( 'translate_object_id', esc_attr( $_POST['product_cat_thumbnail_id'] ), 'attachment', true, $translation->language_code ) );
199
- }
200
- }
201
- }
202
- }
203
-
204
- global $wp_taxonomies;
205
- if(in_array('product', $wp_taxonomies[$taxonomy]->object_type) || in_array('product_variation', $wp_taxonomies[$taxonomy]->object_type)){
206
- $this->update_terms_translated_status($taxonomy);
207
- }
208
-
209
- }
210
-
211
- function is_original_category( $tt_id, $taxonomy ){
212
- $is_original = $this->wpdb->get_var($this->wpdb->prepare("SELECT source_language_code IS NULL FROM {$this->wpdb->prefix}icl_translations WHERE element_id=%d AND element_type=%s", $tt_id, $taxonomy ));
213
- return $is_original ? true : false;
214
- }
215
-
216
- public function wcml_update_term_translated_warnings(){
217
- $ret = array();
218
-
219
- $taxonomy = filter_input( INPUT_POST, 'taxonomy', FILTER_SANITIZE_FULL_SPECIAL_CHARS );
220
-
221
- $wcml_settings = $this->woocommerce_wpml->get_settings();
222
-
223
- $attribute_taxonomies = $this->woocommerce_wpml->attributes->get_translatable_attributes();
224
-
225
- $attribute_taxonomies_arr = array();
226
- foreach($attribute_taxonomies as $a){
227
- $attribute_taxonomies_arr[] = 'pa_' . $a->attribute_name;
228
- }
229
-
230
- $ret['is_attribute'] = intval( in_array( $taxonomy, $attribute_taxonomies_arr ) );
231
-
232
- if( isset( $wcml_settings['untranstaled_terms'][$taxonomy] ) &&
233
- (
234
- $wcml_settings['untranstaled_terms'][$taxonomy]['status'] == $this->ALL_TAXONOMY_TERMS_TRANSLATED ||
235
- $wcml_settings['untranstaled_terms'][$taxonomy]['status'] == $this->NEW_TAXONOMY_IGNORED
236
- )
237
- ){
238
-
239
- $ret['hide'] = 1;
240
- }else{
241
-
242
- $ret['hide'] = 0;
243
-
244
- if( isset( $wcml_settings[ 'sync_'.$taxonomy ]) ){
245
- $ret[ 'show_button' ] = $wcml_settings[ 'sync_'.$taxonomy ];
246
- }elseif( in_array( $taxonomy, $attribute_taxonomies_arr ) ) {
247
- $ret[ 'show_button' ] = $wcml_settings[ 'sync_variations' ];
248
- }
249
- }
250
-
251
- if( $ret[ 'is_attribute' ] ){
252
- $ret['hide'] = $this->woocommerce_wpml->attributes->is_attributes_fully_translated();
253
- }
254
-
255
- echo json_encode($ret);
256
- exit;
257
-
258
- }
259
-
260
- public function update_terms_translated_status($taxonomy){
261
-
262
- $wcml_settings = $this->woocommerce_wpml->get_settings();
263
- $is_translatable= 1;
264
- $not_translated_count = 0;
265
- $original_terms = array();
266
-
267
- if( isset( $wcml_settings[ 'attributes_settings' ][ $taxonomy ] ) && !$wcml_settings[ 'attributes_settings' ][ $taxonomy ] ){
268
- $is_translatable = 0;
269
- }
270
-
271
- if( $is_translatable ){
272
-
273
- $active_languages = $this->sitepress->get_active_languages();
274
-
275
- foreach($active_languages as $language){
276
- $terms = $this->wpdb->get_results($this->wpdb->prepare("
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
277
  SELECT t1.element_id AS e1, t2.element_id AS e2 FROM {$this->wpdb->term_taxonomy} x
278
  JOIN {$this->wpdb->prefix}icl_translations t1 ON x.term_taxonomy_id = t1.element_id AND t1.element_type = %s AND t1.source_language_code IS NULL
279
  LEFT JOIN {$this->wpdb->prefix}icl_translations t2 ON t2.trid = t1.trid AND t2.language_code = %s
280
- ", 'tax_' . $taxonomy, $language['code']));
281
- foreach($terms as $term){
282
- if( empty( $term->e2 ) && !in_array( $term->e1, $original_terms ) ){
283
- $original_terms[] = $term->e1;
284
- $not_translated_count ++;
285
- }
286
- }
287
- }
288
- }
289
-
290
- $status = $not_translated_count ? $this->NEW_TAXONOMY_TERMS : $this->ALL_TAXONOMY_TERMS_TRANSLATED;
291
-
292
- if( isset( $wcml_settings[ 'untranstaled_terms' ][ $taxonomy ] ) && $wcml_settings[ 'untranstaled_terms' ][ $taxonomy ] === $this->NEW_TAXONOMY_IGNORED ){
293
- $status = $this->NEW_TAXONOMY_IGNORED;
294
- }
295
-
296
- $wcml_settings[ 'untranstaled_terms' ][ $taxonomy ] = array( 'count' => $not_translated_count , 'status' => $status );
297
-
298
- $this->woocommerce_wpml->update_settings( $wcml_settings );
299
-
300
- return $wcml_settings[ 'untranstaled_terms' ][ $taxonomy ];
301
-
302
- }
303
-
304
- public function is_fully_translated($taxonomy){
305
-
306
- $wcml_settings = $this->woocommerce_wpml->get_settings();
307
-
308
- $return = true;
309
-
310
- if( !isset($wcml_settings['untranstaled_terms'][$taxonomy]) ){
311
- $wcml_settings['untranstaled_terms'][$taxonomy] = $this->update_terms_translated_status($taxonomy);
312
- }
313
-
314
- if($wcml_settings['untranstaled_terms'][$taxonomy]['status'] == $this->NEW_TAXONOMY_TERMS){
315
- $return = false;
316
- }
317
-
318
-
319
- return $return;
320
- }
321
-
322
- public function get_untranslated_terms_number( $taxonomy, $force_update = false ){
323
-
324
- $wcml_settings = $this->woocommerce_wpml->get_settings();
325
-
326
- if( $force_update || !isset($wcml_settings['untranstaled_terms'][$taxonomy] ) ){
327
- $wcml_settings['untranstaled_terms'][$taxonomy] = $this->update_terms_translated_status($taxonomy);
328
- }
329
-
330
- return $wcml_settings['untranstaled_terms'][$taxonomy]['count'];
331
-
332
- }
333
-
334
- public function set_flag_for_variation_on_attribute_update($term_id, $tt_id, $taxonomy){
335
-
336
- $attribute_taxonomies = wc_get_attribute_taxonomies();
337
- foreach($attribute_taxonomies as $a){
338
- $attribute_taxonomies_arr[] = 'pa_' . $a->attribute_name;
339
- }
340
-
341
- if(isset( $attribute_taxonomies_arr ) && in_array($taxonomy, $attribute_taxonomies_arr)){
342
 
343
- $wcml_settings = $this->woocommerce_wpml->get_settings();
344
 
345
- // get term language
346
- $term_language = $this->sitepress->get_element_language_details($tt_id, 'tax_' . $taxonomy);
 
347
 
348
- if( isset( $term_language->language_code ) && $term_language->language_code != $this->sitepress->get_default_language()){
349
- // get term in the default language
350
- $term_id = apply_filters( 'translate_object_id',$term_id, $taxonomy, false, $this->sitepress->get_default_language());
 
351
 
352
- //does it belong to any posts (variations)
353
- $objects = get_objects_in_term($term_id, $taxonomy);
354
 
355
- if(!isset($wcml_settings['variations_needed'][$taxonomy])){
356
- $wcml_settings['variations_needed'][$taxonomy] = 0;
357
- }
358
- $wcml_settings['variations_needed'][$taxonomy] += count($objects);
359
 
360
- $this->woocommerce_wpml->update_settings($wcml_settings);
361
 
362
- }
 
 
 
 
 
363
  }
364
-
365
- }
366
-
367
- public function sync_taxonomy_translations( $html, $taxonomy, $taxonomy_obj ){
368
-
369
- $is_wcml = is_admin() && $taxonomy && isset($_GET['page']) && $_GET['page'] == 'wpml-wcml' && isset($_GET['tab']);
370
- $is_ajax = is_ajax() && $taxonomy && isset( $_POST['action'] ) && $_POST['action'] === 'wpml_get_terms_and_labels_for_taxonomy_table';
371
-
372
- if( $is_wcml || $is_ajax ){
373
-
374
- $sync_tax = new WCML_Sync_Taxonomy( $this->woocommerce_wpml, $taxonomy, $taxonomy_obj );
375
- $html = $sync_tax->get_view();
376
- }
377
-
378
- return $html;
379
- }
380
-
381
- public function wcml_sync_product_variations($taxonomy){
382
- $nonce = filter_input( INPUT_POST, 'wcml_nonce', FILTER_SANITIZE_FULL_SPECIAL_CHARS );
383
- if(!$nonce || !wp_verify_nonce($nonce, 'wcml_sync_product_variations')){
384
- die('Invalid nonce');
385
- }
386
-
387
- $VARIATIONS_THRESHOLD = 20;
388
-
389
- $wcml_settings = $this->woocommerce_wpml->get_settings();
390
- $response = array();
391
-
392
- $taxonomy = filter_input( INPUT_POST, 'taxonomy', FILTER_SANITIZE_FULL_SPECIAL_CHARS );
393
-
394
- $languages_processed = intval( $_POST['languages_processed']);
395
-
396
- $condition = $languages_processed?'>=':'>';
397
-
398
- $where = isset($_POST['last_post_id']) && $_POST['last_post_id'] ? ' ID '.$condition.' ' . intval($_POST['last_post_id']) . ' AND ' : '';
399
-
400
- $post_ids = $this->wpdb->get_col($this->wpdb->prepare("
401
- SELECT DISTINCT tr.object_id
402
- FROM {$this->wpdb->term_relationships} tr
403
- JOIN {$this->wpdb->term_taxonomy} tx on tr.term_taxonomy_id = tx.term_taxonomy_id
404
- JOIN {$this->wpdb->posts} p ON tr.object_id = p.ID
405
- JOIN {$this->wpdb->prefix}icl_translations t ON t.element_id = p.ID
406
- WHERE {$where} tx.taxonomy = %s AND p.post_type = 'product' AND t.element_type='post_product' AND t.language_code = %s
407
- ORDER BY ID ASC
408
-
409
- ", $taxonomy, $this->sitepress->get_default_language()));
410
-
411
- if($post_ids){
412
-
413
- $variations_processed = 0;
414
- $posts_processed = 0;
415
- foreach($post_ids as $post_id){
416
- $terms = wp_get_post_terms($post_id, $taxonomy);
417
- $terms_count = count($terms);
418
-
419
- $trid = $this->sitepress->get_element_trid($post_id, 'post_product');
420
- $translations = $this->sitepress->get_element_translations($trid, 'post_product');
421
-
422
- $i = 1;
423
-
424
- foreach($translations as $translation){
425
-
426
- if($i > $languages_processed && $translation->element_id != $post_id){
427
- $this->woocommerce_wpml->sync_product_data->sync_product_taxonomies($post_id, $translation->element_id, $translation->language_code);
428
- $this->woocommerce_wpml->sync_variations_data->sync_product_variations( $post_id, $translation->element_id, $translation->language_code, [ 'is_troubleshooting' => true ] );
429
- $this->woocommerce_wpml->translation_editor->create_product_translation_package($post_id,$trid, $translation->language_code,ICL_TM_COMPLETE);
430
- $variations_processed += $terms_count*2;
431
- $response['languages_processed'] = $i;
432
- $i++;
433
- //check if sum of 2 iterations doesn't exceed $VARIATIONS_THRESHOLD
434
- if($variations_processed >= $VARIATIONS_THRESHOLD){
435
- break;
436
- }
437
- }else{
438
- $i++;
439
- }
440
- }
441
- $response['last_post_id'] = $post_id;
442
- if(--$i == count($translations)){
443
- $response['languages_processed'] = 0;
444
- $languages_processed = 0;
445
- }else{
446
- break;
447
- }
448
-
449
- $posts_processed ++;
450
-
451
- }
452
 
453
- $response['go'] = 1;
454
-
455
- }else{
456
-
457
- $response['go'] = 0;
458
-
459
- }
460
-
461
- $response['progress'] = $response['go'] ? sprintf(__('%d products left', 'woocommerce-multilingual'), count($post_ids) - $posts_processed) : __('Synchronization complete!', 'woocommerce-multilingual');
462
-
463
- if($response['go'] && isset($wcml_settings['variations_needed'][$taxonomy]) && !empty($variations_processed)){
464
- $wcml_settings['variations_needed'][$taxonomy] = max($wcml_settings['variations_needed'][$taxonomy] - $variations_processed, 0);
465
- }else{
466
- if($response['go'] == 0){
467
- $wcml_settings['variations_needed'][$taxonomy] = 0;
468
- }
469
- }
470
- $wcml_settings['sync_variations'] = 0;
471
 
472
- $this->woocommerce_wpml->update_settings($wcml_settings);
473
-
474
- echo json_encode($response);
475
- exit;
476
- }
477
 
478
- public function wcml_sync_taxonomies_in_content_preview(){
479
- $nonce = filter_input( INPUT_POST, 'wcml_nonce', FILTER_SANITIZE_FULL_SPECIAL_CHARS );
480
- if(!$nonce || !wp_verify_nonce($nonce, 'wcml_sync_taxonomies_in_content_preview')){
481
- die('Invalid nonce');
482
- }
483
 
484
- global $wp_taxonomies;
485
 
486
- $html = $message = $errors = '';
 
 
487
 
 
488
 
489
- if(isset($wp_taxonomies[$_POST['taxonomy']])){
490
- $object_types = $wp_taxonomies[$_POST['taxonomy']]->object_type;
491
 
492
- foreach($object_types as $object_type){
493
 
494
- $html .= $this->render_assignment_status($object_type, $_POST['taxonomy'], $preview = true);
 
 
 
495
 
496
- }
497
 
498
- }else{
499
- $errors = sprintf(__('Invalid taxonomy %s', 'woocommerce-multilingual'), $_POST['taxonomy']);
500
- }
501
 
 
 
502
 
503
- echo json_encode(array('html' => $html, 'message'=> $message, 'errors' => $errors));
504
- exit;
505
- }
506
 
507
- public function wcml_sync_taxonomies_in_content(){
508
- $nonce = filter_input( INPUT_POST, 'wcml_nonce', FILTER_SANITIZE_FULL_SPECIAL_CHARS );
509
- if(!$nonce || !wp_verify_nonce($nonce, 'wcml_sync_taxonomies_in_content')){
510
- die('Invalid nonce');
511
- }
512
 
513
- global $wp_taxonomies;
 
 
 
514
 
515
- $html = $message = $errors = '';
516
 
517
- if(isset($wp_taxonomies[$_POST['taxonomy']])){
518
- $html .= $this->render_assignment_status($_POST['post'], $_POST['taxonomy'], $preview = false);
519
 
520
- }else{
521
- $errors .= sprintf(__('Invalid taxonomy %s', 'woocommerce-multilingual'), $_POST['taxonomy']);
522
- }
523
 
 
524
 
525
- echo json_encode(array('html' => $html, 'errors' => $errors));
526
- exit;
527
- }
528
 
529
- public function render_assignment_status($object_type, $taxonomy, $preview = true){
530
- global $wp_post_types, $wp_taxonomies;
531
 
532
- $default_language = $this->sitepress->get_default_language();
533
- $is_taxonomy_translatable = $this->is_translatable_wc_taxonomy( $taxonomy );
 
534
 
535
- $posts = $this->wpdb->get_results($this->wpdb->prepare( "SELECT * FROM {$this->wpdb->posts} AS p LEFT JOIN {$this->wpdb->prefix}icl_translations AS tr ON tr.element_id = p.ID WHERE p.post_status = 'publish' AND p.post_type = %s AND tr.source_language_code is NULL", $object_type ) );
 
536
 
537
- foreach($posts as $post){
 
 
 
 
538
 
539
- $terms = wp_get_post_terms($post->ID, $taxonomy);
540
 
541
- $term_ids = array();
542
- foreach($terms as $term){
543
- $term_ids[] = $term->term_id;
544
- }
545
 
546
- $trid = $this->sitepress->get_element_trid($post->ID, 'post_' . $post->post_type);
547
- $translations = $this->sitepress->get_element_translations($trid, 'post_' . $post->post_type, true, true);
548
 
549
- foreach($translations as $language => $translation){
550
 
551
- if($language != $default_language && $translation->element_id){
552
 
553
- $terms_of_translation = wp_get_post_terms($translation->element_id, $taxonomy);
554
 
555
- $translation_term_ids = array();
556
- foreach($terms_of_translation as $term){
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
557
 
558
- $term_id_original = apply_filters( 'translate_object_id',$term->term_id, $taxonomy, false, $default_language );
559
- if(!$term_id_original || !in_array($term_id_original, $term_ids)){
560
- // remove term
561
 
562
- if($preview){
563
- $needs_sync = true;
564
- break(3);
565
- }
566
 
567
- $current_terms = wp_get_post_terms($translation->element_id, $taxonomy);
568
- $updated_terms = array();
569
- foreach($current_terms as $cterm){
570
- if($cterm->term_id != $term->term_id){
571
- $updated_terms[] = $is_taxonomy_translatable ? $term->term_id : $term->name;
572
- }
573
- if(!$preview){
574
 
575
- if( $is_taxonomy_translatable && !is_taxonomy_hierarchical($taxonomy)){
576
- $updated_terms = array_unique( array_map( 'intval', $updated_terms ) );
577
- }
578
 
579
- wp_set_post_terms($translation->element_id, $updated_terms, $taxonomy);
580
- }
581
 
582
- }
583
 
584
- }else{
585
- $translation_term_ids[] = $term_id_original;
586
- }
587
 
588
- }
 
 
 
 
 
 
 
589
 
590
- foreach($term_ids as $term_id){
591
 
592
- if(!in_array($term_id, $translation_term_ids)){
593
- // add term
 
594
 
595
- if($preview){
596
- $needs_sync = true;
597
- break(3);
598
- }
599
- $terms_array = array();
600
- $term_id_translated = apply_filters( 'translate_object_id',$term_id, $taxonomy, false, $language);
601
 
602
- // not using get_term
603
- $translated_term = $this->wpdb->get_row($this->wpdb->prepare("
604
- SELECT * FROM {$this->wpdb->terms} t JOIN {$this->wpdb->term_taxonomy} x ON x.term_id = t.term_id WHERE t.term_id = %d AND x.taxonomy = %s", $term_id_translated, $taxonomy));
605
 
606
- if( $translated_term ){
607
- $terms_array[] = $translated_term->term_id;
608
- }
609
 
610
- if(!$preview){
 
611
 
612
- if( $is_taxonomy_translatable && !is_taxonomy_hierarchical($taxonomy)){
613
- $terms_array = array_unique( array_map( 'intval', $terms_array ) );
614
- }
615
 
616
- wp_set_post_terms($translation->element_id, $terms_array, $taxonomy, true);
617
- }
618
 
619
- }
 
 
 
620
 
621
- }
 
 
 
 
 
 
 
 
622
 
623
- }
 
 
 
 
 
 
 
 
 
 
 
624
 
625
- }
 
 
 
 
 
 
 
 
 
 
 
626
 
627
- }
 
628
 
629
- $wcml_settings = $this->woocommerce_wpml->get_settings();
630
- $wcml_settings['sync_'.$taxonomy] = 0;
631
- $this->woocommerce_wpml->update_settings($wcml_settings);
632
 
633
- $out = '';
634
 
635
- if($preview){
636
 
637
- $out .= '<div class="wcml_tt_sync_row">';
638
- if(!empty($needs_sync)){
639
- $out .= '<form class="wcml_tt_do_sync">';
640
- $out .= '<input type="hidden" name="post" value="' . $object_type . '" />';
641
- $out .= wp_nonce_field('wcml_sync_taxonomies_in_content', 'wcml_sync_taxonomies_in_content_nonce',true,false);
642
- $out .= '<input type="hidden" name="taxonomy" value="' . $taxonomy . '" />';
643
- $out .= sprintf(__('Some translated %s have different %s assignments.', 'woocommerce-multilingual'),
644
- '<strong>' . mb_strtolower($wp_post_types[$object_type]->labels->name) . '</strong>',
645
- '<strong>' . mb_strtolower($wp_taxonomies[$taxonomy]->labels->name) . '</strong>');
646
- $out .= '&nbsp;<a class="submit button-secondary" href="#">' . sprintf(__('Update %s for all translated %s', 'woocommerce-multilingual'),
647
- '<strong>' . mb_strtolower($wp_taxonomies[$taxonomy]->labels->name) . '</strong>',
648
- '<strong>' . mb_strtolower($wp_post_types[$object_type]->labels->name) . '</strong>') . '</a>' .
649
- '&nbsp;<img src="'. ICL_PLUGIN_URL . '/res/img/ajax-loader.gif" alt="loading" height="16" width="16" class="wcml_tt_spinner" />';
650
- $out .= "</form>";
651
- }else{
652
- $out .= sprintf(__('All %s have the same %s assignments.', 'woocommerce-multilingual'),
653
- '<strong>' . mb_strtolower($wp_taxonomies[$taxonomy]->labels->name) . '</strong>',
654
- '<strong>' . mb_strtolower($wp_post_types[$object_type]->labels->name) . '</strong>');
655
- }
656
- $out .= "</div>";
657
 
658
- }else{
 
 
 
659
 
660
- $out .= sprintf(__('Successfully updated %s for all translated %s.', 'woocommerce-multilingual'), $wp_taxonomies[$taxonomy]->labels->name, $wp_post_types[$object_type]->labels->name);
 
661
 
662
- }
663
 
664
- return $out;
665
- }
666
 
667
- function shipping_terms($terms, $post_id, $taxonomy){
668
- global $pagenow;
669
 
670
- if( isset( $_POST['action'] ) && $_POST['action'] == 'woocommerce_load_variations' ){
671
- return $terms;
672
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
673
 
674
- if( $pagenow != 'post.php' && ( get_post_type($post_id) == 'product' || get_post_type($post_id) == 'product_variation' ) && $taxonomy == 'product_shipping_class'){
 
 
 
675
 
676
- remove_filter('get_the_terms',array($this,'shipping_terms'), 10, 3);
677
- $terms = get_the_terms( apply_filters( 'translate_object_id', $post_id, get_post_type($post_id), true, $this->sitepress->get_current_language() ),'product_shipping_class');
678
- add_filter('get_the_terms',array($this,'shipping_terms'), 10, 3);
679
- return $terms;
680
- }
 
 
 
 
 
 
 
 
681
 
682
- return $terms;
683
- }
684
 
685
- public function filter_shipping_classes_terms( $terms, $taxonomies, $args ){
686
 
687
- if( $taxonomies && is_admin() && in_array( 'product_shipping_class', $taxonomies ) ){
688
  $on_wc_settings_page = isset( $_GET[ 'page' ] ) && $_GET[ 'page' ] === 'wc-settings';
689
  $on_shipping_tab = isset( $_GET[ 'tab' ] ) && $_GET[ 'tab' ] === 'shipping';
690
  $on_classes_section = isset( $_GET[ 'section' ] ) && $_GET[ 'section' ] === 'classes';
691
 
692
- if( $on_wc_settings_page && $on_shipping_tab && !$on_classes_section ){
693
- remove_filter( 'get_terms', array( $this, 'filter_shipping_classes_terms' ) );
694
- remove_filter( 'get_terms', array( 'WPML_Terms_Translations', 'get_terms_filter' ), 10, 2 );
695
- $this->sitepress->switch_lang( $this->sitepress->get_default_language() );
696
- $terms = get_terms( $args );
697
- add_filter( 'get_terms', array( 'WPML_Terms_Translations', 'get_terms_filter' ), 10, 2 );
698
- add_filter( 'get_terms', array( $this, 'filter_shipping_classes_terms' ), 10, 3 );
699
- $this->sitepress->switch_lang();
700
- }
701
- }
702
 
703
- return $terms;
704
- }
705
 
706
- function wcml_delete_term($term, $tt_id, $taxonomy, $deleted_term){
707
- global $wp_taxonomies;
708
 
709
- foreach($wp_taxonomies as $key=>$taxonomy_obj){
710
- if((in_array('product',$taxonomy_obj->object_type) || in_array('product_variation',$taxonomy_obj->object_type) ) && $key==$taxonomy){
711
- $this->update_terms_translated_status($taxonomy);
712
- break;
713
- }
714
- }
715
 
716
- }
717
 
718
- function get_product_terms_filter( $terms, $product_id, $taxonomy, $args ) {
719
 
720
  $language = $this->sitepress->get_language_for_element( $product_id, 'post_' . get_post_type( $product_id ) );
721
 
722
  $is_objects_array = is_object( current( $terms ) );
723
 
724
- $filtered_terms = array();
725
 
726
  foreach ( $terms as $term ) {
727
 
@@ -748,10 +821,13 @@ class WCML_Terms{
748
  if ( isset( $is_slug ) ) {
749
  $filtered_terms[] = get_term( $trnsl_term_id, $taxonomy )->slug;
750
  } else {
751
- $filtered_terms[] = ( is_ajax() && isset( $_POST['action'] ) && in_array( $_POST['action'], array(
 
 
752
  'woocommerce_add_variation',
753
- 'woocommerce_link_all_variations'
754
- ) ) ) ? strtolower( get_term( $trnsl_term_id, $taxonomy )->name ) : get_term( $trnsl_term_id, $taxonomy )->name;
 
755
  }
756
  }
757
  }
@@ -759,7 +835,7 @@ class WCML_Terms{
759
  return $filtered_terms;
760
  }
761
 
762
- function set_flag_to_sync( $taxonomy, $el_id, $language_code ) {
763
  if ( $el_id ) {
764
  $elem_details = $this->sitepress->get_element_language_details( $el_id, 'tax_' . $taxonomy );
765
  if ( null !== $elem_details->source_language_code ) {
@@ -768,200 +844,215 @@ class WCML_Terms{
768
  }
769
  }
770
 
771
- function check_if_sync_terms_needed(){
772
 
773
- $wcml_settings = $this->woocommerce_wpml->get_settings();
774
- $wcml_settings['sync_variations'] = 0;
775
- $wcml_settings['sync_product_cat'] = 0;
776
- $wcml_settings['sync_product_tag'] = 0;
777
- $wcml_settings['sync_product_shipping_class'] = 0;
778
- $this->woocommerce_wpml->update_settings( $wcml_settings );
779
 
780
- $taxonomies_to_check = array( 'product_cat', 'product_tag', 'product_shipping_class' );
781
 
782
- foreach( $taxonomies_to_check as $check_taxonomy ){
783
- $terms = get_terms( $check_taxonomy, array( 'hide_empty' => false, 'fields' => 'ids' ) );
784
- if (is_array($terms)){
785
- foreach( $terms as $term ){
786
- if( $this->check_if_sync_term_translation_needed( $term[ 'term_taxonomy_id' ], $check_taxonomy ) ){
787
- break;
788
- }
789
- }
790
- }
791
- }
792
-
793
- $attribute_taxonomies = wc_get_attribute_taxonomies();
794
- $flag_set = false;
795
- foreach( $attribute_taxonomies as $a ){
796
-
797
- $terms = get_terms( 'pa_' . $a->attribute_name, array( 'hide_empty' => false, 'fields' => 'ids' ) );
798
- if (is_array($terms)){
799
- foreach( $terms as $term ){
800
- $flag_set = $this->check_if_sync_term_translation_needed( $term[ 'term_taxonomy_id' ], 'pa_' . $a->attribute_name );
801
- if( $flag_set ){
802
- break;
803
- }
804
- }
805
- }
806
 
807
- if( $flag_set ){
808
- break;
809
- }
810
- }
811
 
812
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
813
 
814
- function check_if_sync_term_translation_needed( $t_id, $taxonomy ){
 
 
 
815
 
816
- $wcml_settings = $this->woocommerce_wpml->get_settings();
817
 
818
- $attribute_taxonomies = wc_get_attribute_taxonomies();
819
- $attribute_taxonomies_arr = array();
820
- foreach($attribute_taxonomies as $a){
821
- $attribute_taxonomies_arr[] = 'pa_' . $a->attribute_name;
822
- }
823
 
824
- if( ( isset( $wcml_settings[ 'sync_'.$taxonomy ]) && $wcml_settings[ 'sync_'.$taxonomy ] ) || ( in_array( $taxonomy, $attribute_taxonomies_arr ) && isset( $wcml_settings[ 'sync_variations' ]) && $wcml_settings['sync_variations'] ) ){
825
- return true;
826
- }
827
 
828
- $translations = $this->wpdb->get_results( $this->wpdb->prepare( "SELECT t2.element_id, t2.source_language_code FROM {$this->wpdb->prefix}icl_translations AS t1 LEFT JOIN {$this->wpdb->prefix}icl_translations AS t2 ON t1.trid = t2.trid WHERE t1.element_id = %d AND t1.element_type = %s ", $t_id, 'tax_'.$taxonomy ) );
 
 
 
 
829
 
830
- foreach( $translations as $key => $translation ){
831
- if ( is_null( $translation->source_language_code ) ) {
832
- $original_count = $this->wpdb->get_var( $this->wpdb->prepare( "SELECT count( object_id ) FROM {$this->wpdb->term_relationships} WHERE term_taxonomy_id = %d ", $translation->element_id ) );
833
- unset( $translations[ $key ] );
834
- }
835
- }
836
 
837
- foreach( $translations as $translation ){
838
 
839
- $count = $this->wpdb->get_var( $this->wpdb->prepare( "SELECT count( object_id ) FROM {$this->wpdb->term_relationships} WHERE term_taxonomy_id = %d ", $translation->element_id ) );
840
- if( $original_count != $count ){
 
 
 
 
841
 
842
- if( in_array( $taxonomy, array( 'product_cat', 'product_tag', 'product_shipping_class' ) ) ){
843
- $wcml_settings[ 'sync_'.$taxonomy ] = 1;
844
- $this->woocommerce_wpml->update_settings($wcml_settings);
845
- return true;
846
- }
847
 
848
- if( isset( $attribute_taxonomies_arr ) && in_array( $taxonomy, $attribute_taxonomies_arr ) ){
849
- $wcml_settings['sync_variations'] = 1;
 
 
 
850
  $this->woocommerce_wpml->update_settings($wcml_settings);
851
  return true;
852
  }
853
 
854
- }
855
-
856
- }
 
 
 
 
857
 
858
- }
859
 
860
- function get_table_taxonomies( $taxonomies ){
861
 
862
- foreach( $taxonomies as $key => $taxonomy ){
863
- if (substr($key, 0, 3) != 'pa_') {
864
- unset( $taxonomies[$key]);
865
- }
866
- }
867
 
868
- return $taxonomies;
869
- }
870
 
871
- function get_wc_taxonomies(){
872
 
873
- global $wp_taxonomies;
874
- $taxonomies = array();
875
 
876
- //don't use get_taxonomies for product, because when one more post type registered for product taxonomy functions returned taxonomies only for product type
877
- foreach ( $wp_taxonomies as $key => $taxonomy ) {
878
 
879
- if (
880
- ( in_array( 'product', $taxonomy->object_type ) || in_array( 'product_variation', $taxonomy->object_type ) ) &&
881
- ! in_array( $key, $taxonomies )
882
- ) {
883
 
884
- if( substr( $key, 0, 3 ) == 'pa_' && !$this->woocommerce_wpml->attributes->is_translatable_attribute( $key ) ){
885
- continue;
886
- }
887
 
888
- $taxonomies[] = $key;
889
- }
890
- }
891
 
892
- return $taxonomies;
893
 
894
- }
895
 
896
- function has_wc_taxonomies_to_translate(){
897
 
898
- $taxonomies = $this->get_wc_taxonomies();
899
 
900
- $no_tax_to_trnls = false;
901
- foreach ( $taxonomies as $taxonomy ){
902
 
903
- $is_fully_translated = 0 === $this->get_untranslated_terms_number( $taxonomy );
904
- if (
905
- ! $this->is_translatable_wc_taxonomy( $taxonomy ) ||
906
- $is_fully_translated
907
- ) {
908
- continue;
909
- } else {
910
- $no_tax_to_trnls = true;
911
- }
912
- }
913
 
914
- return $no_tax_to_trnls;
915
 
916
- }
917
 
918
- /*
919
- * Use custom query, because get_term_by function return false for terms with "0" slug *
920
- */
921
- public function wcml_get_term_id_by_slug( $taxonomy, $slug ){
922
 
923
- return $this->wpdb->get_var(
924
- $this->wpdb->prepare(
925
- "SELECT tt.term_id FROM {$this->wpdb->terms} AS t
926
  INNER JOIN {$this->wpdb->term_taxonomy} AS tt
927
  ON t.term_id = tt.term_id
928
  WHERE tt.taxonomy = %s AND t.slug = %s LIMIT 1",
929
- $taxonomy, sanitize_title( $slug ) )
930
- );
931
- }
 
 
932
 
933
- public function wcml_get_term_by_id( $term_id, $taxonomy ){
934
 
935
- return $this->wpdb->get_row(
936
- $this->wpdb->prepare("
 
937
  SELECT * FROM {$this->wpdb->terms} t
938
  JOIN {$this->wpdb->term_taxonomy} x
939
  ON x.term_id = t.term_id
940
  WHERE t.term_id = %d AND x.taxonomy = %s",
941
- $term_id, $taxonomy )
942
- );
943
- }
 
 
944
 
945
- public function wcml_get_translated_term( $term_id, $taxonomy, $language ){
946
 
947
- $tr_id = apply_filters( 'translate_object_id', $term_id, $taxonomy, false, $language );
948
 
949
- if( !is_null( $tr_id ) ) {
950
- $term_id = $tr_id;
951
- }
952
 
953
- return $this->wcml_get_term_by_id( $term_id, $taxonomy );
954
- }
955
 
956
  public function is_translatable_wc_taxonomy( $taxonomy ) {
957
- if ( in_array( $taxonomy, array( 'product_type', 'product_visibility' ), true ) ) {
958
  return false;
959
  }
960
 
961
  return true;
962
  }
963
 
964
- function pre_option_default_product_cat( ) {
965
 
966
  $lang = $this->sitepress->get_current_language();
967
 
@@ -981,7 +1072,7 @@ class WCML_Terms{
981
  );
982
  }
983
 
984
- function update_option_default_product_cat( $oldvalue, $new_value ) {
985
  $new_value = $this->wpdb->get_var( $this->wpdb->prepare( "SELECT term_taxonomy_id FROM {$this->wpdb->term_taxonomy} WHERE taxonomy='product_cat' AND term_id=%d", $new_value ) );
986
  $translations = $this->sitepress->get_element_translations( $this->sitepress->get_element_trid( $new_value, 'tax_product_cat' ) );
987
  $wcml_settings = $this->woocommerce_wpml->get_settings();
@@ -999,7 +1090,7 @@ class WCML_Terms{
999
  public function update_category_count_meta( $meta_id, $object_id, $meta_key, $meta_value ) {
1000
 
1001
  if ( 'product_count_product_cat' === $meta_key ) {
1002
- remove_action( 'update_term_meta', array( $this, 'update_category_count_meta' ), 10, 4 );
1003
 
1004
  $trid = $this->sitepress->get_element_trid( $object_id, 'tax_product_cat' );
1005
  $translations = $this->sitepress->get_element_translations( $trid, 'tax_product_cat' );
@@ -1010,7 +1101,7 @@ class WCML_Terms{
1010
  }
1011
  }
1012
 
1013
- add_action( 'update_term_meta', array( $this, 'update_category_count_meta' ), 10, 4 );
1014
  }
1015
  }
1016
 
@@ -1019,8 +1110,8 @@ class WCML_Terms{
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
  }
1
  <?php
2
+
3
+ class WCML_Terms {
4
+
5
+ const PRODUCT_SHIPPING_CLASS = 'product_shipping_class';
6
+ private $ALL_TAXONOMY_TERMS_TRANSLATED = 0;
7
+ private $NEW_TAXONOMY_TERMS = 1;
8
+ private $NEW_TAXONOMY_IGNORED = 2;
9
 
10
  /** @var woocommerce_wpml */
11
  private $woocommerce_wpml;
12
  /** @var SitePress */
13
  private $sitepress;
14
  /** @var wpdb */
15
+ private $wpdb;
16
 
17
  /**
18
  * WCML_Terms constructor.
19
  *
20
  * @param woocommerce_wpml $woocommerce_wpml
21
+ * @param SitePress $sitepress
22
+ * @param wpdb $wpdb
23
  */
24
+ public function __construct( woocommerce_wpml $woocommerce_wpml, SitePress $sitepress, wpdb $wpdb ) {
25
+ $this->woocommerce_wpml = $woocommerce_wpml;
26
+ $this->sitepress = $sitepress;
27
+ $this->wpdb = $wpdb;
28
+ }
29
 
30
  public function add_hooks() {
31
 
32
+ add_action( 'updated_woocommerce_term_meta', [ $this, 'sync_term_order' ], 100, 4 );
33
+
34
+ add_filter( 'wp_get_object_terms', [ $this->sitepress, 'get_terms_filter' ] );
35
+ add_action( 'created_term', [ $this, 'translated_terms_status_update' ], 10, 3 );
36
+ add_action( 'edit_term', [ $this, 'translated_terms_status_update' ], 10, 3 );
37
+ add_action(
38
+ 'wp_ajax_wcml_update_term_translated_warnings',
39
+ [
40
+ $this,
41
+ 'wcml_update_term_translated_warnings',
42
+ ]
43
+ );
44
+
45
+ add_action( 'created_term', [ $this, 'set_flag_for_variation_on_attribute_update' ], 10, 3 );
46
+
47
+ add_filter( 'wpml_taxonomy_translation_bottom', [ $this, 'sync_taxonomy_translations' ], 10, 3 );
48
+
49
+ add_action( 'wp_ajax_wcml_sync_product_variations', [ $this, 'wcml_sync_product_variations' ] );
50
+ add_action( 'wp_ajax_wcml_tt_sync_taxonomies_in_content', [ $this, 'wcml_sync_taxonomies_in_content' ] );
51
+ add_action(
52
+ 'wp_ajax_wcml_tt_sync_taxonomies_in_content_preview',
53
+ [
54
+ $this,
55
+ 'wcml_sync_taxonomies_in_content_preview',
56
+ ]
57
+ );
58
 
59
+ if ( is_admin() ) {
60
+ add_action( 'admin_menu', [ $this, 'admin_menu_setup' ] );
 
 
 
 
 
61
 
62
+ add_filter( 'pre_option_default_product_cat', [ $this, 'pre_option_default_product_cat' ] );
63
+ add_filter( 'update_option_default_product_cat', [ $this, 'update_option_default_product_cat' ], 1, 2 );
64
+ }
65
 
66
+ add_action( 'update_term_meta', [ $this, 'update_category_count_meta' ], 10, 4 );
67
+ add_action( 'delete_term', [ $this, 'wcml_delete_term' ], 10, 4 );
68
+ add_filter( 'get_the_terms', [ $this, 'shipping_terms' ], 10, 3 );
69
+ add_filter( 'get_terms', [ $this, 'filter_shipping_classes_terms' ], 10, 3 );
70
 
71
+ add_filter( 'woocommerce_get_product_terms', [ $this, 'get_product_terms_filter' ], 10, 4 );
72
+ add_action( 'created_term_translation', [ $this, 'set_flag_to_sync' ], 10, 3 );
 
 
 
 
73
 
74
+ add_filter( 'woocommerce_get_product_subcategories_cache_key', [ $this, 'add_lang_parameter_to_cache_key' ] );
75
+ }
76
 
77
+ public function admin_menu_setup() {
78
+ global $pagenow;
79
+ if ( $pagenow == 'edit-tags.php' && isset( $_GET['action'] ) && $_GET['action'] == 'edit' ) {
80
+ add_action( 'admin_notices', [ $this, 'show_term_translation_screen_notices' ] );
81
  }
82
 
83
+ $page = isset( $_GET['page'] ) ? $_GET['page'] : '';
84
+ if ( $page === ICL_PLUGIN_FOLDER . '/menu/taxonomy-translation.php' ) {
85
+ WCML_Resources::load_management_css();
86
+ WCML_Resources::load_taxonomy_translation_scripts();
87
+ }
88
 
89
+ }
90
+
91
+ public function show_term_translation_screen_notices() {
92
+
93
+ $taxonomies = array_keys( get_taxonomies( [ 'object_type' => [ 'product' ] ], 'objects' ) );
94
+ $taxonomies = $taxonomies + array_keys( get_taxonomies( [ 'object_type' => [ 'product_variations' ] ], 'objects' ) );
95
+ $taxonomies = array_unique( $taxonomies );
96
+ $taxonomy = isset( $_GET['taxonomy'] ) ? $_GET['taxonomy'] : false;
97
+ if ( $taxonomy && in_array( $taxonomy, $taxonomies ) ) {
98
+ $taxonomy_obj = get_taxonomy( $taxonomy );
99
+ $message = sprintf(
100
+ __( 'To translate %1$s please use the %2$s translation%3$s page, inside the %4$sWooCommerce Multilingual admin%5$s.', 'woocommerce-multilingual' ),
101
+ $taxonomy_obj->labels->name,
102
+ '<strong><a href="' . admin_url( 'admin.php?page=wpml-wcml&tab=' . $taxonomy ) . '">' . $taxonomy_obj->labels->singular_name,
103
+ '</a></strong>',
104
+ '<strong><a href="' . admin_url( 'admin.php?page=wpml-wcml">' ),
105
+ '</a></strong>'
106
+ );
107
+
108
+ echo '<div class="updated"><p>' . $message . '</p></div>';
109
+ }
110
 
 
111
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
112
 
113
+ public function sync_term_order_globally() {
114
+ // syncs the term order of any taxonomy in $this->wpdb->prefix.'woocommerce_attribute_taxonomies'.
115
+ // use it when term orderings have become unsynched, e.g. before WCML 3.3.
116
+ if ( ! defined( 'WOOCOMMERCE_VERSION' ) ) {
117
+ return;
118
+ }
119
 
120
+ $cur_lang = $this->sitepress->get_current_language();
121
+ $lang = $this->sitepress->get_default_language();
122
+ $this->sitepress->switch_lang( $lang );
123
+
124
+ $taxes = wc_get_attribute_taxonomies();
125
+
126
+ if ( $taxes ) {
127
+ foreach ( $taxes as $woo_tax ) {
128
+ $tax = 'pa_' . $woo_tax->attribute_name;
129
+ $meta_key = 'order_' . $tax;
130
+ // if ($tax != 'pa_frame') continue;
131
+ $terms = get_terms( $tax );
132
+ if ( $terms ) {
133
+ foreach ( $terms as $term ) {
134
+ $term_order = get_term_meta( $term->term_id, $meta_key, true );
135
+ $trid = $this->sitepress->get_element_trid( $term->term_taxonomy_id, 'tax_' . $tax );
136
+ $translations = $this->sitepress->get_element_translations( $trid, 'tax_' . $tax );
137
+ if ( $translations ) {
138
+ foreach ( $translations as $trans ) {
139
+ if ( $trans->language_code != $lang ) {
140
+ update_term_meta( $trans->term_id, $meta_key, $term_order );
141
+ }
142
+ }
143
+ }
144
+ }
145
+ }
146
+ }
147
+ }
148
 
149
+ // sync product categories ordering.
150
+ $terms = get_terms( 'product_cat' );
151
+ if ( $terms ) {
152
+ foreach ( $terms as $term ) {
153
+ $term_order = get_term_meta( $term->term_id, 'order', true );
154
+ $trid = $this->sitepress->get_element_trid( $term->term_taxonomy_id, 'tax_product_cat' );
155
+ $translations = $this->sitepress->get_element_translations( $trid, 'tax_product_cat' );
156
+ if ( $translations ) {
157
+ foreach ( $translations as $trans ) {
158
+ if ( $trans->language_code != $lang ) {
159
+ update_term_meta( $trans->term_id, 'order', $term_order );
160
+ }
161
+ }
162
+ }
163
+ }
164
+ }
165
+
166
+ $this->sitepress->switch_lang( $cur_lang );
167
+
168
+ $this->woocommerce_wpml->settings['is_term_order_synced'] = 'yes';
169
+ $this->woocommerce_wpml->update_settings();
170
+
171
+ }
172
+
173
+ public function sync_term_order( $meta_id, $object_id, $meta_key, $meta_value ) {
174
+
175
+ // WooCommerce before termmeta table migration.
176
+ $wc_before_term_meta = get_option( 'db_version' ) < 34370;
177
+
178
+ if ( ! isset( $_POST['thetaxonomy'] ) || ! taxonomy_exists( $_POST['thetaxonomy'] ) || substr( $meta_key, 0, 5 ) !== 'order' ) {
179
+ return;
180
+ }
181
+
182
+ $tax = filter_input( INPUT_POST, 'thetaxonomy', FILTER_SANITIZE_FULL_SPECIAL_CHARS );
183
+
184
+ $term_taxonomy_id = $this->wpdb->get_var( $this->wpdb->prepare( "SELECT term_taxonomy_id FROM {$this->wpdb->term_taxonomy} WHERE term_id=%d AND taxonomy=%s", $object_id, $tax ) );
185
+ $trid = $this->sitepress->get_element_trid( $term_taxonomy_id, 'tax_' . $tax );
186
+ $translations = $this->sitepress->get_element_translations( $trid, 'tax_' . $tax );
187
+ if ( $translations ) {
188
+ foreach ( $translations as $trans ) {
189
+ if ( $trans->element_id != $term_taxonomy_id ) {
190
+
191
+ // Backwards compatibility - WooCommerce termmeta table.
192
+ if ( $wc_before_term_meta ) {
193
+ $this->wpdb->update(
194
+ $this->wpdb->prefix . 'woocommerce_termmeta',
195
+ [ 'meta_value' => $meta_value ],
196
+ [
197
+ 'woocommerce_term_id' => $trans->term_id,
198
+ 'meta_key' => $meta_key,
199
+ ]
200
+ );
201
+ // END Backwards compatibility - WooCommerce termmeta table.
202
+ } else {
203
+ update_term_meta( $trans->term_id, $meta_key, $meta_value );
204
+ }
205
+ }
206
+ }
207
+ }
208
+
209
+ }
210
+
211
+ public function translated_terms_status_update( $term_id, $tt_id, $taxonomy ) {
212
+
213
+ if ( isset( $_POST['product_cat_thumbnail_id'] ) || isset( $_POST['display_type'] ) ) {
214
+ global $sitepress_settings;
215
+
216
+ if ( $this->is_original_category( $tt_id, 'tax_' . $taxonomy ) ) {
217
+ $trid = $this->sitepress->get_element_trid( $tt_id, 'tax_' . $taxonomy );
218
+ $translations = $this->sitepress->get_element_translations( $trid, 'tax_' . $taxonomy );
219
+
220
+ foreach ( $translations as $translation ) {
221
+ if ( ! $translation->original ) {
222
+ if ( isset( $_POST['display_type'] ) ) {
223
+ update_term_meta( $translation->term_id, 'display_type', esc_attr( $_POST['display_type'] ) );
224
+ }
225
+ update_term_meta( $translation->term_id, 'thumbnail_id', apply_filters( 'translate_object_id', esc_attr( $_POST['product_cat_thumbnail_id'] ), 'attachment', true, $translation->language_code ) );
226
+ }
227
+ }
228
+ }
229
+ }
230
+
231
+ global $wp_taxonomies;
232
+ if ( in_array( 'product', $wp_taxonomies[ $taxonomy ]->object_type ) || in_array( 'product_variation', $wp_taxonomies[ $taxonomy ]->object_type ) ) {
233
+ $this->update_terms_translated_status( $taxonomy );
234
+ }
235
+
236
+ }
237
+
238
+ public function is_original_category( $tt_id, $taxonomy ) {
239
+ $is_original = $this->wpdb->get_var( $this->wpdb->prepare( "SELECT source_language_code IS NULL FROM {$this->wpdb->prefix}icl_translations WHERE element_id=%d AND element_type=%s", $tt_id, $taxonomy ) );
240
+ return $is_original ? true : false;
241
+ }
242
+
243
+ public function wcml_update_term_translated_warnings() {
244
+ $ret = [];
245
+
246
+ $taxonomy = filter_input( INPUT_POST, 'taxonomy', FILTER_SANITIZE_FULL_SPECIAL_CHARS );
247
+
248
+ $wcml_settings = $this->woocommerce_wpml->get_settings();
249
+
250
+ $attribute_taxonomies = $this->woocommerce_wpml->attributes->get_translatable_attributes();
251
+
252
+ $attribute_taxonomies_arr = [];
253
+ foreach ( $attribute_taxonomies as $a ) {
254
+ $attribute_taxonomies_arr[] = 'pa_' . $a->attribute_name;
255
+ }
256
+
257
+ $ret['is_attribute'] = intval( in_array( $taxonomy, $attribute_taxonomies_arr ) );
258
+
259
+ if ( isset( $wcml_settings['untranstaled_terms'][ $taxonomy ] ) &&
260
+ (
261
+ $wcml_settings['untranstaled_terms'][ $taxonomy ]['status'] == $this->ALL_TAXONOMY_TERMS_TRANSLATED ||
262
+ $wcml_settings['untranstaled_terms'][ $taxonomy ]['status'] == $this->NEW_TAXONOMY_IGNORED
263
+ )
264
+ ) {
265
+
266
+ $ret['hide'] = 1;
267
+ } else {
268
+
269
+ $ret['hide'] = 0;
270
+
271
+ if ( isset( $wcml_settings[ 'sync_' . $taxonomy ] ) ) {
272
+ $ret['show_button'] = $wcml_settings[ 'sync_' . $taxonomy ];
273
+ } elseif ( in_array( $taxonomy, $attribute_taxonomies_arr ) ) {
274
+ $ret['show_button'] = $wcml_settings['sync_variations'];
275
+ }
276
+ }
277
+
278
+ if ( $ret['is_attribute'] ) {
279
+ $ret['hide'] = $this->woocommerce_wpml->attributes->is_attributes_fully_translated();
280
+ }
281
+
282
+ echo json_encode( $ret );
283
+ exit;
284
+
285
+ }
286
+
287
+ public function update_terms_translated_status( $taxonomy ) {
288
+
289
+ $wcml_settings = $this->woocommerce_wpml->get_settings();
290
+ $is_translatable = 1;
291
+ $not_translated_count = 0;
292
+ $original_terms = [];
293
+
294
+ if ( isset( $wcml_settings['attributes_settings'][ $taxonomy ] ) && ! $wcml_settings['attributes_settings'][ $taxonomy ] ) {
295
+ $is_translatable = 0;
296
+ }
297
+
298
+ if ( $is_translatable ) {
299
+
300
+ $active_languages = $this->sitepress->get_active_languages();
301
+
302
+ foreach ( $active_languages as $language ) {
303
+ $terms = $this->wpdb->get_results(
304
+ $this->wpdb->prepare(
305
+ "
306
  SELECT t1.element_id AS e1, t2.element_id AS e2 FROM {$this->wpdb->term_taxonomy} x
307
  JOIN {$this->wpdb->prefix}icl_translations t1 ON x.term_taxonomy_id = t1.element_id AND t1.element_type = %s AND t1.source_language_code IS NULL
308
  LEFT JOIN {$this->wpdb->prefix}icl_translations t2 ON t2.trid = t1.trid AND t2.language_code = %s
309
+ ",
310
+ 'tax_' . $taxonomy,
311
+ $language['code']
312
+ )
313
+ );
314
+ foreach ( $terms as $term ) {
315
+ if ( empty( $term->e2 ) && ! in_array( $term->e1, $original_terms ) ) {
316
+ $original_terms[] = $term->e1;
317
+ $not_translated_count ++;
318
+ }
319
+ }
320
+ }
321
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
322
 
323
+ $status = $not_translated_count ? $this->NEW_TAXONOMY_TERMS : $this->ALL_TAXONOMY_TERMS_TRANSLATED;
324
 
325
+ if ( isset( $wcml_settings['untranstaled_terms'][ $taxonomy ] ) && $wcml_settings['untranstaled_terms'][ $taxonomy ] === $this->NEW_TAXONOMY_IGNORED ) {
326
+ $status = $this->NEW_TAXONOMY_IGNORED;
327
+ }
328
 
329
+ $wcml_settings['untranstaled_terms'][ $taxonomy ] = [
330
+ 'count' => $not_translated_count,
331
+ 'status' => $status,
332
+ ];
333
 
334
+ $this->woocommerce_wpml->update_settings( $wcml_settings );
 
335
 
336
+ return $wcml_settings['untranstaled_terms'][ $taxonomy ];
337
+
338
+ }
 
339
 
340
+ public function is_fully_translated( $taxonomy ) {
341
 
342
+ $wcml_settings = $this->woocommerce_wpml->get_settings();
343
+
344
+ $return = true;
345
+
346
+ if ( ! isset( $wcml_settings['untranstaled_terms'][ $taxonomy ] ) ) {
347
+ $wcml_settings['untranstaled_terms'][ $taxonomy ] = $this->update_terms_translated_status( $taxonomy );
348
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
349
 
350
+ if ( $wcml_settings['untranstaled_terms'][ $taxonomy ]['status'] == $this->NEW_TAXONOMY_TERMS ) {
351
+ $return = false;
352
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
353
 
354
+ return $return;
355
+ }
 
 
 
356
 
357
+ public function get_untranslated_terms_number( $taxonomy, $force_update = false ) {
 
 
 
 
358
 
359
+ $wcml_settings = $this->woocommerce_wpml->get_settings();
360
 
361
+ if ( $force_update || ! isset( $wcml_settings['untranstaled_terms'][ $taxonomy ] ) ) {
362
+ $wcml_settings['untranstaled_terms'][ $taxonomy ] = $this->update_terms_translated_status( $taxonomy );
363
+ }
364
 
365
+ return $wcml_settings['untranstaled_terms'][ $taxonomy ]['count'];
366
 
367
+ }
 
368
 
369
+ public function set_flag_for_variation_on_attribute_update( $term_id, $tt_id, $taxonomy ) {
370
 
371
+ $attribute_taxonomies = wc_get_attribute_taxonomies();
372
+ foreach ( $attribute_taxonomies as $a ) {
373
+ $attribute_taxonomies_arr[] = 'pa_' . $a->attribute_name;
374
+ }
375
 
376
+ if ( isset( $attribute_taxonomies_arr ) && in_array( $taxonomy, $attribute_taxonomies_arr ) ) {
377
 
378
+ $wcml_settings = $this->woocommerce_wpml->get_settings();
 
 
379
 
380
+ // get term language.
381
+ $term_language = $this->sitepress->get_element_language_details( $tt_id, 'tax_' . $taxonomy );
382
 
383
+ if ( isset( $term_language->language_code ) && $term_language->language_code != $this->sitepress->get_default_language() ) {
384
+ // get term in the default language.
385
+ $term_id = apply_filters( 'translate_object_id', $term_id, $taxonomy, false, $this->sitepress->get_default_language() );
386
 
387
+ // does it belong to any posts (variations).
388
+ $objects = get_objects_in_term( $term_id, $taxonomy );
 
 
 
389
 
390
+ if ( ! isset( $wcml_settings['variations_needed'][ $taxonomy ] ) ) {
391
+ $wcml_settings['variations_needed'][ $taxonomy ] = 0;
392
+ }
393
+ $wcml_settings['variations_needed'][ $taxonomy ] += count( $objects );
394
 
395
+ $this->woocommerce_wpml->update_settings( $wcml_settings );
396
 
397
+ }
398
+ }
399
 
400
+ }
 
 
401
 
402
+ public function sync_taxonomy_translations( $html, $taxonomy, $taxonomy_obj ) {
403
 
404
+ $is_wcml = is_admin() && $taxonomy && isset( $_GET['page'] ) && $_GET['page'] == 'wpml-wcml' && isset( $_GET['tab'] );
405
+ $is_ajax = is_ajax() && $taxonomy && isset( $_POST['action'] ) && $_POST['action'] === 'wpml_get_terms_and_labels_for_taxonomy_table';
 
406
 
407
+ if ( $is_wcml || $is_ajax ) {
 
408
 
409
+ $sync_tax = new WCML_Sync_Taxonomy( $this->woocommerce_wpml, $taxonomy, $taxonomy_obj );
410
+ $html = $sync_tax->get_view();
411
+ }
412
 
413
+ return $html;
414
+ }
415
 
416
+ public function wcml_sync_product_variations( $taxonomy ) {
417
+ $nonce = filter_input( INPUT_POST, 'wcml_nonce', FILTER_SANITIZE_FULL_SPECIAL_CHARS );
418
+ if ( ! $nonce || ! wp_verify_nonce( $nonce, 'wcml_sync_product_variations' ) ) {
419
+ die( 'Invalid nonce' );
420
+ }
421
 
422
+ $VARIATIONS_THRESHOLD = 20;
423
 
424
+ $wcml_settings = $this->woocommerce_wpml->get_settings();
425
+ $response = [];
 
 
426
 
427
+ $taxonomy = filter_input( INPUT_POST, 'taxonomy', FILTER_SANITIZE_FULL_SPECIAL_CHARS );
 
428
 
429
+ $languages_processed = intval( $_POST['languages_processed'] );
430
 
431
+ $condition = $languages_processed ? '>=' : '>';
432
 
433
+ $where = isset( $_POST['last_post_id'] ) && $_POST['last_post_id'] ? ' ID ' . $condition . ' ' . intval( $_POST['last_post_id'] ) . ' AND ' : '';
434
 
435
+ $post_ids = $this->wpdb->get_col(
436
+ $this->wpdb->prepare(
437
+ "
438
+ SELECT DISTINCT tr.object_id
439
+ FROM {$this->wpdb->term_relationships} tr
440
+ JOIN {$this->wpdb->term_taxonomy} tx on tr.term_taxonomy_id = tx.term_taxonomy_id
441
+ JOIN {$this->wpdb->posts} p ON tr.object_id = p.ID
442
+ JOIN {$this->wpdb->prefix}icl_translations t ON t.element_id = p.ID
443
+ WHERE {$where} tx.taxonomy = %s AND p.post_type = 'product' AND t.element_type='post_product' AND t.language_code = %s
444
+ ORDER BY ID ASC
445
+
446
+ ",
447
+ $taxonomy,
448
+ $this->sitepress->get_default_language()
449
+ )
450
+ );
451
+
452
+ if ( $post_ids ) {
453
+
454
+ $variations_processed = 0;
455
+ $posts_processed = 0;
456
+ foreach ( $post_ids as $post_id ) {
457
+ $terms = wp_get_post_terms( $post_id, $taxonomy );
458
+ $terms_count = count( $terms );
459
+
460
+ $trid = $this->sitepress->get_element_trid( $post_id, 'post_product' );
461
+ $translations = $this->sitepress->get_element_translations( $trid, 'post_product' );
462
+
463
+ $i = 1;
464
+
465
+ foreach ( $translations as $translation ) {
466
+
467
+ if ( $i > $languages_processed && $translation->element_id != $post_id ) {
468
+ $this->woocommerce_wpml->sync_product_data->sync_product_taxonomies( $post_id, $translation->element_id, $translation->language_code );
469
+ $this->woocommerce_wpml->sync_variations_data->sync_product_variations( $post_id, $translation->element_id, $translation->language_code, [ 'is_troubleshooting' => true ] );
470
+ $this->woocommerce_wpml->translation_editor->create_product_translation_package( $post_id, $trid, $translation->language_code, ICL_TM_COMPLETE );
471
+ $variations_processed += $terms_count * 2;
472
+ $response['languages_processed'] = $i;
473
+ $i++;
474
+ // check if sum of 2 iterations doesn't exceed $VARIATIONS_THRESHOLD.
475
+ if ( $variations_processed >= $VARIATIONS_THRESHOLD ) {
476
+ break;
477
+ }
478
+ } else {
479
+ $i++;
480
+ }
481
+ }
482
+ $response['last_post_id'] = $post_id;
483
+ if ( --$i == count( $translations ) ) {
484
+ $response['languages_processed'] = 0;
485
+ $languages_processed = 0;
486
+ } else {
487
+ break;
488
+ }
489
 
490
+ $posts_processed ++;
 
 
491
 
492
+ }
 
 
 
493
 
494
+ $response['go'] = 1;
 
 
 
 
 
 
495
 
496
+ } else {
 
 
497
 
498
+ $response['go'] = 0;
 
499
 
500
+ }
501
 
502
+ $response['progress'] = $response['go'] ? sprintf( __( '%d products left', 'woocommerce-multilingual' ), count( $post_ids ) - $posts_processed ) : __( 'Synchronization complete!', 'woocommerce-multilingual' );
 
 
503
 
504
+ if ( $response['go'] && isset( $wcml_settings['variations_needed'][ $taxonomy ] ) && ! empty( $variations_processed ) ) {
505
+ $wcml_settings['variations_needed'][ $taxonomy ] = max( $wcml_settings['variations_needed'][ $taxonomy ] - $variations_processed, 0 );
506
+ } else {
507
+ if ( $response['go'] == 0 ) {
508
+ $wcml_settings['variations_needed'][ $taxonomy ] = 0;
509
+ }
510
+ }
511
+ $wcml_settings['sync_variations'] = 0;
512
 
513
+ $this->woocommerce_wpml->update_settings( $wcml_settings );
514
 
515
+ echo json_encode( $response );
516
+ exit;
517
+ }
518
 
519
+ public function wcml_sync_taxonomies_in_content_preview() {
520
+ $nonce = filter_input( INPUT_POST, 'wcml_nonce', FILTER_SANITIZE_FULL_SPECIAL_CHARS );
521
+ if ( ! $nonce || ! wp_verify_nonce( $nonce, 'wcml_sync_taxonomies_in_content_preview' ) ) {
522
+ die( 'Invalid nonce' );
523
+ }
 
524
 
525
+ global $wp_taxonomies;
 
 
526
 
527
+ $html = $message = $errors = '';
 
 
528
 
529
+ if ( isset( $wp_taxonomies[ $_POST['taxonomy'] ] ) ) {
530
+ $object_types = $wp_taxonomies[ $_POST['taxonomy'] ]->object_type;
531
 
532
+ foreach ( $object_types as $object_type ) {
 
 
533
 
534
+ $html .= $this->render_assignment_status( $object_type, $_POST['taxonomy'], $preview = true );
 
535
 
536
+ }
537
+ } else {
538
+ $errors = sprintf( __( 'Invalid taxonomy %s', 'woocommerce-multilingual' ), $_POST['taxonomy'] );
539
+ }
540
 
541
+ echo json_encode(
542
+ [
543
+ 'html' => $html,
544
+ 'message' => $message,
545
+ 'errors' => $errors,
546
+ ]
547
+ );
548
+ exit;
549
+ }
550
 
551
+ public function wcml_sync_taxonomies_in_content() {
552
+ $nonce = filter_input( INPUT_POST, 'wcml_nonce', FILTER_SANITIZE_FULL_SPECIAL_CHARS );
553
+ if ( ! $nonce || ! wp_verify_nonce( $nonce, 'wcml_sync_taxonomies_in_content' ) ) {
554
+ die( 'Invalid nonce' );
555
+ }
556
+
557
+ global $wp_taxonomies;
558
+
559
+ $html = $message = $errors = '';
560
+
561
+ if ( isset( $wp_taxonomies[ $_POST['taxonomy'] ] ) ) {
562
+ $html .= $this->render_assignment_status( $_POST['post'], $_POST['taxonomy'], $preview = false );
563
 
564
+ } else {
565
+ $errors .= sprintf( __( 'Invalid taxonomy %s', 'woocommerce-multilingual' ), $_POST['taxonomy'] );
566
+ }
567
+
568
+ echo json_encode(
569
+ [
570
+ 'html' => $html,
571
+ 'errors' => $errors,
572
+ ]
573
+ );
574
+ exit;
575
+ }
576
 
577
+ public function render_assignment_status( $object_type, $taxonomy, $preview = true ) {
578
+ global $wp_post_types, $wp_taxonomies;
579
 
580
+ $default_language = $this->sitepress->get_default_language();
581
+ $is_taxonomy_translatable = $this->is_translatable_wc_taxonomy( $taxonomy );
 
582
 
583
+ $posts = $this->wpdb->get_results( $this->wpdb->prepare( "SELECT * FROM {$this->wpdb->posts} AS p LEFT JOIN {$this->wpdb->prefix}icl_translations AS tr ON tr.element_id = p.ID WHERE p.post_status = 'publish' AND p.post_type = %s AND tr.source_language_code is NULL", $object_type ) );
584
 
585
+ foreach ( $posts as $post ) {
586
 
587
+ $terms = wp_get_post_terms( $post->ID, $taxonomy );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
588
 
589
+ $term_ids = [];
590
+ foreach ( $terms as $term ) {
591
+ $term_ids[] = $term->term_id;
592
+ }
593
 
594
+ $trid = $this->sitepress->get_element_trid( $post->ID, 'post_' . $post->post_type );
595
+ $translations = $this->sitepress->get_element_translations( $trid, 'post_' . $post->post_type, true, true );
596
 
597
+ foreach ( $translations as $language => $translation ) {
598
 
599
+ if ( $language != $default_language && $translation->element_id ) {
 
600
 
601
+ $terms_of_translation = wp_get_post_terms( $translation->element_id, $taxonomy );
 
602
 
603
+ $translation_term_ids = [];
604
+ foreach ( $terms_of_translation as $term ) {
605
+
606
+ $term_id_original = apply_filters( 'translate_object_id', $term->term_id, $taxonomy, false, $default_language );
607
+ if ( ! $term_id_original || ! in_array( $term_id_original, $term_ids ) ) {
608
+ // remove term.
609
+ if ( $preview ) {
610
+ $needs_sync = true;
611
+ break( 3 );
612
+ }
613
+
614
+ $current_terms = wp_get_post_terms( $translation->element_id, $taxonomy );
615
+ $updated_terms = [];
616
+ foreach ( $current_terms as $cterm ) {
617
+ if ( $cterm->term_id != $term->term_id ) {
618
+ $updated_terms[] = $is_taxonomy_translatable ? $term->term_id : $term->name;
619
+ }
620
+ if ( ! $preview ) {
621
+
622
+ if ( $is_taxonomy_translatable && ! is_taxonomy_hierarchical( $taxonomy ) ) {
623
+ $updated_terms = array_unique( array_map( 'intval', $updated_terms ) );
624
+ }
625
+
626
+ wp_set_post_terms( $translation->element_id, $updated_terms, $taxonomy );
627
+ }
628
+ }
629
+ } else {
630
+ $translation_term_ids[] = $term_id_original;
631
+ }
632
+ }
633
+
634
+ foreach ( $term_ids as $term_id ) {
635
+
636
+ if ( ! in_array( $term_id, $translation_term_ids ) ) {
637
+ // add term.
638
+ if ( $preview ) {
639
+ $needs_sync = true;
640
+ break( 3 );
641
+ }
642
+ $terms_array = [];
643
+ $term_id_translated = apply_filters( 'translate_object_id', $term_id, $taxonomy, false, $language );
644
+
645
+ // not using get_term.
646
+ $translated_term = $this->wpdb->get_row(
647
+ $this->wpdb->prepare(
648
+ "
649
+ SELECT * FROM {$this->wpdb->terms} t JOIN {$this->wpdb->term_taxonomy} x ON x.term_id = t.term_id WHERE t.term_id = %d AND x.taxonomy = %s",
650
+ $term_id_translated,
651
+ $taxonomy
652
+ )
653
+ );
654
+
655
+ if ( $translated_term ) {
656
+ $terms_array[] = $translated_term->term_id;
657
+ }
658
+
659
+ if ( ! $preview ) {
660
+
661
+ if ( $is_taxonomy_translatable && ! is_taxonomy_hierarchical( $taxonomy ) ) {
662
+ $terms_array = array_unique( array_map( 'intval', $terms_array ) );
663
+ }
664
+
665
+ wp_set_post_terms( $translation->element_id, $terms_array, $taxonomy, true );
666
+ }
667
+ }
668
+ }
669
+ }
670
+ }
671
+ }
672
+
673
+ $wcml_settings = $this->woocommerce_wpml->get_settings();
674
+ $wcml_settings[ 'sync_' . $taxonomy ] = 0;
675
+ $this->woocommerce_wpml->update_settings( $wcml_settings );
676
+
677
+ $out = '';
678
+
679
+ if ( $preview ) {
680
+
681
+ $out .= '<div class="wcml_tt_sync_row">';
682
+ if ( ! empty( $needs_sync ) ) {
683
+ $out .= '<form class="wcml_tt_do_sync">';
684
+ $out .= '<input type="hidden" name="post" value="' . $object_type . '" />';
685
+ $out .= wp_nonce_field( 'wcml_sync_taxonomies_in_content', 'wcml_sync_taxonomies_in_content_nonce', true, false );
686
+ $out .= '<input type="hidden" name="taxonomy" value="' . $taxonomy . '" />';
687
+ $out .= sprintf(
688
+ __( 'Some translated %1$s have different %2$s assignments.', 'woocommerce-multilingual' ),
689
+ '<strong>' . mb_strtolower( $wp_post_types[ $object_type ]->labels->name ) . '</strong>',
690
+ '<strong>' . mb_strtolower( $wp_taxonomies[ $taxonomy ]->labels->name ) . '</strong>'
691
+ );
692
+ $out .= '&nbsp;<a class="submit button-secondary" href="#">' . sprintf(
693
+ __( 'Update %1$s for all translated %2$s', 'woocommerce-multilingual' ),
694
+ '<strong>' . mb_strtolower( $wp_taxonomies[ $taxonomy ]->labels->name ) . '</strong>',
695
+ '<strong>' . mb_strtolower( $wp_post_types[ $object_type ]->labels->name ) . '</strong>'
696
+ ) . '</a>' .
697
+ '&nbsp;<img src="' . ICL_PLUGIN_URL . '/res/img/ajax-loader.gif" alt="loading" height="16" width="16" class="wcml_tt_spinner" />';
698
+ $out .= '</form>';
699
+ } else {
700
+ $out .= sprintf(
701
+ __( 'All %1$s have the same %2$s assignments.', 'woocommerce-multilingual' ),
702
+ '<strong>' . mb_strtolower( $wp_taxonomies[ $taxonomy ]->labels->name ) . '</strong>',
703
+ '<strong>' . mb_strtolower( $wp_post_types[ $object_type ]->labels->name ) . '</strong>'
704
+ );
705
+ }
706
+ $out .= '</div>';
707
+
708
+ } else {
709
+
710
+ $out .= sprintf( __( 'Successfully updated %1$s for all translated %2$s.', 'woocommerce-multilingual' ), $wp_taxonomies[ $taxonomy ]->labels->name, $wp_post_types[ $object_type ]->labels->name );
711
+
712
+ }
713
+
714
+ return $out;
715
+ }
716
+
717
+ /**
718
+ * Filter shipping terms
719
+ *
720
+ * @param WP_Term[]|false|WP_Error $terms Terms to filter.
721
+ * @param int $post_id Post ID.
722
+ * @param string $taxonomy Taxonomy.
723
+ *
724
+ * @return WP_Term[]|false|WP_Error
725
+ */
726
+ public function shipping_terms( $terms, $post_id, $taxonomy ) {
727
+ global $pagenow;
728
+
729
+ if (
730
+ 'post.php' === $pagenow ||
731
+ self::PRODUCT_SHIPPING_CLASS !== $taxonomy ||
732
+ ( isset( $_POST['action'] ) && 'woocommerce_load_variations' === $_POST['action'] ) ) {
733
+ return $terms;
734
+ }
735
 
736
+ $post_type = get_post_type( $post_id );
737
+ if ( ! in_array( $post_type, [ 'product', 'product_variation' ], true ) ) {
738
+ return $terms;
739
+ }
740
 
741
+ $current_language = $this->sitepress->get_current_language();
742
+ $key = md5( wp_json_encode( [ $post_id, $current_language ] ) );
743
+ $found = false;
744
+ $terms = WPML_Non_Persistent_Cache::get( $key, __CLASS__, $found );
745
+ if ( ! $found ) {
746
+ remove_filter( 'get_the_terms', [ $this, 'shipping_terms' ], 10 );
747
+ $terms = get_the_terms(
748
+ apply_filters( 'translate_object_id', $post_id, $post_type, true, $current_language ),
749
+ self::PRODUCT_SHIPPING_CLASS
750
+ );
751
+ add_filter( 'get_the_terms', [ $this, 'shipping_terms' ], 10, 3 );
752
+ WPML_Non_Persistent_Cache::set( $key, $terms, __CLASS__ );
753
+ }
754
 
755
+ return $terms;
756
+ }
757
 
758
+ public function filter_shipping_classes_terms( $terms, $taxonomies, $args ) {
759
 
760
+ if( $taxonomies && is_admin() && in_array( self::PRODUCT_SHIPPING_CLASS, $taxonomies ) ){
761
  $on_wc_settings_page = isset( $_GET[ 'page' ] ) && $_GET[ 'page' ] === 'wc-settings';
762
  $on_shipping_tab = isset( $_GET[ 'tab' ] ) && $_GET[ 'tab' ] === 'shipping';
763
  $on_classes_section = isset( $_GET[ 'section' ] ) && $_GET[ 'section' ] === 'classes';
764
 
765
+ if ( $on_wc_settings_page && $on_shipping_tab && ! $on_classes_section ) {
766
+ remove_filter( 'get_terms', [ $this, 'filter_shipping_classes_terms' ] );
767
+ remove_filter( 'get_terms', [ 'WPML_Terms_Translations', 'get_terms_filter' ], 10, 2 );
768
+ $this->sitepress->switch_lang( $this->sitepress->get_default_language() );
769
+ $terms = get_terms( $args );
770
+ add_filter( 'get_terms', [ 'WPML_Terms_Translations', 'get_terms_filter' ], 10, 2 );
771
+ add_filter( 'get_terms', [ $this, 'filter_shipping_classes_terms' ], 10, 3 );
772
+ $this->sitepress->switch_lang();
773
+ }
774
+ }
775
 
776
+ return $terms;
777
+ }
778
 
779
+ public function wcml_delete_term( $term, $tt_id, $taxonomy, $deleted_term ) {
780
+ global $wp_taxonomies;
781
 
782
+ foreach ( $wp_taxonomies as $key => $taxonomy_obj ) {
783
+ if ( ( in_array( 'product', $taxonomy_obj->object_type ) || in_array( 'product_variation', $taxonomy_obj->object_type ) ) && $key == $taxonomy ) {
784
+ $this->update_terms_translated_status( $taxonomy );
785
+ break;
786
+ }
787
+ }
788
 
789
+ }
790
 
791
+ public function get_product_terms_filter( $terms, $product_id, $taxonomy, $args ) {
792
 
793
  $language = $this->sitepress->get_language_for_element( $product_id, 'post_' . get_post_type( $product_id ) );
794
 
795
  $is_objects_array = is_object( current( $terms ) );
796
 
797
+ $filtered_terms = [];
798
 
799
  foreach ( $terms as $term ) {
800
 
821
  if ( isset( $is_slug ) ) {
822
  $filtered_terms[] = get_term( $trnsl_term_id, $taxonomy )->slug;
823
  } else {
824
+ $filtered_terms[] = ( is_ajax() && isset( $_POST['action'] ) && in_array(
825
+ $_POST['action'],
826
+ [
827
  'woocommerce_add_variation',
828
+ 'woocommerce_link_all_variations',
829
+ ]
830
+ ) ) ? strtolower( get_term( $trnsl_term_id, $taxonomy )->name ) : get_term( $trnsl_term_id, $taxonomy )->name;
831
  }
832
  }
833
  }
835
  return $filtered_terms;
836
  }
837
 
838
+ public function set_flag_to_sync( $taxonomy, $el_id, $language_code ) {
839
  if ( $el_id ) {
840
  $elem_details = $this->sitepress->get_element_language_details( $el_id, 'tax_' . $taxonomy );
841
  if ( null !== $elem_details->source_language_code ) {
844
  }
845
  }
846
 
847
+ public function check_if_sync_terms_needed() {
848
 
849
+ $wcml_settings = $this->woocommerce_wpml->get_settings();
850
+ $wcml_settings['sync_variations'] = 0;
851
+ $wcml_settings['sync_product_cat'] = 0;
852
+ $wcml_settings['sync_product_tag'] = 0;
853
+ $wcml_settings['sync_product_shipping_class'] = 0;
854
+ $this->woocommerce_wpml->update_settings( $wcml_settings );
855
 
856
+ $taxonomies_to_check = [ 'product_cat', 'product_tag', self::PRODUCT_SHIPPING_CLASS ];
857
 
858
+ foreach ( $taxonomies_to_check as $check_taxonomy ) {
859
+ $terms = get_terms(
860
+ $check_taxonomy,
861
+ [
862
+ 'hide_empty' => false,
863
+ 'fields' => 'ids',
864
+ ]
865
+ );
866
+ if ( is_array( $terms ) ) {
867
+ foreach ( $terms as $term ) {
868
+ if ( $this->check_if_sync_term_translation_needed( $term['term_taxonomy_id'], $check_taxonomy ) ) {
869
+ break;
870
+ }
871
+ }
872
+ }
873
+ }
 
 
 
 
 
 
 
 
874
 
875
+ $attribute_taxonomies = wc_get_attribute_taxonomies();
876
+ $flag_set = false;
877
+ foreach ( $attribute_taxonomies as $a ) {
 
878
 
879
+ $terms = get_terms(
880
+ 'pa_' . $a->attribute_name,
881
+ [
882
+ 'hide_empty' => false,
883
+ 'fields' => 'ids',
884
+ ]
885
+ );
886
+ if ( is_array( $terms ) ) {
887
+ foreach ( $terms as $term ) {
888
+ $flag_set = $this->check_if_sync_term_translation_needed( $term['term_taxonomy_id'], 'pa_' . $a->attribute_name );
889
+ if ( $flag_set ) {
890
+ break;
891
+ }
892
+ }
893
+ }
894
 
895
+ if ( $flag_set ) {
896
+ break;
897
+ }
898
+ }
899
 
900
+ }
901
 
902
+ public function check_if_sync_term_translation_needed( $t_id, $taxonomy ) {
 
 
 
 
903
 
904
+ $wcml_settings = $this->woocommerce_wpml->get_settings();
 
 
905
 
906
+ $attribute_taxonomies = wc_get_attribute_taxonomies();
907
+ $attribute_taxonomies_arr = [];
908
+ foreach ( $attribute_taxonomies as $a ) {
909
+ $attribute_taxonomies_arr[] = 'pa_' . $a->attribute_name;
910
+ }
911
 
912
+ if ( ( isset( $wcml_settings[ 'sync_' . $taxonomy ] ) && $wcml_settings[ 'sync_' . $taxonomy ] ) || ( in_array( $taxonomy, $attribute_taxonomies_arr ) && isset( $wcml_settings['sync_variations'] ) && $wcml_settings['sync_variations'] ) ) {
913
+ return true;
914
+ }
 
 
 
915
 
916
+ $translations = $this->wpdb->get_results( $this->wpdb->prepare( "SELECT t2.element_id, t2.source_language_code FROM {$this->wpdb->prefix}icl_translations AS t1 LEFT JOIN {$this->wpdb->prefix}icl_translations AS t2 ON t1.trid = t2.trid WHERE t1.element_id = %d AND t1.element_type = %s ", $t_id, 'tax_' . $taxonomy ) );
917
 
918
+ foreach ( $translations as $key => $translation ) {
919
+ if ( is_null( $translation->source_language_code ) ) {
920
+ $original_count = $this->wpdb->get_var( $this->wpdb->prepare( "SELECT count( object_id ) FROM {$this->wpdb->term_relationships} WHERE term_taxonomy_id = %d ", $translation->element_id ) );
921
+ unset( $translations[ $key ] );
922
+ }
923
+ }
924
 
925
+ foreach ( $translations as $translation ) {
 
 
 
 
926
 
927
+ $count = $this->wpdb->get_var( $this->wpdb->prepare( "SELECT count( object_id ) FROM {$this->wpdb->term_relationships} WHERE term_taxonomy_id = %d ", $translation->element_id ) );
928
+ if ( $original_count != $count ) {
929
+
930
+ if ( in_array( $taxonomy, [ 'product_cat', 'product_tag', self::PRODUCT_SHIPPING_CLASS ] ) ) {
931
+ $wcml_settings[ 'sync_'.$taxonomy ] = 1;
932
  $this->woocommerce_wpml->update_settings($wcml_settings);
933
  return true;
934
  }
935
 
936
+ if ( isset( $attribute_taxonomies_arr ) && in_array( $taxonomy, $attribute_taxonomies_arr ) ) {
937
+ $wcml_settings['sync_variations'] = 1;
938
+ $this->woocommerce_wpml->update_settings( $wcml_settings );
939
+ return true;
940
+ }
941
+ }
942
+ }
943
 
944
+ }
945
 
946
+ public function get_table_taxonomies( $taxonomies ) {
947
 
948
+ foreach ( $taxonomies as $key => $taxonomy ) {
949
+ if ( substr( $key, 0, 3 ) !== 'pa_' ) {
950
+ unset( $taxonomies[ $key ] );
951
+ }
952
+ }
953
 
954
+ return $taxonomies;
955
+ }
956
 
957
+ public function get_wc_taxonomies() {
958
 
959
+ global $wp_taxonomies;
960
+ $taxonomies = [];
961
 
962
+ // don't use get_taxonomies for product, because when one more post type registered for product taxonomy functions returned taxonomies only for product type.
963
+ foreach ( $wp_taxonomies as $key => $taxonomy ) {
964
 
965
+ if (
966
+ ( in_array( 'product', $taxonomy->object_type ) || in_array( 'product_variation', $taxonomy->object_type ) ) &&
967
+ ! in_array( $key, $taxonomies )
968
+ ) {
969
 
970
+ if ( substr( $key, 0, 3 ) == 'pa_' && ! $this->woocommerce_wpml->attributes->is_translatable_attribute( $key ) ) {
971
+ continue;
972
+ }
973
 
974
+ $taxonomies[] = $key;
975
+ }
976
+ }
977
 
978
+ return $taxonomies;
979
 
980
+ }
981
 
982
+ public function has_wc_taxonomies_to_translate() {
983
 
984
+ $taxonomies = $this->get_wc_taxonomies();
985
 
986
+ $no_tax_to_trnls = false;
987
+ foreach ( $taxonomies as $taxonomy ) {
988
 
989
+ $is_fully_translated = 0 === $this->get_untranslated_terms_number( $taxonomy );
990
+ if (
991
+ ! $this->is_translatable_wc_taxonomy( $taxonomy ) ||
992
+ $is_fully_translated
993
+ ) {
994
+ continue;
995
+ } else {
996
+ $no_tax_to_trnls = true;
997
+ }
998
+ }
999
 
1000
+ return $no_tax_to_trnls;
1001
 
1002
+ }
1003
 
1004
+ /*
1005
+ * Use custom query, because get_term_by function return false for terms with "0" slug *
1006
+ */
1007
+ public function wcml_get_term_id_by_slug( $taxonomy, $slug ) {
1008
 
1009
+ return $this->wpdb->get_var(
1010
+ $this->wpdb->prepare(
1011
+ "SELECT tt.term_id FROM {$this->wpdb->terms} AS t
1012
  INNER JOIN {$this->wpdb->term_taxonomy} AS tt
1013
  ON t.term_id = tt.term_id
1014
  WHERE tt.taxonomy = %s AND t.slug = %s LIMIT 1",
1015
+ $taxonomy,
1016
+ sanitize_title( $slug )
1017
+ )
1018
+ );
1019
+ }
1020
 
1021
+ public function wcml_get_term_by_id( $term_id, $taxonomy ) {
1022
 
1023
+ return $this->wpdb->get_row(
1024
+ $this->wpdb->prepare(
1025
+ "
1026
  SELECT * FROM {$this->wpdb->terms} t
1027
  JOIN {$this->wpdb->term_taxonomy} x
1028
  ON x.term_id = t.term_id
1029
  WHERE t.term_id = %d AND x.taxonomy = %s",
1030
+ $term_id,
1031
+ $taxonomy
1032
+ )
1033
+ );
1034
+ }
1035
 
1036
+ public function wcml_get_translated_term( $term_id, $taxonomy, $language ) {
1037
 
1038
+ $tr_id = apply_filters( 'translate_object_id', $term_id, $taxonomy, false, $language );
1039
 
1040
+ if ( ! is_null( $tr_id ) ) {
1041
+ $term_id = $tr_id;
1042
+ }
1043
 
1044
+ return $this->wcml_get_term_by_id( $term_id, $taxonomy );
1045
+ }
1046
 
1047
  public function is_translatable_wc_taxonomy( $taxonomy ) {
1048
+ if ( in_array( $taxonomy, [ 'product_type', 'product_visibility' ], true ) ) {
1049
  return false;
1050
  }
1051
 
1052
  return true;
1053
  }
1054
 
1055
+ public function pre_option_default_product_cat() {
1056
 
1057
  $lang = $this->sitepress->get_current_language();
1058
 
1072
  );
1073
  }
1074
 
1075
+ public function update_option_default_product_cat( $oldvalue, $new_value ) {
1076
  $new_value = $this->wpdb->get_var( $this->wpdb->prepare( "SELECT term_taxonomy_id FROM {$this->wpdb->term_taxonomy} WHERE taxonomy='product_cat' AND term_id=%d", $new_value ) );
1077
  $translations = $this->sitepress->get_element_translations( $this->sitepress->get_element_trid( $new_value, 'tax_product_cat' ) );
1078
  $wcml_settings = $this->woocommerce_wpml->get_settings();
1090
  public function update_category_count_meta( $meta_id, $object_id, $meta_key, $meta_value ) {
1091
 
1092
  if ( 'product_count_product_cat' === $meta_key ) {
1093
+ remove_action( 'update_term_meta', [ $this, 'update_category_count_meta' ], 10, 4 );
1094
 
1095
  $trid = $this->sitepress->get_element_trid( $object_id, 'tax_product_cat' );
1096
  $translations = $this->sitepress->get_element_translations( $trid, 'tax_product_cat' );
1101
  }
1102
  }
1103
 
1104
+ add_action( 'update_term_meta', [ $this, 'update_category_count_meta' ], 10, 4 );
1105
  }
1106
  }
1107
 
1110
  *
1111
  * @return string
1112
  */
1113
+ public function add_lang_parameter_to_cache_key( $key ) {
1114
+ return $key . '-' . $this->sitepress->get_current_language();
1115
  }
1116
 
1117
  }
inc/class-wcml-tp-support.php CHANGED
@@ -42,8 +42,10 @@ class WCML_TP_Support {
42
  add_filter( 'wpml_tm_translation_job_data', array( $this, 'append_slug_to_translation_package' ), 10, 2 );
43
  add_action( 'wpml_translation_job_saved', array( $this, 'save_slug_translations' ), 10, 2 );
44
 
45
- add_filter( 'wpml_tm_translation_job_data', array( $this, 'append_images_to_translation_package' ), 10, 2 );
46
- add_action( 'wpml_translation_job_saved', array( $this, 'save_images_translations' ), 10, 3 );
 
 
47
  }
48
 
49
  public function append_custom_attributes_to_translation_package( $package, $post ) {
42
  add_filter( 'wpml_tm_translation_job_data', array( $this, 'append_slug_to_translation_package' ), 10, 2 );
43
  add_action( 'wpml_translation_job_saved', array( $this, 'save_slug_translations' ), 10, 2 );
44
 
45
+ if ( ! defined( 'WPML_MEDIA_VERSION' ) ) {
46
+ add_filter( 'wpml_tm_translation_job_data', array( $this, 'append_images_to_translation_package' ), 10, 2 );
47
+ add_action( 'wpml_translation_job_saved', array( $this, 'save_images_translations' ), 10, 3 );
48
+ }
49
  }
50
 
51
  public function append_custom_attributes_to_translation_package( $package, $post ) {
inc/class-wcml-troubleshooting.php CHANGED
@@ -1,12 +1,12 @@
1
  <?php
2
 
3
- class WCML_Troubleshooting{
4
 
5
  const ITEMS_PER_AJAX = 5;
6
 
7
- private $woocommerce_wpml;
8
- private $sitepress;
9
- private $wpdb;
10
 
11
  /**
12
  * WCML_Troubleshooting constructor.
@@ -24,309 +24,314 @@ class WCML_Troubleshooting{
24
  add_action( 'init', [ $this, 'init' ] );
25
  }
26
 
27
- function init() {
28
- add_action('wp_ajax_trbl_sync_variations', array($this,'trbl_sync_variations'));
29
- add_action('wp_ajax_trbl_gallery_images', array($this,'trbl_gallery_images'));
30
- add_action('wp_ajax_trbl_update_count', array($this,'trbl_update_count'));
31
- add_action('wp_ajax_trbl_sync_categories', array($this,'trbl_sync_categories'));
32
- add_action('wp_ajax_trbl_duplicate_terms', array($this,'trbl_duplicate_terms'));
33
- add_action('wp_ajax_trbl_fix_product_type_terms', array($this,'trbl_fix_product_type_terms'));
34
- add_action( 'wp_ajax_trbl_sync_stock', array( $this, 'trbl_sync_stock' ) );
35
- add_action( 'wp_ajax_fix_translated_variations_relationships', array( $this, 'fix_translated_variations_relationships' ) );
36
- add_action( 'wp_ajax_sync_deleted_meta', array( $this, 'sync_deleted_meta' ) );
37
- }
38
 
39
- function wcml_count_products_with_variations(){
40
- return count(get_option('wcml_products_to_sync'));
41
- }
42
 
43
- function trbl_update_count(){
44
 
45
- $nonce = filter_input( INPUT_POST, 'wcml_nonce', FILTER_SANITIZE_FULL_SPECIAL_CHARS );
46
- if(!$nonce || !wp_verify_nonce($nonce, 'trbl_update_count')){
47
- wp_send_json_error('Invalid nonce');
48
- }
49
 
50
- $this->wcml_sync_variations_update_option();
51
 
52
- $result = array(
53
- 'count' => $this->wcml_count_products_with_variations()
54
- );
55
 
56
- wp_send_json_success( $result );
57
- }
58
 
59
- function wcml_sync_variations_update_option(){
60
-
61
- $get_variation_term_taxonomy_ids = $this->wpdb->get_var("SELECT tt.term_taxonomy_id FROM {$this->wpdb->terms} AS t LEFT JOIN {$this->wpdb->term_taxonomy} AS tt ON t.term_id = tt.term_id WHERE t.name = 'variable'");
62
- $get_variation_term_taxonomy_ids = apply_filters('wcml_variation_term_taxonomy_ids',(array)$get_variation_term_taxonomy_ids);
63
 
64
- $get_variables_products = $this->wpdb->get_results($this->wpdb->prepare("SELECT tr.element_id as id,tr.language_code as lang FROM {$this->wpdb->prefix}icl_translations AS tr LEFT JOIN {$this->wpdb->term_relationships} as t ON tr.element_id = t.object_id LEFT JOIN {$this->wpdb->posts} AS p ON tr.element_id = p.ID
65
- WHERE p.post_status = 'publish' AND tr.source_language_code is NULL AND tr.element_type = 'post_product' AND t.term_taxonomy_id IN (%s) ORDER BY tr.element_id",join(',',$get_variation_term_taxonomy_ids)),ARRAY_A);
66
 
67
- update_option('wcml_products_to_sync',$get_variables_products);
68
- }
 
 
 
 
 
 
69
 
70
- function wcml_count_products(){
71
-
72
- $get_products_count = $this->wpdb->get_var("SELECT count(ID) FROM {$this->wpdb->posts} AS p LEFT JOIN {$this->wpdb->prefix}icl_translations AS tr ON tr.element_id = p.ID WHERE p.post_status = 'publish' AND p.post_type = 'product' AND tr.source_language_code is NULL");
73
- return $get_products_count;
74
- }
75
 
76
- function wcml_count_products_for_gallery_sync(){
77
- $all_products = $this->get_products_needs_gallery_sync( false );
78
 
79
- return count($all_products);
80
- }
 
81
 
82
- function wcml_count_product_categories(){
 
83
 
84
- $get_product_categories = $this->get_product_categories_needs_sync( );
 
85
 
86
- return count($get_product_categories);
87
- }
88
 
 
89
 
90
- function trbl_sync_variations(){
 
91
 
92
- $nonce = filter_input( INPUT_POST, 'wcml_nonce', FILTER_SANITIZE_FULL_SPECIAL_CHARS );
93
- if(!$nonce || !wp_verify_nonce($nonce, 'trbl_sync_variations')){
94
- wp_send_json_error('Invalid nonce');
95
- }
96
 
97
- $get_variables_products = get_option('wcml_products_to_sync');
98
- $all_active_lang = $this->sitepress->get_active_languages();
99
- $unset_keys = array();
100
- $products_for_one_ajax = array_slice($get_variables_products,0,3,true);
101
 
 
 
 
 
102
 
103
- foreach ($products_for_one_ajax as $key => $product){
104
- foreach($all_active_lang as $language){
105
- if($language['code'] != $product['lang']){
106
- $tr_product_id = apply_filters( 'translate_object_id',$product['id'],'product',false,$language['code']);
107
 
108
- if(!is_null($tr_product_id)){
109
- $this->woocommerce_wpml->sync_variations_data->sync_product_variations( $product['id'], $tr_product_id, $language['code'], [ 'is_troubleshooting' => true ] );
110
- }
111
- if(!in_array($key,$unset_keys)){
112
- $unset_keys[] = $key;
113
- }
114
- }
115
- }
116
- }
117
 
 
 
 
 
 
 
 
 
 
118
 
119
- foreach($unset_keys as $unset_key){
120
- unset($get_variables_products[$unset_key]);
121
- }
122
 
123
- update_option('wcml_products_to_sync',$get_variables_products);
124
 
125
- $wcml_settings = get_option('_wcml_settings');
126
- if(isset($wcml_settings['notifications']) && isset($wcml_settings['notifications']['varimages'])){
127
- $wcml_settings['notifications']['varimages']['show'] = 0;
128
- update_option('_wcml_settings', $wcml_settings);
129
- }
130
 
131
- wp_send_json_success();
132
- }
133
 
134
- function trbl_gallery_images(){
135
  $nonce = filter_input( INPUT_POST, 'wcml_nonce', FILTER_SANITIZE_FULL_SPECIAL_CHARS );
136
- if(!$nonce || !wp_verify_nonce($nonce, 'trbl_gallery_images')){
137
- wp_send_json_error('Invalid nonce');
138
  }
139
 
140
  $all_products = $this->get_products_needs_gallery_sync( true );
141
 
142
- foreach( $all_products as $product ){
143
- $this->woocommerce_wpml->media->sync_product_gallery($product->ID);
144
- add_post_meta($product->ID,'gallery_sync',true);
145
  }
146
 
147
  wp_send_json_success();
148
 
149
  }
150
 
151
- function get_products_needs_gallery_sync( $limit = false ){
152
 
153
- $sql = "SELECT p.ID FROM {$this->wpdb->posts} AS p
154
  LEFT JOIN {$this->wpdb->prefix}icl_translations AS tr
155
  ON tr.element_id = p.ID
156
  WHERE p.post_status = 'publish' AND p.post_type = 'product' AND tr.source_language_code is NULL
157
  AND ( SELECT COUNT( pm.meta_key ) FROM {$this->wpdb->postmeta} AS pm WHERE pm.post_id = p.ID AND pm.meta_key = 'gallery_sync' ) = 0 ";
158
 
159
- if( $limit ){
160
- $sql .= "ORDER BY p.ID LIMIT ".self::ITEMS_PER_AJAX;
161
- }
162
-
163
- $all_products = $this->wpdb->get_results( $sql );
164
 
165
- return $all_products;
166
- }
167
 
168
- function trbl_sync_categories(){
169
- $nonce = filter_input( INPUT_POST, 'wcml_nonce', FILTER_SANITIZE_FULL_SPECIAL_CHARS );
170
- if(!$nonce || !wp_verify_nonce($nonce, 'trbl_sync_categories')){
171
- wp_send_json_error('Invalid nonce');
172
- }
173
 
174
- $all_categories = $this->get_product_categories_needs_sync( true );
 
 
 
 
175
 
176
- foreach($all_categories as $category){
177
- add_option('wcml_sync_category_'.$category->term_taxonomy_id,true);
178
- $trid = $this->sitepress->get_element_trid($category->term_taxonomy_id,'tax_product_cat');
179
- $translations = $this->sitepress->get_element_translations($trid,'tax_product_cat');
180
- $type = get_term_meta( $category->term_id, 'display_type',true );
181
- $thumbnail_id = get_term_meta( $category->term_id, 'thumbnail_id',true );
182
- foreach($translations as $translation){
183
- if($translation->language_code != $category->language_code ){
184
- update_term_meta( $translation->term_id, 'display_type', $type );
185
- update_term_meta( $translation->term_id, 'thumbnail_id', apply_filters( 'translate_object_id', $thumbnail_id, 'attachment', true, $translation->language_code ) );
186
- }
187
- }
188
- }
 
 
189
 
190
- wp_send_json_success();
191
 
192
- }
193
 
194
 
195
- function get_product_categories_needs_sync( $limit = false ){
196
 
197
- $sql = "SELECT t.term_taxonomy_id,t.term_id,tr.language_code FROM {$this->wpdb->term_taxonomy} AS t
198
  LEFT JOIN {$this->wpdb->prefix}icl_translations AS tr
199
  ON tr.element_id = t.term_taxonomy_id
200
  WHERE t.taxonomy = 'product_cat' AND tr.element_type = 'tax_product_cat' AND tr.source_language_code is NULL
201
  AND ( SELECT COUNT( option_id ) FROM {$this->wpdb->options} WHERE option_name = CONCAT( 'wcml_sync_category_',t.term_taxonomy_id ) ) = 0 ";
202
 
203
- if( $limit ){
204
- $sql .= "ORDER BY t.term_taxonomy_id LIMIT ".self::ITEMS_PER_AJAX;
205
- }
206
-
207
- $all_categories = $this->wpdb->get_results( $sql );
208
 
209
- return $all_categories;
210
- }
211
 
 
 
212
 
213
- function trbl_duplicate_terms(){
214
- $nonce = filter_input( INPUT_POST, 'wcml_nonce', FILTER_SANITIZE_FULL_SPECIAL_CHARS );
215
- if(!$nonce || !wp_verify_nonce($nonce, 'trbl_duplicate_terms')){
216
- wp_send_json_error('Invalid nonce');
217
- }
218
 
219
- $attr = isset($_POST['attr'])?$_POST['attr']:false;
 
 
 
 
220
 
221
- if ( $attr ) {
222
- $terms = get_terms( $attr, 'hide_empty=0' );
223
- $i = 0;
224
- $languages = $this->sitepress->get_active_languages();
225
- foreach ( $terms as $term ) {
226
- foreach ( $languages as $language ) {
227
- $tr_id = apply_filters( 'translate_object_id', $term->term_id, $attr, false, $language['code'] );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
228
 
229
- if ( is_null( $tr_id ) ) {
230
- $term_args = array();
231
- // hierarchy - parents
232
- if ( is_taxonomy_hierarchical( $attr ) ) {
233
- // fix hierarchy
234
- if ( $term->parent ) {
235
- $original_parent_translated = apply_filters( 'translate_object_id', $term->parent, $attr, false, $language['code'] );
236
- if ( $original_parent_translated ) {
237
- $term_args['parent'] = $original_parent_translated;
238
- }
239
- }
240
- }
241
 
242
- $term_name = $term->name;
243
- $slug = $term->name . '-' . $language['code'];
244
- $slug = WPML_Terms_Translations::term_unique_slug( $slug, $attr, $language['code'] );
245
- $term_args['slug'] = $slug;
 
 
 
 
 
246
 
247
- $new_term = wp_insert_term( $term_name, $attr, $term_args );
248
- if ( $new_term && ! is_wp_error( $new_term ) ) {
249
- $tt_id = $this->sitepress->get_element_trid( $term->term_taxonomy_id, 'tax_' . $attr );
250
- $this->sitepress->set_element_language_details( $new_term['term_taxonomy_id'], 'tax_' . $attr, $tt_id, $language['code'] );
251
- }
252
- }
253
- }
254
 
255
- }
256
- }
 
 
 
257
 
258
- wp_send_json_success();
259
- }
260
 
261
- function trbl_fix_product_type_terms(){
262
- $nonce = filter_input( INPUT_POST, 'wcml_nonce', FILTER_SANITIZE_FULL_SPECIAL_CHARS );
263
- if(!$nonce || !wp_verify_nonce($nonce, 'trbl_product_type_terms')){
264
- wp_send_json_error('Invalid nonce');
265
- }
266
 
267
- WCML_Install::check_product_type_terms();
268
 
269
- wp_send_json_success();
270
- }
271
 
272
- function wcml_count_products_and_variations(){
 
273
 
274
- $results = $this->get_original_products_and_variations();
275
 
276
- return count( $results );
277
- }
 
 
278
 
279
- function trbl_sync_stock(){
280
 
281
- $nonce = array_key_exists( 'wcml_nonce', $_POST ) ? sanitize_text_field( $_POST[ 'wcml_nonce' ] ) : false;
282
- if(!$nonce || !wp_verify_nonce($nonce, 'trbl_sync_stock')){
283
- wp_send_json_error('Invalid nonce');
284
- }
285
 
286
- $results = $this->get_original_products_and_variations();
287
 
288
- foreach( $results as $product ){
289
 
290
- if( get_post_meta( $product->ID, '_manage_stock', true ) === 'yes' ){
 
291
 
292
- $translations = $this->sitepress->get_element_translations( $product->trid, $product->element_type );
 
 
 
 
 
 
 
293
 
294
- $min_stock = false;
295
- $stock_status = 'instock';
 
 
 
 
 
296
 
297
- //collect min stock
298
- foreach( $translations as $translation ){
299
- $stock = get_post_meta( $translation->element_id, '_stock', true );
300
- if( !$min_stock || $stock < $min_stock ){
301
- $min_stock = $stock;
302
- $stock_status = get_post_meta( $translation->element_id, '_stock_status', true );
303
- }
304
- }
305
 
306
- //update stock value
307
- foreach( $translations as $translation ){
308
- update_post_meta( $translation->element_id, '_stock', $min_stock );
309
- update_post_meta( $translation->element_id, '_stock_status', $stock_status );
310
- }
311
- }
312
- }
313
-
314
- wp_send_json_success();
315
- }
316
-
317
- function get_original_products_and_variations(){
318
 
319
- $results = $this->wpdb->get_results("
 
320
  SELECT p.ID, t.trid, t.element_type
321
  FROM {$this->wpdb->posts} p
322
  JOIN {$this->wpdb->prefix}icl_translations t ON t.element_id = p.ID AND t.element_type IN ('post_product', 'post_product_variation')
323
  WHERE p.post_type in ('product', 'product_variation') AND t.source_language_code IS NULL
324
- ");
 
325
 
326
  return $results;
327
  }
328
 
329
- public function fix_translated_variations_relationships(){
330
 
331
  $nonce = array_key_exists( 'wcml_nonce', $_POST ) ? sanitize_text_field( $_POST['wcml_nonce'] ) : false;
332
  if ( ! $nonce || ! wp_verify_nonce( $nonce, 'fix_relationships' ) ) {
@@ -339,12 +344,12 @@ class WCML_Troubleshooting{
339
 
340
  $translated_variations = get_option( 'wcml_trbl_translated_variations' );
341
 
342
- if( !$translated_variations ){
343
  $translated_variations = $this->get_products_variations_needs_fix_relationships();
344
  }
345
 
346
  foreach ( array_slice( $translated_variations, 0, self::ITEMS_PER_AJAX, true ) as $key => $translated_variation ) {
347
- //check relationships
348
  $tr_info_for_original_variation = $this->get_translation_info_for_element( $translated_variation->meta_value, 'post_product_variation' );
349
 
350
  $language = $this->sitepress->get_language_for_element( wp_get_post_parent_id( $translated_variation->meta_value ), 'post_product' );
@@ -353,41 +358,44 @@ class WCML_Troubleshooting{
353
 
354
  $tr_info_for_current_variation = $this->get_translation_info_for_element( $translated_variation->post_id, 'post_product_variation' );
355
 
356
- //delete wrong element_type for exists variations
357
  if ( ! $tr_info_for_current_variation ) {
358
  $tr_info_for_current_variation = $this->get_translation_info_for_element( $translated_variation->post_id, 'post_product' );
359
  if ( $tr_info_for_current_variation ) {
360
- $this->wpdb->update( $this->wpdb->prefix . 'icl_translations', array( 'element_type' => 'post_product_variation' ), array( 'translation_id' => $tr_info_for_current_variation->translation_id ) );
361
  }
362
  }
363
 
364
  $check_duplicated_post_type = $this->get_translation_info_for_element( $translated_variation->post_id, 'post_product' );
365
  if ( $check_duplicated_post_type ) {
366
- $this->wpdb->delete( $this->wpdb->prefix . 'icl_translations', array( 'translation_id' => $check_duplicated_post_type->translation_id ) );
367
  }
368
 
369
-
370
- //set language info for variation if not exists
371
  if ( ! $tr_info_for_original_variation ) {
372
 
373
- $tr_info_for_original_variation = $this->get_translation_info_for_element( $translated_variation->meta_value, 'post_product' );
374
  if ( $tr_info_for_original_variation ) {
375
- $this->wpdb->update( $this->wpdb->prefix . 'icl_translations', array( 'element_type' => 'post_product_variation' ), array( 'translation_id' => $tr_info_for_original_variation->translation_id ) );
376
  } else {
377
  $this->sitepress->set_element_language_details( $translated_variation->meta_value, 'post_product_variation', $tr_info_for_current_variation->trid, $language );
378
- $tr_info_for_original_variation = $this->get_translation_info_for_element( $translated_variation->meta_value, 'post_product' );
379
  }
380
 
381
- $this->wpdb->update( $this->wpdb->prefix . 'icl_translations', array( 'source_language_code' => $language ), array( 'translation_id' => $tr_info_for_current_variation->translation_id ) );
382
  }
383
 
384
  if ( $tr_info_for_original_variation->trid != $tr_info_for_current_variation->trid ) {
385
 
386
- $this->wpdb->update( $this->wpdb->prefix . 'icl_translations', array(
387
- 'trid' => $tr_info_for_original_variation->trid,
388
- 'language_code' => $language_current,
389
- 'source_language_code' => $language
390
- ), array( 'translation_id' => $tr_info_for_current_variation->translation_id ) );
 
 
 
 
391
 
392
  }
393
 
@@ -396,32 +404,32 @@ class WCML_Troubleshooting{
396
 
397
  update_option( 'wcml_trbl_translated_variations', $translated_variations );
398
 
399
- wp_send_json_success();
400
- }
401
 
402
  /**
403
- * @param int $element_id
404
  * @param string $element_type
405
  *
406
  * @return object|null
407
  */
408
- private function get_translation_info_for_element( $element_id, $element_type ){
409
- return $this->wpdb->get_row( $this->wpdb->prepare( "SELECT trid, translation_id FROM {$this->wpdb->prefix}icl_translations WHERE element_id = %d AND element_type = %s", $element_id, $element_type ) );
410
- }
411
 
412
- private function get_products_variations_needs_fix_relationships(){
413
- return $this->wpdb->get_results( "SELECT post_id, meta_value FROM {$this->wpdb->postmeta} WHERE meta_key ='_wcml_duplicate_of_variation'" );
414
- }
415
 
416
- public function wcml_count_product_fix_relationships(){
417
 
418
- $results = $this->get_products_variations_needs_fix_relationships();
419
 
420
- return count( $results );
421
- }
422
 
423
 
424
- public function sync_deleted_meta(){
425
 
426
  $nonce = array_key_exists( 'wcml_nonce', $_POST ) ? sanitize_text_field( $_POST['wcml_nonce'] ) : false;
427
  if ( ! $nonce || ! wp_verify_nonce( $nonce, 'sync_deleted_meta' ) ) {
@@ -434,24 +442,24 @@ class WCML_Troubleshooting{
434
 
435
  $products_needs_fix_postmeta = get_option( 'wcml_trbl_products_needs_fix_postmeta' );
436
 
437
- if( !$products_needs_fix_postmeta ){
438
  $products_needs_fix_postmeta = $this->get_original_products_and_variations();
439
  }
440
 
441
  $iclTranslationManagement = wpml_load_core_tm();
442
- $settings_factory = new WPML_Custom_Field_Setting_Factory( $iclTranslationManagement );
443
 
444
  foreach ( array_slice( $products_needs_fix_postmeta, 0, self::ITEMS_PER_AJAX, true ) as $key => $product ) {
445
 
446
  $translations = $this->sitepress->get_element_translations( $product->trid, $product->element_type );
447
 
448
- foreach ( $translations as $translation ){
449
- if( !$translation->original ){
450
  $all_post_meta_keys = $this->wpdb->get_col( $this->wpdb->prepare( "SELECT meta_key FROM {$this->wpdb->postmeta} WHERE post_id = %d", $translation->element_id ) );
451
- foreach( $all_post_meta_keys as $meta_key ){
452
  $setting = $settings_factory->post_meta_setting( $meta_key );
453
  if ( WPML_COPY_CUSTOM_FIELD === $setting->status() ) {
454
- if( !metadata_exists('post', $product->ID, $meta_key) ){
455
  delete_post_meta( $translation->element_id, $meta_key );
456
  }
457
  }
@@ -467,4 +475,4 @@ class WCML_Troubleshooting{
467
  wp_send_json_success();
468
  }
469
 
470
- }
1
  <?php
2
 
3
+ class WCML_Troubleshooting {
4
 
5
  const ITEMS_PER_AJAX = 5;
6
 
7
+ private $woocommerce_wpml;
8
+ private $sitepress;
9
+ private $wpdb;
10
 
11
  /**
12
  * WCML_Troubleshooting constructor.
24
  add_action( 'init', [ $this, 'init' ] );
25
  }
26
 
27
+ public function init() {
28
+ add_action( 'wp_ajax_trbl_sync_variations', [ $this, 'trbl_sync_variations' ] );
29
+ add_action( 'wp_ajax_trbl_gallery_images', [ $this, 'trbl_gallery_images' ] );
30
+ add_action( 'wp_ajax_trbl_update_count', [ $this, 'trbl_update_count' ] );
31
+ add_action( 'wp_ajax_trbl_sync_categories', [ $this, 'trbl_sync_categories' ] );
32
+ add_action( 'wp_ajax_trbl_duplicate_terms', [ $this, 'trbl_duplicate_terms' ] );
33
+ add_action( 'wp_ajax_trbl_fix_product_type_terms', [ $this, 'trbl_fix_product_type_terms' ] );
34
+ add_action( 'wp_ajax_trbl_sync_stock', [ $this, 'trbl_sync_stock' ] );
35
+ add_action( 'wp_ajax_fix_translated_variations_relationships', [ $this, 'fix_translated_variations_relationships' ] );
36
+ add_action( 'wp_ajax_sync_deleted_meta', [ $this, 'sync_deleted_meta' ] );
37
+ }
38
 
39
+ public function wcml_count_products_with_variations() {
40
+ return count( get_option( 'wcml_products_to_sync' ) );
41
+ }
42
 
43
+ public function trbl_update_count() {
44
 
45
+ $nonce = filter_input( INPUT_POST, 'wcml_nonce', FILTER_SANITIZE_FULL_SPECIAL_CHARS );
46
+ if ( ! $nonce || ! wp_verify_nonce( $nonce, 'trbl_update_count' ) ) {
47
+ wp_send_json_error( 'Invalid nonce' );
48
+ }
49
 
50
+ $this->wcml_sync_variations_update_option();
51
 
52
+ $result = [
53
+ 'count' => $this->wcml_count_products_with_variations(),
54
+ ];
55
 
56
+ wp_send_json_success( $result );
57
+ }
58
 
59
+ public function wcml_sync_variations_update_option() {
 
 
 
60
 
61
+ $get_variation_term_taxonomy_ids = $this->wpdb->get_var( "SELECT tt.term_taxonomy_id FROM {$this->wpdb->terms} AS t LEFT JOIN {$this->wpdb->term_taxonomy} AS tt ON t.term_id = tt.term_id WHERE t.name = 'variable'" );
62
+ $get_variation_term_taxonomy_ids = apply_filters( 'wcml_variation_term_taxonomy_ids', (array) $get_variation_term_taxonomy_ids );
63
 
64
+ $get_variables_products = $this->wpdb->get_results(
65
+ $this->wpdb->prepare(
66
+ "SELECT tr.element_id as id,tr.language_code as lang FROM {$this->wpdb->prefix}icl_translations AS tr LEFT JOIN {$this->wpdb->term_relationships} as t ON tr.element_id = t.object_id LEFT JOIN {$this->wpdb->posts} AS p ON tr.element_id = p.ID
67
+ WHERE p.post_status = 'publish' AND tr.source_language_code is NULL AND tr.element_type = 'post_product' AND t.term_taxonomy_id IN (%s) ORDER BY tr.element_id",
68
+ join( ',', $get_variation_term_taxonomy_ids )
69
+ ),
70
+ ARRAY_A
71
+ );
72
 
73
+ update_option( 'wcml_products_to_sync', $get_variables_products );
74
+ }
 
 
 
75
 
76
+ public function wcml_count_products() {
 
77
 
78
+ $get_products_count = $this->wpdb->get_var( "SELECT count(ID) FROM {$this->wpdb->posts} AS p LEFT JOIN {$this->wpdb->prefix}icl_translations AS tr ON tr.element_id = p.ID WHERE p.post_status = 'publish' AND p.post_type = 'product' AND tr.source_language_code is NULL" );
79
+ return $get_products_count;
80
+ }
81
 
82
+ public function wcml_count_products_for_gallery_sync() {
83
+ $all_products = $this->get_products_needs_gallery_sync( false );
84
 
85
+ return count( $all_products );
86
+ }
87
 
88
+ public function wcml_count_product_categories() {
 
89
 
90
+ $get_product_categories = $this->get_product_categories_needs_sync();
91
 
92
+ return count( $get_product_categories );
93
+ }
94
 
 
 
 
 
95
 
96
+ public function trbl_sync_variations() {
 
 
 
97
 
98
+ $nonce = filter_input( INPUT_POST, 'wcml_nonce', FILTER_SANITIZE_FULL_SPECIAL_CHARS );
99
+ if ( ! $nonce || ! wp_verify_nonce( $nonce, 'trbl_sync_variations' ) ) {
100
+ wp_send_json_error( 'Invalid nonce' );
101
+ }
102
 
103
+ $get_variables_products = get_option( 'wcml_products_to_sync' );
104
+ $all_active_lang = $this->sitepress->get_active_languages();
105
+ $unset_keys = [];
106
+ $products_for_one_ajax = array_slice( $get_variables_products, 0, 3, true );
107
 
108
+ foreach ( $products_for_one_ajax as $key => $product ) {
109
+ foreach ( $all_active_lang as $language ) {
110
+ if ( $language['code'] != $product['lang'] ) {
111
+ $tr_product_id = apply_filters( 'translate_object_id', $product['id'], 'product', false, $language['code'] );
 
 
 
 
 
112
 
113
+ if ( ! is_null( $tr_product_id ) ) {
114
+ $this->woocommerce_wpml->sync_variations_data->sync_product_variations( $product['id'], $tr_product_id, $language['code'], [ 'is_troubleshooting' => true ] );
115
+ }
116
+ if ( ! in_array( $key, $unset_keys ) ) {
117
+ $unset_keys[] = $key;
118
+ }
119
+ }
120
+ }
121
+ }
122
 
123
+ foreach ( $unset_keys as $unset_key ) {
124
+ unset( $get_variables_products[ $unset_key ] );
125
+ }
126
 
127
+ update_option( 'wcml_products_to_sync', $get_variables_products );
128
 
129
+ $wcml_settings = get_option( '_wcml_settings' );
130
+ if ( isset( $wcml_settings['notifications'] ) && isset( $wcml_settings['notifications']['varimages'] ) ) {
131
+ $wcml_settings['notifications']['varimages']['show'] = 0;
132
+ update_option( '_wcml_settings', $wcml_settings );
133
+ }
134
 
135
+ wp_send_json_success();
136
+ }
137
 
138
+ public function trbl_gallery_images() {
139
  $nonce = filter_input( INPUT_POST, 'wcml_nonce', FILTER_SANITIZE_FULL_SPECIAL_CHARS );
140
+ if ( ! $nonce || ! wp_verify_nonce( $nonce, 'trbl_gallery_images' ) ) {
141
+ wp_send_json_error( 'Invalid nonce' );
142
  }
143
 
144
  $all_products = $this->get_products_needs_gallery_sync( true );
145
 
146
+ foreach ( $all_products as $product ) {
147
+ $this->woocommerce_wpml->media->sync_product_gallery( $product->ID );
148
+ add_post_meta( $product->ID, 'gallery_sync', true );
149
  }
150
 
151
  wp_send_json_success();
152
 
153
  }
154
 
155
+ public function get_products_needs_gallery_sync( $limit = false ) {
156
 
157
+ $sql = "SELECT p.ID FROM {$this->wpdb->posts} AS p
158
  LEFT JOIN {$this->wpdb->prefix}icl_translations AS tr
159
  ON tr.element_id = p.ID
160
  WHERE p.post_status = 'publish' AND p.post_type = 'product' AND tr.source_language_code is NULL
161
  AND ( SELECT COUNT( pm.meta_key ) FROM {$this->wpdb->postmeta} AS pm WHERE pm.post_id = p.ID AND pm.meta_key = 'gallery_sync' ) = 0 ";
162
 
163
+ if ( $limit ) {
164
+ $sql .= 'ORDER BY p.ID LIMIT ' . self::ITEMS_PER_AJAX;
165
+ }
 
 
166
 
167
+ $all_products = $this->wpdb->get_results( $sql );
 
168
 
169
+ return $all_products;
170
+ }
 
 
 
171
 
172
+ public function trbl_sync_categories() {
173
+ $nonce = filter_input( INPUT_POST, 'wcml_nonce', FILTER_SANITIZE_FULL_SPECIAL_CHARS );
174
+ if ( ! $nonce || ! wp_verify_nonce( $nonce, 'trbl_sync_categories' ) ) {
175
+ wp_send_json_error( 'Invalid nonce' );
176
+ }
177
 
178
+ $all_categories = $this->get_product_categories_needs_sync( true );
179
+
180
+ foreach ( $all_categories as $category ) {
181
+ add_option( 'wcml_sync_category_' . $category->term_taxonomy_id, true );
182
+ $trid = $this->sitepress->get_element_trid( $category->term_taxonomy_id, 'tax_product_cat' );
183
+ $translations = $this->sitepress->get_element_translations( $trid, 'tax_product_cat' );
184
+ $type = get_term_meta( $category->term_id, 'display_type', true );
185
+ $thumbnail_id = get_term_meta( $category->term_id, 'thumbnail_id', true );
186
+ foreach ( $translations as $translation ) {
187
+ if ( $translation->language_code != $category->language_code ) {
188
+ update_term_meta( $translation->term_id, 'display_type', $type );
189
+ update_term_meta( $translation->term_id, 'thumbnail_id', apply_filters( 'translate_object_id', $thumbnail_id, 'attachment', true, $translation->language_code ) );
190
+ }
191
+ }
192
+ }
193
 
194
+ wp_send_json_success();
195
 
196
+ }
197
 
198
 
199
+ public function get_product_categories_needs_sync( $limit = false ) {
200
 
201
+ $sql = "SELECT t.term_taxonomy_id,t.term_id,tr.language_code FROM {$this->wpdb->term_taxonomy} AS t
202
  LEFT JOIN {$this->wpdb->prefix}icl_translations AS tr
203
  ON tr.element_id = t.term_taxonomy_id
204
  WHERE t.taxonomy = 'product_cat' AND tr.element_type = 'tax_product_cat' AND tr.source_language_code is NULL
205
  AND ( SELECT COUNT( option_id ) FROM {$this->wpdb->options} WHERE option_name = CONCAT( 'wcml_sync_category_',t.term_taxonomy_id ) ) = 0 ";
206
 
207
+ if ( $limit ) {
208
+ $sql .= 'ORDER BY t.term_taxonomy_id LIMIT ' . self::ITEMS_PER_AJAX;
209
+ }
 
 
210
 
211
+ $all_categories = $this->wpdb->get_results( $sql );
 
212
 
213
+ return $all_categories;
214
+ }
215
 
 
 
 
 
 
216
 
217
+ public function trbl_duplicate_terms() {
218
+ $nonce = filter_input( INPUT_POST, 'wcml_nonce', FILTER_SANITIZE_FULL_SPECIAL_CHARS );
219
+ if ( ! $nonce || ! wp_verify_nonce( $nonce, 'trbl_duplicate_terms' ) ) {
220
+ wp_send_json_error( 'Invalid nonce' );
221
+ }
222
 
223
+ $attr = isset( $_POST['attr'] ) ? $_POST['attr'] : false;
224
+
225
+ if ( $attr ) {
226
+ $terms = get_terms( $attr, 'hide_empty=0' );
227
+ $i = 0;
228
+ $languages = $this->sitepress->get_active_languages();
229
+ foreach ( $terms as $term ) {
230
+ foreach ( $languages as $language ) {
231
+ $tr_id = apply_filters( 'translate_object_id', $term->term_id, $attr, false, $language['code'] );
232
+
233
+ if ( is_null( $tr_id ) ) {
234
+ $term_args = [];
235
+ // hierarchy - parents.
236
+ if ( is_taxonomy_hierarchical( $attr ) ) {
237
+ // fix hierarchy.
238
+ if ( $term->parent ) {
239
+ $original_parent_translated = apply_filters( 'translate_object_id', $term->parent, $attr, false, $language['code'] );
240
+ if ( $original_parent_translated ) {
241
+ $term_args['parent'] = $original_parent_translated;
242
+ }
243
+ }
244
+ }
245
 
246
+ $term_name = $term->name;
247
+ $slug = $term->name . '-' . $language['code'];
248
+ $slug = WPML_Terms_Translations::term_unique_slug( $slug, $attr, $language['code'] );
249
+ $term_args['slug'] = $slug;
 
 
 
 
 
 
 
 
250
 
251
+ $new_term = wp_insert_term( $term_name, $attr, $term_args );
252
+ if ( $new_term && ! is_wp_error( $new_term ) ) {
253
+ $tt_id = $this->sitepress->get_element_trid( $term->term_taxonomy_id, 'tax_' . $attr );
254
+ $this->sitepress->set_element_language_details( $new_term['term_taxonomy_id'], 'tax_' . $attr, $tt_id, $language['code'] );
255
+ }
256
+ }
257
+ }
258
+ }
259
+ }
260
 
261
+ wp_send_json_success();
262
+ }
 
 
 
 
 
263
 
264
+ public function trbl_fix_product_type_terms() {
265
+ $nonce = filter_input( INPUT_POST, 'wcml_nonce', FILTER_SANITIZE_FULL_SPECIAL_CHARS );
266
+ if ( ! $nonce || ! wp_verify_nonce( $nonce, 'trbl_product_type_terms' ) ) {
267
+ wp_send_json_error( 'Invalid nonce' );
268
+ }
269
 
270
+ WCML_Install::check_product_type_terms();
 
271
 
272
+ wp_send_json_success();
273
+ }
 
 
 
274
 
275
+ public function wcml_count_products_and_variations() {
276
 
277
+ $results = $this->get_original_products_and_variations();
 
278
 
279
+ return count( $results );
280
+ }
281
 
282
+ public function trbl_sync_stock() {
283
 
284
+ $nonce = array_key_exists( 'wcml_nonce', $_POST ) ? sanitize_text_field( $_POST['wcml_nonce'] ) : false;
285
+ if ( ! $nonce || ! wp_verify_nonce( $nonce, 'trbl_sync_stock' ) ) {
286
+ wp_send_json_error( 'Invalid nonce' );
287
+ }
288
 
289
+ $results = $this->get_original_products_and_variations();
290
 
291
+ foreach ( $results as $product ) {
 
 
 
292
 
293
+ if ( get_post_meta( $product->ID, '_manage_stock', true ) === 'yes' ) {
294
 
295
+ $translations = $this->sitepress->get_element_translations( $product->trid, $product->element_type );
296
 
297
+ $min_stock = false;
298
+ $stock_status = 'instock';
299
 
300
+ // collect min stock.
301
+ foreach ( $translations as $translation ) {
302
+ $stock = get_post_meta( $translation->element_id, '_stock', true );
303
+ if ( ! $min_stock || $stock < $min_stock ) {
304
+ $min_stock = $stock;
305
+ $stock_status = get_post_meta( $translation->element_id, '_stock_status', true );
306
+ }
307
+ }
308
 
309
+ // update stock value.
310
+ foreach ( $translations as $translation ) {
311
+ update_post_meta( $translation->element_id, '_stock', $min_stock );
312
+ update_post_meta( $translation->element_id, '_stock_status', $stock_status );
313
+ }
314
+ }
315
+ }
316
 
317
+ wp_send_json_success();
318
+ }
 
 
 
 
 
 
319
 
320
+ public function get_original_products_and_variations() {
 
 
 
 
 
 
 
 
 
 
 
321
 
322
+ $results = $this->wpdb->get_results(
323
+ "
324
  SELECT p.ID, t.trid, t.element_type
325
  FROM {$this->wpdb->posts} p
326
  JOIN {$this->wpdb->prefix}icl_translations t ON t.element_id = p.ID AND t.element_type IN ('post_product', 'post_product_variation')
327
  WHERE p.post_type in ('product', 'product_variation') AND t.source_language_code IS NULL
328
+ "
329
+ );
330
 
331
  return $results;
332
  }
333
 
334
+ public function fix_translated_variations_relationships() {
335
 
336
  $nonce = array_key_exists( 'wcml_nonce', $_POST ) ? sanitize_text_field( $_POST['wcml_nonce'] ) : false;
337
  if ( ! $nonce || ! wp_verify_nonce( $nonce, 'fix_relationships' ) ) {
344
 
345
  $translated_variations = get_option( 'wcml_trbl_translated_variations' );
346
 
347
+ if ( ! $translated_variations ) {
348
  $translated_variations = $this->get_products_variations_needs_fix_relationships();
349
  }
350
 
351
  foreach ( array_slice( $translated_variations, 0, self::ITEMS_PER_AJAX, true ) as $key => $translated_variation ) {
352
+ // check relationships.
353
  $tr_info_for_original_variation = $this->get_translation_info_for_element( $translated_variation->meta_value, 'post_product_variation' );
354
 
355
  $language = $this->sitepress->get_language_for_element( wp_get_post_parent_id( $translated_variation->meta_value ), 'post_product' );
358
 
359
  $tr_info_for_current_variation = $this->get_translation_info_for_element( $translated_variation->post_id, 'post_product_variation' );
360
 
361
+ // delete wrong element_type for exists variations.
362
  if ( ! $tr_info_for_current_variation ) {
363
  $tr_info_for_current_variation = $this->get_translation_info_for_element( $translated_variation->post_id, 'post_product' );
364
  if ( $tr_info_for_current_variation ) {
365
+ $this->wpdb->update( $this->wpdb->prefix . 'icl_translations', [ 'element_type' => 'post_product_variation' ], [ 'translation_id' => $tr_info_for_current_variation->translation_id ] );
366
  }
367
  }
368
 
369
  $check_duplicated_post_type = $this->get_translation_info_for_element( $translated_variation->post_id, 'post_product' );
370
  if ( $check_duplicated_post_type ) {
371
+ $this->wpdb->delete( $this->wpdb->prefix . 'icl_translations', [ 'translation_id' => $check_duplicated_post_type->translation_id ] );
372
  }
373
 
374
+ // set language info for variation if not exists.
 
375
  if ( ! $tr_info_for_original_variation ) {
376
 
377
+ $tr_info_for_original_variation = $this->get_translation_info_for_element( $translated_variation->meta_value, 'post_product' );
378
  if ( $tr_info_for_original_variation ) {
379
+ $this->wpdb->update( $this->wpdb->prefix . 'icl_translations', [ 'element_type' => 'post_product_variation' ], [ 'translation_id' => $tr_info_for_original_variation->translation_id ] );
380
  } else {
381
  $this->sitepress->set_element_language_details( $translated_variation->meta_value, 'post_product_variation', $tr_info_for_current_variation->trid, $language );
382
+ $tr_info_for_original_variation = $this->get_translation_info_for_element( $translated_variation->meta_value, 'post_product' );
383
  }
384
 
385
+ $this->wpdb->update( $this->wpdb->prefix . 'icl_translations', [ 'source_language_code' => $language ], [ 'translation_id' => $tr_info_for_current_variation->translation_id ] );
386
  }
387
 
388
  if ( $tr_info_for_original_variation->trid != $tr_info_for_current_variation->trid ) {
389
 
390
+ $this->wpdb->update(
391
+ $this->wpdb->prefix . 'icl_translations',
392
+ [
393
+ 'trid' => $tr_info_for_original_variation->trid,
394
+ 'language_code' => $language_current,
395
+ 'source_language_code' => $language,
396
+ ],
397
+ [ 'translation_id' => $tr_info_for_current_variation->translation_id ]
398
+ );
399
 
400
  }
401
 
404
 
405
  update_option( 'wcml_trbl_translated_variations', $translated_variations );
406
 
407
+ wp_send_json_success();
408
+ }
409
 
410
  /**
411
+ * @param int $element_id
412
  * @param string $element_type
413
  *
414
  * @return object|null
415
  */
416
+ private function get_translation_info_for_element( $element_id, $element_type ) {
417
+ return $this->wpdb->get_row( $this->wpdb->prepare( "SELECT trid, translation_id FROM {$this->wpdb->prefix}icl_translations WHERE element_id = %d AND element_type = %s", $element_id, $element_type ) );
418
+ }
419
 
420
+ private function get_products_variations_needs_fix_relationships() {
421
+ return $this->wpdb->get_results( "SELECT post_id, meta_value FROM {$this->wpdb->postmeta} WHERE meta_key ='_wcml_duplicate_of_variation'" );
422
+ }
423
 
424
+ public function wcml_count_product_fix_relationships() {
425
 
426
+ $results = $this->get_products_variations_needs_fix_relationships();
427
 
428
+ return count( $results );
429
+ }
430
 
431
 
432
+ public function sync_deleted_meta() {
433
 
434
  $nonce = array_key_exists( 'wcml_nonce', $_POST ) ? sanitize_text_field( $_POST['wcml_nonce'] ) : false;
435
  if ( ! $nonce || ! wp_verify_nonce( $nonce, 'sync_deleted_meta' ) ) {
442
 
443
  $products_needs_fix_postmeta = get_option( 'wcml_trbl_products_needs_fix_postmeta' );
444
 
445
+ if ( ! $products_needs_fix_postmeta ) {
446
  $products_needs_fix_postmeta = $this->get_original_products_and_variations();
447
  }
448
 
449
  $iclTranslationManagement = wpml_load_core_tm();
450
+ $settings_factory = new WPML_Custom_Field_Setting_Factory( $iclTranslationManagement );
451
 
452
  foreach ( array_slice( $products_needs_fix_postmeta, 0, self::ITEMS_PER_AJAX, true ) as $key => $product ) {
453
 
454
  $translations = $this->sitepress->get_element_translations( $product->trid, $product->element_type );
455
 
456
+ foreach ( $translations as $translation ) {
457
+ if ( ! $translation->original ) {
458
  $all_post_meta_keys = $this->wpdb->get_col( $this->wpdb->prepare( "SELECT meta_key FROM {$this->wpdb->postmeta} WHERE post_id = %d", $translation->element_id ) );
459
+ foreach ( $all_post_meta_keys as $meta_key ) {
460
  $setting = $settings_factory->post_meta_setting( $meta_key );
461
  if ( WPML_COPY_CUSTOM_FIELD === $setting->status() ) {
462
+ if ( ! metadata_exists( 'post', $product->ID, $meta_key ) ) {
463
  delete_post_meta( $translation->element_id, $meta_key );
464
  }
465
  }
475
  wp_send_json_success();
476
  }
477
 
478
+ }
inc/class-wcml-upgrade.php CHANGED
@@ -32,6 +32,7 @@ class WCML_Upgrade {
32
  '4.6.8',
33
  '4.7.3',
34
  '4.7.6',
 
35
  ];
36
 
37
  public function __construct() {
@@ -797,4 +798,33 @@ class WCML_Upgrade {
797
  WHERE `context` = 'woocommerce' AND `name` LIKE '%_shipping_method_title'"
798
  );
799
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
800
  }
32
  '4.6.8',
33
  '4.7.3',
34
  '4.7.6',
35
+ '4.7.8',
36
  ];
37
 
38
  public function __construct() {
798
  WHERE `context` = 'woocommerce' AND `name` LIKE '%_shipping_method_title'"
799
  );
800
  }
801
+
802
+ private function upgrade_4_7_8() {
803
+ $emailOptions = [
804
+ 'woocommerce_new_order_settings',
805
+ 'woocommerce_cancelled_order_settings',
806
+ 'woocommerce_failed_order_settings',
807
+ 'woocommerce_customer_on_hold_order_settings',
808
+ 'woocommerce_customer_processing_order_settings',
809
+ 'woocommerce_customer_completed_order_settings',
810
+ 'woocommerce_customer_refunded_order_settings',
811
+ 'woocommerce_customer_invoice_settings',
812
+ 'woocommerce_customer_note_settings',
813
+ 'woocommerce_customer_reset_password_settings',
814
+ 'woocommerce_customer_new_account_settings'
815
+ ];
816
+
817
+
818
+ foreach ( $emailOptions as $emailOption ) {
819
+
820
+ $emailSettings = get_option( $emailOption );
821
+
822
+ if ( isset( $emailSettings['additional_content'] ) && $emailSettings['additional_content'] ) {
823
+ $domain = 'admin_texts_' . $emailOption;
824
+ $name = '[' . $emailOption . ']additional_content';
825
+
826
+ icl_register_string( $domain, $name, $emailSettings['additional_content'], false, '' );
827
+ }
828
+ }
829
+ }
830
  }
inc/class-wcml-url-translation.php CHANGED
@@ -20,11 +20,10 @@ class WCML_Url_Translation {
20
  * WCML_Url_Translation constructor.
21
  *
22
  * @param woocommerce_wpml $woocommerce_wpml
23
- * @param SitePress $sitepress
24
- * @param wpdb $wpdb
25
  */
26
- public function __construct( woocommerce_wpml $woocommerce_wpml, SitePress $sitepress, wpdb $wpdb )
27
- {
28
  $this->woocommerce_wpml = $woocommerce_wpml;
29
  $this->sitepress = $sitepress;
30
  $this->wpdb = $wpdb;
@@ -36,46 +35,65 @@ class WCML_Url_Translation {
36
  $this->default_product_tag_gettext_base = _x( 'product-tag', 'slug', 'woocommerce' );
37
  }
38
 
39
- function set_up() {
40
 
41
  $this->wc_permalinks = get_option( 'woocommerce_permalinks' );
42
 
43
- add_filter( 'pre_update_option_woocommerce_permalinks', array(
44
- $this,
45
- 'register_product_and_taxonomy_bases'
46
- ), 10, 2 );
 
 
 
 
 
47
 
48
  if ( ! is_admin() ) {
49
- add_filter( 'option_woocommerce_permalinks', array(
50
- $this,
51
- 'use_untranslated_default_url_bases'
52
- ), 1, 1 ); // avoid using the _x translations
53
- add_action( 'init', array(
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
54
  $this,
55
- 'fix_post_object_rewrite_slug'
56
- ), 6 ); // handle the particular case of the default product base: wpmlst-540
57
- }
58
-
59
- add_filter( 'pre_update_option_rewrite_rules', array(
60
- $this,
61
- 'force_bases_in_strings_languages'
62
- ), 1, 1 ); // high priority
63
- add_filter( 'option_rewrite_rules', array( $this, 'translate_bases_in_rewrite_rules' ), 0, 1 ); // high priority
64
- add_filter( 'term_link', array( $this, 'translate_taxonomy_base' ), 0, 3 ); // high priority
65
-
66
- add_action( 'wp_ajax_wcml_update_base_translation', array( $this, 'wcml_update_base_translation' ) );
67
- add_filter( 'redirect_canonical', array( $this, 'check_wc_tax_url_on_redirect' ), 10, 2 );
68
- add_filter( 'query_vars', array( $this, 'translate_query_var_for_product' ) );
69
- add_filter( 'wp_redirect', array( $this, 'encode_shop_slug' ), 10, 2 );
70
- add_action( 'switch_blog', array( $this, 'maybe_remove_query_vars_filter' ) );
71
-
72
- add_filter( 'post_type_link', array( $this, 'translate_product_post_type_link' ), 10, 2 );
73
 
74
  if ( empty( $this->woocommerce_wpml->settings['url_translation_set_up'] ) ) {
75
 
76
  $this->clean_up_product_and_taxonomy_bases();
77
 
78
- //set translate product by default
79
  $this->translate_product_base();
80
 
81
  $this->register_product_and_taxonomy_bases();
@@ -86,25 +104,24 @@ class WCML_Url_Translation {
86
 
87
  }
88
 
89
- function clean_up_product_and_taxonomy_bases() {
90
 
91
  $base = $this->get_woocommerce_product_base();
92
 
93
- //delete other old product bases
94
  $this->wpdb->query( "DELETE FROM {$this->wpdb->prefix}icl_strings WHERE context = 'WordPress' AND value != '" . trim( $base, '/' ) . "' AND name LIKE 'URL slug:%' " );
95
 
96
- //update name for current base
97
-
98
  $this->wpdb->update(
99
  $this->wpdb->prefix . 'icl_strings',
100
- array(
101
  'context' => 'WordPress',
102
- 'name' => 'URL slug: product'
103
- ),
104
- array(
105
  'context' => 'WordPress',
106
- 'name' => sprintf( 'Url slug: %s', trim( $base, '/' ) )
107
- )
108
  );
109
 
110
  $woocommerce_permalinks = maybe_unserialize( get_option( 'woocommerce_permalinks' ) );
@@ -130,12 +147,11 @@ class WCML_Url_Translation {
130
  if ( $taxonomy ) {
131
  $this->wpdb->query( "DELETE FROM {$this->wpdb->prefix}icl_strings WHERE context LIKE '" . sprintf( 'URL %s slugs - ', $taxonomy ) . "%'" );
132
  }
133
-
134
  }
135
 
136
  }
137
 
138
- function fix_post_object_rewrite_slug() {
139
  global $wp_post_types, $wp_rewrite;
140
 
141
  if ( empty( $this->wc_permalinks['product_base'] ) ) {
@@ -146,7 +162,7 @@ class WCML_Url_Translation {
146
  }
147
  }
148
 
149
- function url_strings_context() {
150
  return 'WordPress';
151
  }
152
 
@@ -171,7 +187,7 @@ class WCML_Url_Translation {
171
  return $name;
172
  }
173
 
174
- function translate_product_base() {
175
 
176
  if ( ! defined( 'WOOCOMMERCE_VERSION' ) || ( ! isset( $GLOBALS['ICL_Pro_Translation'] ) || is_null( $GLOBALS['ICL_Pro_Translation'] ) ) ) {
177
  return;
@@ -181,7 +197,7 @@ class WCML_Url_Translation {
181
  do_action( 'wpml_activate_slug_translation', 'product', $slug );
182
  }
183
 
184
- function get_woocommerce_product_base() {
185
 
186
  if ( isset( $this->wc_permalinks['product_base'] ) && ! empty( $this->wc_permalinks['product_base'] ) ) {
187
  return trim( $this->wc_permalinks['product_base'], '/' );
@@ -193,7 +209,7 @@ class WCML_Url_Translation {
193
 
194
  }
195
 
196
- function register_product_and_taxonomy_bases( $value = false, $old_value = false ) {
197
 
198
  if ( empty( $value ) ) {
199
  $permalink_options = $this->wc_permalinks;
@@ -255,7 +271,6 @@ class WCML_Url_Translation {
255
  $this->add_default_slug_translations( $tag_base, $name );
256
  }
257
 
258
-
259
  if ( isset( $permalink_options['attribute_base'] ) && $permalink_options['attribute_base'] ) {
260
  $attr_base = trim( $permalink_options['attribute_base'], '/' );
261
 
@@ -278,7 +293,7 @@ class WCML_Url_Translation {
278
  *
279
  * @return mixed
280
  */
281
- function use_untranslated_default_url_bases( $permalinks ) {
282
 
283
  // exception (index.php in WP permalink structure) #wcml-1939
284
  if ( preg_match( '#^/?index\.php/#', get_option( 'permalink_structure' ) ) ) {
@@ -298,7 +313,7 @@ class WCML_Url_Translation {
298
  return $permalinks;
299
  }
300
 
301
- function add_default_slug_translations( $slug, $name ) {
302
 
303
  $string_id = icl_get_string_id( $slug, $this->url_strings_context(), $name );
304
  $string_language = $this->woocommerce_wpml->strings->get_string_language( $slug, $this->url_strings_context(), $name );
@@ -326,24 +341,27 @@ class WCML_Url_Translation {
326
  // add string translation
327
  icl_add_string_translation( $string_id, $language, $slug_translation, ICL_STRING_TRANSLATION_COMPLETE );
328
  }
329
-
330
  }
331
-
332
  }
333
  }
334
 
335
  }
336
 
337
- function force_bases_in_strings_languages( $value ) {
338
 
339
- if ( $value && $this->sitepress->get_current_language() != 'en' ) {
340
 
341
- remove_filter( 'gettext_with_context', array(
342
- $this->woocommerce_wpml->strings,
343
- 'category_base_in_strings_language'
344
- ), 99, 3 );
345
- $taxonomies = array(
346
- 'product_cat' => array(
 
 
 
 
 
347
  'base' => 'category_base',
348
  'base_translated' => apply_filters(
349
  'wpml_translate_single_string',
@@ -351,9 +369,9 @@ class WCML_Url_Translation {
351
  $this->url_strings_context(),
352
  $this->url_string_name( 'product_cat' )
353
  ),
354
- 'default' => $this->default_product_category_base
355
- ),
356
- 'product_tag' => array(
357
  'base' => 'tag_base',
358
  'base_translated' => apply_filters(
359
  'wpml_translate_single_string',
@@ -361,29 +379,32 @@ class WCML_Url_Translation {
361
  $this->url_strings_context(),
362
  $this->url_string_name( 'product_tag' )
363
  ),
364
- 'default' => $this->default_product_tag_base
365
- ),
 
 
 
 
 
 
 
 
 
366
  );
367
- add_filter( 'gettext_with_context', array(
368
- $this->woocommerce_wpml->strings,
369
- 'category_base_in_strings_language'
370
- ), 99, 3 );
371
  foreach ( $taxonomies as $taxonomy => $taxonomy_details ) {
372
 
373
  if ( empty( $this->wc_permalinks[ $taxonomy_details['base'] ] ) && $value ) {
374
 
375
- $new_value = array();
376
  foreach ( $value as $k => $v ) {
377
- $k = preg_replace( "#" . $taxonomy_details['base_translated'] . "/#", $taxonomy_details['default'] . '/', $k );
378
  $new_value[ $k ] = $v;
379
  }
380
  $value = $new_value;
381
  unset( $new_value );
382
 
383
  }
384
-
385
  }
386
-
387
  }
388
 
389
  return $value;
@@ -395,7 +416,7 @@ class WCML_Url_Translation {
395
  *
396
  * @return array
397
  */
398
- function translate_bases_in_rewrite_rules( $value ) {
399
 
400
  if ( ! empty( $value ) ) {
401
  $value = $this->translate_wc_default_taxonomies_bases_in_rewrite_rules( $value );
@@ -411,8 +432,8 @@ class WCML_Url_Translation {
411
  *
412
  * @return array
413
  */
414
- public function translate_wc_default_taxonomies_bases_in_rewrite_rules( $value ){
415
- $taxonomies = array( 'product_cat', 'product_tag' );
416
 
417
  foreach ( $taxonomies as $taxonomy ) {
418
  $slug_details = $this->get_translated_tax_slug( $taxonomy );
@@ -427,12 +448,12 @@ class WCML_Url_Translation {
427
  $slug_match = addslashes( ltrim( $slug_details['slug'], '/' ) );
428
  $slug_translation_match = ltrim( $slug_details['translated_slug'], '/' );
429
 
430
- $buff_value = array();
431
 
432
  foreach ( (array) $value as $k => $v ) {
433
 
434
  if ( $slug_details['slug'] != $slug_details['translated_slug'] && preg_match( '#(^|^/)' . $slug_match . '/#', $k ) ) {
435
- $k = preg_replace( '#(^|^/)' . $slug_match . '/#', '$1'. $slug_translation_match . '/', $k );
436
  }
437
 
438
  $buff_value[ $k ] = $v;
@@ -440,7 +461,6 @@ class WCML_Url_Translation {
440
  $value = $buff_value;
441
  unset( $buff_value );
442
  }
443
-
444
  }
445
 
446
  return $value;
@@ -455,7 +475,7 @@ class WCML_Url_Translation {
455
 
456
  // handle attributes
457
  $wc_taxonomies = wc_get_attribute_taxonomies();
458
- $wc_taxonomies_wc_format = array();
459
  foreach ( $wc_taxonomies as $k => $v ) {
460
  $wc_taxonomies_wc_format[] = 'pa_' . $v->attribute_name;
461
  }
@@ -492,16 +512,14 @@ class WCML_Url_Translation {
492
  } elseif ( $attribute_slug_translation && $attribute_slug !== $attribute_slug_translation ) {
493
 
494
  $slug_match = addslashes( ltrim( $attribute_slug, '/' ) );
495
- $pattern = "#(^|\/)" . $slug_match . "/(.*)#";
496
  $replacement = '$1' . $attribute_slug_translation . '/$2';
497
 
498
  $value = $this->replace_bases_in_rewrite_rules( $value, $pattern, $pattern, $replacement );
499
 
500
  }
501
-
502
  }
503
  }
504
-
505
  }
506
 
507
  return $value;
@@ -513,8 +531,8 @@ class WCML_Url_Translation {
513
  *
514
  * @return array
515
  */
516
- public function translate_shop_page_base_in_rewrite_rules( $value ){
517
- //filter shop page rewrite slug
518
  $current_shop_id = wc_get_page_id( 'shop' );
519
  $default_shop_id = apply_filters( 'translate_object_id', $current_shop_id, 'page', true, $this->sitepress->get_default_language() );
520
 
@@ -522,16 +540,16 @@ class WCML_Url_Translation {
522
  return $value;
523
  }
524
 
525
- $current_slug = get_post( $current_shop_id )->post_name;
526
- $default_slug = get_post( $default_shop_id )->post_name;
527
 
528
  if ( $current_slug != $default_slug ) {
529
- $buff_value = array();
530
  foreach ( (array) $value as $k => $v ) {
531
 
532
  if ( preg_match( '#^' . $default_slug . '/\?\$$#', $k ) ||
533
- preg_match( '#^' . $default_slug . '/\(?feed#', $k ) ||
534
- preg_match( '#^' . $default_slug . '/page#', $k )
535
  ) {
536
 
537
  $k = preg_replace( '#^' . $default_slug . '/#', $current_slug . '/', $k );
@@ -548,18 +566,18 @@ class WCML_Url_Translation {
548
  }
549
 
550
  /**
551
- * @param array $value
552
  * @param string $pattern
553
  * @param string $replacement_pattern
554
  * @param string $replacement
555
  *
556
  * @return array
557
  */
558
- public function replace_bases_in_rewrite_rules( $value, $pattern, $replacement_pattern, $replacement ){
559
 
560
- $buff_value = array();
561
  foreach ( (array) $value as $k => $v ) {
562
- if ( preg_match( $pattern , $k ) ) {
563
  $k = preg_replace( $replacement_pattern, $replacement, $k );
564
  }
565
  $buff_value[ $k ] = $v;
@@ -571,12 +589,11 @@ class WCML_Url_Translation {
571
  return $value;
572
  }
573
 
574
- function translate_taxonomy_base( $termlink, $term, $taxonomy ) {
575
  global $wp_rewrite, $wpml_term_translations;
576
  static $no_recursion_flag;
577
 
578
  // handles product categories, product tags and attributes
579
-
580
  $wc_taxonomies = wc_get_attribute_taxonomies();
581
  foreach ( $wc_taxonomies as $k => $v ) {
582
  $wc_taxonomies_wc_format[] = 'pa_' . $v->attribute_name;
@@ -608,7 +625,7 @@ class WCML_Url_Translation {
608
 
609
  $buff = $wp_rewrite->extra_permastructs[ $taxonomy ]['struct'];
610
 
611
- if( $base_translated !== $base ){
612
  // translate the attribute base
613
  $wp_rewrite->extra_permastructs[ $taxonomy ]['struct'] = preg_replace( '#^' . $base . '/(.*)#', $base_translated . '/$1', $wp_rewrite->extra_permastructs[ $taxonomy ]['struct'] );
614
  }
@@ -626,13 +643,13 @@ class WCML_Url_Translation {
626
 
627
  if ( $attribute_slug_translation != $attribute_slug ) {
628
 
629
- if( $base ){
630
  $wp_rewrite->extra_permastructs[ $taxonomy ]['struct'] = preg_replace(
631
  '#^' . $base_translated . '/([^/]+)/(.+)$#',
632
  $base_translated . '/' . $attribute_slug_translation . '/$2',
633
  $wp_rewrite->extra_permastructs[ $taxonomy ]['struct']
634
  );
635
- }else{
636
  $wp_rewrite->extra_permastructs[ $taxonomy ]['struct'] = preg_replace(
637
  '#' . $attribute_slug_default . '/(.+)$#',
638
  $attribute_slug_translation . '/$1',
@@ -647,24 +664,21 @@ class WCML_Url_Translation {
647
  $wp_rewrite->extra_permastructs[ $taxonomy ]['struct'] = $buff;
648
 
649
  }
650
-
651
  }
652
 
653
  $no_recursion_flag = false;
654
 
655
  wp_cache_add( $cache_key, $termlink, 'terms', 0 );
656
  }
657
-
658
  }
659
 
660
  return $termlink;
661
  }
662
 
663
- function get_translated_tax_slug( $taxonomy, $language = false ) {
664
 
665
  switch ( $taxonomy ) {
666
  case 'product_tag':
667
-
668
  if ( ! empty( $this->wc_permalinks['tag_base'] ) ) {
669
  $slug = $gettext_slug = trim( $this->wc_permalinks['tag_base'], '/' );
670
  } else {
@@ -676,7 +690,6 @@ class WCML_Url_Translation {
676
  break;
677
 
678
  case 'product_cat':
679
-
680
  if ( ! empty( $this->wc_permalinks['category_base'] ) ) {
681
  $slug = $gettext_slug = trim( $this->wc_permalinks['category_base'], '/' );
682
  } else {
@@ -701,24 +714,24 @@ class WCML_Url_Translation {
701
  $language = $this->sitepress->get_current_language();
702
  }
703
 
704
- if ( $slug && $language != 'all' && $language != $string_language ) {
705
 
706
  $slug_translation = apply_filters( 'wpml_translate_single_string', $slug, $this->url_strings_context(), $this->url_string_name( $taxonomy ), $language, false );
707
 
708
- return array(
709
  'slug' => $slug,
710
- 'translated_slug' => $slug_translation
711
- );
712
  }
713
 
714
- return array(
715
  'slug' => $slug,
716
- 'translated_slug' => $slug
717
- );
718
 
719
  }
720
 
721
- function get_base_translation( $base, $language ) {
722
 
723
  // case of attribute slugs
724
  if ( strpos( $base, 'attribute_slug-' ) === 0 ) {
@@ -784,11 +797,11 @@ class WCML_Url_Translation {
784
  return $return;
785
 
786
  }
787
-
788
- private function get_endpoint_string_context(){
789
-
790
  return class_exists( 'WPML_Endpoints_Support' ) ? WPML_Endpoints_Support::STRING_CONTEXT : 'WooCommerce Endpoints';
791
-
792
  }
793
 
794
  /**
@@ -800,10 +813,10 @@ class WCML_Url_Translation {
800
 
801
  if ( $base == 'shop' ) {
802
  $source_language = $this->sitepress->get_language_for_element( wc_get_page_id( 'shop' ), 'post_page' );
803
- } elseif ( in_array( $base, array( 'product', 'product_cat', 'product_tag', 'attribute' ) ) ) {
804
  $source_language = $this->woocommerce_wpml->strings->get_string_language( $base, $this->url_strings_context(), $this->url_string_name( $base ) );
805
  } elseif ( strpos( $base, 'attribute_slug-' ) === 0 ) {
806
- $slug = preg_replace( '#^attribute_slug-#', '', $base );
807
  $source_language = $this->woocommerce_wpml->strings->get_string_language( $base, $this->url_strings_context(), $this->url_string_name( 'attribute_slug', $slug ) );
808
  } else {
809
  $source_language = $this->woocommerce_wpml->strings->get_string_language( $base, $this->get_endpoint_string_context(), $base );
@@ -812,7 +825,7 @@ class WCML_Url_Translation {
812
  return $source_language;
813
  }
814
 
815
- function wcml_update_base_translation() {
816
 
817
  $nonce = filter_input( INPUT_POST, 'wcml_nonce', FILTER_SANITIZE_FULL_SPECIAL_CHARS );
818
  if ( ! $nonce || ! wp_verify_nonce( $nonce, 'wcml_update_base_translation' ) ) {
@@ -832,12 +845,11 @@ class WCML_Url_Translation {
832
 
833
  $trnsl_shop_obj = get_post( $translated_shop_id );
834
  $new_slug = wp_unique_post_slug( sanitize_title( $_POST['base_translation'] ), $translated_shop_id, $trnsl_shop_obj->post_status, $trnsl_shop_obj->post_type, $trnsl_shop_obj->post_parent );
835
- $this->wpdb->update( $this->wpdb->posts, array( 'post_name' => $new_slug ), array( 'ID' => $translated_shop_id ) );
836
 
837
  }
838
-
839
  } else {
840
- if ( in_array( $original_base, array( 'product', 'product_cat', 'product_tag', 'attribute' ) ) ) {
841
  $string_id = icl_get_string_id( $original_base_value, $this->url_strings_context(), $this->url_string_name( $original_base ) );
842
  } elseif ( strpos( $original_base, 'attribute_slug-' ) === 0 ) {
843
  $slug = preg_replace( '#^attribute_slug-#', '', $original_base );
@@ -849,7 +861,7 @@ class WCML_Url_Translation {
849
  $string_id = icl_register_string( $this->get_endpoint_string_context(), $original_base, $original_base_value );
850
  }
851
 
852
- if( method_exists( $this->woocommerce_wpml->endpoints, 'add_endpoints' ) ){
853
  $this->woocommerce_wpml->endpoints->add_endpoints();
854
  $this->woocommerce_wpml->endpoints->flush_rules_for_endpoints_translations();
855
  }
@@ -865,18 +877,17 @@ class WCML_Url_Translation {
865
  echo json_encode( $html );
866
  die();
867
 
868
-
869
  }
870
 
871
  // return correct redirect URL for WC standard taxonomies when pretty permalink uses with lang as parameter in WPML
872
- function check_wc_tax_url_on_redirect( $redirect_url, $requested_url ) {
873
  global $wp_query;
874
 
875
  if ( is_tax() ) {
876
  $original = @parse_url( $requested_url );
877
  if ( isset( $original['query'] ) ) {
878
  parse_str( $original['query'], $query_args );
879
- if ( ( isset( $query_args['product_cat'] ) || isset( $query_args['product_tag'] ) ) && isset ( $query_args['lang'] ) ) {
880
  $obj = $wp_query->get_queried_object();
881
  $tax_url = get_term_link( (int) $obj->term_id, $obj->taxonomy );
882
 
@@ -901,15 +912,14 @@ class WCML_Url_Translation {
901
  unset( $_GET[ $translated_slug ] );
902
  $_GET[ $product_permalink ] = $buff;
903
  }
904
-
905
  }
906
 
907
  return $public_query_vars;
908
  }
909
 
910
  public function maybe_remove_query_vars_filter() {
911
- if ( !is_plugin_active( basename( $this->sitepress->get_wp_api()->constant( 'WPML_ST_PATH' ) ) . '/plugin.php' ) ) {
912
- remove_filter( 'query_vars', array( $this, 'translate_query_var_for_product' ) );
913
  }
914
  }
915
 
@@ -962,4 +972,4 @@ class WCML_Url_Translation {
962
  return $permalink;
963
  }
964
 
965
- }
20
  * WCML_Url_Translation constructor.
21
  *
22
  * @param woocommerce_wpml $woocommerce_wpml
23
+ * @param SitePress $sitepress
24
+ * @param wpdb $wpdb
25
  */
26
+ public function __construct( woocommerce_wpml $woocommerce_wpml, SitePress $sitepress, wpdb $wpdb ) {
 
27
  $this->woocommerce_wpml = $woocommerce_wpml;
28
  $this->sitepress = $sitepress;
29
  $this->wpdb = $wpdb;
35
  $this->default_product_tag_gettext_base = _x( 'product-tag', 'slug', 'woocommerce' );
36
  }
37
 
38
+ public function set_up() {
39
 
40
  $this->wc_permalinks = get_option( 'woocommerce_permalinks' );
41
 
42
+ add_filter(
43
+ 'pre_update_option_woocommerce_permalinks',
44
+ [
45
+ $this,
46
+ 'register_product_and_taxonomy_bases',
47
+ ],
48
+ 10,
49
+ 2
50
+ );
51
 
52
  if ( ! is_admin() ) {
53
+ add_filter(
54
+ 'option_woocommerce_permalinks',
55
+ [
56
+ $this,
57
+ 'use_untranslated_default_url_bases',
58
+ ],
59
+ 1,
60
+ 1
61
+ ); // avoid using the _x translations.
62
+ add_action(
63
+ 'init',
64
+ [
65
+ $this,
66
+ 'fix_post_object_rewrite_slug',
67
+ ],
68
+ 6
69
+ ); // handle the particular case of the default product base: wpmlst-540.
70
+ }
71
+
72
+ add_filter(
73
+ 'pre_update_option_rewrite_rules',
74
+ [
75
  $this,
76
+ 'force_bases_in_strings_languages',
77
+ ],
78
+ 1,
79
+ 1
80
+ ); // high priority.
81
+ add_filter( 'option_rewrite_rules', [ $this, 'translate_bases_in_rewrite_rules' ], 0, 1 ); // high priority
82
+ add_filter( 'term_link', [ $this, 'translate_taxonomy_base' ], 0, 3 ); // high priority
83
+
84
+ add_action( 'wp_ajax_wcml_update_base_translation', [ $this, 'wcml_update_base_translation' ] );
85
+ add_filter( 'redirect_canonical', [ $this, 'check_wc_tax_url_on_redirect' ], 10, 2 );
86
+ add_filter( 'query_vars', [ $this, 'translate_query_var_for_product' ] );
87
+ add_filter( 'wp_redirect', [ $this, 'encode_shop_slug' ], 10, 2 );
88
+ add_action( 'switch_blog', [ $this, 'maybe_remove_query_vars_filter' ] );
89
+
90
+ add_filter( 'post_type_link', [ $this, 'translate_product_post_type_link' ], 10, 2 );
 
 
 
91
 
92
  if ( empty( $this->woocommerce_wpml->settings['url_translation_set_up'] ) ) {
93
 
94
  $this->clean_up_product_and_taxonomy_bases();
95
 
96
+ // set translate product by default
97
  $this->translate_product_base();
98
 
99
  $this->register_product_and_taxonomy_bases();
104
 
105
  }
106
 
107
+ public function clean_up_product_and_taxonomy_bases() {
108
 
109
  $base = $this->get_woocommerce_product_base();
110
 
111
+ // delete other old product bases
112
  $this->wpdb->query( "DELETE FROM {$this->wpdb->prefix}icl_strings WHERE context = 'WordPress' AND value != '" . trim( $base, '/' ) . "' AND name LIKE 'URL slug:%' " );
113
 
114
+ // update name for current base
 
115
  $this->wpdb->update(
116
  $this->wpdb->prefix . 'icl_strings',
117
+ [
118
  'context' => 'WordPress',
119
+ 'name' => 'URL slug: product',
120
+ ],
121
+ [
122
  'context' => 'WordPress',
123
+ 'name' => sprintf( 'Url slug: %s', trim( $base, '/' ) ),
124
+ ]
125
  );
126
 
127
  $woocommerce_permalinks = maybe_unserialize( get_option( 'woocommerce_permalinks' ) );
147
  if ( $taxonomy ) {
148
  $this->wpdb->query( "DELETE FROM {$this->wpdb->prefix}icl_strings WHERE context LIKE '" . sprintf( 'URL %s slugs - ', $taxonomy ) . "%'" );
149
  }
 
150
  }
151
 
152
  }
153
 
154
+ public function fix_post_object_rewrite_slug() {
155
  global $wp_post_types, $wp_rewrite;
156
 
157
  if ( empty( $this->wc_permalinks['product_base'] ) ) {
162
  }
163
  }
164
 
165
+ public function url_strings_context() {
166
  return 'WordPress';
167
  }
168
 
187
  return $name;
188
  }
189
 
190
+ public function translate_product_base() {
191
 
192
  if ( ! defined( 'WOOCOMMERCE_VERSION' ) || ( ! isset( $GLOBALS['ICL_Pro_Translation'] ) || is_null( $GLOBALS['ICL_Pro_Translation'] ) ) ) {
193
  return;
197
  do_action( 'wpml_activate_slug_translation', 'product', $slug );
198
  }
199
 
200
+ public function get_woocommerce_product_base() {
201
 
202
  if ( isset( $this->wc_permalinks['product_base'] ) && ! empty( $this->wc_permalinks['product_base'] ) ) {
203
  return trim( $this->wc_permalinks['product_base'], '/' );
209
 
210
  }
211
 
212
+ public function register_product_and_taxonomy_bases( $value = false, $old_value = false ) {
213
 
214
  if ( empty( $value ) ) {
215
  $permalink_options = $this->wc_permalinks;
271
  $this->add_default_slug_translations( $tag_base, $name );
272
  }
273
 
 
274
  if ( isset( $permalink_options['attribute_base'] ) && $permalink_options['attribute_base'] ) {
275
  $attr_base = trim( $permalink_options['attribute_base'], '/' );
276
 
293
  *
294
  * @return mixed
295
  */
296
+ public function use_untranslated_default_url_bases( $permalinks ) {
297
 
298
  // exception (index.php in WP permalink structure) #wcml-1939
299
  if ( preg_match( '#^/?index\.php/#', get_option( 'permalink_structure' ) ) ) {
313
  return $permalinks;
314
  }
315
 
316
+ public function add_default_slug_translations( $slug, $name ) {
317
 
318
  $string_id = icl_get_string_id( $slug, $this->url_strings_context(), $name );
319
  $string_language = $this->woocommerce_wpml->strings->get_string_language( $slug, $this->url_strings_context(), $name );
341
  // add string translation
342
  icl_add_string_translation( $string_id, $language, $slug_translation, ICL_STRING_TRANSLATION_COMPLETE );
343
  }
 
344
  }
 
345
  }
346
  }
347
 
348
  }
349
 
350
+ public function force_bases_in_strings_languages( $value ) {
351
 
352
+ if ( $value && $this->sitepress->get_current_language() !== 'en' ) {
353
 
354
+ remove_filter(
355
+ 'gettext_with_context',
356
+ [
357
+ $this->woocommerce_wpml->strings,
358
+ 'category_base_in_strings_language',
359
+ ],
360
+ 99,
361
+ 3
362
+ );
363
+ $taxonomies = [
364
+ 'product_cat' => [
365
  'base' => 'category_base',
366
  'base_translated' => apply_filters(
367
  'wpml_translate_single_string',
369
  $this->url_strings_context(),
370
  $this->url_string_name( 'product_cat' )
371
  ),
372
+ 'default' => $this->default_product_category_base,
373
+ ],
374
+ 'product_tag' => [
375
  'base' => 'tag_base',
376
  'base_translated' => apply_filters(
377
  'wpml_translate_single_string',
379
  $this->url_strings_context(),
380
  $this->url_string_name( 'product_tag' )
381
  ),
382
+ 'default' => $this->default_product_tag_base,
383
+ ],
384
+ ];
385
+ add_filter(
386
+ 'gettext_with_context',
387
+ [
388
+ $this->woocommerce_wpml->strings,
389
+ 'category_base_in_strings_language',
390
+ ],
391
+ 99,
392
+ 3
393
  );
 
 
 
 
394
  foreach ( $taxonomies as $taxonomy => $taxonomy_details ) {
395
 
396
  if ( empty( $this->wc_permalinks[ $taxonomy_details['base'] ] ) && $value ) {
397
 
398
+ $new_value = [];
399
  foreach ( $value as $k => $v ) {
400
+ $k = preg_replace( '#' . $taxonomy_details['base_translated'] . '/#', $taxonomy_details['default'] . '/', $k );
401
  $new_value[ $k ] = $v;
402
  }
403
  $value = $new_value;
404
  unset( $new_value );
405
 
406
  }
 
407
  }
 
408
  }
409
 
410
  return $value;
416
  *
417
  * @return array
418
  */
419
+ public function translate_bases_in_rewrite_rules( $value ) {
420
 
421
  if ( ! empty( $value ) ) {
422
  $value = $this->translate_wc_default_taxonomies_bases_in_rewrite_rules( $value );
432
  *
433
  * @return array
434
  */
435
+ public function translate_wc_default_taxonomies_bases_in_rewrite_rules( $value ) {
436
+ $taxonomies = [ 'product_cat', 'product_tag' ];
437
 
438
  foreach ( $taxonomies as $taxonomy ) {
439
  $slug_details = $this->get_translated_tax_slug( $taxonomy );
448
  $slug_match = addslashes( ltrim( $slug_details['slug'], '/' ) );
449
  $slug_translation_match = ltrim( $slug_details['translated_slug'], '/' );
450
 
451
+ $buff_value = [];
452
 
453
  foreach ( (array) $value as $k => $v ) {
454
 
455
  if ( $slug_details['slug'] != $slug_details['translated_slug'] && preg_match( '#(^|^/)' . $slug_match . '/#', $k ) ) {
456
+ $k = preg_replace( '#(^|^/)' . $slug_match . '/#', '$1' . $slug_translation_match . '/', $k );
457
  }
458
 
459
  $buff_value[ $k ] = $v;
461
  $value = $buff_value;
462
  unset( $buff_value );
463
  }
 
464
  }
465
 
466
  return $value;
475
 
476
  // handle attributes
477
  $wc_taxonomies = wc_get_attribute_taxonomies();
478
+ $wc_taxonomies_wc_format = [];
479
  foreach ( $wc_taxonomies as $k => $v ) {
480
  $wc_taxonomies_wc_format[] = 'pa_' . $v->attribute_name;
481
  }
512
  } elseif ( $attribute_slug_translation && $attribute_slug !== $attribute_slug_translation ) {
513
 
514
  $slug_match = addslashes( ltrim( $attribute_slug, '/' ) );
515
+ $pattern = '#(^|\/)' . $slug_match . '/(.*)#';
516
  $replacement = '$1' . $attribute_slug_translation . '/$2';
517
 
518
  $value = $this->replace_bases_in_rewrite_rules( $value, $pattern, $pattern, $replacement );
519
 
520
  }
 
521
  }
522
  }
 
523
  }
524
 
525
  return $value;
531
  *
532
  * @return array
533
  */
534
+ public function translate_shop_page_base_in_rewrite_rules( $value ) {
535
+ // filter shop page rewrite slug
536
  $current_shop_id = wc_get_page_id( 'shop' );
537
  $default_shop_id = apply_filters( 'translate_object_id', $current_shop_id, 'page', true, $this->sitepress->get_default_language() );
538
 
540
  return $value;
541
  }
542
 
543
+ $current_slug = get_page_uri( $current_shop_id );
544
+ $default_slug = get_page_uri( $default_shop_id );
545
 
546
  if ( $current_slug != $default_slug ) {
547
+ $buff_value = [];
548
  foreach ( (array) $value as $k => $v ) {
549
 
550
  if ( preg_match( '#^' . $default_slug . '/\?\$$#', $k ) ||
551
+ preg_match( '#^' . $default_slug . '/\(?feed#', $k ) ||
552
+ preg_match( '#^' . $default_slug . '/page#', $k )
553
  ) {
554
 
555
  $k = preg_replace( '#^' . $default_slug . '/#', $current_slug . '/', $k );
566
  }
567
 
568
  /**
569
+ * @param array $value
570
  * @param string $pattern
571
  * @param string $replacement_pattern
572
  * @param string $replacement
573
  *
574
  * @return array
575
  */
576
+ public function replace_bases_in_rewrite_rules( $value, $pattern, $replacement_pattern, $replacement ) {
577
 
578
+ $buff_value = [];
579
  foreach ( (array) $value as $k => $v ) {
580
+ if ( preg_match( $pattern, $k ) ) {
581
  $k = preg_replace( $replacement_pattern, $replacement, $k );
582
  }
583
  $buff_value[ $k ] = $v;
589
  return $value;
590
  }
591
 
592
+ public function translate_taxonomy_base( $termlink, $term, $taxonomy ) {
593
  global $wp_rewrite, $wpml_term_translations;
594
  static $no_recursion_flag;
595
 
596
  // handles product categories, product tags and attributes
 
597
  $wc_taxonomies = wc_get_attribute_taxonomies();
598
  foreach ( $wc_taxonomies as $k => $v ) {
599
  $wc_taxonomies_wc_format[] = 'pa_' . $v->attribute_name;
625
 
626
  $buff = $wp_rewrite->extra_permastructs[ $taxonomy ]['struct'];
627
 
628
+ if ( $base_translated !== $base ) {
629
  // translate the attribute base
630
  $wp_rewrite->extra_permastructs[ $taxonomy ]['struct'] = preg_replace( '#^' . $base . '/(.*)#', $base_translated . '/$1', $wp_rewrite->extra_permastructs[ $taxonomy ]['struct'] );
631
  }
643
 
644
  if ( $attribute_slug_translation != $attribute_slug ) {
645
 
646
+ if ( $base ) {
647
  $wp_rewrite->extra_permastructs[ $taxonomy ]['struct'] = preg_replace(
648
  '#^' . $base_translated . '/([^/]+)/(.+)$#',
649
  $base_translated . '/' . $attribute_slug_translation . '/$2',
650
  $wp_rewrite->extra_permastructs[ $taxonomy ]['struct']
651
  );
652
+ } else {
653
  $wp_rewrite->extra_permastructs[ $taxonomy ]['struct'] = preg_replace(
654
  '#' . $attribute_slug_default . '/(.+)$#',
655
  $attribute_slug_translation . '/$1',
664
  $wp_rewrite->extra_permastructs[ $taxonomy ]['struct'] = $buff;
665
 
666
  }
 
667
  }
668
 
669
  $no_recursion_flag = false;
670
 
671
  wp_cache_add( $cache_key, $termlink, 'terms', 0 );
672
  }
 
673
  }
674
 
675
  return $termlink;
676
  }
677
 
678
+ public function get_translated_tax_slug( $taxonomy, $language = false ) {
679
 
680
  switch ( $taxonomy ) {
681
  case 'product_tag':
 
682
  if ( ! empty( $this->wc_permalinks['tag_base'] ) ) {
683
  $slug = $gettext_slug = trim( $this->wc_permalinks['tag_base'], '/' );
684
  } else {
690
  break;
691
 
692
  case 'product_cat':
 
693
  if ( ! empty( $this->wc_permalinks['category_base'] ) ) {
694
  $slug = $gettext_slug = trim( $this->wc_permalinks['category_base'], '/' );
695
  } else {
714
  $language = $this->sitepress->get_current_language();
715
  }
716
 
717
+ if ( $slug && $language !== 'all' && $language !== $string_language ) {
718
 
719
  $slug_translation = apply_filters( 'wpml_translate_single_string', $slug, $this->url_strings_context(), $this->url_string_name( $taxonomy ), $language, false );
720
 
721
+ return [
722
  'slug' => $slug,
723
+ 'translated_slug' => $slug_translation,
724
+ ];
725
  }
726
 
727
+ return [
728
  'slug' => $slug,
729
+ 'translated_slug' => $slug,
730
+ ];
731
 
732
  }
733
 
734
+ public function get_base_translation( $base, $language ) {
735
 
736
  // case of attribute slugs
737
  if ( strpos( $base, 'attribute_slug-' ) === 0 ) {
797
  return $return;
798
 
799
  }
800
+
801
+ private function get_endpoint_string_context() {
802
+
803
  return class_exists( 'WPML_Endpoints_Support' ) ? WPML_Endpoints_Support::STRING_CONTEXT : 'WooCommerce Endpoints';
804
+
805
  }
806
 
807
  /**
813
 
814
  if ( $base == 'shop' ) {
815
  $source_language = $this->sitepress->get_language_for_element( wc_get_page_id( 'shop' ), 'post_page' );
816
+ } elseif ( in_array( $base, [ 'product', 'product_cat', 'product_tag', 'attribute' ] ) ) {
817
  $source_language = $this->woocommerce_wpml->strings->get_string_language( $base, $this->url_strings_context(), $this->url_string_name( $base ) );
818
  } elseif ( strpos( $base, 'attribute_slug-' ) === 0 ) {
819
+ $slug = preg_replace( '#^attribute_slug-#', '', $base );
820
  $source_language = $this->woocommerce_wpml->strings->get_string_language( $base, $this->url_strings_context(), $this->url_string_name( 'attribute_slug', $slug ) );
821
  } else {
822
  $source_language = $this->woocommerce_wpml->strings->get_string_language( $base, $this->get_endpoint_string_context(), $base );
825
  return $source_language;
826
  }
827
 
828
+ public function wcml_update_base_translation() {
829
 
830
  $nonce = filter_input( INPUT_POST, 'wcml_nonce', FILTER_SANITIZE_FULL_SPECIAL_CHARS );
831
  if ( ! $nonce || ! wp_verify_nonce( $nonce, 'wcml_update_base_translation' ) ) {
845
 
846
  $trnsl_shop_obj = get_post( $translated_shop_id );
847
  $new_slug = wp_unique_post_slug( sanitize_title( $_POST['base_translation'] ), $translated_shop_id, $trnsl_shop_obj->post_status, $trnsl_shop_obj->post_type, $trnsl_shop_obj->post_parent );
848
+ $this->wpdb->update( $this->wpdb->posts, [ 'post_name' => $new_slug ], [ 'ID' => $translated_shop_id ] );
849
 
850
  }
 
851
  } else {
852
+ if ( in_array( $original_base, [ 'product', 'product_cat', 'product_tag', 'attribute' ] ) ) {
853
  $string_id = icl_get_string_id( $original_base_value, $this->url_strings_context(), $this->url_string_name( $original_base ) );
854
  } elseif ( strpos( $original_base, 'attribute_slug-' ) === 0 ) {
855
  $slug = preg_replace( '#^attribute_slug-#', '', $original_base );
861
  $string_id = icl_register_string( $this->get_endpoint_string_context(), $original_base, $original_base_value );
862
  }
863
 
864
+ if ( method_exists( $this->woocommerce_wpml->endpoints, 'add_endpoints' ) ) {
865
  $this->woocommerce_wpml->endpoints->add_endpoints();
866
  $this->woocommerce_wpml->endpoints->flush_rules_for_endpoints_translations();
867
  }
877
  echo json_encode( $html );
878
  die();
879
 
 
880
  }
881
 
882
  // return correct redirect URL for WC standard taxonomies when pretty permalink uses with lang as parameter in WPML
883
+ public function check_wc_tax_url_on_redirect( $redirect_url, $requested_url ) {
884
  global $wp_query;
885
 
886
  if ( is_tax() ) {
887
  $original = @parse_url( $requested_url );
888
  if ( isset( $original['query'] ) ) {
889
  parse_str( $original['query'], $query_args );
890
+ if ( ( isset( $query_args['product_cat'] ) || isset( $query_args['product_tag'] ) ) && isset( $query_args['lang'] ) ) {
891
  $obj = $wp_query->get_queried_object();
892
  $tax_url = get_term_link( (int) $obj->term_id, $obj->taxonomy );
893
 
912
  unset( $_GET[ $translated_slug ] );
913
  $_GET[ $product_permalink ] = $buff;
914
  }
 
915
  }
916
 
917
  return $public_query_vars;
918
  }
919
 
920
  public function maybe_remove_query_vars_filter() {
921
+ if ( ! is_plugin_active( basename( $this->sitepress->get_wp_api()->constant( 'WPML_ST_PATH' ) ) . '/plugin.php' ) ) {
922
+ remove_filter( 'query_vars', [ $this, 'translate_query_var_for_product' ] );
923
  }
924
  }
925
 
972
  return $permalink;
973
  }
974
 
975
+ }
inc/class-wcml-wc-gateways.php CHANGED
@@ -1,9 +1,9 @@
1
  <?php
2
 
3
- class WCML_WC_Gateways{
4
 
5
- const WCML_BACS_ACCOUNTS_CURRENCIES_OPTION = 'wcml_bacs_accounts_currencies';
6
- const STRINGS_CONTEXT = 'admin_texts_woocommerce_gateways';
7
  private $current_language;
8
 
9
  /** @var woocommerce_wpml */
@@ -15,60 +15,60 @@ class WCML_WC_Gateways{
15
  * WCML_WC_Gateways constructor.
16
  *
17
  * @param woocommerce_wpml $woocommerce_wpml
18
- * @param SitePress $sitepress
19
  */
20
- function __construct( woocommerce_wpml $woocommerce_wpml, SitePress $sitepress ) {
21
  $this->sitepress = $sitepress;
22
  $this->woocommerce_wpml = $woocommerce_wpml;
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
  public function add_hooks() {
31
- add_action( 'init', array( $this, 'on_init_hooks' ), 11 );
32
- add_filter( 'woocommerce_payment_gateways', array( $this, 'loaded_woocommerce_payment_gateways' ) );
33
  }
34
 
35
  public function on_init_hooks() {
36
  global $pagenow;
37
 
38
- add_filter( 'woocommerce_gateway_title', array( $this, 'translate_gateway_title' ), 10, 2 );
39
- add_filter( 'woocommerce_gateway_description', array( $this, 'translate_gateway_description' ), 10, 2 );
40
 
41
  if ( is_admin() && 'admin.php' === $pagenow && isset( $_GET['page'] ) && 'wc-settings' === $_GET['page'] && isset( $_GET['tab'] ) && 'checkout' === $_GET['tab'] ) {
42
- add_action( 'admin_footer', array( $this, 'show_language_links_for_gateways' ) );
43
  if ( isset( $_GET['section'] ) && 'bacs' === $_GET['section'] && wcml_is_multi_currency_on() ) {
44
  $this->set_bacs_gateway_currency();
45
- add_action( 'admin_footer', array( $this, 'append_currency_selector_to_bacs_account_settings' ) );
46
  }
47
  }
48
  }
49
 
50
- function loaded_woocommerce_payment_gateways( $load_gateways ){
51
 
52
- foreach( $load_gateways as $key => $gateway ){
53
 
54
- $load_gateway = is_string( $gateway ) ? new $gateway() : $gateway;
55
 
56
- $this->register_gateway_settings_strings( $load_gateway->id, $load_gateway->settings );
57
- $this->payment_gateways_filters( $load_gateway );
58
- $load_gateways[ $key ] = $load_gateway;
59
- }
60
 
61
- return $load_gateways;
62
- }
63
 
64
  /**
65
  * @param string $gateway_id
66
- * @param array $settings
67
  */
68
  public function register_gateway_settings_strings( $gateway_id, $settings ) {
69
  if ( isset( $settings['enabled'] ) && 'yes' === $settings['enabled'] ) {
70
  foreach ( $this->get_gateway_text_keys_to_translate() as $text_key ) {
71
- if ( isset( $settings[ $text_key ] ) && !$this->get_gateway_string_id( $settings[ $text_key ], $gateway_id, $text_key ) ) {
72
  $language = $this->gateway_setting_language( $settings[ $text_key ], $gateway_id, $text_key );
73
  icl_register_string( self::STRINGS_CONTEXT, $gateway_id . '_gateway_' . $text_key, $settings[ $text_key ], false, $language );
74
  }
@@ -76,43 +76,43 @@ class WCML_WC_Gateways{
76
  }
77
  }
78
 
79
- function payment_gateways_filters( $gateway ){
80
 
81
- if( isset( $gateway->id ) ){
82
- $gateway_id = $gateway->id;
83
- $this->translate_gateway_strings( $gateway );
84
- }
85
 
86
- }
87
 
88
- function translate_gateway_strings( $gateway ){
89
 
90
- if( isset( $gateway->enabled ) && $gateway->enabled != 'no' ){
91
 
92
- if( isset( $gateway->instructions ) ){
93
- $gateway->instructions = $this->translate_gateway_instructions( $gateway->instructions, $gateway->id );
94
- }
95
 
96
- if( isset( $gateway->description ) ){
97
- $gateway->description = $this->translate_gateway_description( $gateway->description, $gateway->id );
98
- }
99
 
100
- if( isset( $gateway->title ) ){
101
- $gateway->title = $this->translate_gateway_title( $gateway->title, $gateway->id );
102
- }
103
- }
104
 
105
- return $gateway;
106
 
107
- }
108
 
109
  public function translate_gateway_title( $title, $gateway_id ) {
110
- return $this->get_translated_gateway_string( $title, $gateway_id, 'title' );
111
- }
112
 
113
- public function translate_gateway_description( $description, $gateway_id) {
114
  return $this->get_translated_gateway_string( $description, $gateway_id, 'description' );
115
- }
116
 
117
  public function translate_gateway_instructions( $instructions, $gateway_id ) {
118
  return $this->get_translated_gateway_string( $instructions, $gateway_id, 'instructions' );
@@ -142,156 +142,161 @@ class WCML_WC_Gateways{
142
  */
143
  private function get_current_gateway_language() {
144
 
145
- $postData = wpml_collect( $_POST );
146
- if( $postData->isNotEmpty() ){
147
-
148
- $is_user_order_note = 'woocommerce_add_order_note' === $postData->get( 'action' ) && 'customer' === $postData->get( 'note_type' );
149
- if( $is_user_order_note ){
150
- return get_post_meta( $postData->get( 'post_id' ), 'wpml_language', true );
151
- }
152
-
153
- $is_refund_line_item = 'woocommerce_refund_line_items' === $postData->get( 'action' );
154
- if( $is_refund_line_item ){
155
- return get_post_meta( $postData->get( 'order_id' ), 'wpml_language', true );
156
- }
157
-
158
- if ( $postData->get( 'post_ID' ) ) {
159
- $is_saving_new_order = wpml_collect( ['auto-draft', 'draft'] )->contains( $postData->get( 'post_status' ) )
160
- && 'editpost' === $postData->get( 'action' )
161
- && $postData->get( 'save' );
162
- if ( $is_saving_new_order && isset( $_COOKIE[ WCML_Orders::DASHBOARD_COOKIE_NAME ] ) ) {
163
- return $_COOKIE[ WCML_Orders::DASHBOARD_COOKIE_NAME ];
164
- }
165
-
166
- $is_order_emails_status = wpml_collect( ['wc-completed', 'wc-processing', 'wc-refunded', 'wc-on-hold'] )->contains( $postData->get( 'order_status' ) );
167
- $is_send_order_details_action = 'send_order_details' === $postData->get( 'wc_order_action' );
168
- if ( $is_order_emails_status || $is_send_order_details_action ) {
169
- return get_post_meta( $postData->get( 'post_ID' ), 'wpml_language', true );
170
- }
171
-
172
- return $this->current_language;
173
- }
174
- }
175
-
176
- $getData = wpml_collect( $_GET );
177
- if( $getData->isNotEmpty() ) {
178
- $is_order_ajax_action = 'woocommerce_mark_order_status' === $getData->get( 'action' ) && wpml_collect( ['completed', 'processing'] )->contains( $getData->get( 'status' ) );
179
- if ( $is_order_ajax_action && $getData->get( 'order_id' ) ) {
180
- return get_post_meta( $getData->get( 'order_id' ), 'wpml_language', true );
181
- }
182
- }
183
-
184
- return $this->current_language;
185
- }
186
-
187
- function show_language_links_for_gateways(){
188
 
189
- $text_keys = $this->get_gateway_text_keys_to_translate();
190
-
191
- $wc_payment_gateways = WC_Payment_Gateways::instance();
192
-
193
- foreach( $wc_payment_gateways->payment_gateways() as $payment_gateway ) {
194
-
195
- if( isset( $_GET['section'] ) && $_GET['section'] == $payment_gateway->id ){
196
 
197
- foreach( $text_keys as $text_key ) {
 
 
 
198
 
199
- if ( isset( $payment_gateway->settings[ $text_key ] ) ) {
200
- $setting_value = $payment_gateway->settings[ $text_key ];
201
- }elseif( $text_key === 'instructions' ){
202
- $setting_value = $payment_gateway->description;
203
- }else{
204
- $setting_value = $payment_gateway->$text_key;
205
- }
206
 
207
- $input_name = $payment_gateway->plugin_id.$payment_gateway->id.'_'.$text_key;
208
- $gateway_option = $payment_gateway->plugin_id.$payment_gateway->id.'_settings';
 
 
 
209
 
210
- $lang_selector = new WPML_Simple_Language_Selector( $this->sitepress );
211
- $language = $this->gateway_setting_language( $setting_value, $payment_gateway->id, $text_key );
 
212
 
213
- $lang_selector->render( array(
214
- 'id' => $gateway_option.'_'.$text_key.'_language_selector',
215
- 'name' => 'wcml_lang-'.$gateway_option.'-'.$text_key,
216
- 'selected' => $language,
217
- 'show_please_select' => false,
218
- 'echo' => true,
219
- 'style' => 'width: 18%;float: left;margin-top: 3px;'
220
- )
221
- );
222
 
223
- $st_page = admin_url( 'admin.php?page=' . WPML_ST_FOLDER . '/menu/string-translation.php&context='.self::STRINGS_CONTEXT.'&search='.esc_attr( preg_replace("/[\n\r]/","",$setting_value) ) );
224
- ?>
225
- <script>
226
- var input = jQuery('#<?php echo esc_js( $input_name ); ?>');
227
- if ( input.length > 0 ) {
228
- input.parent().append('<div class="translation_controls"></div>');
229
- input.parent().find('.translation_controls').append('<a href="<?php echo $st_page ?>" style="margin-left: 10px"><?php _e('translations', 'woocommerce-multilingual') ?></a>');
230
- jQuery('#<?php echo $gateway_option.'_'.$text_key.'_language_selector' ?>').prependTo( input.parent().find('.translation_controls') );
231
- }else{
232
- jQuery('#<?php echo $gateway_option.'_'.$text_key.'_language_selector' ?>').remove();
233
- }
234
- </script>
235
- <?php }
236
- }
237
- }
238
- }
239
 
240
- private function gateway_setting_language( $setting_value, $gateway_id, $text_key ){
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
241
 
242
- if( $this->get_gateway_string_id( $setting_value, $gateway_id, $text_key ) ){
243
- return $this->woocommerce_wpml->strings->get_string_language( $setting_value, self::STRINGS_CONTEXT, $gateway_id .'_gateway_'. $text_key );
244
- }else{
245
- return $this->sitepress->get_default_language();
246
- }
247
 
248
- }
 
 
 
 
249
 
250
- private function get_gateway_string_id( $value, $gateway_id, $name ){
251
- return icl_get_string_id( $value, self::STRINGS_CONTEXT, $gateway_id .'_gateway_'. $name );
252
- }
253
 
254
- function set_bacs_gateway_currency(){
 
 
255
 
256
- foreach( $_POST as $key => $value ){
 
257
 
258
- if( '_enabled' === substr( $key, -8 ) ){
259
- $gateway = str_replace( '_enabled', '', $key );
260
- }
261
- }
262
 
263
- if ( isset( $gateway ) ) {
264
- if( 'woocommerce_bacs' === $gateway && isset( $_POST['bacs-currency'] ) ){
265
- update_option( self::WCML_BACS_ACCOUNTS_CURRENCIES_OPTION, filter_var_array( $_POST['bacs-currency'], FILTER_SANITIZE_STRING ) );
266
- }
267
- }
268
 
269
- }
270
 
271
- public function get_gateway_text_keys_to_translate(){
272
 
273
- $text_keys = array(
274
- 'title',
275
- 'description',
276
- 'instructions'
277
- );
278
 
279
- return apply_filters( 'wcml_gateway_text_keys_to_translate', $text_keys );
280
- }
281
 
282
  public function append_currency_selector_to_bacs_account_settings() {
283
 
284
- $template_loader = new WPML_Twig_Template_Loader( array( $this->sitepress->get_wp_api()->constant( 'WCML_PLUGIN_PATH' ) . '/templates/multi-currency/' ) );
285
- $currencies_dropdown_ui = new WCML_Currencies_Dropdown_UI( $template_loader );
286
 
287
  list( $default_dropdown, $currencies_output ) = $this->get_dropdown( $currencies_dropdown_ui );
288
 
289
- wp_enqueue_script( 'wcml-bacs-accounts-currencies', WCML_PLUGIN_URL . '/res/js/bacs-accounts-currencies' . WCML_JS_MIN . '.js', array( 'jquery' ), WCML_VERSION, true );
290
- wp_localize_script( 'wcml-bacs-accounts-currencies', 'wcml_data', array(
291
- 'currencies_dropdown' => $currencies_output,
292
- 'label' => __( 'Currency', 'woocommerce-multilingual' ),
293
- 'default_dropdown' => $default_dropdown
294
- ) );
 
 
 
 
295
  }
296
 
297
  /**
@@ -301,23 +306,22 @@ class WCML_WC_Gateways{
301
  */
302
  public function get_dropdown( $currencies_dropdown_ui ) {
303
 
304
- $bacs_settings = get_option( 'woocommerce_bacs_accounts', array() );
305
  $active_currencies = $this->woocommerce_wpml->multi_currency->get_currency_codes();
306
  $default_currency = wcml_get_woocommerce_currency_option();
307
- $bacs_accounts_currencies = get_option( self::WCML_BACS_ACCOUNTS_CURRENCIES_OPTION, array() );
308
- $currencies_output = array();
309
 
310
  $default_dropdown = $currencies_dropdown_ui->get( $active_currencies, $default_currency );
311
 
312
  if ( $bacs_settings ) {
313
  foreach ( $bacs_settings as $id => $account_settings ) {
314
- $currencies_output[ $id ] = isset( $bacs_accounts_currencies[ $id ] ) ? $currencies_dropdown_ui->get( $active_currencies, $bacs_accounts_currencies[ $id ] ) : $default_dropdown;
315
  }
316
  } else {
317
  $currencies_output[] = $default_dropdown;
318
  }
319
 
320
- return array( $default_dropdown, $currencies_output );
321
  }
322
-
323
- }
1
  <?php
2
 
3
+ class WCML_WC_Gateways {
4
 
5
+ const WCML_BACS_ACCOUNTS_CURRENCIES_OPTION = 'wcml_bacs_accounts_currencies';
6
+ const STRINGS_CONTEXT = 'admin_texts_woocommerce_gateways';
7
  private $current_language;
8
 
9
  /** @var woocommerce_wpml */
15
  * WCML_WC_Gateways constructor.
16
  *
17
  * @param woocommerce_wpml $woocommerce_wpml
18
+ * @param SitePress $sitepress
19
  */
20
+ public function __construct( woocommerce_wpml $woocommerce_wpml, SitePress $sitepress ) {
21
  $this->sitepress = $sitepress;
22
  $this->woocommerce_wpml = $woocommerce_wpml;
23
 
24
  $this->current_language = $this->sitepress->get_current_language();
25
+ if ( 'all' === $this->current_language ) {
26
  $this->current_language = $this->sitepress->get_default_language();
27
  }
28
  }
29
 
30
  public function add_hooks() {
31
+ add_action( 'init', [ $this, 'on_init_hooks' ], 11 );
32
+ add_filter( 'woocommerce_payment_gateways', [ $this, 'loaded_woocommerce_payment_gateways' ] );
33
  }
34
 
35
  public function on_init_hooks() {
36
  global $pagenow;
37
 
38
+ add_filter( 'woocommerce_gateway_title', [ $this, 'translate_gateway_title' ], 10, 2 );
39
+ add_filter( 'woocommerce_gateway_description', [ $this, 'translate_gateway_description' ], 10, 2 );
40
 
41
  if ( is_admin() && 'admin.php' === $pagenow && isset( $_GET['page'] ) && 'wc-settings' === $_GET['page'] && isset( $_GET['tab'] ) && 'checkout' === $_GET['tab'] ) {
42
+ add_action( 'admin_footer', [ $this, 'show_language_links_for_gateways' ] );
43
  if ( isset( $_GET['section'] ) && 'bacs' === $_GET['section'] && wcml_is_multi_currency_on() ) {
44
  $this->set_bacs_gateway_currency();
45
+ add_action( 'admin_footer', [ $this, 'append_currency_selector_to_bacs_account_settings' ] );
46
  }
47
  }
48
  }
49
 
50
+ public function loaded_woocommerce_payment_gateways( $load_gateways ) {
51
 
52
+ foreach ( $load_gateways as $key => $gateway ) {
53
 
54
+ $load_gateway = is_string( $gateway ) ? new $gateway() : $gateway;
55
 
56
+ $this->register_gateway_settings_strings( $load_gateway->id, $load_gateway->settings );
57
+ $this->payment_gateways_filters( $load_gateway );
58
+ $load_gateways[ $key ] = $load_gateway;
59
+ }
60
 
61
+ return $load_gateways;
62
+ }
63
 
64
  /**
65
  * @param string $gateway_id
66
+ * @param array $settings
67
  */
68
  public function register_gateway_settings_strings( $gateway_id, $settings ) {
69
  if ( isset( $settings['enabled'] ) && 'yes' === $settings['enabled'] ) {
70
  foreach ( $this->get_gateway_text_keys_to_translate() as $text_key ) {
71
+ if ( isset( $settings[ $text_key ] ) && ! $this->get_gateway_string_id( $settings[ $text_key ], $gateway_id, $text_key ) ) {
72
  $language = $this->gateway_setting_language( $settings[ $text_key ], $gateway_id, $text_key );
73
  icl_register_string( self::STRINGS_CONTEXT, $gateway_id . '_gateway_' . $text_key, $settings[ $text_key ], false, $language );
74
  }
76
  }
77
  }
78
 
79
+ public function payment_gateways_filters( $gateway ) {
80
 
81
+ if ( isset( $gateway->id ) ) {
82
+ $gateway_id = $gateway->id;
83
+ $this->translate_gateway_strings( $gateway );
84
+ }
85
 
86
+ }
87
 
88
+ public function translate_gateway_strings( $gateway ) {
89
 
90
+ if ( isset( $gateway->enabled ) && $gateway->enabled !== 'no' ) {
91
 
92
+ if ( isset( $gateway->instructions ) ) {
93
+ $gateway->instructions = $this->translate_gateway_instructions( $gateway->instructions, $gateway->id );
94
+ }
95
 
96
+ if ( isset( $gateway->description ) ) {
97
+ $gateway->description = $this->translate_gateway_description( $gateway->description, $gateway->id );
98
+ }
99
 
100
+ if ( isset( $gateway->title ) ) {
101
+ $gateway->title = $this->translate_gateway_title( $gateway->title, $gateway->id );
102
+ }
103
+ }
104
 
105
+ return $gateway;
106
 
107
+ }
108
 
109
  public function translate_gateway_title( $title, $gateway_id ) {
110
+ return $this->get_translated_gateway_string( $title, $gateway_id, 'title' );
111
+ }
112
 
113
+ public function translate_gateway_description( $description, $gateway_id ) {
114
  return $this->get_translated_gateway_string( $description, $gateway_id, 'description' );
115
+ }
116
 
117
  public function translate_gateway_instructions( $instructions, $gateway_id ) {
118
  return $this->get_translated_gateway_string( $instructions, $gateway_id, 'instructions' );
142
  */
143
  private function get_current_gateway_language() {
144
 
145
+ $postData = wpml_collect( $_POST );
146
+ if ( $postData->isNotEmpty() ) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
147
 
148
+ $is_user_order_note = 'woocommerce_add_order_note' === $postData->get( 'action' ) && 'customer' === $postData->get( 'note_type' );
149
+ if ( $is_user_order_note ) {
150
+ return get_post_meta( $postData->get( 'post_id' ), 'wpml_language', true );
151
+ }
 
 
 
152
 
153
+ $is_refund_line_item = 'woocommerce_refund_line_items' === $postData->get( 'action' );
154
+ if ( $is_refund_line_item ) {
155
+ return get_post_meta( $postData->get( 'order_id' ), 'wpml_language', true );
156
+ }
157
 
158
+ if ( $postData->get( 'post_ID' ) ) {
159
+ $is_saving_new_order = wpml_collect( [ 'auto-draft', 'draft' ] )->contains( $postData->get( 'post_status' ) )
160
+ && 'editpost' === $postData->get( 'action' )
161
+ && $postData->get( 'save' );
162
+ if ( $is_saving_new_order && isset( $_COOKIE[ WCML_Orders::DASHBOARD_COOKIE_NAME ] ) ) {
163
+ return $_COOKIE[ WCML_Orders::DASHBOARD_COOKIE_NAME ];
164
+ }
165
 
166
+ $is_order_emails_status = wpml_collect( [ 'wc-completed', 'wc-processing', 'wc-refunded', 'wc-on-hold' ] )->contains( $postData->get( 'order_status' ) );
167
+ $is_send_order_details_action = 'send_order_details' === $postData->get( 'wc_order_action' );
168
+ if ( $is_order_emails_status || $is_send_order_details_action ) {
169
+ return get_post_meta( $postData->get( 'post_ID' ), 'wpml_language', true );
170
+ }
171
 
172
+ return $this->current_language;
173
+ }
174
+ }
175
 
176
+ $getData = wpml_collect( $_GET );
177
+ if ( $getData->isNotEmpty() ) {
178
+ $is_order_ajax_action = 'woocommerce_mark_order_status' === $getData->get( 'action' ) && wpml_collect( [ 'completed', 'processing' ] )->contains( $getData->get( 'status' ) );
179
+ if ( $is_order_ajax_action && $getData->get( 'order_id' ) ) {
180
+ return get_post_meta( $getData->get( 'order_id' ), 'wpml_language', true );
181
+ }
182
+ }
 
 
183
 
184
+ return $this->current_language;
185
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
186
 
187
+ public function show_language_links_for_gateways() {
188
+
189
+ $text_keys = $this->get_gateway_text_keys_to_translate();
190
+
191
+ $wc_payment_gateways = WC_Payment_Gateways::instance();
192
+
193
+ foreach ( $wc_payment_gateways->payment_gateways() as $payment_gateway ) {
194
+
195
+ if ( isset( $_GET['section'] ) && $_GET['section'] == $payment_gateway->id ) {
196
+
197
+ foreach ( $text_keys as $text_key ) {
198
+
199
+ if ( isset( $payment_gateway->settings[ $text_key ] ) ) {
200
+ $setting_value = $payment_gateway->settings[ $text_key ];
201
+ } elseif ( $text_key === 'instructions' ) {
202
+ $setting_value = $payment_gateway->description;
203
+ } else {
204
+ $setting_value = $payment_gateway->$text_key;
205
+ }
206
+
207
+ $input_name = $payment_gateway->plugin_id . $payment_gateway->id . '_' . $text_key;
208
+ $gateway_option = $payment_gateway->plugin_id . $payment_gateway->id . '_settings';
209
+
210
+ $lang_selector = new WPML_Simple_Language_Selector( $this->sitepress );
211
+ $language = $this->gateway_setting_language( $setting_value, $payment_gateway->id, $text_key );
212
+
213
+ $lang_selector->render(
214
+ [
215
+ 'id' => $gateway_option . '_' . $text_key . '_language_selector',
216
+ 'name' => 'wcml_lang-' . $gateway_option . '-' . $text_key,
217
+ 'selected' => $language,
218
+ 'show_please_select' => false,
219
+ 'echo' => true,
220
+ 'style' => 'width: 18%;float: left;margin-top: 3px;',
221
+ ]
222
+ );
223
+
224
+ $st_page = admin_url( 'admin.php?page=' . WPML_ST_FOLDER . '/menu/string-translation.php&context=' . self::STRINGS_CONTEXT . '&search=' . esc_attr( preg_replace( "/[\n\r]/", '', $setting_value ) ) );
225
+ ?>
226
+ <script>
227
+ var input = jQuery('#<?php echo esc_js( $input_name ); ?>');
228
+ if ( input.length > 0 ) {
229
+ input.parent().append('<div class="translation_controls"></div>');
230
+ input.parent().find('.translation_controls').append('<a href="<?php echo $st_page; ?>" style="margin-left: 10px"><?php _e( 'translations', 'woocommerce-multilingual' ); ?></a>');
231
+ jQuery('#<?php echo $gateway_option . '_' . $text_key . '_language_selector'; ?>').prependTo( input.parent().find('.translation_controls') );
232
+ }else{
233
+ jQuery('#<?php echo $gateway_option . '_' . $text_key . '_language_selector'; ?>').remove();
234
+ }
235
+ </script>
236
+ <?php
237
+ }
238
+ }
239
+ }
240
+ }
241
 
242
+ private function gateway_setting_language( $setting_value, $gateway_id, $text_key ) {
 
 
 
 
243
 
244
+ if ( $this->get_gateway_string_id( $setting_value, $gateway_id, $text_key ) ) {
245
+ return $this->woocommerce_wpml->strings->get_string_language( $setting_value, self::STRINGS_CONTEXT, $gateway_id . '_gateway_' . $text_key );
246
+ } else {
247
+ return $this->sitepress->get_default_language();
248
+ }
249
 
250
+ }
 
 
251
 
252
+ private function get_gateway_string_id( $value, $gateway_id, $name ) {
253
+ return icl_get_string_id( $value, self::STRINGS_CONTEXT, $gateway_id . '_gateway_' . $name );
254
+ }
255
 
256
+ public function set_bacs_gateway_currency() {
257
+ foreach ( $_POST as $key => $value ) {
258
 
259
+ if ( '_enabled' === substr( $key, -8 ) ) {
260
+ $gateway = str_replace( '_enabled', '', $key );
261
+ }
262
+ }
263
 
264
+ if ( isset( $gateway ) ) {
265
+ if ( 'woocommerce_bacs' === $gateway && isset( $_POST['bacs-currency'] ) ) {
266
+ update_option( self::WCML_BACS_ACCOUNTS_CURRENCIES_OPTION, filter_var_array( $_POST['bacs-currency'], FILTER_SANITIZE_STRING ) );
267
+ }
268
+ }
269
 
270
+ }
271
 
272
+ public function get_gateway_text_keys_to_translate() {
273
 
274
+ $text_keys = [
275
+ 'title',
276
+ 'description',
277
+ 'instructions',
278
+ ];
279
 
280
+ return apply_filters( 'wcml_gateway_text_keys_to_translate', $text_keys );
281
+ }
282
 
283
  public function append_currency_selector_to_bacs_account_settings() {
284
 
285
+ $template_loader = new WPML_Twig_Template_Loader( [ $this->sitepress->get_wp_api()->constant( 'WCML_PLUGIN_PATH' ) . '/templates/multi-currency/' ] );
286
+ $currencies_dropdown_ui = new WCML_Currencies_Dropdown_UI( $template_loader );
287
 
288
  list( $default_dropdown, $currencies_output ) = $this->get_dropdown( $currencies_dropdown_ui );
289
 
290
+ wp_enqueue_script( 'wcml-bacs-accounts-currencies', WCML_PLUGIN_URL . '/res/js/bacs-accounts-currencies' . WCML_JS_MIN . '.js', [ 'jquery' ], WCML_VERSION, true );
291
+ wp_localize_script(
292
+ 'wcml-bacs-accounts-currencies',
293
+ 'wcml_data',
294
+ [
295
+ 'currencies_dropdown' => $currencies_output,
296
+ 'label' => __( 'Currency', 'woocommerce-multilingual' ),
297
+ 'default_dropdown' => $default_dropdown,
298
+ ]
299
+ );
300
  }
301
 
302
  /**
306
  */
307
  public function get_dropdown( $currencies_dropdown_ui ) {
308
 
309
+ $bacs_settings = get_option( 'woocommerce_bacs_accounts', [] );
310
  $active_currencies = $this->woocommerce_wpml->multi_currency->get_currency_codes();
311
  $default_currency = wcml_get_woocommerce_currency_option();
312
+ $bacs_accounts_currencies = get_option( self::WCML_BACS_ACCOUNTS_CURRENCIES_OPTION, [] );
313
+ $currencies_output = [];
314
 
315
  $default_dropdown = $currencies_dropdown_ui->get( $active_currencies, $default_currency );
316
 
317
  if ( $bacs_settings ) {
318
  foreach ( $bacs_settings as $id => $account_settings ) {
319
+ $currencies_output[ $id ] = isset( $bacs_accounts_currencies[ $id ] ) ? $currencies_dropdown_ui->get( $active_currencies, $bacs_accounts_currencies[ $id ] ) : $default_dropdown;
320
  }
321
  } else {
322
  $currencies_output[] = $default_dropdown;
323
  }
324
 
325
+ return [ $default_dropdown, $currencies_output ];
326
  }
327
+ }
 
inc/class-wcml-wc-shipping.php CHANGED
@@ -1,10 +1,10 @@
1
  <?php
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 */
@@ -13,126 +13,136 @@ class WCML_WC_Shipping{
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
 
33
- add_action('woocommerce_tax_rate_added', array($this, 'register_tax_rate_label_string'), 10, 2 );
34
- add_action('wp_ajax_woocommerce_shipping_zone_methods_save_settings', array( $this, 'save_shipping_zone_method_from_ajax'), 9 );
35
- add_action( 'icl_save_term_translation', array( $this, 'sync_class_costs_for_new_shipping_classes' ), 100, 2 );
36
- add_action( 'wp_ajax_woocommerce_shipping_zone_methods_save_settings', array( $this, 'update_woocommerce_shipping_settings_for_class_costs_from_ajax'), 9);
37
 
38
- add_filter('woocommerce_package_rates', array($this, 'translate_shipping_methods_in_package'));
39
- add_filter('woocommerce_rate_label',array($this,'translate_woocommerce_rate_label'));
40
- add_filter( 'pre_update_option_woocommerce_flat_rate_settings', array( $this, 'update_woocommerce_shipping_settings_for_class_costs' ) );
41
- add_filter( 'pre_update_option_woocommerce_international_delivery_settings', array( $this, 'update_woocommerce_shipping_settings_for_class_costs' ) );
42
- add_filter( 'woocommerce_shipping_flat_rate_instance_option', array( $this, 'get_original_shipping_class_rate' ), 10, 3 );
43
 
44
- $this->shipping_methods_filters();
45
- }
46
 
47
- function shipping_methods_filters(){
48
 
49
- $shipping_methods = WC()->shipping->get_shipping_methods();
50
 
51
- foreach ( $shipping_methods as $shipping_method ) {
52
 
53
- if ( isset( $shipping_method->id ) ) {
54
- $shipping_method_id = $shipping_method->id;
55
- } else {
56
- continue;
57
- }
58
 
59
- add_filter( 'woocommerce_shipping_' . $shipping_method_id . '_instance_settings_values', array(
60
- $this,
61
- 'register_zone_shipping_strings'
62
- ), 9, 2 );
63
- add_filter( 'option_woocommerce_' . $shipping_method_id . '_settings', array(
64
- $this,
65
- 'translate_shipping_strings'
66
- ), 9, 2 );
67
- }
68
- }
 
 
 
 
 
 
 
 
 
 
69
 
70
- function save_shipping_zone_method_from_ajax(){
71
- foreach( $_POST['data'] as $key => $value ){
72
- if( strstr( $key, '_title' ) ){
73
- $shipping_id = str_replace( 'woocommerce_', '', $key );
74
- $shipping_id = str_replace( '_title', '', $shipping_id );
75
- $this->register_shipping_title( $shipping_id.$_POST['instance_id'], $value );
76
- break;
77
- }
78
- }
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
 
86
- $instance_settings = $this->sync_flat_rate_class_cost( $object->get_post_data(), $instance_settings );
87
- }
88
 
89
- return $instance_settings;
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 ){
97
 
98
- if( $option && isset( $value['enabled']) && $value['enabled'] == 'no' ){
99
- return $value;
100
- }
101
 
102
- $shipping_id = str_replace( 'woocommerce_', '', $option );
103
- $shipping_id = str_replace( '_settings', '', $shipping_id );
104
 
105
- if( isset( $value['title'] ) ){
106
- $value['title'] = $this->translate_shipping_method_title( $value['title'], $shipping_id );
107
- }
108
 
109
- return $value;
110
- }
111
 
112
- function translate_shipping_methods_in_package( $available_methods ){
113
 
114
- foreach($available_methods as $key => $method){
115
  /**
116
  * @since 4.6.5
117
  */
118
- if( apply_filters( 'wcml_translate_shipping_method_in_package', true, $key, $method ) ){
119
- $available_methods[$key]->label = $this->translate_shipping_method_title( $method->label, $key );
120
- }
121
- }
122
-
123
- return apply_filters( 'wcml_translated_package_rates', $available_methods );
124
- }
125
-
126
- /**
127
- * @param string $title
128
- * @param string $shipping_id
129
- * @param string|bool $language
130
- *
131
- * @return string
132
- */
133
  public function translate_shipping_method_title( $title, $shipping_id, $language = false ) {
134
 
135
- if ( is_admin() && did_action( 'admin_init' ) && did_action( 'current_screen' ) ) {
136
  $screen = get_current_screen();
137
  $is_edit_order = $screen->id === 'shop_order';
138
  } else {
@@ -157,87 +167,83 @@ class WCML_WC_Shipping{
157
  return $title;
158
  }
159
 
160
- function translate_woocommerce_rate_label( $label ){
161
-
162
- $label = apply_filters( 'wpml_translate_single_string', $label, 'woocommerce taxes', $label );
163
-
164
- return $label;
165
- }
166
-
167
- function register_tax_rate_label_string( $id, $tax_rate ){
168
 
169
- if( !empty( $tax_rate['tax_rate_name'] ) ){
170
- do_action('wpml_register_single_string', 'woocommerce taxes', $tax_rate['tax_rate_name'] , $tax_rate['tax_rate_name'] );
171
- }
172
 
173
- }
174
-
175
- function sync_class_costs_for_new_shipping_classes( $original_tax, $result ){
176
- //update flat rate options for shipping classes
177
- if( $original_tax->taxonomy == 'product_shipping_class' ){
178
 
179
- $settings = get_option( 'woocommerce_flat_rate_settings' );
180
- if( is_array( $settings ) ){
181
- update_option( 'woocommerce_flat_rate_settings', $this->update_woocommerce_shipping_settings_for_class_costs( $settings ) );
182
- }
183
 
184
- $settings = get_option( 'woocommerce_international_delivery_settings' );
185
- if( is_array( $settings ) ){
186
- update_option( 'woocommerce_international_delivery_settings', $this->update_woocommerce_shipping_settings_for_class_costs( $settings ) );
187
- }
188
 
189
- }
190
- }
191
 
192
- public function update_woocommerce_shipping_settings_for_class_costs( $settings ){
193
- remove_filter( 'get_term', array( $this->sitepress, 'get_term_adjust_id' ), 1 );
194
- foreach( $settings as $setting_key => $value ){
195
 
196
- if( substr($setting_key, 0, 11) == 'class_cost_' ){
 
 
 
197
 
198
- $shipp_class_key = substr($setting_key, 11 );
 
 
 
 
 
199
 
200
- if( is_numeric( $shipp_class_key ) ){
201
- $shipp_class = get_term( $shipp_class_key, 'product_shipping_class' );
202
- }else{
203
- $shipp_class = get_term_by( 'slug', $shipp_class_key, 'product_shipping_class' );
204
- }
205
- $trid = $this->sitepress->get_element_trid( $shipp_class->term_taxonomy_id, 'tax_product_shipping_class' );
206
 
207
- $translations = $this->sitepress->get_element_translations( $trid, 'tax_product_shipping_class' );
208
 
209
- foreach( $translations as $translation ){
210
 
211
- $tr_shipp_class = get_term_by( 'term_taxonomy_id', $translation->element_id, 'product_shipping_class' );
 
 
 
 
 
212
 
213
- if( is_numeric( $shipp_class_key ) ){
214
- $settings[ 'class_cost_'.$tr_shipp_class->term_id ] = $value;
215
- }else{
216
- $settings[ 'class_cost_'.$tr_shipp_class->slug ] = $value;
217
- }
218
 
219
- }
220
 
221
- }
222
 
223
- }
224
- add_filter( 'get_term', array( $this->sitepress, 'get_term_adjust_id' ), 1 );
 
 
 
 
 
 
 
225
 
226
- return $settings;
227
- }
228
 
229
- function update_woocommerce_shipping_settings_for_class_costs_from_ajax(){
230
 
231
- if (isset($_POST['data']['woocommerce_flat_rate_type']) && $_POST['data']['woocommerce_flat_rate_type'] == 'class') {
232
 
233
- $flat_rate_setting_id = 'woocommerce_flat_rate_' . $_POST['data']['instance_id'] . '_settings';
234
- $settings = get_option( $flat_rate_setting_id, true );
235
 
236
- $settings = $this->sync_flat_rate_class_cost( $_POST['data'], $settings );
237
 
238
- update_option($flat_rate_setting_id, $settings);
239
- }
240
- }
241
 
242
  /**
243
  * @param array $data
@@ -245,35 +251,35 @@ class WCML_WC_Shipping{
245
  *
246
  * @return array|mixed
247
  */
248
- public function sync_flat_rate_class_cost( $data, $inst_settings ){
249
 
250
- $settings = array();
251
- foreach ( $data as $key => $value ) {
252
- if ( 0 === strpos( $key, 'woocommerce_flat_rate_class_cost_') ) {
253
- $limit = strlen( 'woocommerce_flat_rate_' );
254
- $settings[ substr( $key, $limit ) ] = stripslashes( $value );
255
- }
256
- }
257
 
258
- $updated_costs_settings = $this->update_woocommerce_shipping_settings_for_class_costs( $settings );
259
 
260
- $inst_settings = is_array( $inst_settings ) ? array_merge( $inst_settings, $updated_costs_settings ) : $updated_costs_settings;
261
 
262
- return $inst_settings;
263
- }
264
 
265
  /**
266
- * @param string $rate
267
- * @param string $class_name
268
  * @param WC_Shipping_Method $shipping_method
269
  *
270
  * @return string
271
  */
272
- public function get_original_shipping_class_rate( $rate, $class_name, $shipping_method ){
273
- if( !$rate && 'class_cost_' === substr( $class_name, 0, 11 ) ){
274
  $original_class_id = $this->sitepress->term_translations()->get_original_element( substr( $class_name, 11 ) );
275
- if( $original_class_id && isset( $shipping_method->instance_settings[ 'class_cost_'.$original_class_id ] ) ){
276
- return $shipping_method->instance_settings[ 'class_cost_'.$original_class_id ];
277
  }
278
  }
279
 
1
  <?php
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 */
13
  /**
14
  * WCML_WC_Shipping constructor.
15
  *
16
+ * @param SitePress $sitepress
17
  * @param WCML_WC_Strings $wcmlStrings
18
  */
19
+ public 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
+ public function add_hooks() {
32
 
33
+ add_action( 'woocommerce_tax_rate_added', [ $this, 'register_tax_rate_label_string' ], 10, 2 );
34
+ add_action( 'wp_ajax_woocommerce_shipping_zone_methods_save_settings', [ $this, 'save_shipping_zone_method_from_ajax' ], 9 );
35
+ add_action( 'icl_save_term_translation', [ $this, 'sync_class_costs_for_new_shipping_classes' ], 100, 2 );
36
+ add_action( 'wp_ajax_woocommerce_shipping_zone_methods_save_settings', [ $this, 'update_woocommerce_shipping_settings_for_class_costs_from_ajax' ], 9 );
37
 
38
+ add_filter( 'woocommerce_package_rates', [ $this, 'translate_shipping_methods_in_package' ] );
39
+ add_filter( 'woocommerce_rate_label', [ $this, 'translate_woocommerce_rate_label' ] );
40
+ add_filter( 'pre_update_option_woocommerce_flat_rate_settings', [ $this, 'update_woocommerce_shipping_settings_for_class_costs' ] );
41
+ add_filter( 'pre_update_option_woocommerce_international_delivery_settings', [ $this, 'update_woocommerce_shipping_settings_for_class_costs' ] );
42
+ add_filter( 'woocommerce_shipping_flat_rate_instance_option', [ $this, 'get_original_shipping_class_rate' ], 10, 3 );
43
 
44
+ $this->shipping_methods_filters();
45
+ }
46
 
47
+ public function shipping_methods_filters() {
48
 
49
+ $shipping_methods = WC()->shipping->get_shipping_methods();
50
 
51
+ foreach ( $shipping_methods as $shipping_method ) {
52
 
53
+ if ( isset( $shipping_method->id ) ) {
54
+ $shipping_method_id = $shipping_method->id;
55
+ } else {
56
+ continue;
57
+ }
58
 
59
+ add_filter(
60
+ 'woocommerce_shipping_' . $shipping_method_id . '_instance_settings_values',
61
+ [
62
+ $this,
63
+ 'register_zone_shipping_strings',
64
+ ],
65
+ 9,
66
+ 2
67
+ );
68
+ add_filter(
69
+ 'option_woocommerce_' . $shipping_method_id . '_settings',
70
+ [
71
+ $this,
72
+ 'translate_shipping_strings',
73
+ ],
74
+ 9,
75
+ 2
76
+ );
77
+ }
78
+ }
79
 
80
+ public function save_shipping_zone_method_from_ajax() {
81
+ foreach ( $_POST['data'] as $key => $value ) {
82
+ if ( strstr( $key, '_title' ) ) {
83
+ $shipping_id = str_replace( 'woocommerce_', '', $key );
84
+ $shipping_id = str_replace( '_title', '', $shipping_id );
85
+ $this->register_shipping_title( $shipping_id . $_POST['instance_id'], $value );
86
+ break;
87
+ }
88
+ }
89
+ }
90
 
91
+ public function register_zone_shipping_strings( $instance_settings, $object ) {
92
 
93
+ if ( ! empty( $instance_settings['title'] ) ) {
94
+ $this->register_shipping_title( $object->id . $object->instance_id, $instance_settings['title'] );
95
 
96
+ $instance_settings = $this->sync_flat_rate_class_cost( $object->get_post_data(), $instance_settings );
97
+ }
98
 
99
+ return $instance_settings;
100
+ }
101
 
102
+ public function register_shipping_title( $shipping_method_id, $title ) {
103
+ do_action( 'wpml_register_single_string', self::STRINGS_CONTEXT, $shipping_method_id . '_shipping_method_title', $title );
104
+ }
105
 
106
+ public function translate_shipping_strings( $value, $option = false ) {
107
 
108
+ if ( $option && isset( $value['enabled'] ) && $value['enabled'] == 'no' ) {
109
+ return $value;
110
+ }
111
 
112
+ $shipping_id = str_replace( 'woocommerce_', '', $option );
113
+ $shipping_id = str_replace( '_settings', '', $shipping_id );
114
 
115
+ if ( isset( $value['title'] ) ) {
116
+ $value['title'] = $this->translate_shipping_method_title( $value['title'], $shipping_id );
117
+ }
118
 
119
+ return $value;
120
+ }
121
 
122
+ public function translate_shipping_methods_in_package( $available_methods ) {
123
 
124
+ foreach ( $available_methods as $key => $method ) {
125
  /**
126
  * @since 4.6.5
127
  */
128
+ if ( apply_filters( 'wcml_translate_shipping_method_in_package', true, $key, $method ) ) {
129
+ $available_methods[ $key ]->label = $this->translate_shipping_method_title( $method->label, $key );
130
+ }
131
+ }
132
+
133
+ return apply_filters( 'wcml_translated_package_rates', $available_methods );
134
+ }
135
+
136
+ /**
137
+ * @param string $title
138
+ * @param string $shipping_id
139
+ * @param string|bool $language
140
+ *
141
+ * @return string
142
+ */
143
  public function translate_shipping_method_title( $title, $shipping_id, $language = false ) {
144
 
145
+ if ( is_admin() && did_action( 'admin_init' ) && did_action( 'current_screen' ) ) {
146
  $screen = get_current_screen();
147
  $is_edit_order = $screen->id === 'shop_order';
148
  } else {
167
  return $title;
168
  }
169
 
170
+ public function translate_woocommerce_rate_label( $label ) {
 
 
 
 
 
 
 
171
 
172
+ $label = apply_filters( 'wpml_translate_single_string', $label, 'woocommerce taxes', $label );
 
 
173
 
174
+ return $label;
175
+ }
 
 
 
176
 
177
+ public function register_tax_rate_label_string( $id, $tax_rate ) {
 
 
 
178
 
179
+ if ( ! empty( $tax_rate['tax_rate_name'] ) ) {
180
+ do_action( 'wpml_register_single_string', 'woocommerce taxes', $tax_rate['tax_rate_name'], $tax_rate['tax_rate_name'] );
181
+ }
 
182
 
183
+ }
 
184
 
185
+ public function sync_class_costs_for_new_shipping_classes( $original_tax, $result ) {
186
+ // update flat rate options for shipping classes.
187
+ if ( $original_tax->taxonomy == 'product_shipping_class' ) {
188
 
189
+ $settings = get_option( 'woocommerce_flat_rate_settings' );
190
+ if ( is_array( $settings ) ) {
191
+ update_option( 'woocommerce_flat_rate_settings', $this->update_woocommerce_shipping_settings_for_class_costs( $settings ) );
192
+ }
193
 
194
+ $settings = get_option( 'woocommerce_international_delivery_settings' );
195
+ if ( is_array( $settings ) ) {
196
+ update_option( 'woocommerce_international_delivery_settings', $this->update_woocommerce_shipping_settings_for_class_costs( $settings ) );
197
+ }
198
+ }
199
+ }
200
 
201
+ public function update_woocommerce_shipping_settings_for_class_costs( $settings ) {
202
+ remove_filter( 'get_term', [ $this->sitepress, 'get_term_adjust_id' ], 1 );
203
+ foreach ( $settings as $setting_key => $value ) {
 
 
 
204
 
205
+ if ( substr( $setting_key, 0, 11 ) == 'class_cost_' ) {
206
 
207
+ $shipp_class_key = substr( $setting_key, 11 );
208
 
209
+ if ( is_numeric( $shipp_class_key ) ) {
210
+ $shipp_class = get_term( $shipp_class_key, 'product_shipping_class' );
211
+ } else {
212
+ $shipp_class = get_term_by( 'slug', $shipp_class_key, 'product_shipping_class' );
213
+ }
214
+ $trid = $this->sitepress->get_element_trid( $shipp_class->term_taxonomy_id, 'tax_product_shipping_class' );
215
 
216
+ $translations = $this->sitepress->get_element_translations( $trid, 'tax_product_shipping_class' );
 
 
 
 
217
 
218
+ foreach ( $translations as $translation ) {
219
 
220
+ $tr_shipp_class = get_term_by( 'term_taxonomy_id', $translation->element_id, 'product_shipping_class' );
221
 
222
+ if ( is_numeric( $shipp_class_key ) ) {
223
+ $settings[ 'class_cost_' . $tr_shipp_class->term_id ] = $value;
224
+ } else {
225
+ $settings[ 'class_cost_' . $tr_shipp_class->slug ] = $value;
226
+ }
227
+ }
228
+ }
229
+ }
230
+ add_filter( 'get_term', [ $this->sitepress, 'get_term_adjust_id' ], 1 );
231
 
232
+ return $settings;
233
+ }
234
 
235
+ public function update_woocommerce_shipping_settings_for_class_costs_from_ajax() {
236
 
237
+ if ( isset( $_POST['data']['woocommerce_flat_rate_type'] ) && $_POST['data']['woocommerce_flat_rate_type'] == 'class' ) {
238
 
239
+ $flat_rate_setting_id = 'woocommerce_flat_rate_' . $_POST['data']['instance_id'] . '_settings';
240
+ $settings = get_option( $flat_rate_setting_id, true );
241
 
242
+ $settings = $this->sync_flat_rate_class_cost( $_POST['data'], $settings );
243
 
244
+ update_option( $flat_rate_setting_id, $settings );
245
+ }
246
+ }
247
 
248
  /**
249
  * @param array $data
251
  *
252
  * @return array|mixed
253
  */
254
+ public function sync_flat_rate_class_cost( $data, $inst_settings ) {
255
 
256
+ $settings = [];
257
+ foreach ( $data as $key => $value ) {
258
+ if ( 0 === strpos( $key, 'woocommerce_flat_rate_class_cost_' ) ) {
259
+ $limit = strlen( 'woocommerce_flat_rate_' );
260
+ $settings[ substr( $key, $limit ) ] = stripslashes( $value );
261
+ }
262
+ }
263
 
264
+ $updated_costs_settings = $this->update_woocommerce_shipping_settings_for_class_costs( $settings );
265
 
266
+ $inst_settings = is_array( $inst_settings ) ? array_merge( $inst_settings, $updated_costs_settings ) : $updated_costs_settings;
267
 
268
+ return $inst_settings;
269
+ }
270
 
271
  /**
272
+ * @param string $rate
273
+ * @param string $class_name
274
  * @param WC_Shipping_Method $shipping_method
275
  *
276
  * @return string
277
  */
278
+ public function get_original_shipping_class_rate( $rate, $class_name, $shipping_method ) {
279
+ if ( ! $rate && 'class_cost_' === substr( $class_name, 0, 11 ) ) {
280
  $original_class_id = $this->sitepress->term_translations()->get_original_element( substr( $class_name, 11 ) );
281
+ if ( $original_class_id && isset( $shipping_method->instance_settings[ 'class_cost_' . $original_class_id ] ) ) {
282
+ return $shipping_method->instance_settings[ 'class_cost_' . $original_class_id ];
283
  }
284
  }
285
 
inc/class-wcml-wc-strings.php CHANGED
@@ -2,8 +2,8 @@
2
 
3
  class WCML_WC_Strings {
4
 
5
- private $translations_from_mo_file = array();
6
- private $mo_files = array();
7
  private $current_language;
8
 
9
  /** @var woocommerce_wpml */
@@ -13,14 +13,14 @@ class WCML_WC_Strings {
13
  /** @var wpdb */
14
  private $wpdb;
15
 
16
- public $settings = array();
17
 
18
  /**
19
  * WCML_WC_Strings constructor.
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;
@@ -28,55 +28,61 @@ class WCML_WC_Strings {
28
  $this->wpdb = $wpdb;
29
  }
30
 
31
- function add_hooks() {
32
 
33
- add_action( 'init', array( $this, 'add_on_init_hooks' ) );
34
- add_action( 'registered_taxonomy', array( $this, 'translate_attributes_label_in_wp_taxonomies' ), 100, 3 );
35
  }
36
 
37
- function add_on_init_hooks() {
38
  global $pagenow;
39
 
40
  $this->current_language = $this->sitepress->get_current_language();
41
- if ( $this->current_language == 'all' ) {
42
  $this->current_language = $this->sitepress->get_default_language();
43
  }
44
 
45
- //translate attribute label
46
- add_filter( 'woocommerce_attribute_label', array( $this, 'translated_attribute_label' ), 10, 3 );
47
- add_filter( 'woocommerce_checkout_product_title', array( $this, 'translated_checkout_product_title' ), 10, 2 );
48
- add_filter( 'woocommerce_cart_item_name', array( $this, 'translated_cart_item_name' ), -1, 2 );
49
 
50
  if ( is_admin() ) {
51
 
52
  if ( 'edit.php' !== $pagenow && ! wpml_is_ajax() ) {
53
- add_filter( 'woocommerce_attribute_taxonomies', array(
54
- $this,
55
- 'translate_attribute_taxonomies_labels'
56
- ) );
 
 
 
57
  }
58
  if ( 'options-permalink.php' === $pagenow ) {
59
- add_filter( 'gettext_with_context', array( $this, 'category_base_in_strings_language' ), 99, 3 );
60
- add_action( 'admin_footer', array( $this, 'show_custom_url_base_translation_links' ) );
61
- add_action( 'admin_footer', array( $this, 'show_custom_url_base_language_requirement' ) );
62
  }
63
  }
64
 
65
- add_action( 'woocommerce_product_options_attributes', array(
66
- $this,
67
- 'notice_after_woocommerce_product_options_attributes'
68
- ) );
 
 
 
69
 
70
- add_filter( 'woocommerce_get_breadcrumb', array( $this, 'filter_woocommerce_breadcrumbs' ), 10, 2 );
71
  }
72
 
73
- function translated_attribute_label( $label, $name, $product_obj = false ) {
74
  global $product, $sitepress_settings;
75
 
76
  $product_id = false;
77
  $lang = $this->sitepress->get_current_language();
78
 
79
- if ( isset( $_GET['post'] ) && get_post_type( $_GET['post'] ) == 'shop_order' ) {
80
  $lang = $this->sitepress->get_user_admin_language( get_current_user_id(), true );
81
  }
82
 
@@ -99,7 +105,6 @@ class WCML_WC_Strings {
99
  return $custom_attr_translation[ $name ];
100
  }
101
  }
102
-
103
  }
104
 
105
  $trnsl_label = apply_filters( 'wpml_translate_single_string', $label, 'WordPress', 'taxonomy singular name: ' . $label, $lang );
@@ -121,10 +126,9 @@ class WCML_WC_Strings {
121
  } else {
122
  return $label;
123
  }
124
-
125
  }
126
 
127
- // backward compatibility for WCML < 3.6.1
128
  $trnsl_labels = get_option( 'wcml_custom_attr_translations' );
129
 
130
  if ( isset( $trnsl_labels[ $lang ][ $name ] ) && ! empty( $trnsl_labels[ $lang ][ $name ] ) ) {
@@ -136,11 +140,11 @@ class WCML_WC_Strings {
136
 
137
  /**
138
  * @param string $title
139
- * @param array $values
140
  *
141
  * @return string
142
  */
143
- function translated_cart_item_name( $title, array $values ) {
144
 
145
  if ( $values ) {
146
 
@@ -159,7 +163,7 @@ class WCML_WC_Strings {
159
  return $title;
160
  }
161
 
162
- function translated_checkout_product_title( $title, $product ) {
163
 
164
  if ( $product ) {
165
  $tr_product_id = apply_filters( 'translate_object_id', $product->get_id(), 'product', true, $this->current_language );
@@ -169,10 +173,10 @@ class WCML_WC_Strings {
169
  return $title;
170
  }
171
 
172
- // Catch the default slugs for translation
173
- function translate_default_slug( $translation, $text, $context, $domain ) {
174
 
175
- if ( $context == 'slug' || $context == 'default-slug' ) {
176
  $wc_slug = $this->woocommerce_wpml->url_translation->get_woocommerce_product_base();
177
  if ( is_admin() ) {
178
  $admin_language = $this->sitepress->get_admin_language();
@@ -181,7 +185,7 @@ class WCML_WC_Strings {
181
 
182
  $strings_language = $this->get_domain_language( 'woocommerce' );
183
 
184
- if ( $text == $wc_slug && $domain == 'woocommerce' && $strings_language ) {
185
  $this->sitepress->switch_lang( $strings_language );
186
  $translation = _x( $text, 'URL slug', $domain );
187
  $this->sitepress->switch_lang( $current_language );
@@ -202,34 +206,37 @@ class WCML_WC_Strings {
202
  }
203
 
204
 
205
- function show_custom_url_base_language_requirement() {
206
  $category_base = ( $c = get_option( 'category_base' ) ) ? $c : 'category';
207
  ?>
208
- <script>
209
- if (jQuery('#woocommerce_permalink_structure').length) {
210
- jQuery('#woocommerce_permalink_structure').parent().append(jQuery('#wpml_wcml_custom_base_req').html());
211
- }
212
- if (jQuery('input[name="woocommerce_product_category_slug"]').length && jQuery('input[name="woocommerce_product_category_slug"]').val() == '<?php echo $category_base ?>') {
213
- jQuery('input[name="woocommerce_product_category_slug"]').parent().append('<br><i class="icon-warning-sign"><?php
214
- _e( 'You are using the same value as for the regular category base. This is known to create conflicts resulting in urls not working properly.', 'woocommerce-multilingual' ) ?></i>');
215
- }
216
- </script>
 
 
 
217
  <?php
218
 
219
  }
220
 
221
- function show_custom_url_base_translation_links() {
222
 
223
  $permalink_options = get_option( 'woocommerce_permalinks' );
224
 
225
  $lang_selector = new WPML_Simple_Language_Selector( $this->sitepress );
226
 
227
- $bases = array(
228
  'tag_base' => 'product_tag',
229
  'category_base' => 'product_cat',
230
  'attribute_base' => 'attribute',
231
- 'product_base' => 'product'
232
- );
233
 
234
  foreach ( $bases as $key => $base ) {
235
 
@@ -263,57 +270,63 @@ class WCML_WC_Strings {
263
  $language = $this->sitepress->get_default_language();
264
  }
265
 
266
- echo $lang_selector->render( array(
267
- 'id' => $key . '_language_selector',
268
- 'name' => $key . '_language',
269
- 'selected' => $language,
270
- 'show_please_select' => false
271
- ) ); ?>
 
 
 
272
 
273
- <script>
274
- var input = jQuery('input[name="<?php echo $input_name ?>"]');
275
 
276
- if (input.length) {
277
 
278
- if ('<?php echo $input_name ?>' == 'product_permalink_structure' && jQuery('input[name="product_permalink"]:checked').val() == '') {
279
- input = jQuery('input[name="product_permalink"]:checked').closest('.form-table').find('code').eq(0);
280
- }
281
 
282
- input.parent().append('<div class="translation_controls"></div>');
283
 
284
- if ('<?php echo $input_name ?>' == 'woocommerce_product_attribute_slug' && input.val() == '') {
285
 
286
- input.parent().find('.translation_controls').append('&nbsp;');
287
 
288
- } else {
289
- input.parent().find('.translation_controls').append('<a href="<?php
 
290
  echo admin_url( 'admin.php?page=wpml-wcml&tab=slugs' )
291
- ?>"><?php _e( 'translations', 'woocommerce-multilingual' ) ?></a>');
292
- }
 
293
 
294
- jQuery('#<?php echo $key ?>_language_selector').prependTo(input.parent().find('.translation_controls'));
295
- }
296
- </script>
297
- <?php }
 
298
 
299
  }
300
 
301
- function category_base_in_strings_language( $text, $original_value, $context ) {
302
- if ( $context == 'slug' && ( $original_value == 'product-category' || $original_value == 'product-tag' ) ) {
303
  $text = $original_value;
304
  }
305
 
306
  return $text;
307
  }
308
 
309
- function product_permalink_slug() {
310
  $permalinks = get_option( 'woocommerce_permalinks' );
311
  $slug = empty( $permalinks['product_base'] ) ? 'product' : trim( $permalinks['product_base'], '/' );
312
 
313
  return $slug;
314
  }
315
 
316
- function get_domain_language( $domain ) {
317
 
318
  $lang_of_domain = new WPML_Language_Of_Domain( $this->sitepress );
319
  $domain_lang = $lang_of_domain->get_language( $domain );
@@ -327,7 +340,7 @@ class WCML_WC_Strings {
327
  return $source_lang;
328
  }
329
 
330
- function get_string_language( $value, $context, $name = false ) {
331
 
332
  if ( $name !== false ) {
333
 
@@ -341,7 +354,7 @@ class WCML_WC_Strings {
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
  }
@@ -354,7 +367,7 @@ class WCML_WC_Strings {
354
 
355
  }
356
 
357
- function set_string_language( $value, $context, $name, $language ) {
358
 
359
  $string_id = icl_get_string_id( $value, $context, $name );
360
 
@@ -369,7 +382,7 @@ class WCML_WC_Strings {
369
  * Filter breadcrumbs
370
  *
371
  */
372
- function filter_woocommerce_breadcrumbs( $breadcrumbs, $object ) {
373
 
374
  $current_language = $this->sitepress->get_current_language();
375
  $default_language = $this->sitepress->get_default_language();
@@ -384,7 +397,7 @@ class WCML_WC_Strings {
384
 
385
  $shop_page = get_post( $woocommerce_shop_page );
386
 
387
- // If permalinks contain the shop page in the URI prepend the breadcrumb with shop
388
  // Similar to WC_Breadcrumb::prepend_shop_page
389
  $trnsl_base = $this->woocommerce_wpml->url_translation->get_base_translation( 'product', $current_language );
390
  if ( $trnsl_base['translated_base'] === '' ) {
@@ -392,12 +405,12 @@ class WCML_WC_Strings {
392
  }
393
 
394
  if ( is_woocommerce() && $shop_page->ID && strstr( $trnsl_base['translated_base'], urldecode( $shop_page->post_name ) ) && get_option( 'page_on_front' ) != $shop_page->ID ) {
395
- $breadcrumbs_buff = array();
396
  $i = 0;
397
 
398
  foreach ( $breadcrumbs as $key => $breadcrumb ) {
399
 
400
- //Prepend the shop page to shop breadcrumbs
401
  if ( $key === 0 ) {
402
 
403
  if ( $breadcrumbs[1][1] != get_post_type_archive_link( 'product' ) ) {
@@ -407,10 +420,10 @@ class WCML_WC_Strings {
407
  $i ++;
408
  }
409
 
410
- $breadcrumbs_buff[ $i ] = array(
411
  $shop_page->post_title,
412
- get_post_type_archive_link( 'product' )
413
- );
414
  $i ++;
415
  }
416
  }
@@ -425,7 +438,6 @@ class WCML_WC_Strings {
425
 
426
  $breadcrumbs = array_values( $breadcrumbs );
427
  }
428
-
429
  }
430
  }
431
 
@@ -435,7 +447,7 @@ class WCML_WC_Strings {
435
  /*
436
  * Add notice message to users
437
  */
438
- function notice_after_woocommerce_product_options_attributes() {
439
 
440
  if ( isset( $_GET['post'] ) && $this->sitepress->get_default_language() != $this->sitepress->get_current_language() ) {
441
  $original_product_id = apply_filters( 'translate_object_id', $_GET['post'], 'product', true, $this->sitepress->get_default_language() );
@@ -444,7 +456,7 @@ class WCML_WC_Strings {
444
  }
445
  }
446
 
447
- function translate_attribute_taxonomies_labels( $attribute_taxonomies ) {
448
 
449
  foreach ( $attribute_taxonomies as $key => $attribute_taxonomy ) {
450
  $string_language = $this->get_string_language( $attribute_taxonomy->attribute_label, 'WordPress', 'taxonomy singular name: ' . $attribute_taxonomy->attribute_label );
@@ -464,14 +476,14 @@ class WCML_WC_Strings {
464
  return $attribute_taxonomies;
465
  }
466
 
467
- function get_translation_from_woocommerce_mo_file( $string, $language, $return_original = true ) {
468
 
469
  $original_string = $string;
470
 
471
  if ( ! isset( $this->translations_from_mo_file[ $original_string ][ $language ] ) ) {
472
 
473
  if ( ! isset( $this->translations_from_mo_file[ $original_string ] ) ) {
474
- $this->translations_from_mo_file[ $original_string ] = array();
475
  }
476
 
477
  if ( ! isset( $this->mo_files[ $language ] ) ) {
@@ -485,7 +497,7 @@ class WCML_WC_Strings {
485
  $this->mo_files[ $language ] = $mo->entries;
486
  }
487
 
488
- if ( in_array( $string, array( 'product', 'product-category', 'product-tag' ) ) ) {
489
  $string = 'slug' . chr( 4 ) . $string;
490
  }
491
 
@@ -500,7 +512,7 @@ class WCML_WC_Strings {
500
 
501
  }
502
 
503
- function translate_attributes_label_in_wp_taxonomies( $taxonomy, $obj_type, $args ) {
504
  global $wp_taxonomies;
505
  $obj_type = array_unique( (array) $obj_type );
506
 
@@ -516,7 +528,6 @@ class WCML_WC_Strings {
516
 
517
  $wp_taxonomies[ $taxonomy ]->labels->name = apply_filters( 'wpml_translate_single_string', $name, 'WordPress', 'taxonomy singular name: ' . $name, $current_language );
518
 
519
-
520
  }
521
 
522
  }
@@ -528,8 +539,8 @@ class WCML_WC_Strings {
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
- }
2
 
3
  class WCML_WC_Strings {
4
 
5
+ private $translations_from_mo_file = [];
6
+ private $mo_files = [];
7
  private $current_language;
8
 
9
  /** @var woocommerce_wpml */
13
  /** @var wpdb */
14
  private $wpdb;
15
 
16
+ public $settings = [];
17
 
18
  /**
19
  * WCML_WC_Strings constructor.
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;
28
  $this->wpdb = $wpdb;
29
  }
30
 
31
+ public function add_hooks() {
32
 
33
+ add_action( 'init', [ $this, 'add_on_init_hooks' ] );
34
+ add_action( 'registered_taxonomy', [ $this, 'translate_attributes_label_in_wp_taxonomies' ], 100, 3 );
35
  }
36
 
37
+ public function add_on_init_hooks() {
38
  global $pagenow;
39
 
40
  $this->current_language = $this->sitepress->get_current_language();
41
+ if ( 'all' === $this->current_language ) {
42
  $this->current_language = $this->sitepress->get_default_language();
43
  }
44
 
45
+ // translate attribute label.
46
+ add_filter( 'woocommerce_attribute_label', [ $this, 'translated_attribute_label' ], 10, 3 );
47
+ add_filter( 'woocommerce_checkout_product_title', [ $this, 'translated_checkout_product_title' ], 10, 2 );
48
+ add_filter( 'woocommerce_cart_item_name', [ $this, 'translated_cart_item_name' ], -1, 2 );
49
 
50
  if ( is_admin() ) {
51
 
52
  if ( 'edit.php' !== $pagenow && ! wpml_is_ajax() ) {
53
+ add_filter(
54
+ 'woocommerce_attribute_taxonomies',
55
+ [
56
+ $this,
57
+ 'translate_attribute_taxonomies_labels',
58
+ ]
59
+ );
60
  }
61
  if ( 'options-permalink.php' === $pagenow ) {
62
+ add_filter( 'gettext_with_context', [ $this, 'category_base_in_strings_language' ], 99, 3 );
63
+ add_action( 'admin_footer', [ $this, 'show_custom_url_base_translation_links' ] );
64
+ add_action( 'admin_footer', [ $this, 'show_custom_url_base_language_requirement' ] );
65
  }
66
  }
67
 
68
+ add_action(
69
+ 'woocommerce_product_options_attributes',
70
+ [
71
+ $this,
72
+ 'notice_after_woocommerce_product_options_attributes',
73
+ ]
74
+ );
75
 
76
+ add_filter( 'woocommerce_get_breadcrumb', [ $this, 'filter_woocommerce_breadcrumbs' ], 10, 2 );
77
  }
78
 
79
+ public function translated_attribute_label( $label, $name, $product_obj = false ) {
80
  global $product, $sitepress_settings;
81
 
82
  $product_id = false;
83
  $lang = $this->sitepress->get_current_language();
84
 
85
+ if ( isset( $_GET['post'] ) && 'shop_order' === get_post_type( $_GET['post'] ) ) {
86
  $lang = $this->sitepress->get_user_admin_language( get_current_user_id(), true );
87
  }
88
 
105
  return $custom_attr_translation[ $name ];
106
  }
107
  }
 
108
  }
109
 
110
  $trnsl_label = apply_filters( 'wpml_translate_single_string', $label, 'WordPress', 'taxonomy singular name: ' . $label, $lang );
126
  } else {
127
  return $label;
128
  }
 
129
  }
130
 
131
+ // backward compatibility for WCML < 3.6.1.
132
  $trnsl_labels = get_option( 'wcml_custom_attr_translations' );
133
 
134
  if ( isset( $trnsl_labels[ $lang ][ $name ] ) && ! empty( $trnsl_labels[ $lang ][ $name ] ) ) {
140
 
141
  /**
142
  * @param string $title
143
+ * @param array $values
144
  *
145
  * @return string
146
  */
147
+ public function translated_cart_item_name( $title, array $values ) {
148
 
149
  if ( $values ) {
150
 
163
  return $title;
164
  }
165
 
166
+ public function translated_checkout_product_title( $title, $product ) {
167
 
168
  if ( $product ) {
169
  $tr_product_id = apply_filters( 'translate_object_id', $product->get_id(), 'product', true, $this->current_language );
173
  return $title;
174
  }
175
 
176
+ // Catch the default slugs for translation.
177
+ public function translate_default_slug( $translation, $text, $context, $domain ) {
178
 
179
+ if ( 'slug' === $context || 'default-slug' === $context ) {
180
  $wc_slug = $this->woocommerce_wpml->url_translation->get_woocommerce_product_base();
181
  if ( is_admin() ) {
182
  $admin_language = $this->sitepress->get_admin_language();
185
 
186
  $strings_language = $this->get_domain_language( 'woocommerce' );
187
 
188
+ if ( $text == $wc_slug && 'woocommerce' === $domain && $strings_language ) {
189
  $this->sitepress->switch_lang( $strings_language );
190
  $translation = _x( $text, 'URL slug', $domain );
191
  $this->sitepress->switch_lang( $current_language );
206
  }
207
 
208
 
209
+ public function show_custom_url_base_language_requirement() {
210
  $category_base = ( $c = get_option( 'category_base' ) ) ? $c : 'category';
211
  ?>
212
+ <script>
213
+ if (jQuery('#woocommerce_permalink_structure').length) {
214
+ jQuery('#woocommerce_permalink_structure').parent().append(jQuery('#wpml_wcml_custom_base_req').html());
215
+ }
216
+ if (jQuery('input[name="woocommerce_product_category_slug"]').length && jQuery('input[name="woocommerce_product_category_slug"]').val() == '<?php echo $category_base; ?>') {
217
+ jQuery('input[name="woocommerce_product_category_slug"]').parent().append('<br><i class="icon-warning-sign">
218
+ <?php
219
+ _e( 'You are using the same value as for the regular category base. This is known to create conflicts resulting in urls not working properly.', 'woocommerce-multilingual' )
220
+ ?>
221
+ </i>');
222
+ }
223
+ </script>
224
  <?php
225
 
226
  }
227
 
228
+ public function show_custom_url_base_translation_links() {
229
 
230
  $permalink_options = get_option( 'woocommerce_permalinks' );
231
 
232
  $lang_selector = new WPML_Simple_Language_Selector( $this->sitepress );
233
 
234
+ $bases = [
235
  'tag_base' => 'product_tag',
236
  'category_base' => 'product_cat',
237
  'attribute_base' => 'attribute',
238
+ 'product_base' => 'product',
239
+ ];
240
 
241
  foreach ( $bases as $key => $base ) {
242
 
270
  $language = $this->sitepress->get_default_language();
271
  }
272
 
273
+ echo $lang_selector->render(
274
+ [
275
+ 'id' => $key . '_language_selector',
276
+ 'name' => $key . '_language',
277
+ 'selected' => $language,
278
+ 'show_please_select' => false,
279
+ ]
280
+ );
281
+ ?>
282
 
283
+ <script>
284
+ var input = jQuery('input[name="<?php echo $input_name; ?>"]');
285
 
286
+ if (input.length) {
287
 
288
+ if ('<?php echo $input_name; ?>'==='product_permalink_structure' && jQuery('input[name="product_permalink"]:checked').val() == '') {
289
+ input = jQuery('input[name="product_permalink"]:checked').closest('.form-table').find('code').eq(0);
290
+ }
291
 
292
+ input.parent().append('<div class="translation_controls"></div>');
293
 
294
+ if ('<?php echo $input_name; ?>'==='woocommerce_product_attribute_slug' && input.val() == '') {
295
 
296
+ input.parent().find('.translation_controls').append('&nbsp;');
297
 
298
+ } else {
299
+ input.parent().find('.translation_controls').append('<a href="
300
+ <?php
301
  echo admin_url( 'admin.php?page=wpml-wcml&tab=slugs' )
302
+ ?>
303
+ "><?php _e( 'translations', 'woocommerce-multilingual' ); ?></a>');
304
+ }
305
 
306
+ jQuery('#<?php echo $key; ?>_language_selector').prependTo(input.parent().find('.translation_controls'));
307
+ }
308
+ </script>
309
+ <?php
310
+ }
311
 
312
  }
313
 
314
+ public function category_base_in_strings_language( $text, $original_value, $context ) {
315
+ if ( $context === 'slug' && ( $original_value === 'product-category' || $original_value === 'product-tag' ) ) {
316
  $text = $original_value;
317
  }
318
 
319
  return $text;
320
  }
321
 
322
+ public function product_permalink_slug() {
323
  $permalinks = get_option( 'woocommerce_permalinks' );
324
  $slug = empty( $permalinks['product_base'] ) ? 'product' : trim( $permalinks['product_base'], '/' );
325
 
326
  return $slug;
327
  }
328
 
329
+ public function get_domain_language( $domain ) {
330
 
331
  $lang_of_domain = new WPML_Language_Of_Domain( $this->sitepress );
332
  $domain_lang = $lang_of_domain->get_language( $domain );
340
  return $source_lang;
341
  }
342
 
343
+ public function get_string_language( $value, $context, $name = false ) {
344
 
345
  if ( $name !== false ) {
346
 
354
  return 'en';
355
  }
356
 
357
+ $string_object = new WPML_ST_String( $string_id, $this->wpdb );
358
  $string_language = $string_object->get_language();
359
 
360
  }
367
 
368
  }
369
 
370
+ public function set_string_language( $value, $context, $name, $language ) {
371
 
372
  $string_id = icl_get_string_id( $value, $context, $name );
373
 
382
  * Filter breadcrumbs
383
  *
384
  */
385
+ public function filter_woocommerce_breadcrumbs( $breadcrumbs, $object ) {
386
 
387
  $current_language = $this->sitepress->get_current_language();
388
  $default_language = $this->sitepress->get_default_language();
397
 
398
  $shop_page = get_post( $woocommerce_shop_page );
399
 
400
+ // If permalinks contain the shop page in the URI prepend the breadcrumb with shop.
401
  // Similar to WC_Breadcrumb::prepend_shop_page
402
  $trnsl_base = $this->woocommerce_wpml->url_translation->get_base_translation( 'product', $current_language );
403
  if ( $trnsl_base['translated_base'] === '' ) {
405
  }
406
 
407
  if ( is_woocommerce() && $shop_page->ID && strstr( $trnsl_base['translated_base'], urldecode( $shop_page->post_name ) ) && get_option( 'page_on_front' ) != $shop_page->ID ) {
408
+ $breadcrumbs_buff = [];
409
  $i = 0;
410
 
411
  foreach ( $breadcrumbs as $key => $breadcrumb ) {
412
 
413
+ // Prepend the shop page to shop breadcrumbs
414
  if ( $key === 0 ) {
415
 
416
  if ( $breadcrumbs[1][1] != get_post_type_archive_link( 'product' ) ) {
420
  $i ++;
421
  }
422
 
423
+ $breadcrumbs_buff[ $i ] = [
424
  $shop_page->post_title,
425
+ get_post_type_archive_link( 'product' ),
426
+ ];
427
  $i ++;
428
  }
429
  }
438
 
439
  $breadcrumbs = array_values( $breadcrumbs );
440
  }
 
441
  }
442
  }
443
 
447
  /*
448
  * Add notice message to users
449
  */
450
+ public function notice_after_woocommerce_product_options_attributes() {
451
 
452
  if ( isset( $_GET['post'] ) && $this->sitepress->get_default_language() != $this->sitepress->get_current_language() ) {
453
  $original_product_id = apply_filters( 'translate_object_id', $_GET['post'], 'product', true, $this->sitepress->get_default_language() );
456
  }
457
  }
458
 
459
+ public function translate_attribute_taxonomies_labels( $attribute_taxonomies ) {
460
 
461
  foreach ( $attribute_taxonomies as $key => $attribute_taxonomy ) {
462
  $string_language = $this->get_string_language( $attribute_taxonomy->attribute_label, 'WordPress', 'taxonomy singular name: ' . $attribute_taxonomy->attribute_label );
476
  return $attribute_taxonomies;
477
  }
478
 
479
+ public function get_translation_from_woocommerce_mo_file( $string, $language, $return_original = true ) {
480
 
481
  $original_string = $string;
482
 
483
  if ( ! isset( $this->translations_from_mo_file[ $original_string ][ $language ] ) ) {
484
 
485
  if ( ! isset( $this->translations_from_mo_file[ $original_string ] ) ) {
486
+ $this->translations_from_mo_file[ $original_string ] = [];
487
  }
488
 
489
  if ( ! isset( $this->mo_files[ $language ] ) ) {
497
  $this->mo_files[ $language ] = $mo->entries;
498
  }
499
 
500
+ if ( in_array( $string, [ 'product', 'product-category', 'product-tag' ] ) ) {
501
  $string = 'slug' . chr( 4 ) . $string;
502
  }
503
 
512
 
513
  }
514
 
515
+ public function translate_attributes_label_in_wp_taxonomies( $taxonomy, $obj_type, $args ) {
516
  global $wp_taxonomies;
517
  $obj_type = array_unique( (array) $obj_type );
518
 
528
 
529
  $wp_taxonomies[ $taxonomy ]->labels->name = apply_filters( 'wpml_translate_single_string', $name, 'WordPress', 'taxonomy singular name: ' . $name, $current_language );
530
 
 
531
  }
532
 
533
  }
539
  *
540
  * @return string
541
  */
542
+ public function get_translated_string_by_name_and_context( $context, $name, $language ) {
543
  return apply_filters( 'wpml_translate_single_string', false, $context, $name, $language );
544
+ }
545
 
546
+ }
inc/class-wcml-widgets.php CHANGED
@@ -1,8 +1,8 @@
1
  <?php
2
 
3
- class WCML_Widgets{
4
 
5
- private $woocommerce_wpml;
6
 
7
  /**
8
  * WCML_Widgets constructor.
@@ -11,7 +11,6 @@ class WCML_Widgets{
11
  */
12
  public function __construct( $woocommerce_wpml ) {
13
  // @todo Cover by tests, required for wcml-3037.
14
-
15
  $this->woocommerce_wpml = $woocommerce_wpml;
16
 
17
  add_action( 'widgets_init', [ $this, 'register_widgets' ] );
@@ -19,14 +18,14 @@ class WCML_Widgets{
19
 
20
  public function register_widgets() {
21
 
22
- if( $this->woocommerce_wpml->settings[ 'enable_multi_currency' ] == WCML_MULTI_CURRENCIES_INDEPENDENT ){
23
- register_widget( 'WCML_Currency_Switcher_Widget' );
24
- }
25
 
26
- if( $this->woocommerce_wpml->settings[ 'cart_sync' ][ 'currency_switch' ] == WCML_CART_CLEAR || $this->woocommerce_wpml->settings[ 'cart_sync' ][ 'lang_switch' ] == WCML_CART_CLEAR ){
27
- register_widget( 'WCML_Cart_Removed_Items_Widget' );
28
- }
29
 
30
- }
31
 
32
- }
1
  <?php
2
 
3
+ class WCML_Widgets {
4
 
5
+ private $woocommerce_wpml;
6
 
7
  /**
8
  * WCML_Widgets constructor.
11
  */
12
  public function __construct( $woocommerce_wpml ) {
13
  // @todo Cover by tests, required for wcml-3037.
 
14
  $this->woocommerce_wpml = $woocommerce_wpml;
15
 
16
  add_action( 'widgets_init', [ $this, 'register_widgets' ] );
18
 
19
  public function register_widgets() {
20
 
21
+ if ( $this->woocommerce_wpml->settings['enable_multi_currency'] == WCML_MULTI_CURRENCIES_INDEPENDENT ) {
22
+ register_widget( 'WCML_Currency_Switcher_Widget' );
23
+ }
24
 
25
+ if ( $this->woocommerce_wpml->settings['cart_sync']['currency_switch'] == WCML_CART_CLEAR || $this->woocommerce_wpml->settings['cart_sync']['lang_switch'] == WCML_CART_CLEAR ) {
26
+ register_widget( 'WCML_Cart_Removed_Items_Widget' );
27
+ }
28
 
29
+ }
30
 
31
+ }
inc/constants.php CHANGED
@@ -1,13 +1,13 @@
1
  <?php
2
 
3
- define('WCML_MULTI_CURRENCIES_DISABLED', 0);
4
- define('WCML_MULTI_CURRENCIES_PER_LANGUAGE', 1); //obsolete - migrate to 2
5
- define('WCML_MULTI_CURRENCIES_INDEPENDENT', 2);
6
 
7
- define( 'WCML_TRANSLATION_METHOD_MANUAL', 0);
8
- define( 'WCML_TRANSLATION_METHOD_EDITOR', 1);
9
 
10
- define( 'WCML_CART_CLEAR', 0);
11
- define( 'WCML_CART_SYNC', 1);
12
 
13
- define( 'WCML_JS_MIN', defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '' : '.min');
1
  <?php
2
 
3
+ define( 'WCML_MULTI_CURRENCIES_DISABLED', 0 );
4
+ define( 'WCML_MULTI_CURRENCIES_PER_LANGUAGE', 1 ); // obsolete - migrate to 2.
5
+ define( 'WCML_MULTI_CURRENCIES_INDEPENDENT', 2 );
6
 
7
+ define( 'WCML_TRANSLATION_METHOD_MANUAL', 0 );
8
+ define( 'WCML_TRANSLATION_METHOD_EDITOR', 1 );
9
 
10
+ define( 'WCML_CART_CLEAR', 0 );
11
+ define( 'WCML_CART_SYNC', 1 );
12
 
13
+ define( 'WCML_JS_MIN', defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '' : '.min' );
inc/currencies/class-wcml-custom-prices.php CHANGED
@@ -1,9 +1,9 @@
1
  <?php
2
 
3
- class WCML_Custom_Prices{
4
 
5
  /** @var woocommerce_wpml */
6
- private $woocommerce_wpml;
7
  /** @var wpdb */
8
  private $wpdb;
9
 
@@ -12,34 +12,33 @@ class WCML_Custom_Prices{
12
  $this->wpdb = $wpdb;
13
  }
14
 
15
- public function add_hooks(){
16
- add_filter( 'init', array( $this, 'custom_prices_init' ) );
17
- }
18
-
19
- public function custom_prices_init(){
20
- if ( is_admin() ) {
21
- add_action( 'woocommerce_variation_options', array($this, 'add_individual_variation_nonce'), 10, 3 );
22
 
23
- //custom prices for different currencies for products/variations [BACKEND]
24
- add_action( 'woocommerce_product_options_pricing', array($this, 'woocommerce_product_options_custom_pricing') );
25
- add_action( 'woocommerce_product_after_variable_attributes', array($this, 'woocommerce_product_after_variable_attributes_custom_pricing'), 10, 3 );
26
 
27
- }else{
28
- add_filter( 'woocommerce_product_is_on_sale', array( $this, 'filter_product_is_on_sale' ), 10, 2 );
29
- }
30
 
31
- add_action( 'woocommerce_variation_is_visible', array( $this, 'filter_product_variations_with_custom_prices' ), 10, 2 );
 
 
32
 
 
33
 
34
- add_filter( 'loop_shop_post_in', array( $this, 'filter_products_with_custom_prices' ), 100 );
35
 
36
- }
37
 
38
- public function add_individual_variation_nonce($loop, $variation_data, $variation){
39
 
40
- wp_nonce_field('wcml_save_custom_prices_variation_' . $variation->ID, '_wcml_custom_prices_variation_' . $variation->ID . '_nonce');
41
 
42
- }
43
 
44
  /**
45
  * @param int $product_id
@@ -48,186 +47,184 @@ class WCML_Custom_Prices{
48
  * @return array|false
49
  */
50
  public function get_product_custom_prices( $product_id, $currency = false ) {
51
- if( empty( $currency ) ){
52
- $currency = $this->woocommerce_wpml->multi_currency->get_client_currency();
53
- }
54
 
55
- if( wcml_get_woocommerce_currency_option() === $currency ){
56
- return false;
57
- }
58
 
59
- $cache_key = $product_id.'_'.$currency;
60
- $cache_group = 'product_custom_prices';
61
- $cache_found = false;
62
- $cache_custom_prices = wp_cache_get( $cache_key, $cache_group, false, $cache_found );
63
- if( $cache_found ) return $cache_custom_prices;
 
 
64
 
65
- $product_meta = get_post_custom( $this->woocommerce_wpml->products->get_original_product_id( $product_id ) );
66
- $custom_prices = false;
67
 
68
- if( !empty( $product_meta['_wcml_custom_prices_status'][0] ) ){
69
 
70
  $prices_keys = wcml_price_custom_fields( $product_id );
71
 
72
- foreach($prices_keys as $key){
73
-
74
- if( isset($product_meta[$key . '_' . $currency][0])){
75
- $custom_prices[$key] = $product_meta[$key . '_' . $currency][0];
76
- }
77
-
78
- }
79
-
80
- }
81
-
82
- if(!isset($custom_prices['_price'])) return false;
83
-
84
- $current__price_value = $custom_prices['_price'];
85
-
86
- if ( $this->is_date_range_set( $product_meta, $currency ) && ! $this->is_on_sale_date_range( $product_meta, $currency ) ) {
87
- $custom_prices['_sale_price'] = '';
88
- $custom_prices['_price'] = $custom_prices['_regular_price'];
89
- }
90
-
91
- if($custom_prices['_price'] != $current__price_value){
92
- update_post_meta($product_id, '_price_' . $currency, $custom_prices['_price']);
93
- }
94
-
95
- // detemine min/max variation prices
96
- if(!empty($product_meta['_min_variation_price'])){
97
-
98
- static $product_min_max_prices = array();
99
-
100
- if(empty($product_min_max_prices[$product_id])){
101
-
102
- // get variation ids
103
- $variation_ids = $this->wpdb->get_col($this->wpdb->prepare("SELECT ID FROM {$this->wpdb->posts} WHERE post_parent = %d", $product_id));
104
-
105
- // variations with custom prices
106
- $res = $this->wpdb->get_results($this->wpdb->prepare("SELECT post_id, meta_value FROM {$this->wpdb->postmeta} WHERE post_id IN(%s) AND meta_key='_wcml_custom_prices_status'",join(',', $variation_ids)));
107
- foreach($res as $row){
108
- $custom_prices_enabled[$row->post_id] = $row->meta_value;
109
- }
110
-
111
- // REGULAR PRICES
112
- // get custom prices
113
- $res = $this->wpdb->get_results($this->wpdb->prepare("SELECT post_id, meta_value FROM {$this->wpdb->postmeta} WHERE post_id IN(%s) AND meta_key='_regular_price_" . $currency . "'",join(',', $variation_ids)));
114
- foreach($res as $row){
115
- $regular_prices[$row->post_id] = $row->meta_value;
116
- }
117
-
118
- // get default prices (default currency)
119
- $res = $this->wpdb->get_results($this->wpdb->prepare("SELECT post_id, meta_value FROM {$this->wpdb->postmeta} WHERE post_id IN(%s) AND meta_key='_regular_price'",join(',', $variation_ids)));
120
- foreach($res as $row){
121
- $default_regular_prices[$row->post_id] = $row->meta_value;
122
- }
123
-
124
- // include the dynamic prices
125
- foreach($variation_ids as $vid){
126
- if(empty($regular_prices[$vid]) && isset($default_regular_prices[$vid])){
127
- $regular_prices[$vid] = apply_filters('wcml_raw_price_amount', $default_regular_prices[$vid] );
128
- }
129
- }
130
-
131
- // SALE PRICES
132
- // get custom prices
133
- $res = $this->wpdb->get_results($this->wpdb->prepare("SELECT post_id, meta_value FROM {$this->wpdb->postmeta} WHERE post_id IN(%s) AND meta_key=%s",join(',', $variation_ids),'_sale_price_'.$currency));
134
- foreach($res as $row){
135
- $custom_sale_prices[$row->post_id] = $row->meta_value;
136
- }
137
-
138
- // get default prices (default currency)
139
- $res = $this->wpdb->get_results($this->wpdb->prepare("SELECT post_id, meta_value FROM {$this->wpdb->postmeta} WHERE post_id IN(%s) AND meta_key='_sale_price' AND meta_value <> ''",join(',', $variation_ids)));
140
- foreach($res as $row){
141
- $default_sale_prices[$row->post_id] = $row->meta_value;
142
- }
143
-
144
- // include the dynamic prices
145
- foreach($variation_ids as $vid){
146
- if(empty($sale_prices[$vid]) && isset($default_sale_prices[$vid])){
147
- $sale_prices[$vid] = apply_filters('wcml_raw_price_amount', $default_sale_prices[$vid]);
148
- }
149
- }
150
-
151
-
152
- // PRICES
153
- // get custom prices
154
- $res = $this->wpdb->get_results($this->wpdb->prepare("SELECT post_id, meta_value FROM {$this->wpdb->postmeta} WHERE post_id IN(%s) AND meta_key=%s",join(',', $variation_ids),'_price_'.$currency));
155
- foreach($res as $row){
156
- $custom_prices_prices[$row->post_id] = $row->meta_value;
157
- }
158
-
159
- // get default prices (default currency)
160
- $res = $this->wpdb->get_results($this->wpdb->prepare("SELECT post_id, meta_value FROM {$this->wpdb->postmeta} WHERE post_id IN(%s) AND meta_key='_price'",join(',', $variation_ids)));
161
- foreach($res as $row){
162
- $default_prices[$row->post_id] = $row->meta_value;
163
- }
164
-
165
- // include the dynamic prices
166
- foreach($variation_ids as $vid){
167
- if(empty($custom_prices_prices[$vid]) && isset($default_prices[$vid])){
168
- $prices[$vid] = apply_filters('wcml_raw_price_amount', $default_prices[$vid]);
169
- }
170
- }
171
-
172
- if(!empty($regular_prices)){
173
- $product_min_max_prices[$product_id]['_min_variation_regular_price'] = min($regular_prices);
174
- $product_min_max_prices[$product_id]['_max_variation_regular_price'] = max($regular_prices);
175
- }
176
-
177
- if(!empty($sale_prices)){
178
- $product_min_max_prices[$product_id]['_min_variation_sale_price'] = min($sale_prices);
179
- $product_min_max_prices[$product_id]['_max_variation_sale_price'] = max($sale_prices);
180
- }
181
-
182
- if(!empty($prices)){
183
- $product_min_max_prices[$product_id]['_min_variation_price'] = min($prices);
184
- $product_min_max_prices[$product_id]['_max_variation_price'] = max($prices);
185
- }
186
-
187
-
188
- }
189
-
190
- if(isset($product_min_max_prices[$product_id]['_min_variation_regular_price'])){
191
- $custom_prices['_min_variation_regular_price'] = $product_min_max_prices[$product_id]['_min_variation_regular_price'];
192
- }
193
- if(isset($product_min_max_prices[$product_id]['_max_variation_regular_price'])){
194
- $custom_prices['_max_variation_regular_price'] = $product_min_max_prices[$product_id]['_max_variation_regular_price'];
195
- }
196
-
197
- if(isset($product_min_max_prices[$product_id]['_min_variation_sale_price'])){
198
- $custom_prices['_min_variation_sale_price'] = $product_min_max_prices[$product_id]['_min_variation_sale_price'];
199
- }
200
- if(isset($product_min_max_prices[$product_id]['_max_variation_sale_price'])){
201
- $custom_prices['_max_variation_sale_price'] = $product_min_max_prices[$product_id]['_max_variation_sale_price'];
202
- }
203
-
204
- if(isset($product_min_max_prices[$product_id]['_min_variation_price'])){
205
- $custom_prices['_min_variation_price'] = $product_min_max_prices[$product_id]['_min_variation_price'];
206
- }
207
- if(isset($product_min_max_prices[$product_id]['_max_variation_price'])){
208
- $custom_prices['_max_variation_price'] = $product_min_max_prices[$product_id]['_max_variation_price'];
209
- }
210
-
211
- }
212
-
213
- $custom_prices = apply_filters( 'wcml_product_custom_prices', $custom_prices, $product_id, $currency );
214
-
215
- wp_cache_set( $cache_key, $custom_prices, $cache_group );
216
-
217
- return $custom_prices;
218
- }
219
 
220
  private function is_date_range_set( $product_meta, $currency ) {
221
 
222
  $current_currency_schedule = isset( $product_meta[ '_sale_price_dates_from_' . $currency ] ) &&
223
- $product_meta[ '_sale_price_dates_from_' . $currency ][0] &&
224
- isset( $product_meta[ '_sale_price_dates_to_' . $currency ] ) &&
225
- $product_meta[ '_sale_price_dates_to_' . $currency ][0];
226
 
227
  $default_currency_schedule = isset( $product_meta['_sale_price_dates_from'] ) &&
228
- $product_meta['_sale_price_dates_from'][0] &&
229
- isset( $product_meta['_sale_price_dates_to'] ) &&
230
- $product_meta['_sale_price_dates_to'][0];
231
 
232
  return $current_currency_schedule || $default_currency_schedule;
233
  }
@@ -247,7 +244,6 @@ class WCML_Custom_Prices{
247
  ) {
248
  return true;
249
  }
250
-
251
  } elseif (
252
  isset( $product_meta['_sale_price_dates_from'] ) &&
253
  isset( $product_meta['_sale_price_dates_to'] ) &&
@@ -260,178 +256,184 @@ class WCML_Custom_Prices{
260
  return false;
261
  }
262
 
263
- public function woocommerce_product_options_custom_pricing(){
264
- global $pagenow;
265
 
266
- $this->load_custom_prices_js_css();
267
 
268
- if( ( isset($_GET['post'] ) && ( get_post_type($_GET['post']) != 'product' || !$this->woocommerce_wpml->products->is_original_product( $_GET['post'] ) ) ) ||
269
- ( isset($_GET['post_type'] ) && $_GET['post_type'] == 'product' && isset( $_GET['source_lang'] ) ) ){
270
- return;
271
- }
272
 
273
- $product_id = 'new';
274
 
275
- if($pagenow == 'post.php' && isset($_GET['post']) && get_post_type($_GET['post']) == 'product'){
276
- $product_id = $_GET['post'];
277
- }
278
 
279
- $this->custom_pricing_output($product_id);
280
 
281
- do_action( 'wcml_after_custom_prices_block', $product_id );
282
 
283
- wp_nonce_field('wcml_save_custom_prices','_wcml_custom_prices_nonce');
284
 
285
- }
286
 
287
- public function woocommerce_product_after_variable_attributes_custom_pricing($loop, $variation_data, $variation){
288
 
289
- if( $this->woocommerce_wpml->products->is_original_product( $variation->post_parent ) ) {
290
 
291
- echo '<tr><td>';
292
- $this->custom_pricing_output( $variation->ID );
293
- echo '</td></tr>';
294
 
295
- }
296
 
297
- }
298
 
299
- private function load_custom_prices_js_css(){
300
- wp_register_style( 'wpml-wcml-prices', WCML_PLUGIN_URL . '/res/css/wcml-prices.css', null, WCML_VERSION );
301
- wp_register_script( 'wcml-tm-scripts-prices', WCML_PLUGIN_URL . '/res/js/prices' . WCML_JS_MIN . '.js', array( 'jquery' ), WCML_VERSION, true );
302
 
303
- wp_enqueue_style('wpml-wcml-prices');
304
- wp_enqueue_script('wcml-tm-scripts-prices');
305
- }
306
 
307
- private function custom_pricing_output( $post_id = false){
308
 
309
- $custom_prices_ui = new WCML_Custom_Prices_UI( $this->woocommerce_wpml, $post_id );
310
- $custom_prices_ui->show();
311
 
312
- }
313
 
314
- //set variations without custom prices to not visible when "Show only products with custom prices in secondary currencies" is enabled
315
- public function filter_product_variations_with_custom_prices( $is_visible, $variation_id ){
316
 
317
- if( $this->woocommerce_wpml->settings['enable_multi_currency'] == WCML_MULTI_CURRENCIES_INDEPENDENT &&
318
- isset($this->woocommerce_wpml->settings['display_custom_prices']) &&
319
- $this->woocommerce_wpml->settings['display_custom_prices'] &&
320
- is_product() )
321
- {
322
 
323
- $orig_child_id = $this->woocommerce_wpml->products->get_original_product_id( $variation_id );
324
 
325
- if( !get_post_meta( $orig_child_id, '_wcml_custom_prices_status', true ) ){
326
- return false;
327
- }
328
- }
329
 
330
- return $is_visible;
331
- }
332
 
333
- // display products with custom prices only if enabled "Show only products with custom prices in secondary currencies" option on settings page
334
- public function filter_products_with_custom_prices( $filtered_posts ) {
335
 
336
- if( $this->woocommerce_wpml->settings[ 'enable_multi_currency' ] == WCML_MULTI_CURRENCIES_INDEPENDENT &&
337
- isset( $this->woocommerce_wpml->settings[ 'display_custom_prices' ] ) &&
338
- $this->woocommerce_wpml->settings[ 'display_custom_prices' ] ){
339
 
340
- $client_currency = $this->woocommerce_wpml->multi_currency->get_client_currency();
341
- $woocommerce_currency = wcml_get_woocommerce_currency_option();
342
 
343
- if( $client_currency == $woocommerce_currency ){
344
- return $filtered_posts;
345
- }
346
- $matched_products = array();
347
- $matched_products_query = $this->wpdb->get_results( "
 
348
  SELECT DISTINCT ID, post_parent, post_type FROM {$this->wpdb->posts}
349
  INNER JOIN {$this->wpdb->postmeta} ON ID = post_id
350
  WHERE post_type IN ( 'product', 'product_variation' ) AND post_status = 'publish' AND meta_key = '_wcml_custom_prices_status' AND meta_value = 1
351
- ", OBJECT_K );
352
-
353
- if ( $matched_products_query ) {
354
- remove_filter( 'get_post_metadata', array( $this->woocommerce_wpml->multi_currency->prices, 'product_price_filter' ), 10, 4);
355
- foreach ( $matched_products_query as $product ) {
356
- if( !get_post_meta( $product->ID,'_price_'.$client_currency, true ) ) continue;
357
- if ( $product->post_type == 'product' )
358
- $matched_products[] = apply_filters( 'translate_object_id', $product->ID, 'product', true );
359
- if ( $product->post_parent > 0 && ! in_array( $product->post_parent, $matched_products ) )
360
- $matched_products[] = apply_filters( 'translate_object_id', $product->post_parent, get_post_type( $product->post_parent ), true );
361
- }
362
- add_filter('get_post_metadata', array( $this->woocommerce_wpml->multi_currency->prices, 'product_price_filter' ), 10, 4);
363
- }
364
-
365
- // Filter the id's
366
- if ( sizeof( $filtered_posts ) == 0) {
367
- $filtered_posts = $matched_products;
368
- $filtered_posts[] = 0;
369
- } else {
370
- $filtered_posts = array_intersect( $filtered_posts, $matched_products );
371
- $filtered_posts[] = 0;
372
- }
373
- }
374
-
375
- return $filtered_posts;
376
- }
377
-
378
- public function save_custom_prices( $post_id ){
379
- $nonce = filter_input( INPUT_POST, '_wcml_custom_prices_nonce', FILTER_SANITIZE_FULL_SPECIAL_CHARS );
380
-
381
- if( isset( $_POST[ '_wcml_custom_prices' ] ) && isset( $nonce ) && wp_verify_nonce( $nonce, 'wcml_save_custom_prices' ) && !$this->woocommerce_wpml->products->is_variable_product( $post_id ) ){
382
- if( isset( $_POST[ '_wcml_custom_prices' ][ $post_id ] ) || isset( $_POST[ '_wcml_custom_prices' ][ 'new' ] ) ) {
383
- $wcml_custom_prices_option = isset( $_POST[ '_wcml_custom_prices' ][ $post_id ] ) ? $_POST[ '_wcml_custom_prices' ][ $post_id ] : $_POST[ '_wcml_custom_prices' ][ 'new' ];
384
- }else{
385
- $current_option = get_post_meta( $post_id, '_wcml_custom_prices_status', true );
386
- $wcml_custom_prices_option = $current_option ? $current_option : 0;
387
- }
388
- update_post_meta( $post_id, '_wcml_custom_prices_status', $wcml_custom_prices_option );
389
-
390
- if( $wcml_custom_prices_option == 1){
391
- $currencies = $this->woocommerce_wpml->multi_currency->get_currencies();
392
- foreach( $currencies as $code => $currency ){
393
- $sale_price = wc_format_decimal( $_POST[ '_custom_sale_price' ][ $code ] );
394
- $regular_price = wc_format_decimal( $_POST[ '_custom_regular_price' ][ $code ] );
395
- $schedule = $_POST[ '_wcml_schedule' ][ $code ];
396
- $date_from = $schedule && isset( $_POST[ '_custom_sale_price_dates_from' ][ $code ] ) ? strtotime( $_POST[ '_custom_sale_price_dates_from' ][ $code ] ) : '';
397
- $date_to = $schedule && isset( $_POST[ '_custom_sale_price_dates_to' ][ $code ] ) ? strtotime( $_POST[ '_custom_sale_price_dates_to' ][ $code ] ) : '';
398
-
399
- $custom_prices = apply_filters( 'wcml_update_custom_prices_values',
400
- array(
401
- '_regular_price' => $regular_price,
402
- '_sale_price' => $sale_price,
403
- '_wcml_schedule' => $schedule,
404
- '_sale_price_dates_from' => $date_from,
405
- '_sale_price_dates_to' => $date_to
406
- ),
407
- $code,
408
- $post_id
409
- );
410
- $product_price = $this->update_custom_prices( $post_id, $custom_prices , $code );
411
-
412
- do_action( 'wcml_after_save_custom_prices', $post_id, $product_price, $custom_prices, $code );
413
- }
414
- }
415
- }
416
- }
 
 
 
 
 
 
 
417
 
418
  public function update_custom_prices( $post_id, $custom_prices, $code ) {
419
  $price = null;
420
 
421
- $defaults = array(
422
  '_sale_price_dates_to' => '',
423
  '_sale_price_dates_from' => '',
424
- '_sale_price' => ''
425
- );
426
 
427
  $custom_prices = array_merge( $defaults, $custom_prices );
428
 
429
-
430
  foreach ( $custom_prices as $custom_price_key => $custom_price_value ) {
431
  update_post_meta( $post_id, $custom_price_key . '_' . $code, $custom_price_value );
432
  }
433
 
434
- if ( $this->is_sale_price_valid( $custom_prices ) ){
435
  $price = stripslashes( $custom_prices['_sale_price'] );
436
  } else {
437
  $price = stripslashes( $custom_prices['_regular_price'] );
@@ -456,15 +458,17 @@ class WCML_Custom_Prices{
456
  update_post_meta( $post_id, '_sale_price_dates_from_' . $code, '' );
457
  update_post_meta( $post_id, '_sale_price_dates_to_' . $code, '' );
458
  } elseif ( ! $date_from ) {
459
- update_post_meta( $post_id,
 
460
  '_sale_price_dates_from_' . $code,
461
- strtotime( 'NOW', current_time( 'timestamp' ) ) );
 
462
  }
463
  }
464
  }
465
 
466
  /**
467
- * @param array $custom_prices
468
  *
469
  * @return bool
470
  */
@@ -477,39 +481,42 @@ class WCML_Custom_Prices{
477
  return $custom_prices['_sale_price'] !== '' && ( $not_depend_on_date || $valid_sale_date );
478
  }
479
 
480
- public function sync_product_variations_custom_prices( $product_id ){
481
-
482
- if( isset( $_POST[ '_wcml_custom_prices' ][ $product_id ] ) ){
483
-
484
- //save custom prices for variation
485
- $nonce = filter_input( INPUT_POST, '_wcml_custom_prices_variation_' . $product_id . '_nonce', FILTER_SANITIZE_FULL_SPECIAL_CHARS );
486
- if( isset( $_POST[ '_wcml_custom_prices' ][ $product_id ] ) && isset( $nonce ) && wp_verify_nonce( $nonce, 'wcml_save_custom_prices_variation_' . $product_id ) ){
487
- update_post_meta( $product_id, '_wcml_custom_prices_status', $_POST[ '_wcml_custom_prices' ][ $product_id ] );
488
- $currencies = $this->woocommerce_wpml->multi_currency->get_currencies();
489
-
490
- if( $_POST[ '_wcml_custom_prices' ][ $product_id ] == 1 ){
491
- foreach( $currencies as $code => $currency ){
492
- $sale_price = wc_format_decimal( $_POST[ '_custom_variation_sale_price' ][ $code ][ $product_id ] );
493
- $regular_price = wc_format_decimal( $_POST[ '_custom_variation_regular_price' ][ $code ][ $product_id ] );
494
- $date_from = strtotime( $_POST[ '_custom_variation_sale_price_dates_from' ][ $code ][ $product_id ] );
495
- $date_to = strtotime( $_POST[ '_custom_variation_sale_price_dates_to' ][ $code ][ $product_id ] );
496
- $schedule = $_POST[ '_wcml_schedule' ][ $code ][ $product_id ];
497
-
498
- $custom_prices = apply_filters( 'wcml_update_custom_prices_values',
499
- array( '_regular_price' => $regular_price,
500
- '_sale_price' => $sale_price,
501
- '_wcml_schedule' => $schedule,
502
- '_sale_price_dates_from' => $date_from,
503
- '_sale_price_dates_to' => $date_to ),
504
- $code,
505
- $product_id
506
- );
507
- $price = $this->update_custom_prices( $product_id, $custom_prices, $code );
508
- }
509
- }
510
- }
511
- }
512
- }
 
 
 
513
 
514
  /**
515
  * @param WC_Product $product_object
@@ -520,10 +527,10 @@ class WCML_Custom_Prices{
520
  $custom_prices = $this->get_product_custom_prices( $product_object->get_id() );
521
 
522
  return $custom_prices
523
- && array_key_exists( '_sale_price', $custom_prices )
524
- && array_key_exists( '_regular_price', $custom_prices )
525
- && '' !== $custom_prices['_sale_price']
526
- && $custom_prices['_sale_price'] !== $custom_prices['_regular_price'];
527
  }
528
 
529
  /**
1
  <?php
2
 
3
+ class WCML_Custom_Prices {
4
 
5
  /** @var woocommerce_wpml */
6
+ private $woocommerce_wpml;
7
  /** @var wpdb */
8
  private $wpdb;
9
 
12
  $this->wpdb = $wpdb;
13
  }
14
 
15
+ public function add_hooks() {
16
+ add_filter( 'init', [ $this, 'custom_prices_init' ] );
17
+ }
 
 
 
 
18
 
19
+ public function custom_prices_init() {
20
+ if ( is_admin() ) {
21
+ add_action( 'woocommerce_variation_options', [ $this, 'add_individual_variation_nonce' ], 10, 3 );
22
 
23
+ // custom prices for different currencies for products/variations [BACKEND].
24
+ add_action( 'woocommerce_product_options_pricing', [ $this, 'woocommerce_product_options_custom_pricing' ] );
25
+ add_action( 'woocommerce_product_after_variable_attributes', [ $this, 'woocommerce_product_after_variable_attributes_custom_pricing' ], 10, 3 );
26
 
27
+ } else {
28
+ add_filter( 'woocommerce_product_is_on_sale', [ $this, 'filter_product_is_on_sale' ], 10, 2 );
29
+ }
30
 
31
+ add_action( 'woocommerce_variation_is_visible', [ $this, 'filter_product_variations_with_custom_prices' ], 10, 2 );
32
 
33
+ add_filter( 'loop_shop_post_in', [ $this, 'filter_products_with_custom_prices' ], 100 );
34
 
35
+ }
36
 
37
+ public function add_individual_variation_nonce( $loop, $variation_data, $variation ) {
38
 
39
+ wp_nonce_field( 'wcml_save_custom_prices_variation_' . $variation->ID, '_wcml_custom_prices_variation_' . $variation->ID . '_nonce' );
40
 
41
+ }
42
 
43
  /**
44
  * @param int $product_id
47
  * @return array|false
48
  */
49
  public function get_product_custom_prices( $product_id, $currency = false ) {
50
+ if ( empty( $currency ) ) {
51
+ $currency = $this->woocommerce_wpml->multi_currency->get_client_currency();
52
+ }
53
 
54
+ if ( wcml_get_woocommerce_currency_option() === $currency ) {
55
+ return false;
56
+ }
57
 
58
+ $cache_key = $product_id . '_' . $currency;
59
+ $cache_group = 'product_custom_prices';
60
+ $cache_found = false;
61
+ $cache_custom_prices = wp_cache_get( $cache_key, $cache_group, false, $cache_found );
62
+ if ( $cache_found ) {
63
+ return $cache_custom_prices;
64
+ }
65
 
66
+ $product_meta = get_post_custom( $this->woocommerce_wpml->products->get_original_product_id( $product_id ) );
67
+ $custom_prices = false;
68
 
69
+ if ( ! empty( $product_meta['_wcml_custom_prices_status'][0] ) ) {
70
 
71
  $prices_keys = wcml_price_custom_fields( $product_id );
72
 
73
+ foreach ( $prices_keys as $key ) {
74
+
75
+ if ( isset( $product_meta[ $key . '_' . $currency ][0] ) ) {
76
+ $custom_prices[ $key ] = $product_meta[ $key . '_' . $currency ][0];
77
+ }
78
+ }
79
+ }
80
+
81
+ if ( ! isset( $custom_prices['_price'] ) ) {
82
+ return false;
83
+ }
84
+
85
+ $current__price_value = $custom_prices['_price'];
86
+
87
+ if ( $this->is_date_range_set( $product_meta, $currency ) && ! $this->is_on_sale_date_range( $product_meta, $currency ) ) {
88
+ $custom_prices['_sale_price'] = '';
89
+ $custom_prices['_price'] = $custom_prices['_regular_price'];
90
+ }
91
+
92
+ if ( $custom_prices['_price'] != $current__price_value ) {
93
+ update_post_meta( $product_id, '_price_' . $currency, $custom_prices['_price'] );
94
+ }
95
+
96
+ // detemine min/max variation prices.
97
+ if ( ! empty( $product_meta['_min_variation_price'] ) ) {
98
+
99
+ static $product_min_max_prices = [];
100
+
101
+ if ( empty( $product_min_max_prices[ $product_id ] ) ) {
102
+
103
+ // get variation ids.
104
+ $variation_ids = $this->wpdb->get_col( $this->wpdb->prepare( "SELECT ID FROM {$this->wpdb->posts} WHERE post_parent = %d", $product_id ) );
105
+
106
+ // variations with custom prices.
107
+ $res = $this->wpdb->get_results( $this->wpdb->prepare( "SELECT post_id, meta_value FROM {$this->wpdb->postmeta} WHERE post_id IN(%s) AND meta_key='_wcml_custom_prices_status'", join( ',', $variation_ids ) ) );
108
+ foreach ( $res as $row ) {
109
+ $custom_prices_enabled[ $row->post_id ] = $row->meta_value;
110
+ }
111
+
112
+ // REGULAR PRICES.
113
+ // get custom prices.
114
+ $res = $this->wpdb->get_results( $this->wpdb->prepare( "SELECT post_id, meta_value FROM {$this->wpdb->postmeta} WHERE post_id IN(%s) AND meta_key='_regular_price_" . $currency . "'", join( ',', $variation_ids ) ) );
115
+ foreach ( $res as $row ) {
116
+ $regular_prices[ $row->post_id ] = $row->meta_value;
117
+ }
118
+
119
+ // get default prices (default currency).
120
+ $res = $this->wpdb->get_results( $this->wpdb->prepare( "SELECT post_id, meta_value FROM {$this->wpdb->postmeta} WHERE post_id IN(%s) AND meta_key='_regular_price'", join( ',', $variation_ids ) ) );
121
+ foreach ( $res as $row ) {
122
+ $default_regular_prices[ $row->post_id ] = $row->meta_value;
123
+ }
124
+
125
+ // include the dynamic prices.
126
+ foreach ( $variation_ids as $vid ) {
127
+ if ( empty( $regular_prices[ $vid ] ) && isset( $default_regular_prices[ $vid ] ) ) {
128
+ $regular_prices[ $vid ] = apply_filters( 'wcml_raw_price_amount', $default_regular_prices[ $vid ] );
129
+ }
130
+ }
131
+
132
+ // SALE PRICES.
133
+ // get custom prices.
134
+ $res = $this->wpdb->get_results( $this->wpdb->prepare( "SELECT post_id, meta_value FROM {$this->wpdb->postmeta} WHERE post_id IN(%s) AND meta_key=%s", join( ',', $variation_ids ), '_sale_price_' . $currency ) );
135
+ foreach ( $res as $row ) {
136
+ $custom_sale_prices[ $row->post_id ] = $row->meta_value;
137
+ }
138
+
139
+ // get default prices (default currency).
140
+ $res = $this->wpdb->get_results( $this->wpdb->prepare( "SELECT post_id, meta_value FROM {$this->wpdb->postmeta} WHERE post_id IN(%s) AND meta_key='_sale_price' AND meta_value <> ''", join( ',', $variation_ids ) ) );
141
+ foreach ( $res as $row ) {
142
+ $default_sale_prices[ $row->post_id ] = $row->meta_value;
143
+ }
144
+
145
+ // include the dynamic prices.
146
+ foreach ( $variation_ids as $vid ) {
147
+ if ( empty( $sale_prices[ $vid ] ) && isset( $default_sale_prices[ $vid ] ) ) {
148
+ $sale_prices[ $vid ] = apply_filters( 'wcml_raw_price_amount', $default_sale_prices[ $vid ] );
149
+ }
150
+ }
151
+
152
+ // PRICES.
153
+ // get custom prices.
154
+ $res = $this->wpdb->get_results( $this->wpdb->prepare( "SELECT post_id, meta_value FROM {$this->wpdb->postmeta} WHERE post_id IN(%s) AND meta_key=%s", join( ',', $variation_ids ), '_price_' . $currency ) );
155
+ foreach ( $res as $row ) {
156
+ $custom_prices_prices[ $row->post_id ] = $row->meta_value;
157
+ }
158
+
159
+ // get default prices (default currency).
160
+ $res = $this->wpdb->get_results( $this->wpdb->prepare( "SELECT post_id, meta_value FROM {$this->wpdb->postmeta} WHERE post_id IN(%s) AND meta_key='_price'", join( ',', $variation_ids ) ) );
161
+ foreach ( $res as $row ) {
162
+ $default_prices[ $row->post_id ] = $row->meta_value;
163
+ }
164
+
165
+ // include the dynamic prices.
166
+ foreach ( $variation_ids as $vid ) {
167
+ if ( empty( $custom_prices_prices[ $vid ] ) && isset( $default_prices[ $vid ] ) ) {
168
+ $prices[ $vid ] = apply_filters( 'wcml_raw_price_amount', $default_prices[ $vid ] );
169
+ }
170
+ }
171
+
172
+ if ( ! empty( $regular_prices ) ) {
173
+ $product_min_max_prices[ $product_id ]['_min_variation_regular_price'] = min( $regular_prices );
174
+ $product_min_max_prices[ $product_id ]['_max_variation_regular_price'] = max( $regular_prices );
175
+ }
176
+
177
+ if ( ! empty( $sale_prices ) ) {
178
+ $product_min_max_prices[ $product_id ]['_min_variation_sale_price'] = min( $sale_prices );
179
+ $product_min_max_prices[ $product_id ]['_max_variation_sale_price'] = max( $sale_prices );
180
+ }
181
+
182
+ if ( ! empty( $prices ) ) {
183
+ $product_min_max_prices[ $product_id ]['_min_variation_price'] = min( $prices );
184
+ $product_min_max_prices[ $product_id ]['_max_variation_price'] = max( $prices );
185
+ }
186
+ }
187
+
188
+ if ( isset( $product_min_max_prices[ $product_id ]['_min_variation_regular_price'] ) ) {
189
+ $custom_prices['_min_variation_regular_price'] = $product_min_max_prices[ $product_id ]['_min_variation_regular_price'];
190
+ }
191
+ if ( isset( $product_min_max_prices[ $product_id ]['_max_variation_regular_price'] ) ) {
192
+ $custom_prices['_max_variation_regular_price'] = $product_min_max_prices[ $product_id ]['_max_variation_regular_price'];
193
+ }
194
+
195
+ if ( isset( $product_min_max_prices[ $product_id ]['_min_variation_sale_price'] ) ) {
196
+ $custom_prices['_min_variation_sale_price'] = $product_min_max_prices[ $product_id ]['_min_variation_sale_price'];
197
+ }
198
+ if ( isset( $product_min_max_prices[ $product_id ]['_max_variation_sale_price'] ) ) {
199
+ $custom_prices['_max_variation_sale_price'] = $product_min_max_prices[ $product_id ]['_max_variation_sale_price'];
200
+ }
201
+
202
+ if ( isset( $product_min_max_prices[ $product_id ]['_min_variation_price'] ) ) {
203
+ $custom_prices['_min_variation_price'] = $product_min_max_prices[ $product_id ]['_min_variation_price'];
204
+ }
205
+ if ( isset( $product_min_max_prices[ $product_id ]['_max_variation_price'] ) ) {
206
+ $custom_prices['_max_variation_price'] = $product_min_max_prices[ $product_id ]['_max_variation_price'];
207
+ }
208
+ }
209
+
210
+ $custom_prices = apply_filters( 'wcml_product_custom_prices', $custom_prices, $product_id, $currency );
211
+
212
+ wp_cache_set( $cache_key, $custom_prices, $cache_group );
213
+
214
+ return $custom_prices;
215
+ }
 
 
 
 
216
 
217
  private function is_date_range_set( $product_meta, $currency ) {
218
 
219
  $current_currency_schedule = isset( $product_meta[ '_sale_price_dates_from_' . $currency ] ) &&
220
+ $product_meta[ '_sale_price_dates_from_' . $currency ][0] &&
221
+ isset( $product_meta[ '_sale_price_dates_to_' . $currency ] ) &&
222
+ $product_meta[ '_sale_price_dates_to_' . $currency ][0];
223
 
224
  $default_currency_schedule = isset( $product_meta['_sale_price_dates_from'] ) &&
225
+ $product_meta['_sale_price_dates_from'][0] &&
226
+ isset( $product_meta['_sale_price_dates_to'] ) &&
227
+ $product_meta['_sale_price_dates_to'][0];
228
 
229
  return $current_currency_schedule || $default_currency_schedule;
230
  }
244
  ) {
245
  return true;
246
  }
 
247
  } elseif (
248
  isset( $product_meta['_sale_price_dates_from'] ) &&
249
  isset( $product_meta['_sale_price_dates_to'] ) &&
256
  return false;
257
  }
258
 
259
+ public function woocommerce_product_options_custom_pricing() {
260
+ global $pagenow;
261
 
262
+ $this->load_custom_prices_js_css();
263
 
264
+ if ( ( isset( $_GET['post'] ) && ( get_post_type( $_GET['post'] ) !== 'product' || ! $this->woocommerce_wpml->products->is_original_product( $_GET['post'] ) ) ) ||
265
+ ( isset( $_GET['post_type'] ) && $_GET['post_type'] === 'product' && isset( $_GET['source_lang'] ) ) ) {
266
+ return;
267
+ }
268
 
269
+ $product_id = 'new';
270
 
271
+ if ( $pagenow === 'post.php' && isset( $_GET['post'] ) && get_post_type( $_GET['post'] ) == 'product' ) {
272
+ $product_id = $_GET['post'];
273
+ }
274
 
275
+ $this->custom_pricing_output( $product_id );
276
 
277
+ do_action( 'wcml_after_custom_prices_block', $product_id );
278
 
279
+ wp_nonce_field( 'wcml_save_custom_prices', '_wcml_custom_prices_nonce' );
280
 
281
+ }
282
 
283
+ public function woocommerce_product_after_variable_attributes_custom_pricing( $loop, $variation_data, $variation ) {
284
 
285
+ if ( $this->woocommerce_wpml->products->is_original_product( $variation->post_parent ) ) {
286
 
287
+ echo '<tr><td>';
288
+ $this->custom_pricing_output( $variation->ID );
289
+ echo '</td></tr>';
290
 
291
+ }
292
 
293
+ }
294
 
295
+ private function load_custom_prices_js_css() {
296
+ wp_register_style( 'wpml-wcml-prices', WCML_PLUGIN_URL . '/res/css/wcml-prices.css', null, WCML_VERSION );
297
+ wp_register_script( 'wcml-tm-scripts-prices', WCML_PLUGIN_URL . '/res/js/prices' . WCML_JS_MIN . '.js', [ 'jquery' ], WCML_VERSION, true );
298
 
299
+ wp_enqueue_style( 'wpml-wcml-prices' );
300
+ wp_enqueue_script( 'wcml-tm-scripts-prices' );
301
+ }
302
 
303
+ private function custom_pricing_output( $post_id = false ) {
304
 
305
+ $custom_prices_ui = new WCML_Custom_Prices_UI( $this->woocommerce_wpml, $post_id );
306
+ $custom_prices_ui->show();
307
 
308
+ }
309
 
310
+ // set variations without custom prices to not visible when "Show only products with custom prices in secondary currencies" is enabled.
311
+ public function filter_product_variations_with_custom_prices( $is_visible, $variation_id ) {
312
 
313
+ if ( $this->woocommerce_wpml->settings['enable_multi_currency'] == WCML_MULTI_CURRENCIES_INDEPENDENT &&
314
+ isset( $this->woocommerce_wpml->settings['display_custom_prices'] ) &&
315
+ $this->woocommerce_wpml->settings['display_custom_prices'] &&
316
+ is_product() ) {
 
317
 
318
+ $orig_child_id = $this->woocommerce_wpml->products->get_original_product_id( $variation_id );
319
 
320
+ if ( ! get_post_meta( $orig_child_id, '_wcml_custom_prices_status', true ) ) {
321
+ return false;
322
+ }
323
+ }
324
 
325
+ return $is_visible;
326
+ }
327
 
328
+ // display products with custom prices only if enabled "Show only products with custom prices in secondary currencies" option on settings page.
329
+ public function filter_products_with_custom_prices( $filtered_posts ) {
330
 
331
+ if ( $this->woocommerce_wpml->settings['enable_multi_currency'] == WCML_MULTI_CURRENCIES_INDEPENDENT &&
332
+ isset( $this->woocommerce_wpml->settings['display_custom_prices'] ) &&
333
+ $this->woocommerce_wpml->settings['display_custom_prices'] ) {
334
 
335
+ $client_currency = $this->woocommerce_wpml->multi_currency->get_client_currency();
336
+ $woocommerce_currency = wcml_get_woocommerce_currency_option();
337
 
338
+ if ( $client_currency == $woocommerce_currency ) {
339
+ return $filtered_posts;
340
+ }
341
+ $matched_products = [];
342
+ $matched_products_query = $this->wpdb->get_results(
343
+ "
344
  SELECT DISTINCT ID, post_parent, post_type FROM {$this->wpdb->posts}
345
  INNER JOIN {$this->wpdb->postmeta} ON ID = post_id
346
  WHERE post_type IN ( 'product', 'product_variation' ) AND post_status = 'publish' AND meta_key = '_wcml_custom_prices_status' AND meta_value = 1
347
+ ",
348
+ OBJECT_K
349
+ );
350
+
351
+ if ( $matched_products_query ) {
352
+ remove_filter( 'get_post_metadata', [ $this->woocommerce_wpml->multi_currency->prices, 'product_price_filter' ], 10, 4 );
353
+ foreach ( $matched_products_query as $product ) {
354
+ if ( ! get_post_meta( $product->ID, '_price_' . $client_currency, true ) ) {
355
+ continue;
356
+ }
357
+ if ( $product->post_type == 'product' ) {
358
+ $matched_products[] = apply_filters( 'translate_object_id', $product->ID, 'product', true );
359
+ }
360
+ if ( $product->post_parent > 0 && ! in_array( $product->post_parent, $matched_products ) ) {
361
+ $matched_products[] = apply_filters( 'translate_object_id', $product->post_parent, get_post_type( $product->post_parent ), true );
362
+ }
363
+ }
364
+ add_filter( 'get_post_metadata', [ $this->woocommerce_wpml->multi_currency->prices, 'product_price_filter' ], 10, 4 );
365
+ }
366
+
367
+ // Filter the id's.
368
+ if ( sizeof( $filtered_posts ) == 0 ) {
369
+ $filtered_posts = $matched_products;
370
+ $filtered_posts[] = 0;
371
+ } else {
372
+ $filtered_posts = array_intersect( $filtered_posts, $matched_products );
373
+ $filtered_posts[] = 0;
374
+ }
375
+ }
376
+
377
+ return $filtered_posts;
378
+ }
379
+
380
+ public function save_custom_prices( $post_id ) {
381
+ $nonce = filter_input( INPUT_POST, '_wcml_custom_prices_nonce', FILTER_SANITIZE_FULL_SPECIAL_CHARS );
382
+
383
+ if ( isset( $_POST['_wcml_custom_prices'] ) && isset( $nonce ) && wp_verify_nonce( $nonce, 'wcml_save_custom_prices' ) && ! $this->woocommerce_wpml->products->is_variable_product( $post_id ) ) {
384
+ if ( isset( $_POST['_wcml_custom_prices'][ $post_id ] ) || isset( $_POST['_wcml_custom_prices']['new'] ) ) {
385
+ $wcml_custom_prices_option = isset( $_POST['_wcml_custom_prices'][ $post_id ] ) ? $_POST['_wcml_custom_prices'][ $post_id ] : $_POST['_wcml_custom_prices']['new'];
386
+ } else {
387
+ $current_option = get_post_meta( $post_id, '_wcml_custom_prices_status', true );
388
+ $wcml_custom_prices_option = $current_option ? $current_option : 0;
389
+ }
390
+ update_post_meta( $post_id, '_wcml_custom_prices_status', $wcml_custom_prices_option );
391
+
392
+ if ( $wcml_custom_prices_option == 1 ) {
393
+ $currencies = $this->woocommerce_wpml->multi_currency->get_currencies();
394
+ foreach ( $currencies as $code => $currency ) {
395
+ $sale_price = wc_format_decimal( $_POST['_custom_sale_price'][ $code ] );
396
+ $regular_price = wc_format_decimal( $_POST['_custom_regular_price'][ $code ] );
397
+ $schedule = $_POST['_wcml_schedule'][ $code ];
398
+ $date_from = $schedule && isset( $_POST['_custom_sale_price_dates_from'][ $code ] ) ? strtotime( $_POST['_custom_sale_price_dates_from'][ $code ] ) : '';
399
+ $date_to = $schedule && isset( $_POST['_custom_sale_price_dates_to'][ $code ] ) ? strtotime( $_POST['_custom_sale_price_dates_to'][ $code ] ) : '';
400
+
401
+ $custom_prices = apply_filters(
402
+ 'wcml_update_custom_prices_values',
403
+ [
404
+ '_regular_price' => $regular_price,
405
+ '_sale_price' => $sale_price,
406
+ '_wcml_schedule' => $schedule,
407
+ '_sale_price_dates_from' => $date_from,
408
+ '_sale_price_dates_to' => $date_to,
409
+ ],
410
+ $code,
411
+ $post_id
412
+ );
413
+ $product_price = $this->update_custom_prices( $post_id, $custom_prices, $code );
414
+
415
+ do_action( 'wcml_after_save_custom_prices', $post_id, $product_price, $custom_prices, $code );
416
+ }
417
+ }
418
+ }
419
+ }
420
 
421
  public function update_custom_prices( $post_id, $custom_prices, $code ) {
422
  $price = null;
423
 
424
+ $defaults = [
425
  '_sale_price_dates_to' => '',
426
  '_sale_price_dates_from' => '',
427
+ '_sale_price' => '',
428
+ ];
429
 
430
  $custom_prices = array_merge( $defaults, $custom_prices );
431
 
 
432
  foreach ( $custom_prices as $custom_price_key => $custom_price_value ) {
433
  update_post_meta( $post_id, $custom_price_key . '_' . $code, $custom_price_value );
434
  }
435
 
436
+ if ( $this->is_sale_price_valid( $custom_prices ) ) {
437
  $price = stripslashes( $custom_prices['_sale_price'] );
438
  } else {
439
  $price = stripslashes( $custom_prices['_regular_price'] );
458
  update_post_meta( $post_id, '_sale_price_dates_from_' . $code, '' );
459
  update_post_meta( $post_id, '_sale_price_dates_to_' . $code, '' );
460
  } elseif ( ! $date_from ) {
461
+ update_post_meta(
462
+ $post_id,
463
  '_sale_price_dates_from_' . $code,
464
+ strtotime( 'NOW', current_time( 'timestamp' ) )
465
+ );
466
  }
467
  }
468
  }
469
 
470
  /**
471
+ * @param array $custom_prices
472
  *
473
  * @return bool
474
  */
481
  return $custom_prices['_sale_price'] !== '' && ( $not_depend_on_date || $valid_sale_date );
482
  }
483
 
484
+ public function sync_product_variations_custom_prices( $product_id ) {
485
+
486
+ if ( isset( $_POST['_wcml_custom_prices'][ $product_id ] ) ) {
487
+
488
+ // save custom prices for variation.
489
+ $nonce = filter_input( INPUT_POST, '_wcml_custom_prices_variation_' . $product_id . '_nonce', FILTER_SANITIZE_FULL_SPECIAL_CHARS );
490
+ if ( isset( $_POST['_wcml_custom_prices'][ $product_id ] ) && isset( $nonce ) && wp_verify_nonce( $nonce, 'wcml_save_custom_prices_variation_' . $product_id ) ) {
491
+ update_post_meta( $product_id, '_wcml_custom_prices_status', $_POST['_wcml_custom_prices'][ $product_id ] );
492
+ $currencies = $this->woocommerce_wpml->multi_currency->get_currencies();
493
+
494
+ if ( $_POST['_wcml_custom_prices'][ $product_id ] == 1 ) {
495
+ foreach ( $currencies as $code => $currency ) {
496
+ $sale_price = wc_format_decimal( $_POST['_custom_variation_sale_price'][ $code ][ $product_id ] );
497
+ $regular_price = wc_format_decimal( $_POST['_custom_variation_regular_price'][ $code ][ $product_id ] );
498
+ $date_from = strtotime( $_POST['_custom_variation_sale_price_dates_from'][ $code ][ $product_id ] );
499
+ $date_to = strtotime( $_POST['_custom_variation_sale_price_dates_to'][ $code ][ $product_id ] );
500
+ $schedule = $_POST['_wcml_schedule'][ $code ][ $product_id ];
501
+
502
+ $custom_prices = apply_filters(
503
+ 'wcml_update_custom_prices_values',
504
+ [
505
+ '_regular_price' => $regular_price,
506
+ '_sale_price' => $sale_price,
507
+ '_wcml_schedule' => $schedule,
508
+ '_sale_price_dates_from' => $date_from,
509
+ '_sale_price_dates_to' => $date_to,
510
+ ],
511
+ $code,
512
+ $product_id
513
+ );
514
+ $price = $this->update_custom_prices( $product_id, $custom_prices, $code );
515
+ }
516
+ }
517
+ }
518
+ }
519
+ }
520
 
521
  /**
522
  * @param WC_Product $product_object
527
  $custom_prices = $this->get_product_custom_prices( $product_object->get_id() );
528
 
529
  return $custom_prices
530
+ && array_key_exists( '_sale_price', $custom_prices )
531
+ && array_key_exists( '_regular_price', $custom_prices )
532
+ && '' !== $custom_prices['_sale_price']
533
+ && $custom_prices['_sale_price'] !== $custom_prices['_regular_price'];
534
  }
535
 
536
  /**
inc/currencies/class-wcml-multi-currency-configuration.php CHANGED
@@ -1,7 +1,7 @@
1
  <?php
2
 
3
- class WCML_Multi_Currency_Configuration
4
- {
5
 
6
  /**
7
  * @var WCML_Multi_Currency
@@ -12,29 +12,28 @@ class WCML_Multi_Currency_Configuration
12
  */
13
  private static $woocommerce_wpml;
14
 
15
- public static function set_up(WCML_Multi_Currency $multi_currency, woocommerce_wpml $woocommerce_wpml)
16
- {
17
 
18
- self::$multi_currency = $multi_currency;
19
  self::$woocommerce_wpml = $woocommerce_wpml;
20
 
21
- if (isset($_POST['action']) && $_POST['action'] == 'save-mc-options') {
22
  self::save_configuration();
23
  }
24
 
25
  self::set_prices_config();
26
 
27
- if (is_ajax()) {
28
 
29
- add_action('wp_ajax_legacy_update_custom_rates', array(__CLASS__, 'legacy_update_custom_rates'));
30
- add_action('wp_ajax_legacy_remove_custom_rates', array(__CLASS__, 'legacy_remove_custom_rates'));
31
 
32
- add_action('wp_ajax_wcml_new_currency', array(__CLASS__, 'edit_currency'));
33
- add_action('wp_ajax_wcml_save_currency', array(__CLASS__, 'save_currency'));
34
- add_action('wp_ajax_wcml_delete_currency', array(__CLASS__, 'delete_currency'));
35
 
36
- add_action('wp_ajax_wcml_update_currency_lang', array(__CLASS__, 'update_currency_lang'));
37
- add_action('wp_ajax_wcml_update_default_currency', array(__CLASS__, 'update_default_currency_ajax'));
38
 
39
  }
40
 
@@ -42,125 +41,124 @@ class WCML_Multi_Currency_Configuration
42
 
43
  public static function save_configuration() {
44
  // @todo Cover by tests, required for wcml-3037.
45
-
46
- if (check_admin_referer('wcml_mc_options', 'wcml_nonce')) {
47
 
48
  $wcml_settings = self::$woocommerce_wpml->settings;
49
 
50
- $wcml_settings['enable_multi_currency'] = isset($_POST['multi_currency']) ? intval($_POST['multi_currency']) : 0;
51
- $wcml_settings['display_custom_prices'] = isset($_POST['display_custom_prices']) ? intval($_POST['display_custom_prices']) : 0;
52
 
53
- //update default currency settings
54
- if ($wcml_settings['enable_multi_currency'] == WCML_MULTI_CURRENCIES_INDEPENDENT) {
55
 
56
- $options = array(
57
- 'woocommerce_currency_pos' => 'position',
58
  'woocommerce_price_thousand_sep' => 'thousand_sep',
59
- 'woocommerce_price_decimal_sep' => 'decimal_sep',
60
- 'woocommerce_price_num_decimals' => 'num_decimals'
61
- );
62
 
63
  $woocommerce_currency = wcml_get_woocommerce_currency_option();
64
 
65
- foreach ($options as $wc_key => $key) {
66
- $wcml_settings['currency_options'][$woocommerce_currency][$key] = get_option($wc_key, true);
67
  }
68
  }
69
 
70
- $wcml_settings['currency_switcher_product_visibility'] = isset($_POST['currency_switcher_product_visibility']) ? intval($_POST['currency_switcher_product_visibility']) : 0;
71
- $wcml_settings['currency_switcher_additional_css'] = isset($_POST['currency_switcher_additional_css']) ? sanitize_text_field($_POST['currency_switcher_additional_css']) : '';
72
 
73
- self::$woocommerce_wpml->update_settings($wcml_settings);
74
 
75
- do_action('wcml_saved_mc_options', $_POST);
76
 
77
- $message = array(
78
- 'id' => 'wcml-settings-saved',
79
- 'text' => __('Your settings have been saved.', 'woocommerce-multilingual'),
80
- 'group' => 'wcml-multi-currency',
81
- 'admin_notice' => true,
82
  'limit_to_page' => true,
83
- 'classes' => array('updated', 'notice', 'notice-success'),
84
- 'show_once' => true
85
- );
86
- ICL_AdminNotifier::add_message($message);
87
 
88
  $wpml_admin_notices = wpml_get_admin_notices();
89
- $wpml_admin_notices->remove_notice('wcml-save-multi-currency-options', 'wcml-fixerio-api-key-required');
90
  }
91
 
92
  }
93
 
94
- public static function edit_currency()
95
- {
96
 
97
- $nonce = filter_input(INPUT_POST, 'wcml_nonce', FILTER_SANITIZE_FULL_SPECIAL_CHARS);
98
- if (wp_verify_nonce($nonce, 'wcml_edit_currency')) {
99
 
100
  self::$multi_currency->init_currencies();
101
- $args['currencies'] = self::$multi_currency->currencies;
102
  $args['wc_currencies'] = get_woocommerce_currencies();
103
 
104
- if (empty($_POST['currency'])) {
105
 
106
- $args['title'] = empty($_POST['currency']) ? __('Add new currency', 'woocommerce-multilingual') : __('Update currency', 'woocommerce-multilingual');
107
 
108
  } else {
109
 
110
- $args['currency_code'] = filter_input(INPUT_POST, 'currency', FILTER_SANITIZE_FULL_SPECIAL_CHARS);
111
- $args['currency_name'] = $args['wc_currencies'][$args['currency_code']];
112
- $args['currency_symbol'] = get_woocommerce_currency_symbol($args['currency_code']);
113
 
114
- $args['title'] = sprintf(__('Update settings for %s', 'woocommerce-multilingual'),
115
- '<strong>' . $args['currency_name'] . ' (' . $args['currency_symbol'] . ')</strong>');
 
 
116
 
117
  }
118
 
119
- $custom_currency_options = new WCML_Custom_Currency_Options($args, self::$woocommerce_wpml);
120
- $return['html'] = $custom_currency_options->get_view();
121
 
122
- echo json_encode($return);
123
 
124
  }
125
 
126
  exit;
127
  }
128
 
129
- public static function add_currency($currency_code)
130
- {
131
  global $sitepress;
132
 
133
  $settings = self::$woocommerce_wpml->get_settings();
134
 
135
- $active_languages = $sitepress->get_active_languages();
136
  $return['languages'] = '';
137
- foreach ($active_languages as $language) {
138
- if (!isset($settings['currency_options'][$currency_code]['languages'][$language['code']])) {
139
- $settings['currency_options'][$currency_code]['languages'][$language['code']] = 1;
140
  }
141
  }
142
- $settings['currency_options'][$currency_code]['rate'] = (double)filter_input(INPUT_POST, 'currency_value', FILTER_VALIDATE_FLOAT, FILTER_FLAG_ALLOW_FRACTION);
143
- $settings['currency_options'][$currency_code]['updated'] = date('Y-m-d H:i:s');
144
 
145
  $wc_currency = wcml_get_woocommerce_currency_option();
146
- if (!isset($settings['currencies_order']))
147
  $settings['currencies_order'][] = $wc_currency;
 
148
 
149
  $settings['currencies_order'][] = $currency_code;
150
 
151
- self::$woocommerce_wpml->update_settings($settings);
152
  self::$multi_currency->init_currencies();
153
 
154
  }
155
 
156
- public static function save_currency()
157
- {
158
- $nonce = filter_input(INPUT_POST, 'wcml_nonce', FILTER_SANITIZE_FULL_SPECIAL_CHARS);
159
- if (!$nonce || !wp_verify_nonce($nonce, 'save_currency')) {
160
- die('Invalid nonce');
161
  }
162
 
163
- $wc_currency = wcml_get_woocommerce_currency_option();
164
  $wc_currencies = get_woocommerce_currencies();
165
 
166
  $options = $_POST['currency_options'];
@@ -180,110 +178,105 @@ class WCML_Multi_Currency_Configuration
180
  self::$multi_currency->currencies_payment_gateways->set_enabled( $currency_code, isset( $options['gateways_enabled'] ) ? true : false );
181
  }
182
 
183
- if( $wc_currency !== $currency_code ){
184
- $options['thousand_sep'] = wc_format_option_price_separators(null, null, $options['thousand_sep']);
185
- $options['decimal_sep'] = wc_format_option_pric
1
  <?php
2
 
3
+ class WCML_Multi_Currency_Configuration {
4
+
5
 
6
  /**
7
  * @var WCML_Multi_Currency
12
  */
13
  private static $woocommerce_wpml;
14
 
15
+ public static function set_up( WCML_Multi_Currency $multi_currency, woocommerce_wpml $woocommerce_wpml ) {
 
16
 
17
+ self::$multi_currency = $multi_currency;
18
  self::$woocommerce_wpml = $woocommerce_wpml;
19
 
20
+ if ( isset( $_POST['action'] ) && $_POST['action'] === 'save-mc-options' ) {
21
  self::save_configuration();
22
  }
23
 
24
  self::set_prices_config();
25
 
26
+ if ( is_ajax() ) {
27
 
28
+ add_action( 'wp_ajax_legacy_update_custom_rates', [ __CLASS__, 'legacy_update_custom_rates' ] );
29
+ add_action( 'wp_ajax_legacy_remove_custom_rates', [ __CLASS__, 'legacy_remove_custom_rates' ] );
30
 
31
+ add_action( 'wp_ajax_wcml_new_currency', [ __CLASS__, 'edit_currency' ] );
32
+ add_action( 'wp_ajax_wcml_save_currency', [ __CLASS__, 'save_currency' ] );
33
+ add_action( 'wp_ajax_wcml_delete_currency', [ __CLASS__, 'delete_currency' ] );
34
 
35
+ add_action( 'wp_ajax_wcml_update_currency_lang', [ __CLASS__, 'update_currency_lang' ] );
36
+ add_action( 'wp_ajax_wcml_update_default_currency', [ __CLASS__, 'update_default_currency_ajax' ] );
37
 
38
  }
39
 
41
 
42
  public static function save_configuration() {
43
  // @todo Cover by tests, required for wcml-3037.
44
+ if ( check_admin_referer( 'wcml_mc_options', 'wcml_nonce' ) ) {
 
45
 
46
  $wcml_settings = self::$woocommerce_wpml->settings;
47
 
48
+ $wcml_settings['enable_multi_currency'] = isset( $_POST['multi_currency'] ) ? intval( $_POST['multi_currency'] ) : 0;
49
+ $wcml_settings['display_custom_prices'] = isset( $_POST['display_custom_prices'] ) ? intval( $_POST['display_custom_prices'] ) : 0;
50
 
51
+ // update default currency settings
52
+ if ( $wcml_settings['enable_multi_currency'] == WCML_MULTI_CURRENCIES_INDEPENDENT ) {
53
 
54
+ $options = [
55
+ 'woocommerce_currency_pos' => 'position',
56
  'woocommerce_price_thousand_sep' => 'thousand_sep',
57
+ 'woocommerce_price_decimal_sep' => 'decimal_sep',
58
+ 'woocommerce_price_num_decimals' => 'num_decimals',
59
+ ];
60
 
61
  $woocommerce_currency = wcml_get_woocommerce_currency_option();
62
 
63
+ foreach ( $options as $wc_key => $key ) {
64
+ $wcml_settings['currency_options'][ $woocommerce_currency ][ $key ] = get_option( $wc_key, true );
65
  }
66
  }
67
 
68
+ $wcml_settings['currency_switcher_product_visibility'] = isset( $_POST['currency_switcher_product_visibility'] ) ? intval( $_POST['currency_switcher_product_visibility'] ) : 0;
69
+ $wcml_settings['currency_switcher_additional_css'] = isset( $_POST['currency_switcher_additional_css'] ) ? sanitize_text_field( $_POST['currency_switcher_additional_css'] ) : '';
70
 
71
+ self::$woocommerce_wpml->update_settings( $wcml_settings );
72
 
73
+ do_action( 'wcml_saved_mc_options', $_POST );
74
 
75
+ $message = [
76
+ 'id' => 'wcml-settings-saved',
77
+ 'text' => __( 'Your settings have been saved.', 'woocommerce-multilingual' ),
78
+ 'group' => 'wcml-multi-currency',
79
+ 'admin_notice' => true,
80
  'limit_to_page' => true,
81
+ 'classes' => [ 'updated', 'notice', 'notice-success' ],
82
+ 'show_once' => true,
83
+ ];
84
+ ICL_AdminNotifier::add_message( $message );
85
 
86
  $wpml_admin_notices = wpml_get_admin_notices();
87
+ $wpml_admin_notices->remove_notice( 'wcml-save-multi-currency-options', 'wcml-fixerio-api-key-required' );
88
  }
89
 
90
  }
91
 
92
+ public static function edit_currency() {
 
93
 
94
+ $nonce = filter_input( INPUT_POST, 'wcml_nonce', FILTER_SANITIZE_FULL_SPECIAL_CHARS );
95
+ if ( wp_verify_nonce( $nonce, 'wcml_edit_currency' ) ) {
96
 
97
  self::$multi_currency->init_currencies();
98
+ $args['currencies'] = self::$multi_currency->currencies;
99
  $args['wc_currencies'] = get_woocommerce_currencies();
100
 
101
+ if ( empty( $_POST['currency'] ) ) {
102
 
103
+ $args['title'] = empty( $_POST['currency'] ) ? __( 'Add new currency', 'woocommerce-multilingual' ) : __( 'Update currency', 'woocommerce-multilingual' );
104
 
105
  } else {
106
 
107
+ $args['currency_code'] = filter_input( INPUT_POST, 'currency', FILTER_SANITIZE_FULL_SPECIAL_CHARS );
108
+ $args['currency_name'] = $args['wc_currencies'][ $args['currency_code'] ];
109
+ $args['currency_symbol'] = get_woocommerce_currency_symbol( $args['currency_code'] );
110
 
111
+ $args['title'] = sprintf(
112
+ __( 'Update settings for %s', 'woocommerce-multilingual' ),
113
+ '<strong>' . $args['currency_name'] . ' (' . $args['currency_symbol'] . ')</strong>'
114
+ );
115
 
116
  }
117
 
118
+ $custom_currency_options = new WCML_Custom_Currency_Options( $args, self::$woocommerce_wpml );
119
+ $return['html'] = $custom_currency_options->get_view();
120
 
121
+ echo json_encode( $return );
122
 
123
  }
124
 
125
  exit;
126
  }
127
 
128
+ public static function add_currency( $currency_code ) {
 
129
  global $sitepress;
130
 
131
  $settings = self::$woocommerce_wpml->get_settings();
132
 
133
+ $active_languages = $sitepress->get_active_languages();
134
  $return['languages'] = '';
135
+ foreach ( $active_languages as $language ) {
136
+ if ( ! isset( $settings['currency_options'][ $currency_code ]['languages'][ $language['code'] ] ) ) {
137
+ $settings['currency_options'][ $currency_code ]['languages'][ $language['code'] ] = 1;
138
  }
139
  }
140
+ $settings['currency_options'][ $currency_code ]['rate'] = (float) filter_input( INPUT_POST, 'currency_value', FILTER_VALIDATE_FLOAT, FILTER_FLAG_ALLOW_FRACTION );
141
+ $settings['currency_options'][ $currency_code ]['updated'] = date( 'Y-m-d H:i:s' );
142
 
143
  $wc_currency = wcml_get_woocommerce_currency_option();
144
+ if ( ! isset( $settings['currencies_order'] ) ) {
145
  $settings['currencies_order'][] = $wc_currency;
146
+ }
147
 
148
  $settings['currencies_order'][] = $currency_code;
149
 
150
+ self::$woocommerce_wpml->update_settings( $settings );
151
  self::$multi_currency->init_currencies();
152
 
153
  }
154
 
155
+ public static function save_currency() {
156
+ $nonce = filter_input( INPUT_POST, 'wcml_nonce', FILTER_SANITIZE_FULL_SPECIAL_CHARS );
157
+ if ( ! $nonce || ! wp_verify_nonce( $nonce, 'save_currency' ) ) {
158
+ die( 'Invalid nonce' );
 
159
  }
160
 
161
+ $wc_currency = wcml_get_woocommerce_currency_option();
162
  $wc_currencies = get_woocommerce_currencies();
163
 
164
  $options = $_POST['currency_options'];
178
  self::$multi_currency->currencies_payment_gateways->set_enabled( $currency_code, isset( $options['gateways_enabled'] ) ? true : false );
179
  }
180