Version Description
- Refactor translation and currency conversion of products & variations in cart
- A problem we had with shipping selection was resolved in WooCommerce itself
- Improved synchronization of global product attributes, whether used for variations or not
- Custom product attributes registered as strings when defined in the backend
- Don't adjust the currency symbol in WooCommerce settings page
- Term and product category order is synchronized among languages
- Additional filters for WooCommerce emails
- Fixed layered nav widgets in translated shop page
- Synchronize Product Categories
Download this release
Release Info
Developer | dgwatkins |
Plugin | WooCommerce Multilingual – run WooCommerce with WPML |
Version | 2.3 |
Comparing to | |
See all releases |
Code changes from version 2.2 to 2.3
- readme.txt +17 -2
- woocommerce_wpml.class.php +258 -174
- wpml-woocommerce.php +2 -2
readme.txt
CHANGED
@@ -1,11 +1,11 @@
|
|
1 |
=== WooCommerce Multilingual - run WooCommerce with WPML ===
|
2 |
-
Contributors: AmirHelzer, dominykasgel, dgwatkins
|
3 |
Donate link: http://wpml.org/documentation/related-projects/woocommerce-multilingual/
|
4 |
Tags: CMS, woocommerce, commerce, ecommerce, e-commerce, products, WPML, multilingual, e-shop, shop
|
5 |
License: GPLv2
|
6 |
Requires at least: 3.0
|
7 |
Tested up to: 3.5
|
8 |
-
Stable tag: 2.
|
9 |
|
10 |
Allows running fully multilingual e-commerce sites using WooCommerce and WPML.
|
11 |
|
@@ -68,6 +68,21 @@ In order for the checkout and store pages to appear translated, you need to crea
|
|
68 |
|
69 |
== Changelog ==
|
70 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
71 |
= 2.1 =
|
72 |
* Add admin notices for required plugins
|
73 |
* Add support for 'Review Order' and 'Lost Password' pages
|
1 |
=== WooCommerce Multilingual - run WooCommerce with WPML ===
|
2 |
+
Contributors: AmirHelzer, dominykasgel, dgwatkins, adelval
|
3 |
Donate link: http://wpml.org/documentation/related-projects/woocommerce-multilingual/
|
4 |
Tags: CMS, woocommerce, commerce, ecommerce, e-commerce, products, WPML, multilingual, e-shop, shop
|
5 |
License: GPLv2
|
6 |
Requires at least: 3.0
|
7 |
Tested up to: 3.5
|
8 |
+
Stable tag: 2.3
|
9 |
|
10 |
Allows running fully multilingual e-commerce sites using WooCommerce and WPML.
|
11 |
|
68 |
|
69 |
== Changelog ==
|
70 |
|
71 |
+
= 2.3 =
|
72 |
+
* Refactor translation and currency conversion of products & variations in cart
|
73 |
+
* A problem we had with shipping selection was resolved in WooCommerce itself
|
74 |
+
* Improved synchronization of global product attributes, whether used for variations or not
|
75 |
+
* Custom product attributes registered as strings when defined in the backend
|
76 |
+
* Don't adjust the currency symbol in WooCommerce settings page
|
77 |
+
* Term and product category order is synchronized among languages
|
78 |
+
* Additional filters for WooCommerce emails
|
79 |
+
* Fixed layered nav widgets in translated shop page
|
80 |
+
* Synchronize Product Categories
|
81 |
+
|
82 |
+
= 2.2 =
|
83 |
+
* Price in mini-cart refreshed when changing language
|
84 |
+
* Fix bug in multilingual currency setting that slipped in 2.1
|
85 |
+
|
86 |
= 2.1 =
|
87 |
* Add admin notices for required plugins
|
88 |
* Add support for 'Review Order' and 'Lost Password' pages
|
woocommerce_wpml.class.php
CHANGED
@@ -64,8 +64,6 @@ class woocommerce_wpml {
|
|
64 |
add_filter('woocommerce_get_checkout_payment_url', array($this, 'do_redirect'));
|
65 |
add_filter('woocommerce_get_cancel_order_url', array($this, 'do_redirect'));
|
66 |
add_filter('woocommerce_get_return_url', array($this, 'do_redirect'));
|
67 |
-
add_filter('woocommerce_in_cart_product_title', array($this, 'in_cart_product_title'), 13, 2);
|
68 |
-
add_filter('woocommerce_in_cart_product_id', array($this, 'in_cart_product_id'), 11, 2);
|
69 |
add_filter('woocommerce_params', array($this, 'ajax_params'));
|
70 |
add_filter('woocommerce_redirect', array($this, 'do_redirect'));
|
71 |
add_filter('woocommerce_attribute_label', array($this, 'translate_attributes'), 14, 2);
|
@@ -78,8 +76,10 @@ class woocommerce_wpml {
|
|
78 |
add_filter('woocommerce_json_search_found_products', array($this, 'search_products'));
|
79 |
add_filter('woocommerce_currency', array($this, 'set_ml_currency'));
|
80 |
add_action('admin_print_scripts', array($this,'js_scripts_setup'), 11);
|
81 |
-
|
82 |
-
|
|
|
|
|
83 |
|
84 |
// Slug translation
|
85 |
add_filter('gettext_with_context', array($this, 'default_slug_translation'), 0, 4);
|
@@ -104,15 +104,20 @@ class woocommerce_wpml {
|
|
104 |
add_filter('raw_woocommerce_price', array($this, 'woocommerce_price'));
|
105 |
add_filter('woocommerce_order_amount_total', array($this, 'woocommerce_price'));
|
106 |
add_filter('woocommerce_order_amount_item_total', array($this, 'woocommerce_price'));
|
|
|
107 |
add_filter('woocommerce_order_amount_shipping', array($this, 'woocommerce_price'));
|
108 |
add_filter('woocommerce_order_amount_total_tax', array($this, 'woocommerce_price'));
|
|
|
109 |
}
|
110 |
-
|
111 |
add_filter('woocommerce_currency_symbol', array($this, 'woocommerce_currency_symbol'), 2);
|
112 |
}
|
113 |
|
114 |
-
|
|
|
|
|
|
|
115 |
add_action('woocommerce_email_footer', array($this, 'email_footer'), 0);
|
|
|
116 |
add_action('localize_woocommerce_on_ajax', array($this, 'localize_on_ajax'));
|
117 |
add_action('woocommerce_shipping_update_ajax', array($this, 'shipping_update'));
|
118 |
|
@@ -134,6 +139,7 @@ class woocommerce_wpml {
|
|
134 |
} else {
|
135 |
add_filter('pre_get_posts', array($this, 'shop_page_query'), 9);
|
136 |
add_filter('icl_ls_languages', array($this, 'translate_ls_shop_url'));
|
|
|
137 |
}
|
138 |
|
139 |
// Hooks for translating product attribute values
|
@@ -242,8 +248,11 @@ class woocommerce_wpml {
|
|
242 |
add_filter('woocommerce_available_shipping_methods', array($this, 'register_shipping_methods'));
|
243 |
add_filter('woocommerce_countries_tax_or_vat', array($this, 'register_tax_label'));
|
244 |
add_action('option_woocommerce_tax_rates', array($this, 'tax_rates'));
|
|
|
|
|
|
|
245 |
}
|
246 |
-
|
247 |
function set_price_config() {
|
248 |
global $sitepress, $iclTranslationManagement;
|
249 |
|
@@ -335,8 +344,64 @@ class woocommerce_wpml {
|
|
335 |
return icl_object_id($id, 'page', true);
|
336 |
}
|
337 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
338 |
function translate_email_notifications() {
|
339 |
-
$email_actions = array(
|
340 |
'woocommerce_order_status_pending_to_processing',
|
341 |
'woocommerce_order_status_pending_to_completed',
|
342 |
'woocommerce_order_status_pending_to_on-hold',
|
@@ -344,10 +409,21 @@ class woocommerce_wpml {
|
|
344 |
'woocommerce_order_status_failed_to_completed',
|
345 |
'woocommerce_order_status_pending_to_processing',
|
346 |
'woocommerce_order_status_pending_to_on-hold',
|
347 |
-
'woocommerce_order_status_completed'
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
348 |
);
|
|
|
|
|
|
|
349 |
foreach ( $email_actions as $action ) {
|
350 |
-
add_action( $action, array(
|
351 |
}
|
352 |
}
|
353 |
|
@@ -362,22 +438,7 @@ class woocommerce_wpml {
|
|
362 |
|
363 |
}
|
364 |
|
365 |
-
|
366 |
-
global $sitepress;
|
367 |
-
$shop_id = get_option('woocommerce_shop_page_id');
|
368 |
-
$front_id = icl_object_id(get_option('page_on_front'), 'page');
|
369 |
-
if (is_post_type_archive('product')) {
|
370 |
-
foreach ($languages as &$language) {
|
371 |
-
if ($front_id == $shop_id) {
|
372 |
-
$url = $sitepress->language_url($language['language_code']);
|
373 |
-
} else {
|
374 |
-
$url = get_permalink(icl_object_id($shop_id, 'page', true, $language['language_code']));
|
375 |
-
}
|
376 |
-
$language['url'] = $url;
|
377 |
-
}
|
378 |
-
}
|
379 |
-
return $languages;
|
380 |
-
}
|
381 |
|
382 |
/**
|
383 |
* Adds admin notice.
|
@@ -574,38 +635,6 @@ class woocommerce_wpml {
|
|
574 |
return get_permalink(icl_object_id(get_option('woocommerce_checkout_page_id'), 'page', true));
|
575 |
}
|
576 |
|
577 |
-
/**
|
578 |
-
* After email translation switch language to default.
|
579 |
-
*
|
580 |
-
* @param type $title
|
581 |
-
* @param $_product
|
582 |
-
* @return type
|
583 |
-
*/
|
584 |
-
function in_cart_product_title($title, $_product){
|
585 |
-
if (is_array($_product)) {
|
586 |
-
$product_id = $_product['product_id']; // backward compatibility
|
587 |
-
} else {
|
588 |
-
$product_id = $_product->id;
|
589 |
-
}
|
590 |
-
$product_id = icl_object_id($product_id, 'product', false, ICL_LANGUAGE_CODE);
|
591 |
-
|
592 |
-
if($product_id){
|
593 |
-
$title = get_the_title($product_id);
|
594 |
-
}
|
595 |
-
|
596 |
-
return $title;
|
597 |
-
}
|
598 |
-
|
599 |
-
/**
|
600 |
-
* Adjusts WooCommerce product ID to be added in cart (original product ID).
|
601 |
-
*
|
602 |
-
* @param type $product_id
|
603 |
-
* @return type
|
604 |
-
*/
|
605 |
-
function in_cart_product_id($product_id) {
|
606 |
-
return icl_object_id($product_id, 'product', true);
|
607 |
-
}
|
608 |
-
|
609 |
/**
|
610 |
* Filters WooCommerce AJAX params
|
611 |
*
|
@@ -671,7 +700,6 @@ class woocommerce_wpml {
|
|
671 |
function translate_attributes($name){
|
672 |
if(function_exists('icl_register_string')){
|
673 |
icl_register_string('woocommerce', $name .'_attribute', $name);
|
674 |
-
|
675 |
$name = icl_t('woocommerce', $name .'_attribute', $name);
|
676 |
}
|
677 |
|
@@ -739,11 +767,7 @@ class woocommerce_wpml {
|
|
739 |
$out = array();
|
740 |
foreach ($terms as $term) {
|
741 |
$term = trim($term);
|
742 |
-
|
743 |
-
$term = icl_translate('woocommerce', $term .'_attribute_name', $term);
|
744 |
-
} else {
|
745 |
-
$term = icl_t('woocommerce', $term .'_attribute_name', $term);
|
746 |
-
}
|
747 |
$out[] = $term;
|
748 |
}
|
749 |
|
@@ -810,25 +834,47 @@ class woocommerce_wpml {
|
|
810 |
}
|
811 |
}
|
812 |
|
813 |
-
|
814 |
-
|
815 |
-
|
816 |
-
|
817 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
818 |
|
819 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
820 |
|
821 |
-
|
822 |
-
$db_currency = $db_currency->code;
|
823 |
-
if(in_array($db_currency, array_keys($this->currencies))){
|
824 |
-
$currency_symbol = $this->currencies[$db_currency];
|
825 |
-
} else {
|
826 |
-
$currency_symbol = $db_currency;
|
827 |
-
}
|
828 |
-
}
|
829 |
|
830 |
-
|
831 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
832 |
|
833 |
/**
|
834 |
* Filters the product price.
|
@@ -850,59 +896,11 @@ class woocommerce_wpml {
|
|
850 |
return $price;
|
851 |
}
|
852 |
|
853 |
-
|
854 |
-
* Translates WooCommerce emails.
|
855 |
-
*
|
856 |
-
* @global type $sitepress
|
857 |
-
* @global type $order_id
|
858 |
-
* @return type
|
859 |
-
*/
|
860 |
-
function email_header() {
|
861 |
-
global $sitepress, $order_id;
|
862 |
-
|
863 |
-
$lang = get_post_meta($order_id, 'wpml_language', TRUE);
|
864 |
-
|
865 |
-
if(empty($lang)){
|
866 |
-
if(isset($_SESSION['wpml_globalcart_language'])){
|
867 |
-
$lang = $_SESSION['wpml_globalcart_language'];
|
868 |
-
} else {
|
869 |
-
$lang = $sitepress->get_current_language();
|
870 |
-
}
|
871 |
-
}
|
872 |
-
|
873 |
-
$sitepress->switch_lang($lang, true);
|
874 |
-
}
|
875 |
-
|
876 |
-
/**
|
877 |
-
* After email translation switch language to default.
|
878 |
-
*
|
879 |
-
* @global type $sitepress
|
880 |
-
* @return type
|
881 |
-
*/
|
882 |
-
function email_footer() {
|
883 |
-
global $sitepress;
|
884 |
-
|
885 |
-
$sitepress->switch_lang();
|
886 |
-
}
|
887 |
-
|
888 |
-
/*
|
889 |
-
* WC compat layer: get product id
|
890 |
-
*/
|
891 |
-
|
892 |
-
function get_product_id_from_order_item($item) {
|
893 |
-
if ( version_compare( WOOCOMMERCE_VERSION, "2.0.0" ) >= 0 ) {
|
894 |
-
// WC 2.0
|
895 |
-
return isset($item['product_id']) ? $item['product_id'] : false;
|
896 |
-
} else {
|
897 |
-
return isset($item['product_id']) ? $item['product_id'] : false;
|
898 |
-
}
|
899 |
-
}
|
900 |
-
|
901 |
-
|
902 |
/*
|
903 |
* WC compat layer: get product
|
904 |
*/
|
905 |
-
|
906 |
function wcml_get_product($product_id) {
|
907 |
if ( version_compare( WOOCOMMERCE_VERSION, "2.0.0" ) >= 0 ) {
|
908 |
// WC 2.0
|
@@ -1107,6 +1105,8 @@ class woocommerce_wpml {
|
|
1107 |
}
|
1108 |
}
|
1109 |
|
|
|
|
|
1110 |
foreach ($posts as $post_id => $translation) {
|
1111 |
$lang = $translation->language_code;
|
1112 |
|
@@ -1175,19 +1175,61 @@ class woocommerce_wpml {
|
|
1175 |
$wpdb->update($wpdb->postmeta, $data, $where);
|
1176 |
}
|
1177 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1178 |
$get_variation_term_id = $wpdb->get_var("SELECT term_id FROM $wpdb->terms WHERE name = 'variable'");
|
1179 |
$get_variation_term_taxonomy_id = $wpdb->get_var("SELECT tt.term_taxonomy_id FROM $wpdb->term_relationships tr
|
1180 |
LEFT JOIN $wpdb->term_taxonomy tt ON tt.term_taxonomy_id = tr.term_taxonomy_id
|
1181 |
-
WHERE object_id = '$duplicated_post_id' AND taxonomy = 'product_type'");
|
1182 |
|
1183 |
$is_post_has_variations = $wpdb->get_results("SELECT * FROM $wpdb->term_relationships WHERE object_id = '$duplicated_post_id' AND term_taxonomy_id = '$get_variation_term_taxonomy_id'");
|
1184 |
if(!empty($is_post_has_variations)) $is_post_has_variations = TRUE;
|
1185 |
|
1186 |
-
// synchronize term data, postmeta and post variations
|
1187 |
if($is_post_has_variations){
|
1188 |
// synchronize post variations
|
1189 |
$get_all_post_variations = $wpdb->get_results("SELECT * FROM $wpdb->posts
|
1190 |
-
WHERE post_status = 'publish' AND post_type = 'product_variation' AND post_parent = '$duplicated_post_id'");
|
1191 |
|
1192 |
$duplicated_post_variation_ids = array();
|
1193 |
foreach($get_all_post_variations as $k => $post_data){
|
@@ -1254,14 +1296,13 @@ class woocommerce_wpml {
|
|
1254 |
'comment_count' => $post_data->comment_count
|
1255 |
));
|
1256 |
update_post_meta($variation_id, '_wcml_duplicate_of_variation', $post_data->ID);
|
1257 |
-
update_post_meta($variation_id, '_icl_duplicate_of', $post_data->ID);
|
1258 |
$trid = $sitepress->get_element_trid($post_data->ID, 'post_product_variation');
|
1259 |
-
$sitepress->set_element_language_details($variation_id, 'post_product_variation', $trid, $lang, $
|
1260 |
}
|
1261 |
}
|
1262 |
|
1263 |
$get_current_post_variations = $wpdb->get_results("SELECT * FROM $wpdb->posts
|
1264 |
-
WHERE post_status = 'publish' AND post_type = 'product_variation' AND post_parent = '$post_id'");
|
1265 |
|
1266 |
// Delete variations that no longer exist
|
1267 |
foreach ($get_current_post_variations as $post_data) {
|
@@ -1280,7 +1321,6 @@ class woocommerce_wpml {
|
|
1280 |
$current_post_variation_ids[] = $post_data->ID;
|
1281 |
}
|
1282 |
|
1283 |
-
$taxs = array();
|
1284 |
foreach($duplicated_post_variation_ids as $dp_key => $duplicated_post_variation_id){
|
1285 |
$get_all_post_meta = $wpdb->get_results("SELECT * FROM $wpdb->postmeta WHERE post_id = '$duplicated_post_variation_id'");
|
1286 |
|
@@ -1293,7 +1333,6 @@ class woocommerce_wpml {
|
|
1293 |
if (substr($meta_key, 0, 10) == 'attribute_') {
|
1294 |
$tax = substr($meta_key, 10);
|
1295 |
if (taxonomy_exists($tax)) {
|
1296 |
-
$taxs[] = $tax;
|
1297 |
$attid = get_term_by('slug', $meta_value, $tax)->term_taxonomy_id;
|
1298 |
$trid = $sitepress->get_element_trid($attid, 'tax_' . $tax);
|
1299 |
if ($trid) {
|
@@ -1311,27 +1350,63 @@ class woocommerce_wpml {
|
|
1311 |
}
|
1312 |
}
|
1313 |
|
1314 |
-
|
1315 |
-
|
1316 |
-
|
1317 |
-
$terms = wp_get_object_terms($duplicated_post_id, $tax);
|
1318 |
-
$update = array();
|
1319 |
-
foreach ($terms as $term) {
|
1320 |
-
$trid = $sitepress->get_element_trid($term->term_taxonomy_id, 'tax_' . $tax);
|
1321 |
-
$translations = $sitepress->get_element_translations($trid,'tax_' . $tax);
|
1322 |
-
if (isset($translations[$lang])) {
|
1323 |
-
$update[] = intval($translations[$lang]->term_id);
|
1324 |
-
}
|
1325 |
-
}
|
1326 |
-
wp_set_object_terms($post_id, $update, $tax);
|
1327 |
-
}
|
1328 |
|
1329 |
-
|
|
|
|
|
|
|
|
|
|
|
1330 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1331 |
}
|
|
|
|
|
|
|
1332 |
|
1333 |
}
|
1334 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1335 |
/**
|
1336 |
* Creates WCML page.
|
1337 |
*/
|
@@ -1484,29 +1559,38 @@ class woocommerce_wpml {
|
|
1484 |
<?php
|
1485 |
}
|
1486 |
}
|
1487 |
-
|
1488 |
-
function
|
1489 |
-
|
1490 |
-
|
1491 |
-
|
1492 |
-
|
1493 |
-
|
1494 |
-
|
1495 |
-
|
1496 |
-
|
1497 |
-
|
1498 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1499 |
}
|
1500 |
-
|
1501 |
-
|
1502 |
-
|
1503 |
}
|
1504 |
|
1505 |
-
|
1506 |
-
|
1507 |
-
|
1508 |
-
|
1509 |
-
|
1510 |
-
|
1511 |
|
1512 |
}
|
64 |
add_filter('woocommerce_get_checkout_payment_url', array($this, 'do_redirect'));
|
65 |
add_filter('woocommerce_get_cancel_order_url', array($this, 'do_redirect'));
|
66 |
add_filter('woocommerce_get_return_url', array($this, 'do_redirect'));
|
|
|
|
|
67 |
add_filter('woocommerce_params', array($this, 'ajax_params'));
|
68 |
add_filter('woocommerce_redirect', array($this, 'do_redirect'));
|
69 |
add_filter('woocommerce_attribute_label', array($this, 'translate_attributes'), 14, 2);
|
76 |
add_filter('woocommerce_json_search_found_products', array($this, 'search_products'));
|
77 |
add_filter('woocommerce_currency', array($this, 'set_ml_currency'));
|
78 |
add_action('admin_print_scripts', array($this,'js_scripts_setup'), 11);
|
79 |
+
|
80 |
+
// cart functions
|
81 |
+
add_action('woocommerce_get_cart_item_from_session', array($this, 'translate_cart_contents'), 10, 3);
|
82 |
+
add_action('woocommerce_cart_loaded_from_session', array($this, 'translate_cart_subtotal'));
|
83 |
|
84 |
// Slug translation
|
85 |
add_filter('gettext_with_context', array($this, 'default_slug_translation'), 0, 4);
|
104 |
add_filter('raw_woocommerce_price', array($this, 'woocommerce_price'));
|
105 |
add_filter('woocommerce_order_amount_total', array($this, 'woocommerce_price'));
|
106 |
add_filter('woocommerce_order_amount_item_total', array($this, 'woocommerce_price'));
|
107 |
+
add_filter('woocommerce_order_amount_item_subtotal', array($this, 'woocommerce_price'));
|
108 |
add_filter('woocommerce_order_amount_shipping', array($this, 'woocommerce_price'));
|
109 |
add_filter('woocommerce_order_amount_total_tax', array($this, 'woocommerce_price'));
|
110 |
+
add_filter('woocommerce_order_amount_cart_discount',array($this,'woocommerce_price'));
|
111 |
}
|
|
|
112 |
add_filter('woocommerce_currency_symbol', array($this, 'woocommerce_currency_symbol'), 2);
|
113 |
}
|
114 |
|
115 |
+
//emails
|
116 |
+
add_action('init', array($this, 'translate_email_notifications'));
|
117 |
+
//wrappers for email's body
|
118 |
+
add_action('woocommerce_email_header', array($this, 'email_header'), 0);
|
119 |
add_action('woocommerce_email_footer', array($this, 'email_footer'), 0);
|
120 |
+
|
121 |
add_action('localize_woocommerce_on_ajax', array($this, 'localize_on_ajax'));
|
122 |
add_action('woocommerce_shipping_update_ajax', array($this, 'shipping_update'));
|
123 |
|
139 |
} else {
|
140 |
add_filter('pre_get_posts', array($this, 'shop_page_query'), 9);
|
141 |
add_filter('icl_ls_languages', array($this, 'translate_ls_shop_url'));
|
142 |
+
add_filter('parse_request', array($this, 'adjust_shop_page'));
|
143 |
}
|
144 |
|
145 |
// Hooks for translating product attribute values
|
248 |
add_filter('woocommerce_available_shipping_methods', array($this, 'register_shipping_methods'));
|
249 |
add_filter('woocommerce_countries_tax_or_vat', array($this, 'register_tax_label'));
|
250 |
add_action('option_woocommerce_tax_rates', array($this, 'tax_rates'));
|
251 |
+
add_action('updated_post_meta', array($this,'update_post_meta'), 100, 4);
|
252 |
+
add_action('added_post_meta', array($this,'update_post_meta'), 100, 4);
|
253 |
+
add_action('updated_woocommerce_term_meta',array($this,'sync_term_order'), 100,4);
|
254 |
}
|
255 |
+
|
256 |
function set_price_config() {
|
257 |
global $sitepress, $iclTranslationManagement;
|
258 |
|
344 |
return icl_object_id($id, 'page', true);
|
345 |
}
|
346 |
|
347 |
+
/**
|
348 |
+
* Translate shop url
|
349 |
+
*/
|
350 |
+
function translate_ls_shop_url($languages) {
|
351 |
+
global $sitepress;
|
352 |
+
$shop_id = get_option('woocommerce_shop_page_id');
|
353 |
+
$front_id = icl_object_id(get_option('page_on_front'), 'page');
|
354 |
+
if (is_post_type_archive('product')) {
|
355 |
+
foreach ($languages as &$language) {
|
356 |
+
if ($front_id == $shop_id) {
|
357 |
+
$url = $sitepress->language_url($language['language_code']);
|
358 |
+
} else {
|
359 |
+
$url = get_permalink(icl_object_id($shop_id, 'page', true, $language['language_code']));
|
360 |
+
}
|
361 |
+
$language['url'] = $url;
|
362 |
+
}
|
363 |
+
}
|
364 |
+
return $languages;
|
365 |
+
}
|
366 |
+
|
367 |
+
/**
|
368 |
+
* Translate WooCommerce emails.
|
369 |
+
*
|
370 |
+
* @global type $sitepress
|
371 |
+
* @global type $order_id
|
372 |
+
* @return type
|
373 |
+
*/
|
374 |
+
function email_header() {
|
375 |
+
//note: $_SESSION is not used since Woocommerce 2.0, but this is set by us
|
376 |
+
//we could actually set $woocommerce->session->wpml_language instead and avoid db access
|
377 |
+
global $sitepress, $order_id;
|
378 |
+
$lang = get_post_meta($order_id, 'wpml_language', TRUE);
|
379 |
+
|
380 |
+
if(empty($lang)){
|
381 |
+
if(isset($_SESSION['wpml_globalcart_language'])){
|
382 |
+
$lang = $_SESSION['wpml_globalcart_language'];
|
383 |
+
} else {
|
384 |
+
$lang = $sitepress->get_current_language();
|
385 |
+
}
|
386 |
+
}
|
387 |
+
|
388 |
+
$sitepress->switch_lang($lang, true);
|
389 |
+
}
|
390 |
+
|
391 |
+
/**
|
392 |
+
* After email translation switch language to default.
|
393 |
+
*
|
394 |
+
* @global type $sitepress
|
395 |
+
* @return type
|
396 |
+
*/
|
397 |
+
function email_footer() {
|
398 |
+
global $sitepress;
|
399 |
+
|
400 |
+
$sitepress->switch_lang();
|
401 |
+
}
|
402 |
+
|
403 |
function translate_email_notifications() {
|
404 |
+
$email_actions = array( //the first ones worked for WC 1.6
|
405 |
'woocommerce_order_status_pending_to_processing',
|
406 |
'woocommerce_order_status_pending_to_completed',
|
407 |
'woocommerce_order_status_pending_to_on-hold',
|
409 |
'woocommerce_order_status_failed_to_completed',
|
410 |
'woocommerce_order_status_pending_to_processing',
|
411 |
'woocommerce_order_status_pending_to_on-hold',
|
412 |
+
'woocommerce_order_status_completed',
|
413 |
+
//next are new, at least since WC 2.04; they also began to add the postfix '_notification'
|
414 |
+
//not clear they are consistent accross versions between 2.0 and 2.0.8, so adding them without postfix as well
|
415 |
+
'woocommerce_new_customer_note',
|
416 |
+
'woocommerce_reset_password'
|
417 |
+
/* the following are not added because messages to admins should not switch language; left here for reference of other _notification actions
|
418 |
+
'woocommerce_low_stock',
|
419 |
+
'woocommerce_no_stock',
|
420 |
+
'woocommerce_product_on_backorder'*/
|
421 |
);
|
422 |
+
//added for WC 2.0.x
|
423 |
+
$email_actions = array_merge($email_actions,array_map(function($val) {return $val.'_notification';},$email_actions));
|
424 |
+
|
425 |
foreach ( $email_actions as $action ) {
|
426 |
+
add_action( $action, array($this, 'translate_email_notification'), 9 );
|
427 |
}
|
428 |
}
|
429 |
|
438 |
|
439 |
}
|
440 |
|
441 |
+
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
442 |
|
443 |
/**
|
444 |
* Adds admin notice.
|
635 |
return get_permalink(icl_object_id(get_option('woocommerce_checkout_page_id'), 'page', true));
|
636 |
}
|
637 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
638 |
/**
|
639 |
* Filters WooCommerce AJAX params
|
640 |
*
|
700 |
function translate_attributes($name){
|
701 |
if(function_exists('icl_register_string')){
|
702 |
icl_register_string('woocommerce', $name .'_attribute', $name);
|
|
|
703 |
$name = icl_t('woocommerce', $name .'_attribute', $name);
|
704 |
}
|
705 |
|
767 |
$out = array();
|
768 |
foreach ($terms as $term) {
|
769 |
$term = trim($term);
|
770 |
+
$term = icl_t('woocommerce', $term .'_attribute_name', $term);
|
|
|
|
|
|
|
|
|
771 |
$out[] = $term;
|
772 |
}
|
773 |
|
834 |
}
|
835 |
}
|
836 |
|
837 |
+
function adjust_shop_page($q) {
|
838 |
+
global $sitepress;
|
839 |
+
if ($sitepress->get_default_language() != $sitepress->get_current_language()) {
|
840 |
+
if (!empty($q->query_vars['pagename'])) {
|
841 |
+
$shop_page = get_post( woocommerce_get_page_id('shop') );
|
842 |
+
if ($shop_page->post_name == $q->query_vars['pagename']) {
|
843 |
+
unset($q->query_vars['page']);
|
844 |
+
unset($q->query_vars['pagename']);
|
845 |
+
$q->query_vars['post_type'] = 'product';
|
846 |
+
}
|
847 |
+
}
|
848 |
+
}
|
849 |
+
}
|
850 |
+
|
851 |
+
/**
|
852 |
+
* Filters the currency symbol.
|
853 |
+
*/
|
854 |
+
function woocommerce_currency_symbol($currency_symbol){
|
855 |
+
global $sitepress, $wpdb;
|
856 |
|
857 |
+
// Dont process currency symbols in the settings screen
|
858 |
+
if(function_exists('get_current_screen')) {
|
859 |
+
$screen = get_current_screen();
|
860 |
+
if (!empty($screen) && $screen->id == 'woocommerce_page_woocommerce_settings') {
|
861 |
+
return $currency_symbol;
|
862 |
+
}
|
863 |
+
}
|
864 |
|
865 |
+
$db_currency = $wpdb->get_row("SELECT code FROM ". $wpdb->prefix ."icl_currencies WHERE language_code = '". $sitepress->get_current_language() ."'");
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
866 |
|
867 |
+
if($db_currency && get_option('icl_enable_multi_currency') == 'yes'){
|
868 |
+
$db_currency = $db_currency->code;
|
869 |
+
if(in_array($db_currency, array_keys($this->currencies))){
|
870 |
+
$currency_symbol = $this->currencies[$db_currency];
|
871 |
+
} else {
|
872 |
+
$currency_symbol = $db_currency;
|
873 |
+
}
|
874 |
+
}
|
875 |
+
|
876 |
+
return $currency_symbol;
|
877 |
+
}
|
878 |
|
879 |
/**
|
880 |
* Filters the product price.
|
896 |
return $price;
|
897 |
}
|
898 |
|
899 |
+
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
900 |
/*
|
901 |
* WC compat layer: get product
|
902 |
*/
|
903 |
+
|
904 |
function wcml_get_product($product_id) {
|
905 |
if ( version_compare( WOOCOMMERCE_VERSION, "2.0.0" ) >= 0 ) {
|
906 |
// WC 2.0
|
1105 |
}
|
1106 |
}
|
1107 |
|
1108 |
+
// TODO: move outside the loop all db queries on duplicated_post_id
|
1109 |
+
// don't want to do it so close to release, just in case
|
1110 |
foreach ($posts as $post_id => $translation) {
|
1111 |
$lang = $translation->language_code;
|
1112 |
|
1175 |
$wpdb->update($wpdb->postmeta, $data, $where);
|
1176 |
}
|
1177 |
|
1178 |
+
//sync product categories
|
1179 |
+
$terms = get_the_terms($duplicated_post_id, 'product_cat');
|
1180 |
+
foreach ($terms as $term) {
|
1181 |
+
$trid = $sitepress->get_element_trid($term->term_id, 'tax_product_cat');
|
1182 |
+
if ($trid) {
|
1183 |
+
$translations = $sitepress->get_element_translations($trid,'tax_product_cat');
|
1184 |
+
if (isset($translations[$lang])) {
|
1185 |
+
$updates[$tax][] = intval($translations[$lang]->term_id);
|
1186 |
+
}
|
1187 |
+
}
|
1188 |
+
}
|
1189 |
+
|
1190 |
+
//synchronize term data, postmeta (Woocommerce "global" product attributes and custom attributes)
|
1191 |
+
$taxs = array();
|
1192 |
+
$updates = array();
|
1193 |
+
|
1194 |
+
$taxonomies = get_post_meta($duplicated_post_id, '_product_attributes', true);
|
1195 |
+
//error_log('Trans tax '.var_export($taxonomies,true));
|
1196 |
+
foreach ($taxonomies as $taxonomy) {
|
1197 |
+
if ($taxonomy['is_taxonomy']) { // Global product attribute
|
1198 |
+
$tax = $taxonomy['name'];
|
1199 |
+
$taxs[] = $tax;
|
1200 |
+
$updates[$tax] = array();
|
1201 |
+
$terms = get_the_terms($duplicated_post_id, $tax);
|
1202 |
+
foreach ($terms as $term) {
|
1203 |
+
$trid = $sitepress->get_element_trid($term->term_id, 'tax_' . $tax);
|
1204 |
+
if ($trid) {
|
1205 |
+
$translations = $sitepress->get_element_translations($trid,'tax_' . $tax);
|
1206 |
+
if (isset($translations[$lang])) {
|
1207 |
+
$updates[$tax][] = intval($translations[$lang]->term_id);
|
1208 |
+
}
|
1209 |
+
}
|
1210 |
+
}
|
1211 |
+
}
|
1212 |
+
}
|
1213 |
+
|
1214 |
+
// Sync terms for main product
|
1215 |
+
$taxs = array_unique($taxs);
|
1216 |
+
foreach ($taxs as $tax) {
|
1217 |
+
wp_set_object_terms($post_id, $updates[$tax], $tax);
|
1218 |
+
}
|
1219 |
+
|
1220 |
+
// synchronize post variations
|
1221 |
$get_variation_term_id = $wpdb->get_var("SELECT term_id FROM $wpdb->terms WHERE name = 'variable'");
|
1222 |
$get_variation_term_taxonomy_id = $wpdb->get_var("SELECT tt.term_taxonomy_id FROM $wpdb->term_relationships tr
|
1223 |
LEFT JOIN $wpdb->term_taxonomy tt ON tt.term_taxonomy_id = tr.term_taxonomy_id
|
1224 |
+
WHERE object_id = '$duplicated_post_id' AND taxonomy = 'product_type' AND tt.term_id = '$get_variation_term_id'");
|
1225 |
|
1226 |
$is_post_has_variations = $wpdb->get_results("SELECT * FROM $wpdb->term_relationships WHERE object_id = '$duplicated_post_id' AND term_taxonomy_id = '$get_variation_term_taxonomy_id'");
|
1227 |
if(!empty($is_post_has_variations)) $is_post_has_variations = TRUE;
|
1228 |
|
|
|
1229 |
if($is_post_has_variations){
|
1230 |
// synchronize post variations
|
1231 |
$get_all_post_variations = $wpdb->get_results("SELECT * FROM $wpdb->posts
|
1232 |
+
WHERE post_status = 'publish' AND post_type = 'product_variation' AND post_parent = '$duplicated_post_id' ORDER BY ID");
|
1233 |
|
1234 |
$duplicated_post_variation_ids = array();
|
1235 |
foreach($get_all_post_variations as $k => $post_data){
|
1296 |
'comment_count' => $post_data->comment_count
|
1297 |
));
|
1298 |
update_post_meta($variation_id, '_wcml_duplicate_of_variation', $post_data->ID);
|
|
|
1299 |
$trid = $sitepress->get_element_trid($post_data->ID, 'post_product_variation');
|
1300 |
+
$sitepress->set_element_language_details($variation_id, 'post_product_variation', $trid, $lang, $language_details->source_language_code);
|
1301 |
}
|
1302 |
}
|
1303 |
|
1304 |
$get_current_post_variations = $wpdb->get_results("SELECT * FROM $wpdb->posts
|
1305 |
+
WHERE post_status = 'publish' AND post_type = 'product_variation' AND post_parent = '$post_id' ORDER BY ID");
|
1306 |
|
1307 |
// Delete variations that no longer exist
|
1308 |
foreach ($get_current_post_variations as $post_data) {
|
1321 |
$current_post_variation_ids[] = $post_data->ID;
|
1322 |
}
|
1323 |
|
|
|
1324 |
foreach($duplicated_post_variation_ids as $dp_key => $duplicated_post_variation_id){
|
1325 |
$get_all_post_meta = $wpdb->get_results("SELECT * FROM $wpdb->postmeta WHERE post_id = '$duplicated_post_variation_id'");
|
1326 |
|
1333 |
if (substr($meta_key, 0, 10) == 'attribute_') {
|
1334 |
$tax = substr($meta_key, 10);
|
1335 |
if (taxonomy_exists($tax)) {
|
|
|
1336 |
$attid = get_term_by('slug', $meta_value, $tax)->term_taxonomy_id;
|
1337 |
$trid = $sitepress->get_element_trid($attid, 'tax_' . $tax);
|
1338 |
if ($trid) {
|
1350 |
}
|
1351 |
}
|
1352 |
|
1353 |
+
}
|
1354 |
+
}
|
1355 |
+
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1356 |
|
1357 |
+
|
1358 |
+
/**
|
1359 |
+
* Sync term order for product attributes, categories and tags
|
1360 |
+
*/
|
1361 |
+
function sync_term_order($meta_id, $object_id, $meta_key, $meta_value) {
|
1362 |
+
global $sitepress,$wpdb,$pagenow;
|
1363 |
|
1364 |
+
if (!isset($_POST['thetaxonomy']) || !taxonomy_exists($_POST['thetaxonomy']) || substr($meta_key,0,5) != 'order')
|
1365 |
+
return;
|
1366 |
+
|
1367 |
+
$tax = $_POST['thetaxonomy'];
|
1368 |
+
//error_log(__FUNCTION__." $tax ".var_export(func_get_args(),true));
|
1369 |
+
|
1370 |
+
$lang_details = $sitepress->get_element_language_details($object_id,'tax_' . $tax);
|
1371 |
+
//error_log(var_export($lang_details,true));
|
1372 |
+
$lang = $lang_details->language_code;
|
1373 |
+
$translations = $sitepress->get_element_translations($lang_details->trid,'tax_' . $tax);
|
1374 |
+
if ($translations) foreach ($translations as $trans) {
|
1375 |
+
if ($trans->language_code != $lang) {
|
1376 |
+
//error_log("set_term_order {$trans->language_code} {$trans->element_id} $meta_key $meta_value");
|
1377 |
+
//cannot use update_woocommerce_termmeta or update_metadata as it would end calling this function again in endless loop
|
1378 |
+
$wpdb->update($wpdb->prefix.'woocommerce_termmeta',
|
1379 |
+
array('meta_value' => $meta_value),
|
1380 |
+
array('woocommerce_term_id' => $trans->element_id,'meta_key' => $meta_key));
|
1381 |
+
}
|
1382 |
}
|
1383 |
+
}
|
1384 |
+
|
1385 |
+
function sync_variation_order($variation_id) {
|
1386 |
|
1387 |
}
|
1388 |
|
1389 |
+
function sanitize_cpa_values($values) {
|
1390 |
+
// Text based, separate by pipe
|
1391 |
+
$values = explode('|', esc_html(stripslashes($values)));
|
1392 |
+
$values = array_map('trim', $values);
|
1393 |
+
$values = implode('|', $values);
|
1394 |
+
return $values;
|
1395 |
+
}
|
1396 |
+
|
1397 |
+
function update_post_meta($meta_id, $object_id, $meta_key, $_meta_value) {
|
1398 |
+
if ($meta_key == '_product_attributes' || $meta_key == 'attribute_names') {
|
1399 |
+
foreach (maybe_unserialize($_meta_value) as $attr_slug => $attr) {
|
1400 |
+
if (isset($attr['value'])) {
|
1401 |
+
$values = explode('|',$this->sanitize_cpa_values($attr['value']));
|
1402 |
+
foreach($values as $value) {
|
1403 |
+
icl_register_string('woocommerce',ucfirst($value).'_attribute_name',$value);
|
1404 |
+
}
|
1405 |
+
}
|
1406 |
+
}
|
1407 |
+
}
|
1408 |
+
}
|
1409 |
+
|
1410 |
/**
|
1411 |
* Creates WCML page.
|
1412 |
*/
|
1559 |
<?php
|
1560 |
}
|
1561 |
}
|
1562 |
+
|
1563 |
+
function translate_cart_contents($item, $values, $key) {
|
1564 |
+
if ( version_compare( WOOCOMMERCE_VERSION, "2.0.0" ) < 0 ) {
|
1565 |
+
// clearing subtotal triggers calculate_totals (WC 1.x)
|
1566 |
+
// for WC 2.x its done with the function below
|
1567 |
+
$_SESSION['subtotal'] = 0;
|
1568 |
+
}
|
1569 |
+
|
1570 |
+
// translate the product id and product data
|
1571 |
+
$item['product_id'] = icl_object_id($item['product_id'], 'product', true);
|
1572 |
+
if ($item['variation_id']) {
|
1573 |
+
$item['variation_id'] = icl_object_id($item['variation_id'], 'product_variation', true);
|
1574 |
+
}
|
1575 |
+
$product_id = $item['variation_id'] ? $item['variation_id'] : $item['product_id'];
|
1576 |
+
return array(
|
1577 |
+
'product_id' => $item['product_id'],
|
1578 |
+
'variation_id' => $item['variation_id'],
|
1579 |
+
'variation' => $item['variation'],
|
1580 |
+
'quantity' => $item['quantity'],
|
1581 |
+
'data' => $this->wcml_get_product($product_id)
|
1582 |
+
);
|
1583 |
}
|
1584 |
+
|
1585 |
+
function translate_cart_subtotal($cart) {
|
1586 |
+
$cart->calculate_totals();
|
1587 |
}
|
1588 |
|
1589 |
+
/**
|
1590 |
+
* WooCommerce Multilingual deactivation hook.
|
1591 |
+
*/
|
1592 |
+
function wcml_deactivate(){
|
1593 |
+
delete_option('wpml_dismiss_doc_main');
|
1594 |
+
}
|
1595 |
|
1596 |
}
|
wpml-woocommerce.php
CHANGED
@@ -5,11 +5,11 @@
|
|
5 |
Description: Allows running fully multilingual e-Commerce sites with WooCommerce and WPML. <a href="http://wpml.org/documentation/related-projects/woocommerce-multilingual/">Documentation</a>.
|
6 |
Author: ICanLocalize
|
7 |
Author URI: http://wpml.org/
|
8 |
-
Version: 2.
|
9 |
*/
|
10 |
|
11 |
if(defined('WCML_VERSION')) return;
|
12 |
-
define('WCML_VERSION', '2.
|
13 |
define('WCML_PLUGIN_PATH', dirname(__FILE__));
|
14 |
define('WCML_PLUGIN_FOLDER', basename(WCML_PLUGIN_PATH));
|
15 |
define('WCML_PLUGIN_URL', plugins_url() . '/' . WCML_PLUGIN_FOLDER);
|
5 |
Description: Allows running fully multilingual e-Commerce sites with WooCommerce and WPML. <a href="http://wpml.org/documentation/related-projects/woocommerce-multilingual/">Documentation</a>.
|
6 |
Author: ICanLocalize
|
7 |
Author URI: http://wpml.org/
|
8 |
+
Version: 2.3
|
9 |
*/
|
10 |
|
11 |
if(defined('WCML_VERSION')) return;
|
12 |
+
define('WCML_VERSION', '2.3');
|
13 |
define('WCML_PLUGIN_PATH', dirname(__FILE__));
|
14 |
define('WCML_PLUGIN_FOLDER', basename(WCML_PLUGIN_PATH));
|
15 |
define('WCML_PLUGIN_URL', plugins_url() . '/' . WCML_PLUGIN_FOLDER);
|