@@ -110,6 +110,360 @@ public static function getRelatedVariation($variatonID, $returnIDS = false)
110
110
{
111
111
$ result = array ();
112
112
113
+ //previous version of code using get_post_meta() was filtered at runtime by Polylang
114
+ //even when adding 'suppress_filters' => true, so there was no way to adjust stock
115
+ //on translations when processing new order
116
+ //it also did not return all versions of post for deletion
117
+ global $ wpdb ;
118
+ $ postids =$ wpdb ->get_col ("select post_id from " . $ table_prefix . "postmeta where meta_key=' " .
119
+ self ::DUPLICATE_KEY . "' and meta_value= " . $ variatonID );
120
+
121
+ if (true === $ returnIDS ) {
122
+ return $ postids ;
123
+ } else {
124
+ $ result = array ();
125
+ foreach ($ postids as $ postid ) {
126
+ $ product = wc_get_product ($ postid );
127
+ if ($ product ) {
128
+ $ result []=$ product ;
129
+ }
130
+ }
131
+ return $ result ;
132
+ }
133
+ }
134
+
135
+ /**
136
+ * Delete all variation related to the given variation ID.
137
+ *
138
+ * @param int $variationID variation ID
139
+ */
140
+ public static function deleteRelatedVariation ($ variationID )
141
+ {
142
+ $ products = (array ) static ::getRelatedVariation ($ variationID );
143
+ foreach ($ products as $ product ) {
144
+ wp_delete_post ($ product ->get_id (), true );
145
+ }
146
+ }
147
+ /**
148
+ * Create new variation.
149
+ *
150
+ * @param \WC_Product_Variation $variation the variation product
151
+ * @param array $metas variation array
152
+ */
153
+ protected function insert (\WC_Product_Variation $ variation , array $ metas )
154
+ {
155
+ // Add the duplicate meta to the default language product variation,
156
+ // just in case the product was created before plugin acivation.
157
+ $ this ->addDuplicateMeta ($ variation ->get_id ());
158
+ $ data = (array ) get_post ($ variation ->get_id ());
159
+ unset($ data ['ID ' ]);
160
+ $ data ['post_parent ' ] = $ this ->to ->get_id ();
161
+ $ ID = wp_insert_post ($ data );
162
+ if ($ ID ) {
163
+ update_post_meta (
164
+ $ ID , self ::DUPLICATE_KEY , $ metas ['variation_id ' ]
165
+ );
166
+ $ this ->copyVariationMetas ($ variation ->get_id (), $ ID );
167
+ }
168
+ }
169
+ /**
170
+ * Update variation product from given post object.
171
+ *
172
+ * @param \WC_Product_Variation $variation
173
+ * @param \WP_Post $post
174
+ * @param array $metas
175
+ */
176
+ protected function update (\WC_Product_Variation $ variation , \WP_Post $ post , array $ metas )
177
+ {
178
+ $ this ->copyVariationMetas ($ variation ->get_id (), $ post ->ID );
179
+ }
180
+ /**
181
+ * Add duplicate meta key to products created before plugin activation.
182
+ *
183
+ * @param int $ID Id of the product in the default language
184
+ */
185
+ public function addDuplicateMeta ($ ID )
186
+ {
187
+ if ($ ID ) {
188
+ $ meta = get_post_meta ($ ID , self ::DUPLICATE_KEY );
189
+ if (empty ($ meta )) {
190
+ update_post_meta ($ ID , self ::DUPLICATE_KEY , $ ID );
191
+ }
192
+ }
193
+ }
194
+ /**
195
+ * Sync Product Shipping Class.
196
+ *
197
+ * Shipping Class translation is not supported after WooCommerce 2.6
198
+ * but it is still implemented by WooCommerce as a taxonomy (no longer a meta).
199
+ * Therefore, Polylang will not copy the Shipping Class meta.
200
+ *
201
+ * @param int $from product variation ID
202
+ * @param int $to product variation ID
203
+ */
204
+ public function syncShippingClass ($ from , $ to )
205
+ {
206
+ if (in_array ('product_shipping_class ' , Meta::getProductMetaToCopy ())) {
207
+ $ variation_from = wc_get_product ($ from );
208
+ if ($ variation_from ) {
209
+ $ shipping_class = $ variation_from ->get_shipping_class ();
210
+ if ($ shipping_class ) {
211
+ $ shipping_terms = get_term_by ('slug ' , $ shipping_class , 'product_shipping_class ' );
212
+ if ($ shipping_terms ) {
213
+ wp_set_post_terms ($ to , array ($ shipping_terms ->term_id ), 'product_shipping_class ' );
214
+ }
215
+ } else {
216
+ //if no shipping class found this would mean "Same as parent"
217
+ //so we need to clear existing setting if there is one
218
+ //however get_shipping_class() actually gets the parent value,
219
+ //so this code shouldn't be executed,
220
+ //instead the parent value will be copied to variation
221
+ wp_set_post_terms ($ to , array (), 'product_shipping_class ' );
222
+ }
223
+ }
224
+ }
225
+ }
226
+ /**
227
+ * Copy variation meta.
228
+ *
229
+ * The method follow the same method polylang use to sync metas between
230
+ * translations
231
+ *
232
+ * @param int $from product variation ID
233
+ * @param int $to product variation ID
234
+ *
235
+ * @return boolean false if something went wrong
236
+ */
237
+ protected function copyVariationMetas ($ from , $ to )
238
+ {
239
+ /* copy or synchronize post metas and allow plugins to do the same */
240
+ $ metas_from = get_post_custom ($ from );
241
+ $ metas_to = get_post_custom ($ to );
242
+ /* get public and protected meta keys */
243
+ $ keys = array_unique (array_merge (array_keys ($ metas_from ), array_keys ($ metas_to )));
244
+ /* metas disabled for sync */
245
+ $ metas_nosync = Meta::getDisabledProductMetaToCopy ();
246
+ /*
247
+ * _variation_description meta is a text-based string and generally needs to be translated.
248
+ * _variation_description meta is copied from product in default language to the translations
249
+ * when the translation is first created. But the meta can be edited/changed and will not be
250
+ * overwriten when product is saved or updated.
251
+ */
252
+ if (isset ($ metas_to ['_variation_description ' ])) {
253
+ $ metas_nosync [] = '_variation_description ' ;
254
+ }
255
+ /* synchronize */
256
+ foreach ($ keys as $ key ) {
257
+ if (!in_array ($ key , $ metas_nosync )) {
258
+ /*
259
+ * the synchronization process of multiple values custom fields is
260
+ * easier if we delete all metas first
261
+ */
262
+ delete_post_meta ($ to , $ key );
263
+ if (isset ($ metas_from [$ key ])) {
264
+ if (substr ($ key , 0 , 10 ) == 'attribute_ ' ) {
265
+ $ translated = array ();
266
+ $ tax = str_replace ('attribute_ ' , '' , $ key );
267
+ foreach ($ metas_from [$ key ] as $ termSlug ) {
268
+ if (pll_is_translated_taxonomy ($ tax )) {
269
+ $ term = $ this ->getTermBySlug ($ tax , $ termSlug );
270
+ if ($ term ) {
271
+ $ term_id = $ term ->term_id ;
272
+ //ok we got a term to translate, now get translation if available
273
+ $ lang = isset ($ _GET ['new_lang ' ]) ? esc_attr ($ _GET ['new_lang ' ]) : pll_get_post_language ($ this ->to ->get_id ());
274
+ $ translated_term = pll_get_term ($ term_id , $ lang );
275
+ if ($ translated_term ) {
276
+ $ translated [] = get_term_by ('id ' , $ translated_term , $ tax )->slug ;
277
+ } else {
278
+ // Attribute term has no translation, so get the previous term
279
+ // and create the translation
280
+ $ result = false ;
281
+ $ fromLang = pll_get_post_language ($ from );
282
+ if (! $ fromLang ) {
283
+ $ fromLang = pll_get_post_language (wc_get_product ($ from )->get_parent_id ());
284
+ }
285
+ if ($ fromLang ) {
286
+ $ term = pll_get_term ($ term_id , $ fromLang );
287
+ if ($ term ) {
288
+ $ term = get_term_by ('id ' , $ term , $ tax );
289
+ $ result = Meta::createDefaultTermTranslation ($ tax , $ term , $ termSlug , $ lang , false );
290
+ }
291
+ }
292
+ if ($ result ) {
293
+ $ translated [] = $ result ;
294
+ } else {
295
+ $ translated [] = $ termSlug ;
296
+ }
297
+ }
298
+ } else {
299
+ $ translated [] = $ termSlug ;
300
+ }
301
+ } else {
302
+ $ translated [] = $ termSlug ;
303
+ }
304
+ }
305
+ $ metas_from [$ key ] = $ translated ;
306
+ }
307
+ foreach ($ metas_from [$ key ] as $ value ) {
308
+ /*
309
+ * Important: always maybe_unserialize value coming from
310
+ * get_post_custom. See codex.
311
+ */
312
+ $ value = maybe_unserialize ($ value );
313
+ add_post_meta ($ to , $ key , $ value );
314
+ }
315
+ }
316
+ }
317
+ }
318
+
319
+ //add shipping class not included in metas as now a taxonomy
320
+ $ this ->syncShippingClass ($ from , $ to );
321
+
322
+ do_action (HooksInterface::PRODUCT_VARIATION_COPY_META_ACTION , $ from , $ to , $ this ->from , $ this ->to );
323
+ }
324
+ /**
325
+ * Get Term By Slug.
326
+ *
327
+ * Why not get_term_by method ?! since 4.8 we were unable to force polylang to
328
+ * fetch terms with the default language
329
+ *
330
+ * @param string $taxonomy taxonomy name
331
+ * @param string $value term slug
332
+ *
333
+ * @return bool false if the term can not fetched , the term object otherwise
334
+ */
335
+ private function getTermBySlug ($ taxonomy , $ value )
336
+ {
337
+ $ query = array (
338
+ 'get ' => 'all ' ,
339
+ 'number ' => 1 ,
340
+ 'taxonomy ' => $ taxonomy ,
341
+ 'update_term_meta_cache ' => false ,
342
+ 'orderby ' => 'none ' ,
343
+ 'suppress_filter ' => true ,
344
+ 'slug ' => $ value ,
345
+ 'lang ' => pll_default_language (),
346
+ );
347
+ $ terms = get_terms ($ query );
348
+ if (is_wp_error ($ terms ) || empty ($ terms )) {
349
+ return false ;
350
+ }
351
+ $ term = array_shift ($ terms );
352
+ return get_term ($ term , $ taxonomy );
353
+ }
354
+ }
355
+ <?php
356
+ /**
357
+ * This file is part of the hyyan/woo-poly-integration plugin.
358
+ * (c) Hyyan Abo Fakher <[email protected] >.
359
+ *
360
+ * For the full copyright and license information, please view the LICENSE
361
+ * file that was distributed with this source code.
362
+ */
363
+ namespace Hyyan \WPI \Product ;
364
+
365
+ use Hyyan \WPI \HooksInterface ;
366
+ use Hyyan \WPI \Product \Meta ;
367
+ use Hyyan \WPI \Utilities ;
368
+
369
+ /**
370
+ * Variation.
371
+ *
372
+ * Handle Variation Duplicate
373
+ *
374
+ * @author Hyyan Abo Fakher <[email protected] >
375
+ */
376
+ class Variation
377
+ {
378
+ const DUPLICATE_KEY = '_point_to_variation ' ;
379
+ /**
380
+ * @var \WC_Product_Variable
381
+ */
382
+ protected $ from ;
383
+ /**
384
+ * @var \WC_Product
385
+ */
386
+ protected $ to ;
387
+ /**
388
+ * Construct object.
389
+ *
390
+ * @param \WC_Product_Variable $from the product which contains variations to
391
+ * copy from
392
+ * @param \WC_Product $to the product which we will copy the variation to
393
+ */
394
+ public function __construct (\WC_Product_Variable $ from , \WC_Product $ to )
395
+ {
396
+ $ this ->from = $ from ;
397
+ $ this ->to = $ to ;
398
+ }
399
+ /**
400
+ * Handle variation duplicate.
401
+ *
402
+ * @return bool false if the from product conatins no variatoins
403
+ */
404
+ public function duplicate ()
405
+ {
406
+ //the variations of the product in the from product language
407
+ $ fromVariation = $ this ->from ->get_available_variations ();
408
+ if (empty ($ fromVariation )) {
409
+ return false ;
410
+ }
411
+ if ($ this ->to ->get_id () === $ this ->from ->get_id ()) {
412
+ /*
413
+ * In such a case just add the duplicate meta
414
+ */
415
+ foreach ($ fromVariation as $ variation ) {
416
+ if (! metadata_exists ('post ' , $ variation ['variation_id ' ], self ::DUPLICATE_KEY )) {
417
+ update_post_meta (
418
+ $ variation ['variation_id ' ], self ::DUPLICATE_KEY , $ variation ['variation_id ' ]
419
+ );
420
+ }
421
+ }
422
+ } else {
423
+ /* This could be a very long operation */
424
+ set_time_limit (0 );
425
+ foreach ($ fromVariation as $ variation ) {
426
+ /*
427
+ * First we check if the "to" product contains the duplicate meta
428
+ * key to find out if we have to update or insert
429
+ */
430
+ $ posts = get_posts (array (
431
+ 'meta_key ' => self ::DUPLICATE_KEY ,
432
+ 'meta_value ' => $ variation ['variation_id ' ],
433
+ 'post_type ' => 'product_variation ' ,
434
+ 'post_parent ' => $ this ->to ->get_id (),
435
+ ));
436
+ switch (count ($ posts )) {
437
+ case 1 :
438
+ // update
439
+ $ this ->update (
440
+ wc_get_product ($ variation ['variation_id ' ]), $ posts [0 ], $ variation
441
+ );
442
+ break ;
443
+ case 0 :
444
+ // insert
445
+ $ this ->insert (wc_get_product ($ variation ['variation_id ' ]), $ variation );
446
+ break ;
447
+ default :
448
+ // we can not handle , something wrong here
449
+ break ;
450
+ }
451
+ }
452
+ /* Restor original timeout */
453
+ set_time_limit (ini_get ('max_execution_time ' ));
454
+ }
455
+ }
456
+ /**
457
+ * Get array of variations IDS which point to the given variation ID.
458
+ *
459
+ * @param int $variatonID variation ID
460
+ *
461
+ * @return array array of posts
462
+ */
463
+ public static function getRelatedVariation ($ variatonID , $ returnIDS = false )
464
+ {
465
+ $ result = array ();
466
+
113
467
//previous version of code using get_post_meta() was filtered at runtime by Polylang
114
468
//even when adding 'suppress_filters' => true, so there was no way to adjust stock
115
469
//on translations when processing new order
0 commit comments