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