PluginProbe ʕ •ᴥ•ʔ
WPML Multilingual & Multicurrency for WooCommerce / 5.5.7
WPML Multilingual & Multicurrency for WooCommerce v5.5.7
5.5.7 5.3.8 5.3.9 5.4.3 5.4.4 5.4.5 5.5.1 5.5.1.1 5.5.2.2 5.5.2.3 5.5.3 5.5.3.1 5.5.4 5.5.5 5.5.6 trunk 0.9 1.0 1.1 1.2 1.3 1.4 1.5 2.0 2.2 2.3 2.3.1 2.3.2 3.0 3.0.1 3.1 3.2 3.2.1 3.2.2 3.3 3.3.1 3.3.2 3.3.3 3.3.4 3.4 3.4.1 3.4.2 3.4.3 3.5 3.5.1 3.5.2 3.5.3 3.5.4 3.5.5 3.6 3.6.1 3.6.10 3.6.11 3.6.2 3.6.3 3.6.4 3.6.5 3.6.5.1 3.6.6 3.6.7 3.6.8 3.6.9 3.7 3.7.1 3.7.10 3.7.11 3.7.12 3.7.13 3.7.14 3.7.15 3.7.16 3.7.2 3.7.3 3.7.4 3.7.5 3.7.6 3.7.7 3.7.8 3.7.9 3.8.0 3.8.1 3.8.2 3.8.3 3.8.4 3.8.5 3.8.6 3.9.0 3.9.1 3.9.1.1 3.9.2 3.9.3 3.9.4 3.9.5 4.0.0 4.0.1 4.0.2 4.0.3 4.0.4 4.1.0 4.1.1 4.1.2 4.1.3 4.1.4 4.10.0 4.10.1 4.10.2 4.10.3 4.10.4 4.11.2 4.11.3.2 4.11.5 4.11.6 4.12.1 4.12.4 4.12.5 4.12.6 4.2.0 4.2.0.1 4.2.1 4.2.1.1 4.2.10 4.2.2 4.2.3 4.2.4 4.2.5 4.2.6 4.2.7 4.2.7.1 4.2.8 4.2.8.1 4.2.9 4.3.0 4.3.1 4.3.2 4.3.2.1 4.3.3 4.3.4 4.3.5 4.3.6 4.3.7 4.4.0 4.4.1 4.4.2 4.4.2.1 4.5.0 4.6.0 4.6.1 4.6.2 4.6.2.1 4.6.3 4.6.5 4.6.6 4.6.7 4.7.0 4.7.1 4.7.2 4.7.3 4.7.4 4.7.5 4.7.6 4.7.7 4.7.8 4.7.9 4.8.0 4.9.0 4.9.1 5.0.1 5.0.2 5.1.1 5.1.2 5.1.3 5.2.0 5.2.1 5.3.2 5.3.3.1 5.3.4 5.3.5 5.3.6 5.3.7
woocommerce-multilingual / inc / class-wcml-tp-support.php
woocommerce-multilingual / inc Last commit date
admin-menus 2 weeks ago currencies 2 weeks ago template-classes 2 weeks ago translation-editor 2 weeks ago class-wcml-ajax-setup.php 2 weeks ago class-wcml-attributes.php 2 weeks ago class-wcml-capabilities.php 2 weeks ago class-wcml-cart-removed-items-widget.php 1 year ago class-wcml-cart-switch-lang-functions.php 2 weeks ago class-wcml-cart-sync-warnings.php 2 weeks ago class-wcml-cart.php 2 weeks ago class-wcml-comments.php 2 weeks ago class-wcml-compatibility.php 2 weeks ago class-wcml-coupons.php 2 weeks ago class-wcml-dependencies.php 2 weeks ago class-wcml-emails.php 2 weeks ago class-wcml-endpoints.php 2 weeks ago class-wcml-install.php 2 weeks ago class-wcml-languages-upgrader.php 2 weeks ago class-wcml-locale.php 2 weeks ago class-wcml-orders.php 2 weeks ago class-wcml-products-screen-options.php 2 weeks ago class-wcml-products.php 2 weeks ago class-wcml-reports.php 2 weeks ago class-wcml-requests.php 2 weeks ago class-wcml-resources.php 2 weeks ago class-wcml-store-pages.php 2 weeks ago class-wcml-terms.php 2 weeks ago class-wcml-tp-support.php 2 weeks ago class-wcml-troubleshooting.php 2 weeks ago class-wcml-upgrade.php 2 weeks ago class-wcml-url-translation.php 2 weeks ago class-wcml-wc-gateways.php 2 weeks ago class-wcml-wc-shipping.php 2 weeks ago class-wcml-wc-strings.php 2 weeks ago class-wcml-widgets.php 2 weeks ago constants.php 2 weeks ago functions-pure.php 2 weeks ago functions.php 2 weeks ago installer-loader.php 2 weeks ago missing-php-functions.php 2 weeks ago wcml-core-functions.php 2 weeks ago wcml-switch-lang-request.php 2 weeks ago
class-wcml-tp-support.php
440 lines
1 <?php
2
3 use WCML\TranslationJob\Hooks;
4 use function WCML\functions\flushProductCachePrefixById;
5
6 class WCML_TP_Support {
7
8 const CUSTOM_FIELD_NAME = 'wc_variation_field:';
9
10 const DOWNLOADABLE_FILES_TRANSLATABLE_FIELDS = [ 'name', 'file' ];
11
12 const PRIORITY_SAVE_VARIATION_CUSTOM_FIELDS_TRANSLATION = 20;
13
14 const PACKAGE_IMAGE_KEY_PREFIX = 'image-id-';
15
16 private $woocommerce_wpml;
17 private $wpdb;
18 private $tp;
19 private $tm_settings;
20
21 public function __construct( woocommerce_wpml $woocommerce_wpml, wpdb $wpdb, WPML_Element_Translation_Package $tp, array $tm_settings ) {
22 $this->woocommerce_wpml = $woocommerce_wpml;
23 $this->wpdb = $wpdb;
24 $this->tp = $tp;
25 $this->tm_settings = $tm_settings;
26 }
27
28 public function add_hooks() {
29 add_filter( 'wpml_tm_translation_job_data', [
30 $this,
31 'append_custom_attributes_to_translation_package'
32 ], 10, 2 );
33 add_action( 'wpml_translation_job_saved', [ $this, 'save_custom_attribute_translations' ], 10, 3 );
34
35 add_filter( 'wpml_tm_translation_job_data', [
36 $this,
37 'append_variation_custom_fields_to_translation_package'
38 ], 10, 2 );
39
40 add_filter( 'wpml_tm_translation_job_data', [
41 $this,
42 'append_variation_downloadable_fields_to_translation_package'
43 ], 10, 2 );
44
45 add_filter( 'wpml_tm_translation_job_data', [
46 $this,
47 'append_simple_downloadable_fields_to_translation_package'
48 ], 10, 2 );
49
50 add_action( 'wpml_pro_translation_completed', [
51 $this,
52 'save_variation_custom_fields_translations'
53 ], self::PRIORITY_SAVE_VARIATION_CUSTOM_FIELDS_TRANSLATION, 3 );
54
55 add_action(
56 'wpml_pro_translation_completed',
57 [
58 $this,
59 'flush_variable_product_cache_prefix',
60 ],
61 self::PRIORITY_SAVE_VARIATION_CUSTOM_FIELDS_TRANSLATION + 10,
62 3
63 );
64
65 add_filter( 'wpml_tm_translation_job_data', [ $this, 'append_images_to_translation_package' ], 10, 2 );
66 add_action( 'wpml_translation_job_saved', [ $this, 'save_images_translations' ], 10, 3 );
67
68 add_filter( 'wpml_custom_field_settings_override_lock_render', [ $this, 'set_wpml_term_custom_field_thumbnail_id_as_read_only' ], 10, 2 );
69 }
70
71 public function set_wpml_term_custom_field_thumbnail_id_as_read_only( $override, $setting ) {
72 if ( 'thumbnail_id' === $setting->get_index() && ( $setting instanceof WPML_Term_Custom_Field_Setting ) ) {
73 if( WPML_COPY_CUSTOM_FIELD === $setting->status() ) {
74 $setting->make_read_only();
75 }
76 }
77
78 return $override;
79 }
80
81 public function append_custom_attributes_to_translation_package( $package, $post ) {
82 if ( $this->isWpPostAWcProduct( $post ) ) {
83
84 $product = wc_get_product( $post->ID );
85
86 if ( ! empty( $product ) ) {
87
88 $attributes = $product->get_attributes();
89
90 foreach ( $attributes as $attribute_key => $attribute ) {
91
92 if ( $this->woocommerce_wpml->attributes->is_a_taxonomy( $attribute ) ) {
93 continue;
94 }
95
96 $package['contents'][ 'wc_attribute_name:' . $attribute_key ] = [
97 'translate' => 1,
98 'data' => $this->tp->encode_field_data( $attribute['name'] ),
99 'format' => 'base64'
100 ];
101 $values = explode( '|', $attribute['value'] );
102 $values = array_map( 'trim', $values );
103
104 foreach ( $values as $value_key => $value ) {
105 $package['contents'][ 'wc_attribute_value:' . $value_key . ':' . $attribute_key ] = [
106 'translate' => 1,
107 'data' => $this->tp->encode_field_data( $value ),
108 'format' => 'base64'
109 ];
110 }
111 }
112 }
113 }
114
115 return $package;
116 }
117
118 public function save_custom_attribute_translations( $post_id, $data, $job ) {
119
120 $translated_attributes = [];
121 $translated_labels = $this->woocommerce_wpml->attributes->get_attr_label_translations( $post_id );
122
123 foreach ( $data as $value ) {
124
125 if ( $value['finished'] && isset( $value['field_type'] ) && strpos( $value['field_type'], 'wc_attribute_' ) === 0 ) {
126
127 if ( strpos( $value['field_type'], 'wc_attribute_name:' ) === 0 ) {
128
129 $exp = explode( ':', $value['field_type'], 2 );
130 $attribute_key = $exp[1];
131
132 $translated_attributes[ $attribute_key ]['name'] = $value['data'];
133
134 } else if ( strpos( $value['field_type'], 'wc_attribute_value:' ) === 0 ) {
135
136 $exp = explode( ':', $value['field_type'], 3 );
137 $value_key = $exp[1];
138 $attribute_key = $exp[2];
139
140 $translated_attributes[ $attribute_key ]['values'][ $value_key ] = $value['data'];
141
142 }
143
144 }
145
146 }
147
148 if ( $translated_attributes ) {
149
150 $product_attributes = get_post_meta( $post_id, '_product_attributes', true ) ?: [];
151
152 if( isset( $job->original_doc_id ) ){
153 $original_post_id = $job->original_doc_id;
154 }else{
155 $original_post_id = $this->woocommerce_wpml->products->get_original_product_id( $post_id );
156 }
157
158 $original_attributes = get_post_meta( $original_post_id, '_product_attributes', true ) ?: [];
159
160 foreach ( $translated_attributes as $attribute_key => $attribute ) {
161 if( isset( $original_attributes[ $attribute_key ] ) ){
162 $product_attributes[ $attribute_key ] = $original_attributes[ $attribute_key ];
163 $product_attributes[ $attribute_key ]['name'] = $attribute['name'];
164 $product_attributes[ $attribute_key ]['value'] = isset( $attribute['values'] )
165 ? join( ' | ', $attribute['values'] )
166 : $product_attributes[ $attribute_key ]['value'];
167
168 $translated_labels[ $job->language_code ][ $attribute_key ] = $attribute['name'];
169 }
170 }
171
172 update_post_meta( $post_id, '_product_attributes', $product_attributes );
173 update_post_meta( $post_id, 'attr_label_translations', $translated_labels );
174 }
175
176 }
177
178 private function get_variation_custom_fields_to_translate( $variation_id ) {
179 $is_field_translatable = function ( $meta_key ) {
180 return isset( $this->tm_settings['custom_fields_translation'][ $meta_key ] )
181 && (int) $this->tm_settings['custom_fields_translation'][ $meta_key ] === WPML_TRANSLATE_CUSTOM_FIELD;
182 };
183
184 return wpml_collect( (array) get_post_custom_keys( $variation_id ) )
185 ->filter( $is_field_translatable )
186 ->toArray();
187 }
188
189 public function append_variation_custom_fields_to_translation_package( $package, $post ) {
190 if ( $this->isWpPostAWcProduct( $post ) ) {
191
192 $product = wc_get_product( $post->ID );
193
194 $allowed_variations_types = apply_filters( 'wcml_xliff_allowed_variations_types', [ 'variable' ] );
195
196 if ( $product instanceof WC_Product && in_array( $product->get_type(), $allowed_variations_types, true ) ) {
197
198 $variations = $this->woocommerce_wpml->sync_variations_data->get_product_variations( $post->ID );
199
200 foreach ( $variations as $variation ) {
201
202 $meta_keys_to_translate = $this->get_variation_custom_fields_to_translate( $variation->ID );
203
204 foreach ( $meta_keys_to_translate as $meta_key ){
205 $meta_value = get_post_meta( $variation->ID, $meta_key, true );
206
207 if ( $meta_value && !is_array( $meta_value ) ) {
208 $package['contents'][ self::CUSTOM_FIELD_NAME.$meta_key.':' . $variation->ID ] = [
209 'translate' => 1,
210 'data' => $this->tp->encode_field_data( $meta_value ),
211 'format' => 'base64'
212 ];
213 }
214 }
215 }
216
217 }
218
219 }
220
221 return $package;
222
223 }
224
225 public function append_variation_downloadable_fields_to_translation_package( $package, $post ) {
226 if ( $this->isWpPostAWcProduct( $post ) ) {
227
228 $product = wc_get_product( $post->ID );
229
230 $allowed_variations_types = apply_filters( 'wcml_xliff_allowed_variations_types', [ 'variable' ] );
231
232 if ( $product instanceof WC_Product && in_array( $product->get_type(), $allowed_variations_types, true ) ) {
233
234 $variations = $this->woocommerce_wpml->sync_variations_data->get_product_variations( $post->ID );
235
236 foreach ( $variations as $variation ) {
237
238 $meta_keys_to_translate = $this->get_variation_custom_fields_to_translate( $variation->ID );
239
240 if ( ! in_array( WCML_Downloadable_Products::DOWNLOADABLE_FILES_META, $meta_keys_to_translate ) ) {
241 continue;
242 }
243
244 $meta_value = get_post_meta( $variation->ID, WCML_Downloadable_Products::DOWNLOADABLE_FILES_META, true );
245
246 $fileNo = 0;
247 foreach ( $meta_value as $downloadableId => $downloadableFile ) {
248 foreach ( $downloadableFile as $name => $value ) {
249 if ( ! in_array( $name, self::DOWNLOADABLE_FILES_TRANSLATABLE_FIELDS ) ) {
250 continue;
251 }
252
253 $productKey = WCML_Downloadable_Products::buildDownloadableFileField( $fileNo, $downloadableId, $name );
254 $productVariantKey = sprintf( '%s:%d', $productKey, $variation->ID );
255
256 $package['contents'][ $productVariantKey ] = [
257 'translate' => 1,
258 'data' => $this->tp->encode_field_data( $value ),
259 'format' => 'base64'
260 ];
261 }
262 $fileNo ++;
263 }
264 }
265 }
266 }
267 return $package;
268 }
269
270 public function append_simple_downloadable_fields_to_translation_package( $package, $post ) {
271 if ( $this->isWpPostAWcProduct( $post ) ) {
272 if ( WCML_Downloadable_Products::isDownloadableFilesSetToUseSame( $post->ID ) ) {
273 return $package;
274 }
275
276 $product = wc_get_product( $post->ID );
277
278 $allowed_types = [ 'simple' ];
279
280 if ( $product instanceof WC_Product && in_array( $product->get_type(), $allowed_types, true ) ) {
281
282 $meta_value = get_post_meta( $post->ID, WCML_Downloadable_Products::DOWNLOADABLE_FILES_META, true );
283
284 if ( ! is_array( $meta_value ) ) {
285 return $package;
286 }
287
288 $fileNo = 0;
289 foreach ( $meta_value as $downloadableId => $downloadableFile ) {
290 foreach ( $downloadableFile as $name => $value ) {
291 if ( ! in_array( $name, self::DOWNLOADABLE_FILES_TRANSLATABLE_FIELDS ) ) {
292 continue;
293 }
294
295 $productKey = WCML_Downloadable_Products::buildDownloadableFileField( $fileNo, $downloadableId, $name );
296
297 $package['contents'][ $productKey ] = [
298 'translate' => 1,
299 'data' => $this->tp->encode_field_data( $value ),
300 'format' => 'base64'
301 ];
302 }
303 $fileNo ++;
304 }
305 }
306 }
307
308 return $package;
309 }
310
311 public function save_variation_custom_fields_translations( $post_id, $data, $job ) {
312 if ( ! Hooks::isProduct( $job ) ) {
313 return null;
314 }
315
316 $language = $job->language_code;
317
318 foreach ( $data as $value ) {
319
320 if ( $value['finished'] && isset( $value['field_type'] ) && strpos( $value['field_type'], self::CUSTOM_FIELD_NAME ) === 0 ) {
321
322 $exp = explode( ':', $value['field_type'], 3 );
323 $meta_key = $exp[1];
324 $variation_id = $exp[2];
325
326 if ( is_post_type_translated( 'product_variation' ) ) {
327 $translated_variation_id = apply_filters( 'wpml_object_id', $variation_id, 'product_variation', false, $language );
328 } else {
329 global $wpml_post_translations;
330 $translations = $wpml_post_translations->get_element_translations( $variation_id );
331 $translated_variation_id = $translations[ $language ] ?? false;
332 }
333
334 if ( $translated_variation_id ) {
335 update_post_meta( $translated_variation_id, $meta_key, $value['data'] );
336 }
337 }
338 }
339
340 }
341
342 public function append_images_to_translation_package( $package, $post ) {
343 if ( $this->isWpPostAWcProduct( $post ) ) {
344
345 $product_images = $this->woocommerce_wpml->media->product_images_ids( $post->ID );
346 foreach ( $product_images as $image_id ) {
347 $attachment_data = $this->wpdb->get_row( $this->wpdb->prepare( "SELECT post_title,post_excerpt,post_content FROM {$this->wpdb->posts} WHERE ID = %d", $image_id ) );
348 if ( ! is_object( $attachment_data ) ) {
349 continue;
350 }
351 $alt_text = get_post_meta( $image_id, '_wp_attachment_image_alt', true );
352 $alt_text = $alt_text ?: '';
353 $this->add_to_package( $package, self::PACKAGE_IMAGE_KEY_PREFIX . $image_id . '-title', $attachment_data->post_title );
354 $this->add_to_package( $package, self::PACKAGE_IMAGE_KEY_PREFIX . $image_id . '-caption', $attachment_data->post_excerpt );
355 $this->add_to_package( $package, self::PACKAGE_IMAGE_KEY_PREFIX . $image_id . '-description', $attachment_data->post_content );
356 $this->add_to_package( $package, self::PACKAGE_IMAGE_KEY_PREFIX . $image_id . '-alt-text', $alt_text );
357
358 }
359 }
360
361 return $package;
362 }
363
364 public function save_images_translations( $post_id, $data, $job ) {
365
366 $language = $job->language_code;
367
368 $product_images = $this->woocommerce_wpml->media->product_images_ids( $job->original_doc_id );
369 foreach ( $product_images as $image_id ) {
370 $translated_prod_image = apply_filters( 'wpml_object_id', $image_id, 'attachment', false, $language );
371 $image_data = $this->get_image_data( $image_id, $data );
372 if ( ! empty( $image_data ) ) {
373
374 $translation = [];
375 if ( isset( $image_data['title'] ) ) {
376 $translation['post_title'] = $image_data['title'];
377 }
378 if ( isset( $image_data['description'] ) ) {
379 $translation['post_content'] = $image_data['description'];
380 }
381 if ( isset( $image_data['caption'] ) ) {
382 $translation['post_excerpt'] = $image_data['caption'];
383 }
384
385 if ( $translation ) {
386 $this->wpdb->update( $this->wpdb->posts, $translation, [ 'id' => $translated_prod_image ] );
387 }
388
389 if ( isset( $image_data['alt-text'] ) ) {
390 update_post_meta( $translated_prod_image, '_wp_attachment_image_alt', $image_data['alt-text'] );
391 }
392 }
393 }
394 }
395
396 private function isWpPostAWcProduct( $post ): bool {
397 return 'product' === $post->post_type;
398 }
399
400 private function get_image_data( $image_id, $data ) {
401 $image_data = [];
402
403 foreach ( $data as $value ) {
404 if ( $value['finished'] && isset( $value['field_type'] ) ) {
405 if ( strpos( $value['field_type'], self::PACKAGE_IMAGE_KEY_PREFIX . $image_id ) === 0 ) {
406 if ( $value['field_type'] === self::PACKAGE_IMAGE_KEY_PREFIX . $image_id . '-title' ) {
407 $image_data['title'] = $value['data'];
408 }
409 if ( $value['field_type'] === self::PACKAGE_IMAGE_KEY_PREFIX . $image_id . '-caption' ) {
410 $image_data['caption'] = $value['data'];
411 }
412 if ( $value['field_type'] === self::PACKAGE_IMAGE_KEY_PREFIX . $image_id . '-description' ) {
413 $image_data['description'] = $value['data'];
414 }
415 if ( $value['field_type'] === self::PACKAGE_IMAGE_KEY_PREFIX . $image_id . '-alt-text' ) {
416 $image_data['alt-text'] = $value['data'];
417 }
418 }
419 }
420 }
421
422 return $image_data;
423 }
424
425 private function add_to_package( &$package, $key, $data ) {
426 $package['contents'][ $key ] = [
427 'translate' => 1,
428 'data' => $this->tp->encode_field_data( $data ),
429 'format' => 'base64'
430 ];
431
432 }
433
434 public function flush_variable_product_cache_prefix( $post_id, $data, $job ) {
435 if ( Hooks::isProduct( $job ) ) {
436 flushProductCachePrefixById( $post_id );
437 }
438 }
439 }
440