WooCommerce Multilingual – run WooCommerce with WPML - Version 3.8.2

Version Description

  • Bug fix: cart strings not displaying in the correct language in some conditions
  • Bug fix: prices in secondary currencies were not updated on the front end after changing the price (the cache was not invalidated)
  • Bug fix: shipping classes were not synchronized for translated products in some circumstances
  • Bug fix: translated endpoints were missing from the rewrite rules after updating the permalinks
  • Bug fix: stock status was sometimes not synchronized correctly when changing the stock manually
  • Bug fix: when using the default category base the language switcher did not show translated urls on the front end
  • Updated the cart cache hashes logic according to new WooCommerce logic
  • Added a new filter: 'wcml_product_custom_prices'
  • Added separate section for translatable fields for external products in the translations editor
  • Fixed compatibility issues with WooCommerce Table Rate Shipping 3.0+
  • Fixed one compatibility issue with WooCommerce Dynamic Pricing: the discount was not shown on the mini-cart
  • Fixed compatibility with Product Add-ons: strings were not translated
Download this release

Release Info

Developer mihaimihai
Plugin Icon 128x128 WooCommerce Multilingual – run WooCommerce with WPML
Version 3.8.2
Comparing to
See all releases

Code changes from version 3.8.1 to 3.8.2

Files changed (83) hide show
  1. compatibility/class-wcml-adventure-tours.php +4 -2
  2. compatibility/class-wcml-bookings.php +364 -272
  3. compatibility/class-wcml-dynamic-pricing.php +3 -3
  4. compatibility/class-wcml-product-addons.php +42 -9
  5. compatibility/class-wcml-tab-manager.php +562 -469
  6. compatibility/class-wcml-table-rate-shipping.php +2 -2
  7. embedded/autoload_52.php +1 -1
  8. embedded/composer/autoload_real_52.php +3 -3
  9. embedded/composer/installed.json +46 -44
  10. embedded/composer/installers/README.md +5 -1
  11. embedded/composer/installers/src/Composer/Installers/BitrixInstaller.php +9 -6
  12. embedded/composer/installers/src/Composer/Installers/DecibelInstaller.php +10 -0
  13. embedded/composer/installers/src/Composer/Installers/ExpressionEngineInstaller.php +29 -0
  14. embedded/composer/installers/src/Composer/Installers/Installer.php +5 -0
  15. embedded/composer/installers/src/Composer/Installers/PhiftyInstaller.php +11 -0
  16. embedded/composer/installers/src/Composer/Installers/RadPHPInstaller.php +24 -0
  17. embedded/otgs/installer/changelog.txt +136 -0
  18. embedded/otgs/installer/includes/class-installer-dependencies.php +278 -0
  19. embedded/otgs/installer/includes/class-installer-theme.php +979 -0
  20. embedded/otgs/installer/includes/installer-api.php +116 -0
  21. embedded/otgs/installer/includes/installer-upgrader-skins.php +37 -0
  22. embedded/otgs/installer/includes/installer.class.php +2559 -0
  23. embedded/otgs/installer/includes/translation-service-info.class.php +40 -0
  24. embedded/otgs/installer/installer.php +22 -0
  25. embedded/otgs/installer/loader.php +151 -0
  26. embedded/otgs/installer/locale/installer-ar.mo +0 -0
  27. embedded/otgs/installer/locale/installer-de_DE.mo +0 -0
  28. embedded/otgs/installer/locale/installer-el.mo +0 -0
  29. embedded/otgs/installer/locale/installer-es_ES.mo +0 -0
  30. embedded/otgs/installer/locale/installer-fr_FR.mo +0 -0
  31. embedded/otgs/installer/locale/installer-he_IL.mo +0 -0
  32. embedded/otgs/installer/locale/installer-it_IT.mo +0 -0
  33. embedded/otgs/installer/locale/installer-ja.mo +0 -0
  34. embedded/otgs/installer/locale/installer-ko_KR.mo +0 -0
  35. embedded/otgs/installer/locale/installer-nl_NL.mo +0 -0
  36. embedded/otgs/installer/locale/installer-pl_PL.mo +0 -0
  37. embedded/otgs/installer/locale/installer-pt_BR.mo +0 -0
  38. embedded/otgs/installer/locale/installer-pt_PT.mo +0 -0
  39. embedded/otgs/installer/locale/installer-ru_RU.mo +0 -0
  40. embedded/otgs/installer/locale/installer-sv_SE.mo +0 -0
  41. embedded/otgs/installer/locale/installer-uk_UA.mo +0 -0
  42. embedded/otgs/installer/locale/installer-vi.mo +0 -0
  43. embedded/otgs/installer/locale/installer-zh_CN.mo +0 -0
  44. embedded/otgs/installer/locale/installer-zh_TW.mo +0 -0
  45. embedded/otgs/installer/locale/orig/installer.po +230 -0
  46. embedded/otgs/installer/repositories.xml +13 -0
  47. embedded/otgs/installer/res/css/admin.css +186 -0
  48. embedded/otgs/installer/res/img/complete.png +0 -0
  49. embedded/otgs/installer/res/img/computer.png +0 -0
  50. embedded/otgs/installer/res/img/dn.gif +0 -0
  51. embedded/otgs/installer/res/img/dn2.gif +0 -0
  52. embedded/otgs/installer/res/img/globe.png +0 -0
  53. embedded/otgs/installer/res/img/icon_error.gif +0 -0
  54. embedded/otgs/installer/res/img/on.png +0 -0
  55. embedded/otgs/installer/res/img/spinner.gif +0 -0
  56. embedded/otgs/installer/res/js/admin.js +403 -0
  57. embedded/otgs/installer/res/js/iframeResizer.min.js +10 -0
  58. embedded/otgs/installer/res/js/installer_theme_install.js +97 -0
  59. embedded/otgs/installer/templates/downloads-list-compact.php +80 -0
  60. embedded/otgs/installer/templates/downloads-list.php +85 -0
  61. embedded/otgs/installer/templates/products-compact.php +129 -0
  62. embedded/otgs/installer/templates/repository-listing.php +179 -0
  63. inc/class-wcml-cart.php +1 -4
  64. inc/class-wcml-compatibility.php +22 -5
  65. inc/class-wcml-endpoints.php +4 -3
  66. inc/class-wcml-resources.php +9 -1
  67. inc/class-wcml-terms.php +0 -80
  68. inc/class-wcml-upgrade.php +36 -24
  69. inc/class-wcml-url-translation.php +27 -7
  70. inc/class-wcml-wc-shipping.php +98 -2
  71. inc/class-woocommerce-wpml.php +2 -2
  72. inc/currencies/class-wcml-custom-prices.php +5 -6
  73. inc/currencies/class-wcml-multi-currency-shipping.php +8 -3
  74. inc/currencies/class-wcml-multi-currency-table-rate-shipping.php +7 -1
  75. inc/currencies/class-wcml-multi-currency.php +1 -1
  76. inc/translation-editor/class-wcml-editor-ui-product-job.php +10 -0
  77. inc/translation-editor/class-wcml-synchronize-product-data.php +8 -3
  78. readme.txt +17 -5
  79. res/js/cart_widget.js +4 -2
  80. res/js/cart_widget.min.js +1 -1
  81. res/js/lock_fields.js +1 -2
  82. res/js/lock_fields.min.js +1 -1
  83. wpml-woocommerce.php +2 -2
compatibility/class-wcml-adventure-tours.php CHANGED
@@ -338,14 +338,16 @@ class WCML_Adventure_tours{
338
  function add_tour_tax_id( $variation_term_taxonomy_ids ){
339
  global $wpdb;
340
  $tour_taxonomy_id = $wpdb->get_var( "SELECT tt.term_taxonomy_id FROM {$wpdb->terms} AS t LEFT JOIN {$wpdb->term_taxonomy} AS tt ON t.term_id = tt.term_id WHERE t.name = 'tour' AND tt.taxonomy = 'product_type'" );
341
- $variation_term_taxonomy_ids[] = $tour_taxonomy_id;
 
 
 
342
 
343
  return $variation_term_taxonomy_ids;
344
 
345
  }
346
 
347
  function is_variable_tour( $is_variable, $product_id ){
348
-
349
  $var_tour_meta = get_post_meta( $product_id, '_variable_tour', true );
350
 
351
  if( $is_variable && $var_tour_meta == 'yes' ){
338
  function add_tour_tax_id( $variation_term_taxonomy_ids ){
339
  global $wpdb;
340
  $tour_taxonomy_id = $wpdb->get_var( "SELECT tt.term_taxonomy_id FROM {$wpdb->terms} AS t LEFT JOIN {$wpdb->term_taxonomy} AS tt ON t.term_id = tt.term_id WHERE t.name = 'tour' AND tt.taxonomy = 'product_type'" );
341
+
342
+ if( $tour_taxonomy_id ){
343
+ $variation_term_taxonomy_ids[] = $tour_taxonomy_id;
344
+ }
345
 
346
  return $variation_term_taxonomy_ids;
347
 
348
  }
349
 
350
  function is_variable_tour( $is_variable, $product_id ){
 
351
  $var_tour_meta = get_post_meta( $product_id, '_variable_tour', true );
352
 
353
  if( $is_variable && $var_tour_meta == 'yes' ){
compatibility/class-wcml-bookings.php CHANGED
@@ -1,12 +1,38 @@
1
  <?php
2
 
3
- class WCML_Bookings{
4
-
 
 
 
 
 
 
5
  public $tp;
6
 
7
- function __construct(){
8
-
9
- add_action( 'woocommerce_bookings_after_booking_base_cost' , array( $this, 'wcml_price_field_after_booking_base_cost' ) );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
10
  add_action( 'woocommerce_bookings_after_booking_block_cost' , array( $this, 'wcml_price_field_after_booking_block_cost' ) );
11
  add_action( 'woocommerce_bookings_after_display_cost' , array( $this, 'wcml_price_field_after_display_cost' ) );
12
  add_action( 'woocommerce_bookings_after_booking_pricing_base_cost' , array( $this, 'wcml_price_field_after_booking_pricing_base_cost' ), 10, 2 );
@@ -19,7 +45,7 @@ class WCML_Bookings{
19
 
20
  add_action( 'init', array( $this, 'load_assets' ) );
21
 
22
- add_action( 'save_post', array( $this, 'save_custom_costs' ), 110, 2 );
23
  add_action( 'wcml_before_sync_product_data', array( $this, 'sync_bookings' ), 10, 3 );
24
  add_action( 'wcml_before_sync_product', array( $this, 'sync_booking_data' ), 10, 2 );
25
 
@@ -141,11 +167,11 @@ class WCML_Bookings{
141
  }
142
 
143
  function echo_wcml_price_field( $post_id, $field, $pricing = false, $check = true, $resource_id = false ){
144
- global $woocommerce_wpml;
145
 
146
- if( ( !$check || $woocommerce_wpml->products->is_original_product( $post_id ) ) && $woocommerce_wpml->settings['enable_multi_currency'] == WCML_MULTI_CURRENCIES_INDEPENDENT ){
147
 
148
- $currencies = $woocommerce_wpml->multi_currency->get_currencies();
 
 
149
 
150
  $wc_currencies = get_woocommerce_currencies();
151
 
@@ -266,9 +292,9 @@ class WCML_Bookings{
266
  }
267
 
268
  function after_bookings_pricing( $post_id ){
269
- global $woocommerce_wpml;
270
 
271
- if( in_array( 'booking', wp_get_post_terms( $post_id, 'product_type', array( "fields" => "names" ) ) ) && $woocommerce_wpml->products->is_original_product( $post_id ) && $woocommerce_wpml->settings['enable_multi_currency'] == WCML_MULTI_CURRENCIES_INDEPENDENT ){
 
272
 
273
  $custom_costs_status = get_post_meta( $post_id, '_wcml_custom_costs_status', true );
274
 
@@ -291,128 +317,41 @@ class WCML_Bookings{
291
 
292
  }
293
 
294
- function save_custom_costs( $post_id, $post ){
295
- global $woocommerce_wpml;
296
 
297
- $nonce = filter_input( INPUT_POST, '_wcml_custom_costs_nonce', FILTER_SANITIZE_FULL_SPECIAL_CHARS );
298
 
299
- if( isset( $_POST['_wcml_custom_costs'] ) && isset( $nonce ) && wp_verify_nonce( $nonce, 'wcml_save_custom_costs' ) ){
300
-
301
  update_post_meta( $post_id, '_wcml_custom_costs_status', $_POST['_wcml_custom_costs'] );
302
 
303
- if( $_POST['_wcml_custom_costs'] == 1 ){
304
-
305
- $currencies = $woocommerce_wpml->multi_currency->get_currencies();
306
-
307
- foreach( $currencies as $code => $currency ){
308
-
309
- $wc_booking_cost = $_POST[ 'wcml_wc_booking_cost' ][ $code ];
310
- update_post_meta( $post_id, '_wc_booking_cost_'.$code, $wc_booking_cost );
311
-
312
- $wc_booking_base_cost = $_POST[ 'wcml_wc_booking_base_cost' ][ $code ];
313
- update_post_meta( $post_id, '_wc_booking_base_cost_'.$code, $wc_booking_base_cost );
314
-
315
- $wc_display_cost = $_POST[ 'wcml_wc_display_cost' ][ $code ];
316
- update_post_meta( $post_id, '_wc_display_cost_'.$code, $wc_display_cost );
317
-
318
- }
319
-
320
- $booking_pricing = get_post_meta( $post_id, '_wc_booking_pricing', true );
321
- foreach ( $booking_pricing as $key => $prices) {
322
-
323
- $updated_meta[$key] = $prices;
324
-
325
- foreach ($currencies as $code => $currency) {
326
-
327
- $updated_meta[$key]['base_cost_' . $code] = $_POST['wcml_wc_booking_pricing_base_cost'][$code][$key];
328
- $updated_meta[$key]['cost_' . $code] = $_POST['wcml_wc_booking_pricing_cost'][$code][$key];
329
-
330
- }
331
-
332
- }
333
-
334
- update_post_meta($post_id, '_wc_booking_pricing', $updated_meta);
335
-
336
- //person costs
337
- if( isset( $_POST[ 'wcml_wc_booking_person_cost' ] ) ) {
338
-
339
- foreach ($_POST['wcml_wc_booking_person_cost'] as $person_id => $costs) {
340
-
341
- foreach ($currencies as $code => $currency) {
342
-
343
- $wc_booking_person_cost = $costs[$code];
344
- update_post_meta($person_id, 'cost_' . $code, $wc_booking_person_cost);
345
-
346
- }
347
-
348
- }
349
-
350
- }
351
-
352
- if( isset( $_POST[ 'wcml_wc_booking_person_cost' ] ) ){
353
-
354
- foreach( $_POST[ 'wcml_wc_booking_person_block_cost' ] as $person_id => $costs ){
355
-
356
- foreach( $currencies as $code => $currency ){
357
-
358
- $wc_booking_person_block_cost = $costs[ $code ];
359
- update_post_meta( $person_id, 'block_cost_'.$code, $wc_booking_person_block_cost );
360
-
361
- }
362
-
363
- }
364
-
365
- }
366
-
367
- if( isset( $_POST[ 'wcml_wc_booking_resource_cost' ] ) ) {
368
-
369
- $updated_meta = get_post_meta( $post_id, '_resource_base_costs', true );
370
-
371
- $wc_booking_resource_costs = array();
372
-
373
- foreach ( $_POST['wcml_wc_booking_resource_cost'] as $resource_id => $costs) {
374
-
375
- foreach ($currencies as $code => $currency) {
376
-
377
- $wc_booking_resource_costs[ $code ][ $resource_id ] = $costs[ $code ];
378
-
379
- }
380
-
381
- }
382
-
383
- $updated_meta[ 'custom_costs' ] = $wc_booking_resource_costs;
384
-
385
- update_post_meta( $post_id, '_resource_base_costs', $updated_meta );
386
-
387
- $this->sync_resource_costs_with_translations( $post_id, '_resource_base_costs' );
388
 
389
- }
390
-
391
- if( isset( $_POST[ 'wcml_wc_booking_resource_block_cost' ] ) ){
392
-
393
- $updated_meta = get_post_meta( $post_id, '_resource_block_costs', true );
394
-
395
- $wc_booking_resource_block_costs = array();
396
-
397
- foreach( $_POST[ 'wcml_wc_booking_resource_block_cost' ] as $resource_id => $costs ){
398
-
399
- foreach( $currencies as $code => $currency ){
400
 
401
- $wc_booking_resource_block_costs[ $code ][ $resource_id ] = $costs[ $code ];
 
402
 
403
- }
404
-
405
- }
406
 
407
- $updated_meta[ 'custom_costs' ] = $wc_booking_resource_block_costs;
 
 
408
 
409
- update_post_meta( $post_id, '_resource_block_costs', $updated_meta );
410
-
411
- $this->sync_resource_costs_with_translations( $post_id, '_resource_block_costs' );
412
-
413
- }
414
 
 
 
 
415
 
 
 
 
 
 
416
  }
417
  }
418
 
@@ -420,39 +359,35 @@ class WCML_Bookings{
420
 
421
  // sync existing product bookings for translations
422
  function sync_bookings( $original_product_id, $product_id, $lang ){
423
- global $wpdb;
424
-
425
- $all_bookings_for_product = $wpdb->get_results( $wpdb->prepare( "SELECT post_id as id FROM $wpdb->postmeta WHERE meta_key = '_booking_product_id' AND meta_value = %d", $original_product_id ) );
426
 
427
  foreach($all_bookings_for_product as $booking ){
428
- $check_if_exists = $wpdb->get_row( $wpdb->prepare( "SELECT pm3.* FROM {$wpdb->postmeta} AS pm1
429
- LEFT JOIN {$wpdb->postmeta} AS pm2 ON pm1.post_id = pm2.post_id
430
- LEFT JOIN {$wpdb->postmeta} AS pm3 ON pm1.post_id = pm3.post_id
431
  WHERE pm1.meta_key = '_booking_duplicate_of' AND pm1.meta_value = %s AND pm2.meta_key = '_language_code' AND pm2.meta_value = %s AND pm3.meta_key = '_booking_product_id'"
432
  , $booking->id, $lang ) );
433
 
434
- if( is_null( $check_if_exists ) ){
435
  $this->duplicate_booking_for_translations( $booking->id, $lang );
436
- }elseif( $check_if_exists->meta_value === '' ){
437
  update_post_meta( $check_if_exists->post_id, '_booking_product_id', $this->get_translated_booking_product_id( $booking->id, $lang ) );
438
  update_post_meta( $check_if_exists->post_id, '_booking_resource_id', $this->get_translated_booking_resource_id( $booking->id, $lang ) );
439
  update_post_meta( $check_if_exists->post_id, '_booking_persons', $this->get_translated_booking_persons_ids( $booking->id, $lang ) );
440
  }
441
  }
442
-
443
-
444
  }
445
 
446
  function sync_booking_data( $original_product_id, $current_product_id ){
447
 
448
  if( has_term( 'booking', 'product_type', $original_product_id ) ){
449
- global $wpdb, $sitepress, $pagenow, $iclTranslationManagement;
450
 
451
  // get language code
452
- $language_details = $sitepress->get_element_language_details( $original_product_id, 'post_product' );
453
  if ( $pagenow == 'admin.php' && empty( $language_details ) ) {
454
  //translation editor support: sidestep icl_translations_cache
455
- $language_details = $wpdb->get_row( $wpdb->prepare( "SELECT element_id, trid, language_code, source_language_code FROM {$wpdb->prefix}icl_translations WHERE element_id = %d AND element_type = 'post_product'", $original_product_id ) );
456
  }
457
  if ( empty( $language_details ) ) {
458
  return;
@@ -460,7 +395,7 @@ class WCML_Bookings{
460
 
461
  // pick posts to sync
462
  $posts = array();
463
- $translations = $sitepress->get_element_translations( $language_details->trid, 'post_product' );
464
  foreach ( $translations as $translation ) {
465
 
466
  if ( !$translation->original ) {
@@ -470,7 +405,7 @@ class WCML_Bookings{
470
 
471
  foreach ( $posts as $post_id => $translation ) {
472
 
473
- $trn_lang = $sitepress->get_language_for_element( $post_id, 'post_product' );
474
 
475
  //sync_resources
476
  $this->sync_resources( $original_product_id, $post_id, $trn_lang );
@@ -484,11 +419,9 @@ class WCML_Bookings{
484
  }
485
 
486
  function sync_resources( $original_product_id, $trnsl_product_id, $lang_code, $duplicate = true ){
487
- global $wpdb;
488
-
489
- $orig_resources = $wpdb->get_results( $wpdb->prepare( "SELECT resource_id, sort_order FROM {$wpdb->prefix}wc_booking_relationships WHERE product_id = %d", $original_product_id ) );
490
 
491
- $trnsl_product_resources = $wpdb->get_col( $wpdb->prepare( "SELECT resource_id FROM {$wpdb->prefix}wc_booking_relationships WHERE product_id = %d", $trnsl_product_id ) );
492
 
493
  foreach ($orig_resources as $resource) {
494
 
@@ -500,8 +433,8 @@ class WCML_Bookings{
500
 
501
  unset($trnsl_product_resources[$key]);
502
 
503
- $wpdb->update(
504
- $wpdb->prefix . 'wc_booking_relationships',
505
  array(
506
  'sort_order' => $resource->sort_order
507
  ),
@@ -535,8 +468,8 @@ class WCML_Bookings{
535
 
536
  foreach ($trnsl_product_resources as $trnsl_product_resource) {
537
 
538
- $wpdb->delete(
539
- $wpdb->prefix . 'wc_booking_relationships',
540
  array(
541
  'product_id' => $trnsl_product_id,
542
  'resource_id' => $trnsl_product_resource
@@ -553,11 +486,11 @@ class WCML_Bookings{
553
  }
554
 
555
  function duplicate_resource( $tr_product_id, $resource, $lang_code){
556
- global $sitepress, $wpdb, $iclTranslationManagement;
557
 
558
- if( method_exists( $sitepress, 'make_duplicate' ) ){
559
 
560
- $trns_resource_id = $sitepress->make_duplicate( $resource->resource_id, $lang_code );
561
 
562
  }else{
563
 
@@ -569,8 +502,8 @@ class WCML_Bookings{
569
 
570
  }
571
 
572
- $wpdb->insert(
573
- $wpdb->prefix . 'wc_booking_relationships',
574
  array(
575
  'product_id' => $tr_product_id,
576
  'resource_id' => $trns_resource_id,
@@ -584,11 +517,9 @@ class WCML_Bookings{
584
  }
585
 
586
  function sync_persons( $original_product_id, $tr_product_id, $lang_code, $duplicate = true ){
587
- global $wpdb, $woocommerce_wpml;
588
 
589
- $orig_persons = $wpdb->get_col( $wpdb->prepare( "SELECT ID FROM $wpdb->posts WHERE post_parent = %d AND post_type = 'bookable_person'", $original_product_id ) );
590
-
591
- $trnsl_persons = $wpdb->get_col( $wpdb->prepare( "SELECT ID FROM $wpdb->posts WHERE post_parent = %d AND post_type = 'bookable_person'", $tr_product_id ) );
592
 
593
 
594
  foreach ($orig_persons as $person) {
@@ -607,13 +538,13 @@ class WCML_Bookings{
607
  update_post_meta( $trnsl_person_id, 'min', get_post_meta( $person, 'min', true ) );
608
 
609
 
610
- if( get_post_meta( $person, '_wcml_custom_costs_status', true ) && $woocommerce_wpml->settings['enable_multi_currency'] == WCML_MULTI_CURRENCIES_INDEPENDENT){
611
- $currencies = $woocommerce_wpml->multi_currency->get_currencies();
612
 
613
  foreach( $currencies as $code => $currency ){
614
 
615
  update_post_meta( $trnsl_person_id, 'block_cost_'.$code, get_post_meta( $person, 'block_cost_'.$code, true ) );
616
- update_post_meta( $trnsl_person_id, 'block_cost_'.$code, get_post_meta( $person, 'cost_'.$code, true ) );
617
 
618
  }
619
  }
@@ -645,11 +576,11 @@ class WCML_Bookings{
645
  }
646
 
647
  function duplicate_person( $tr_product_id, $person_id, $lang_code ){
648
- global $sitepress, $wpdb, $iclTranslationManagement;
649
 
650
- if( method_exists( $sitepress, 'make_duplicate' ) ){
651
 
652
- $new_person_id = $sitepress->make_duplicate( $person_id, $lang_code );
653
 
654
  }else{
655
 
@@ -661,8 +592,8 @@ class WCML_Bookings{
661
 
662
  }
663
 
664
- $wpdb->update(
665
- $wpdb->posts,
666
  array(
667
  'post_parent' => $tr_product_id
668
  ),
@@ -680,15 +611,15 @@ class WCML_Bookings{
680
 
681
  if( in_array( $meta_key, array( '_wc_booking_cost', '_wc_booking_base_cost', '_wc_display_cost', '_wc_booking_pricing', 'cost', 'block_cost', '_resource_base_costs', '_resource_block_costs' ) ) ){
682
 
683
- global $woocommerce_wpml;
684
 
685
- if( $woocommerce_wpml->settings['enable_multi_currency'] == WCML_MULTI_CURRENCIES_INDEPENDENT ){
686
 
687
- $original_id = apply_filters( 'translate_object_id', $object_id, 'product', true, $woocommerce_wpml->products->get_original_product_language( $object_id ) );
 
 
688
 
689
  $cost_status = get_post_meta( $original_id, '_wcml_custom_costs_status', true );
690
 
691
- $currency = $woocommerce_wpml->multi_currency->get_client_currency();
692
 
693
  if ( $currency == get_option('woocommerce_currency') ){
694
  return $check;
@@ -712,7 +643,7 @@ class WCML_Bookings{
712
 
713
  add_filter( 'get_post_metadata', array( $this, 'filter_wc_booking_cost' ), 10, 4 );
714
 
715
- return $woocommerce_wpml->multi_currency->prices->convert_price_amount( $cost, $currency );
716
  }
717
 
718
  } else {
@@ -750,7 +681,7 @@ class WCML_Bookings{
750
  $converted_values = array();
751
 
752
  foreach( $costs as $resource_id => $cost ){
753
- $converted_values[0][ $resource_id ] = $woocommerce_wpml->multi_currency->prices->convert_price_amount( $cost, $currency );
754
  }
755
 
756
  $value = $converted_values;
@@ -776,7 +707,7 @@ class WCML_Bookings{
776
 
777
  $value = get_post_meta( $original_id, $meta_key, true );
778
 
779
- $value = $woocommerce_wpml->multi_currency->prices->convert_price_amount( $value, $currency );
780
 
781
  add_filter( 'get_post_metadata', array( $this, 'filter_wc_booking_cost' ), 10, 4 );
782
 
@@ -792,14 +723,14 @@ class WCML_Bookings{
792
  }
793
 
794
  function sync_resource_costs_with_translations( $object_id, $meta_key, $check = false ){
795
- global $sitepress,$woocommerce_wpml;
796
 
797
- $original_product_id = apply_filters( 'translate_object_id', $object_id, 'product', true, $woocommerce_wpml->products->get_original_product_language( $object_id ) );
 
798
 
799
  if( $object_id == $original_product_id ){
800
 
801
- $trid = $sitepress->get_element_trid( $object_id, 'post_product' );
802
- $translations = $sitepress->get_element_translations( $trid, 'post_product' );
803
 
804
  foreach ( $translations as $translation ) {
805
 
@@ -814,7 +745,7 @@ class WCML_Bookings{
814
 
815
  }else{
816
 
817
- $language_code = $sitepress->get_language_for_element( $object_id, 'post_product' );
818
 
819
  $this->sync_resource_costs( $original_product_id, $object_id, $meta_key, $language_code );
820
 
@@ -874,11 +805,11 @@ class WCML_Bookings{
874
  }
875
 
876
  function filter_pricing_cost( $cost, $fields, $name, $key ){
877
- global $woocommerce_wpml, $product;
878
 
879
- if( $woocommerce_wpml->settings['enable_multi_currency'] == WCML_MULTI_CURRENCIES_INDEPENDENT ){
880
 
881
- $currency = $woocommerce_wpml->multi_currency->get_client_currency();
882
 
883
  if ( $currency == get_option('woocommerce_currency') ) {
884
  return $cost;
@@ -896,7 +827,7 @@ class WCML_Bookings{
896
  }
897
 
898
  if( isset( $booking_id ) ){
899
- $original_id = apply_filters( 'translate_object_id', $booking_id, 'product', true, $woocommerce_wpml->products->get_original_product_language( $booking_id ) );
900
 
901
  if( $booking_id != $original_id ){
902
  $fields = maybe_unserialize( get_post_meta( $original_id, '_wc_booking_pricing', true ) );
@@ -907,7 +838,7 @@ class WCML_Bookings{
907
  if( isset( $fields[ $name.$currency ] ) ){
908
  return $fields[ $name.$currency ];
909
  }else{
910
- return $woocommerce_wpml->multi_currency->prices->convert_price_amount( $cost, $currency );
911
  }
912
 
913
  }
@@ -917,9 +848,11 @@ class WCML_Bookings{
917
  }
918
 
919
  function load_assets( ){
920
- global $pagenow, $woocommerce_wpml;
 
 
921
 
922
- if( ( $pagenow == 'post.php' && isset( $_GET[ 'post' ] ) && wc_get_product( $_GET[ 'post' ] )->product_type == 'booking' ) || $pagenow == 'post-new.php' ){
923
 
924
  wp_register_style( 'wcml-bookings-css', WCML_PLUGIN_URL . '/compatibility/res/css/wcml-bookings.css', array(), WCML_VERSION );
925
  wp_enqueue_style( 'wcml-bookings-css' );
@@ -945,7 +878,7 @@ class WCML_Bookings{
945
  function filter_bundled_product_in_cart_contents( $cart_item, $key, $current_language ){
946
 
947
  if( $cart_item[ 'data' ] instanceof WC_Product_Booking && isset( $cart_item[ 'booking' ] ) ){
948
- global $woocommerce_wpml;
949
 
950
  $current_id = apply_filters( 'translate_object_id', $cart_item[ 'data' ]->id, 'product', true, $current_language );
951
  $cart_product_id = $cart_item['data']->id;
@@ -956,7 +889,7 @@ class WCML_Bookings{
956
 
957
  }
958
 
959
- if( $woocommerce_wpml->settings['enable_multi_currency'] == WCML_MULTI_CURRENCIES_INDEPENDENT || $current_id != $cart_product_id ){
960
 
961
  $booking_info = array(
962
  'wc_bookings_field_start_date_year' => $cart_item[ 'booking' ][ '_year' ],
@@ -1002,13 +935,13 @@ class WCML_Bookings{
1002
  }
1003
 
1004
  function booking_currency_dropdown(){
1005
- global $woocommerce_wpml, $sitepress;
1006
 
1007
- if( $woocommerce_wpml->settings['enable_multi_currency'] == WCML_MULTI_CURRENCIES_INDEPENDENT ){
 
1008
  $current_booking_currency = $this->get_cookie_booking_currency();
1009
 
1010
  $wc_currencies = get_woocommerce_currencies();
1011
- $currencies = $woocommerce_wpml->multi_currency->get_currencies( $include_default = true );
1012
  ?>
1013
  <tr valign="top">
1014
  <th scope="row"><?php _e( 'Booking currency', 'woocommerce-multilingual' ); ?></th>
@@ -1071,12 +1004,12 @@ class WCML_Bookings{
1071
  function set_booking_currency( $currency_code = false ){
1072
 
1073
  if( !isset( $_COOKIE [ '_wcml_booking_currency' ]) && !headers_sent()) {
1074
- global $woocommerce_wpml;
1075
 
1076
  $currency_code = get_woocommerce_currency();
1077
 
1078
- if ( $woocommerce_wpml->settings['enable_multi_currency'] == WCML_MULTI_CURRENCIES_INDEPENDENT ){
1079
- $order_currencies = $woocommerce_wpml->multi_currency->orders->get_orders_currencies();
1080
 
1081
  if (!isset($order_currencies[$currency_code])) {
1082
  foreach ($order_currencies as $currency_code => $count) {
@@ -1131,11 +1064,9 @@ class WCML_Bookings{
1131
  }
1132
 
1133
  function set_order_currency_on_create_booking_page( $order_id ){
1134
- global $sitepress;
1135
-
1136
  update_post_meta( $order_id, '_order_currency', $this->get_cookie_booking_currency() );
1137
 
1138
- update_post_meta( $order_id, 'wpml_language', $sitepress->get_current_language() );
1139
 
1140
  }
1141
 
@@ -1147,8 +1078,6 @@ class WCML_Bookings{
1147
  }
1148
 
1149
  function custom_box_html( $obj, $product_id, $data ){
1150
- global $wpdb;
1151
-
1152
  if( wc_get_product($product_id)->product_type != 'booking' ){
1153
  return;
1154
  }
@@ -1222,13 +1151,15 @@ class WCML_Bookings{
1222
 
1223
  $orig_resources = $this->get_original_resources( $product_id );
1224
 
1225
- if( $orig_resources ){
1226
 
1227
  foreach ( $orig_resources as $resource_id => $cost) {
1228
 
1229
- if ($resource_id == 'custom_costs') continue;
 
 
1230
  $data[ 'bookings-resource_'.$resource_id.'_title' ] = array( 'original' => get_the_title( $resource_id ) );
1231
-
1232
  $trns_resource_id = apply_filters('translate_object_id', $resource_id, 'bookable_resource', false, $lang);
1233
  $data[ 'bookings-resource_'.$resource_id.'_title' ][ 'translation' ] = $trns_resource_id ? get_the_title( $trns_resource_id ) : '';
1234
  }
@@ -1257,8 +1188,7 @@ class WCML_Bookings{
1257
  }
1258
 
1259
  function get_original_persons( $product_id ){
1260
- global $wpdb;
1261
- $original_persons = $wpdb->get_col( $wpdb->prepare( "SELECT ID FROM $wpdb->posts WHERE post_parent = %d AND post_type = 'bookable_person' AND post_status = 'publish'", $product_id ) );
1262
  return $original_persons;
1263
  }
1264
 
@@ -1290,7 +1220,7 @@ class WCML_Bookings{
1290
  }
1291
 
1292
  function wcml_products_tab_sync_resources_and_persons( $original_product_id, $tr_product_id, $data, $language ){
1293
- global $wpdb, $woocommerce_wpml, $wpml_post_translations;
1294
 
1295
  remove_action ( 'save_post', array( $wpml_post_translations, 'save_post_actions' ), 100, 2 );
1296
 
@@ -1301,7 +1231,7 @@ class WCML_Bookings{
1301
  foreach( $orig_resources as $orig_resource_id => $cost ){
1302
 
1303
  $resource_id = apply_filters( 'translate_object_id', $orig_resource_id, 'bookable_resource', false, $language );
1304
- $orig_resource = $wpdb->get_row( $wpdb->prepare( "SELECT resource_id, sort_order FROM {$wpdb->prefix}wc_booking_relationships WHERE resource_id = %d AND product_id = %d", $orig_resource_id, $original_product_id ), OBJECT );
1305
 
1306
  if( is_null( $resource_id ) ){
1307
 
@@ -1314,12 +1244,12 @@ class WCML_Bookings{
1314
  }else{
1315
  //update_relationship
1316
 
1317
- $exist = $wpdb->get_var( $wpdb->prepare( "SELECT ID FROM {$wpdb->prefix}wc_booking_relationships WHERE resource_id = %d AND product_id = %d", $resource_id, $tr_product_id ) );
1318
 
1319
  if( !$exist ){
1320
 
1321
- $wpdb->insert(
1322
- $wpdb->prefix . 'wc_booking_relationships',
1323
  array(
1324
  'product_id' => $tr_product_id,
1325
  'resource_id' => $resource_id,
@@ -1333,8 +1263,8 @@ class WCML_Bookings{
1333
 
1334
 
1335
 
1336
- $wpdb->update(
1337
- $wpdb->posts,
1338
  array(
1339
  'post_title' => $data[ md5( 'bookings-resource_'.$orig_resource_id.'_title') ]
1340
  ),
@@ -1367,8 +1297,8 @@ class WCML_Bookings{
1367
 
1368
  }else{
1369
 
1370
- $wpdb->update(
1371
- $wpdb->posts,
1372
  array(
1373
  'post_parent' => $tr_product_id
1374
  ),
@@ -1379,8 +1309,8 @@ class WCML_Bookings{
1379
 
1380
  }
1381
 
1382
- $wpdb->update(
1383
- $wpdb->posts,
1384
  array(
1385
  'post_title' => $data[ md5 ( 'bookings-person_'.$original_person_id.'_title' ) ],
1386
  'post_excerpt' => $data[ md5( 'bookings-person_'.$original_person_id.'_description' ) ],
@@ -1404,8 +1334,6 @@ class WCML_Bookings{
1404
  }
1405
 
1406
  function duplicate_booking_for_translations( $booking_id, $lang = false ){
1407
- global $sitepress;
1408
-
1409
  $booking_object = get_post( $booking_id );
1410
 
1411
  $booking_data = array(
@@ -1416,14 +1344,14 @@ class WCML_Bookings{
1416
  'post_parent' => $booking_object->post_parent,
1417
  );
1418
 
1419
- $active_languages = $sitepress->get_active_languages();
1420
 
1421
  foreach( $active_languages as $language ){
1422
 
1423
  $booking_product_id = get_post_meta( $booking_id, '_booking_product_id', true );
1424
 
1425
  if( !$lang ){
1426
- $booking_language = $sitepress->get_element_language_details( $booking_product_id, 'post_product' );
1427
  if ( $booking_language->language_code == $language['code'] ) {
1428
  continue;
1429
  }
@@ -1434,19 +1362,23 @@ class WCML_Bookings{
1434
  $booking_persons = maybe_unserialize( get_post_meta( $booking_id, '_booking_persons', true ) );
1435
  $trnsl_booking_persons = array();
1436
 
1437
- foreach( $booking_persons as $person_id => $person_count ){
 
1438
 
1439
- $trnsl_person_id = apply_filters( 'translate_object_id', $person_id, 'bookable_person', false, $language['code'] );
1440
 
1441
- if( is_null( $trnsl_person_id ) ){
1442
- $trnsl_booking_persons[] = $person_count;
1443
- }else{
1444
- $trnsl_booking_persons[ $trnsl_person_id ] = $person_count;
1445
- }
1446
 
1447
- }
 
1448
 
1449
  $trnsl_booking_id = wp_insert_post( $booking_data );
 
 
1450
 
1451
  $meta_args = array(
1452
  '_booking_order_item_id' => get_post_meta( $booking_id, '_booking_order_item_id', true ),
@@ -1459,8 +1391,8 @@ class WCML_Bookings{
1459
  '_booking_all_day' => intval( get_post_meta( $booking_id, '_booking_all_day', true ) ),
1460
  '_booking_parent_id' => get_post_meta( $booking_id, '_booking_parent_id', true ),
1461
  '_booking_customer_id' => get_post_meta( $booking_id, '_booking_customer_id', true ),
1462
- '_booking_duplicate_of' => $booking_id,
1463
- '_language_code' => $language['code'],
1464
  );
1465
 
1466
  foreach ( $meta_args as $key => $value ) {
@@ -1477,6 +1409,7 @@ class WCML_Bookings{
1477
  function get_translated_booking_product_id( $booking_id, $language ){
1478
 
1479
  $booking_product_id = get_post_meta( $booking_id, '_booking_product_id', true );
 
1480
 
1481
  if( $booking_product_id ){
1482
  $trnsl_booking_product_id = apply_filters( 'translate_object_id', $booking_product_id, 'product', false, $language );
@@ -1510,34 +1443,33 @@ class WCML_Bookings{
1510
  $booking_persons = maybe_unserialize( get_post_meta( $booking_id, '_booking_persons', true ) );
1511
  $trnsl_booking_persons = array();
1512
 
1513
- foreach( $booking_persons as $person_id => $person_count ){
 
1514
 
1515
- $trnsl_person_id = apply_filters( 'translate_object_id', $person_id, 'bookable_person', false, $language );
1516
 
1517
- if( is_null( $trnsl_person_id ) ){
1518
- $trnsl_booking_persons[] = $person_count;
1519
- }else{
1520
- $trnsl_booking_persons[ $trnsl_person_id ] = $person_count;
1521
- }
1522
-
1523
- }
1524
 
 
 
1525
  return $trnsl_booking_persons;
1526
 
1527
  }
1528
 
1529
  function update_status_for_translations( $booking_id ){
1530
- global $wpdb;
1531
-
1532
  $translated_bookings = $this->get_translated_bookings( $booking_id );
1533
 
1534
  foreach( $translated_bookings as $booking ){
1535
 
1536
- $status = $wpdb->get_var( $wpdb->prepare( "SELECT post_status FROM {$wpdb->posts} WHERE ID = %d", $booking_id ) ); //get_post_status( $booking_id );
1537
  $language = get_post_meta( $booking->post_id, '_language_code', true );
1538
 
1539
- $wpdb->update(
1540
- $wpdb->posts,
1541
  array(
1542
  'post_status' => $status,
1543
  'post_parent' => wp_get_post_parent_id( $booking_id ),
@@ -1556,23 +1488,21 @@ class WCML_Bookings{
1556
  }
1557
 
1558
  function get_translated_bookings($booking_id){
1559
- global $wpdb;
1560
-
1561
- $translated_bookings = $wpdb->get_results( $wpdb->prepare( "SELECT post_id FROM {$wpdb->postmeta} WHERE meta_key = '_booking_duplicate_of' AND meta_value = %d", $booking_id ) );
1562
 
1563
  return $translated_bookings;
1564
  }
1565
 
1566
  public function booking_filters_query( $query ) {
1567
- global $typenow, $sitepress, $wpdb;
1568
 
1569
  if ( ( isset( $query->query_vars['post_type'] ) && $query->query_vars['post_type'] == 'wc_booking' ) ) {
1570
 
1571
- $current_lang = $sitepress->get_current_language();
1572
 
1573
- $product_ids = $wpdb->get_col( $wpdb->prepare(
1574
  "SELECT element_id
1575
- FROM {$wpdb->prefix}icl_translations
1576
  WHERE language_code = %s AND element_type = 'post_product'", $current_lang ) );
1577
 
1578
  $product_ids = array_diff( $product_ids, array( NULL ) );
@@ -1593,15 +1523,15 @@ class WCML_Bookings{
1593
  );
1594
  }
1595
  }
 
 
1596
  }
1597
 
1598
  function bookings_in_date_range_query($booking_ids){
1599
- global $sitepress;
1600
-
1601
  foreach ( $booking_ids as $key => $booking_id ) {
1602
 
1603
- $language_code = $sitepress->get_language_for_element( get_post_meta( $booking_id, '_booking_product_id', true ) , 'post_product' );
1604
- $current_language = $sitepress->get_current_language();
1605
 
1606
  if( $language_code != $current_language ){
1607
  unset( $booking_ids[$key] );
@@ -1617,10 +1547,9 @@ class WCML_Bookings{
1617
 
1618
  if ( isset( $_GET['post_type'] ) && $_GET['post_type'] == 'wc_booking' && isset( $_GET['page'] ) && $_GET['page'] == 'booking_calendar' ) {
1619
 
1620
- global $wpdb;
1621
  //delete transient fields
1622
- $wpdb->query("
1623
- DELETE FROM $wpdb->options
1624
  WHERE option_name LIKE '%book_dr_%'
1625
  ");
1626
 
@@ -1637,11 +1566,8 @@ class WCML_Bookings{
1637
  remove_action( 'before_delete_post', array( $this, 'delete_bookings' ) );
1638
 
1639
  foreach( $translated_bookings as $booking ){
1640
-
1641
- global $wpdb;
1642
-
1643
- $wpdb->update(
1644
- $wpdb->posts,
1645
  array(
1646
  'post_parent' => 0
1647
  ),
@@ -1666,10 +1592,9 @@ class WCML_Bookings{
1666
  $translated_bookings = $this->get_translated_bookings( $booking_id );
1667
 
1668
  foreach( $translated_bookings as $booking ){
1669
- global $wpdb;
1670
 
1671
- $wpdb->update(
1672
- $wpdb->posts,
1673
  array(
1674
  'post_status' => 'trash'
1675
  ),
@@ -1723,8 +1648,6 @@ class WCML_Bookings{
1723
  }
1724
 
1725
  function save_person_translation($post_id, $data, $job ){
1726
- global $sitepress;
1727
-
1728
  $person_translations = array();
1729
 
1730
  foreach($data as $value){
@@ -1746,7 +1669,7 @@ class WCML_Bookings{
1746
 
1747
  foreach( $person_translations as $person_id => $pt ){
1748
 
1749
- $person_trid = $sitepress->get_element_trid( $person_id, 'post_bookable_person');
1750
 
1751
 
1752
  $person_id_translated = apply_filters( 'translate_object_id', $person_id, 'bookable_person', false, $job->language_code );
@@ -1765,7 +1688,7 @@ class WCML_Bookings{
1765
 
1766
  $person_id_translated = wp_insert_post( $person_post );
1767
 
1768
- $sitepress->set_element_language_details( $person_id_translated, 'post_bookable_person', $person_trid, $job->language_code );
1769
 
1770
  } else {
1771
 
@@ -1816,8 +1739,6 @@ class WCML_Bookings{
1816
  }
1817
 
1818
  function save_resource_translation( $post_id, $data, $job ){
1819
- global $sitepress, $wpdb;
1820
-
1821
  $resource_translations = array();
1822
 
1823
  foreach($data as $value){
@@ -1839,7 +1760,7 @@ class WCML_Bookings{
1839
 
1840
  foreach( $resource_translations as $resource_id => $rt ){
1841
 
1842
- $resource_trid = $sitepress->get_element_trid( $resource_id, 'post_bookable_resource');
1843
 
1844
  $resource_id_translated = apply_filters( 'translate_object_id', $resource_id, 'bookable_resource', false, $job->language_code );
1845
 
@@ -1855,15 +1776,15 @@ class WCML_Bookings{
1855
 
1856
  $resource_id_translated = wp_insert_post( $resource_post );
1857
 
1858
- $sitepress->set_element_language_details( $resource_id_translated, 'post_bookable_resource', $resource_trid, $job->language_code );
1859
 
1860
- $sort_order = $wpdb->get_var( $wpdb->prepare( "SELECT sort_order FROM {$wpdb->prefix}wc_booking_relationships WHERE resource_id=%d", $resource_id ) );
1861
  $relationship = array(
1862
  'product_id' => $post_id,
1863
  'resource_id' => $resource_id_translated,
1864
  'sort_order' => $sort_order
1865
  );
1866
- $wpdb->insert( $wpdb->prefix . 'wc_booking_relationships', $relationship);
1867
 
1868
  } else {
1869
 
@@ -1874,8 +1795,8 @@ class WCML_Bookings{
1874
 
1875
  wp_update_post( $resource_post );
1876
 
1877
- $sort_order = $wpdb->get_var( $wpdb->prepare( "SELECT sort_order FROM {$wpdb->prefix}wc_booking_relationships WHERE resource_id=%d", $resource_id ) );
1878
- $wpdb->update( $wpdb->prefix . 'wc_booking_relationships', array( 'sort_order' => $sort_order ),
1879
  array ( 'product_id' => $post_id, 'resource_id' => $resource_id_translated) );
1880
 
1881
 
@@ -1921,4 +1842,175 @@ class WCML_Bookings{
1921
  return $ids;
1922
  }
1923
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1924
  }
1
  <?php
2
 
3
+ /**
4
+ * Class WCML_Bookings.
5
+ */
6
+ class WCML_Bookings {
7
+
8
+ /**
9
+ * @var WPML_Element_Translation_Package
10
+ */
11
  public $tp;
12
 
13
+ /**
14
+ * @var SitePress
15
+ */
16
+ public $sitepress;
17
+
18
+ /**
19
+ * @var woocommerce_wpml
20
+ */
21
+ public $woocommerce_wpml;
22
+
23
+ /**
24
+ * @var wpdb
25
+ */
26
+ public $wpdb;
27
+
28
+ /**
29
+ * WCML_Bookings constructor.
30
+ */
31
+ function __construct( &$sitepress, &$woocommerce_wpml, &$wpdb ) {
32
+ $this->sitepress = $sitepress;
33
+ $this->woocommerce_wpml = $woocommerce_wpml;
34
+ $this->wpdb = $wpdb;
35
+ add_action( 'woocommerce_bookings_after_booking_base_cost', array( $this, 'wcml_price_field_after_booking_base_cost' ) );
36
  add_action( 'woocommerce_bookings_after_booking_block_cost' , array( $this, 'wcml_price_field_after_booking_block_cost' ) );
37
  add_action( 'woocommerce_bookings_after_display_cost' , array( $this, 'wcml_price_field_after_display_cost' ) );
38
  add_action( 'woocommerce_bookings_after_booking_pricing_base_cost' , array( $this, 'wcml_price_field_after_booking_pricing_base_cost' ), 10, 2 );
45
 
46
  add_action( 'init', array( $this, 'load_assets' ) );
47
 
48
+ add_action( 'save_post', array( $this, 'save_custom_costs' ), 110, 1 );
49
  add_action( 'wcml_before_sync_product_data', array( $this, 'sync_bookings' ), 10, 3 );
50
  add_action( 'wcml_before_sync_product', array( $this, 'sync_booking_data' ), 10, 2 );
51
 
167
  }
168
 
169
  function echo_wcml_price_field( $post_id, $field, $pricing = false, $check = true, $resource_id = false ){
 
170
 
 
171
 
172
+ if( ( !$check || $this->woocommerce_wpml->products->is_original_product( $post_id ) ) && $this->woocommerce_wpml->settings['enable_multi_currency'] == WCML_MULTI_CURRENCIES_INDEPENDENT ){
173
+
174
+ $currencies = $this->woocommerce_wpml->multi_currency->get_currencies();
175
 
176
  $wc_currencies = get_woocommerce_currencies();
177
 
292
  }
293
 
294
  function after_bookings_pricing( $post_id ){
 
295
 
296
+
297
+ if( in_array( 'booking', wp_get_post_terms( $post_id, 'product_type', array( "fields" => "names" ) ) ) && $this->woocommerce_wpml->products->is_original_product( $post_id ) && $this->woocommerce_wpml->settings['enable_multi_currency'] == WCML_MULTI_CURRENCIES_INDEPENDENT ){
298
 
299
  $custom_costs_status = get_post_meta( $post_id, '_wcml_custom_costs_status', true );
300
 
317
 
318
  }
319
 
320
+ function save_custom_costs( $post_id ) {
321
+ $nonce = filter_var( isset( $_POST['_wcml_custom_costs_nonce'] ) ? $_POST['_wcml_custom_costs_nonce'] : '', FILTER_SANITIZE_FULL_SPECIAL_CHARS );
322
 
323
+ if( isset( $_POST['_wcml_custom_costs'] ) && isset( $nonce ) && wp_verify_nonce( $nonce, 'wcml_save_custom_costs' ) ) {
324
 
 
 
325
  update_post_meta( $post_id, '_wcml_custom_costs_status', $_POST['_wcml_custom_costs'] );
326
 
327
+ if( 1 === (int) $_POST['_wcml_custom_costs'] ) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
328
 
329
+ $currencies = $this->woocommerce_wpml->multi_currency->get_currencies();
330
+ if( empty( $currencies ) || 0 === $post_id ) {
331
+ return false;
332
+ }
 
 
 
 
 
 
 
333
 
334
+ $this->update_booking_costs( $currencies, $post_id );
335
+ $this->update_booking_pricing( $currencies, $post_id );
336
 
 
 
 
337
 
338
+ if( isset( $_POST['wcml_wc_booking_person_cost'] ) && is_array( $_POST['wcml_wc_booking_person_cost'] ) ) {
339
+ $this->update_booking_person_cost( $currencies, $_POST['wcml_wc_booking_person_cost'] );
340
+ }
341
 
342
+ if( isset( $_POST['wcml_wc_booking_person_block_cost'] ) && is_array( $_POST['wcml_wc_booking_person_block_cost'] ) ) {
343
+ $this->update_booking_person_block_cost( $currencies, $_POST['wcml_wc_booking_person_block_cost'] );
344
+ }
 
 
345
 
346
+ if( isset( $_POST['wcml_wc_booking_resource_cost'] ) && is_array( $_POST['wcml_wc_booking_resource_cost'] ) ) {
347
+ $this->update_booking_resource_cost( $currencies, $post_id, $_POST['wcml_wc_booking_resource_cost'] );
348
+ }
349
 
350
+ if( isset( $_POST['wcml_wc_booking_resource_block_cost'] ) && is_array( $_POST['wcml_wc_booking_resource_block_cost'] ) ) {
351
+ $this->update_booking_resource_block_cost( $currencies, $post_id, $_POST[ 'wcml_wc_booking_resource_block_cost' ] );
352
+ }
353
+ } else {
354
+ return false;
355
  }
356
  }
357
 
359
 
360
  // sync existing product bookings for translations
361
  function sync_bookings( $original_product_id, $product_id, $lang ){
362
+ $all_bookings_for_product = $this->wpdb->get_results( $this->wpdb->prepare( "SELECT post_id as id FROM {$this->wpdb->postmeta} WHERE meta_key = '_booking_product_id' AND meta_value = %d", $original_product_id ) );
 
 
363
 
364
  foreach($all_bookings_for_product as $booking ){
365
+ $check_if_exists = $this->wpdb->get_row( $this->wpdb->prepare( "SELECT pm3.* FROM {$this->wpdb->postmeta} AS pm1
366
+ LEFT JOIN {$this->wpdb->postmeta} AS pm2 ON pm1.post_id = pm2.post_id
367
+ LEFT JOIN {$this->wpdb->postmeta} AS pm3 ON pm1.post_id = pm3.post_id
368
  WHERE pm1.meta_key = '_booking_duplicate_of' AND pm1.meta_value = %s AND pm2.meta_key = '_language_code' AND pm2.meta_value = %s AND pm3.meta_key = '_booking_product_id'"
369
  , $booking->id, $lang ) );
370
 
371
+ if( is_null( $check_if_exists ) ) {
372
  $this->duplicate_booking_for_translations( $booking->id, $lang );
373
+ } elseif ( '' === $check_if_exists->meta_value ) {
374
  update_post_meta( $check_if_exists->post_id, '_booking_product_id', $this->get_translated_booking_product_id( $booking->id, $lang ) );
375
  update_post_meta( $check_if_exists->post_id, '_booking_resource_id', $this->get_translated_booking_resource_id( $booking->id, $lang ) );
376
  update_post_meta( $check_if_exists->post_id, '_booking_persons', $this->get_translated_booking_persons_ids( $booking->id, $lang ) );
377
  }
378
  }
 
 
379
  }
380
 
381
  function sync_booking_data( $original_product_id, $current_product_id ){
382
 
383
  if( has_term( 'booking', 'product_type', $original_product_id ) ){
384
+ global $pagenow, $iclTranslationManagement;
385
 
386
  // get language code
387
+ $language_details = $this->sitepress->get_element_language_details( $original_product_id, 'post_product' );
388
  if ( $pagenow == 'admin.php' && empty( $language_details ) ) {
389
  //translation editor support: sidestep icl_translations_cache
390
+ $language_details = $this->wpdb->get_row( $this->wpdb->prepare( "SELECT element_id, trid, language_code, source_language_code FROM {$this->wpdb->prefix}icl_translations WHERE element_id = %d AND element_type = 'post_product'", $original_product_id ) );
391
  }
392
  if ( empty( $language_details ) ) {
393
  return;
395
 
396
  // pick posts to sync
397
  $posts = array();
398
+ $translations = $this->sitepress->get_element_translations( $language_details->trid, 'post_product' );
399
  foreach ( $translations as $translation ) {
400
 
401
  if ( !$translation->original ) {
405
 
406
  foreach ( $posts as $post_id => $translation ) {
407
 
408
+ $trn_lang = $this->sitepress->get_language_for_element( $post_id, 'post_product' );
409
 
410
  //sync_resources
411
  $this->sync_resources( $original_product_id, $post_id, $trn_lang );
419
  }
420
 
421
  function sync_resources( $original_product_id, $trnsl_product_id, $lang_code, $duplicate = true ){
422
+ $orig_resources = $this->wpdb->get_results( $this->wpdb->prepare( "SELECT resource_id, sort_order FROM {$this->wpdb->prefix}wc_booking_relationships WHERE product_id = %d", $original_product_id ) );
 
 
423
 
424
+ $trnsl_product_resources = $this->wpdb->get_col( $this->wpdb->prepare( "SELECT resource_id FROM {$this->wpdb->prefix}wc_booking_relationships WHERE product_id = %d", $trnsl_product_id ) );
425
 
426
  foreach ($orig_resources as $resource) {
427
 
433
 
434
  unset($trnsl_product_resources[$key]);
435
 
436
+ $this->wpdb->update(
437
+ $this->wpdb->prefix . 'wc_booking_relationships',
438
  array(
439
  'sort_order' => $resource->sort_order
440
  ),
468
 
469
  foreach ($trnsl_product_resources as $trnsl_product_resource) {
470
 
471
+ $this->wpdb->delete(
472
+ $this->wpdb->prefix . 'wc_booking_relationships',
473
  array(
474
  'product_id' => $trnsl_product_id,
475
  'resource_id' => $trnsl_product_resource
486
  }
487
 
488
  function duplicate_resource( $tr_product_id, $resource, $lang_code){
489
+ global $iclTranslationManagement;
490
 
491
+ if( method_exists( $this->sitepress, 'make_duplicate' ) ){
492
 
493
+ $trns_resource_id = $this->sitepress->make_duplicate( $resource->resource_id, $lang_code );
494
 
495
  }else{
496
 
502
 
503
  }
504
 
505
+ $this->wpdb->insert(
506
+ $this->wpdb->prefix . 'wc_booking_relationships',
507
  array(
508
  'product_id' => $tr_product_id,
509
  'resource_id' => $trns_resource_id,
517
  }
518
 
519
  function sync_persons( $original_product_id, $tr_product_id, $lang_code, $duplicate = true ){
520
+ $orig_persons = $this->wpdb->get_col( $this->wpdb->prepare( "SELECT ID FROM {$this->wpdb->posts} WHERE post_parent = %d AND post_type = 'bookable_person'", $original_product_id ) );
521
 
522
+ $trnsl_persons = $this->wpdb->get_col( $this->wpdb->prepare( "SELECT ID FROM {$this->wpdb->posts} WHERE post_parent = %d AND post_type = 'bookable_person'", $tr_product_id ) );
 
 
523
 
524
 
525
  foreach ($orig_persons as $person) {
538
  update_post_meta( $trnsl_person_id, 'min', get_post_meta( $person, 'min', true ) );
539
 
540
 
541
+ if( get_post_meta( $person, '_wcml_custom_costs_status', true ) && $this->woocommerce_wpml->settings['enable_multi_currency'] == WCML_MULTI_CURRENCIES_INDEPENDENT){
542
+ $currencies = $this->woocommerce_wpml->multi_currency->get_currencies();
543
 
544
  foreach( $currencies as $code => $currency ){
545
 
546
  update_post_meta( $trnsl_person_id, 'block_cost_'.$code, get_post_meta( $person, 'block_cost_'.$code, true ) );
547
+ update_post_meta( $trnsl_person_id, 'cost_'.$code, get_post_meta( $person, 'cost_'.$code, true ) );
548
 
549
  }
550
  }
576
  }
577
 
578
  function duplicate_person( $tr_product_id, $person_id, $lang_code ){
579
+ global $iclTranslationManagement;
580
 
581
+ if( method_exists( $this->sitepress, 'make_duplicate' ) ){
582
 
583
+ $new_person_id = $this->sitepress->make_duplicate( $person_id, $lang_code );
584
 
585
  }else{
586
 
592
 
593
  }
594
 
595
+ $this->wpdb->update(
596
+ $this->wpdb->posts,
597
  array(
598
  'post_parent' => $tr_product_id
599
  ),
611
 
612
  if( in_array( $meta_key, array( '_wc_booking_cost', '_wc_booking_base_cost', '_wc_display_cost', '_wc_booking_pricing', 'cost', 'block_cost', '_resource_base_costs', '_resource_block_costs' ) ) ){
613
 
 
614
 
 
615
 
616
+ if( $this->woocommerce_wpml->settings['enable_multi_currency'] == WCML_MULTI_CURRENCIES_INDEPENDENT ){
617
+
618
+ $original_id = apply_filters( 'translate_object_id', $object_id, 'product', true, $this->woocommerce_wpml->products->get_original_product_language( $object_id ) );
619
 
620
  $cost_status = get_post_meta( $original_id, '_wcml_custom_costs_status', true );
621
 
622
+ $currency = $this->woocommerce_wpml->multi_currency->get_client_currency();
623
 
624
  if ( $currency == get_option('woocommerce_currency') ){
625
  return $check;
643
 
644
  add_filter( 'get_post_metadata', array( $this, 'filter_wc_booking_cost' ), 10, 4 );
645
 
646
+ return $this->woocommerce_wpml->multi_currency->prices->convert_price_amount( $cost, $currency );
647
  }
648
 
649
  } else {
681
  $converted_values = array();
682
 
683
  foreach( $costs as $resource_id => $cost ){
684
+ $converted_values[0][ $resource_id ] = $this->woocommerce_wpml->multi_currency->prices->convert_price_amount( $cost, $currency );
685
  }
686
 
687
  $value = $converted_values;
707
 
708
  $value = get_post_meta( $original_id, $meta_key, true );
709
 
710
+ $value = $this->woocommerce_wpml->multi_currency->prices->convert_price_amount( $value, $currency );
711
 
712
  add_filter( 'get_post_metadata', array( $this, 'filter_wc_booking_cost' ), 10, 4 );
713
 
723
  }
724
 
725
  function sync_resource_costs_with_translations( $object_id, $meta_key, $check = false ){
 
726
 
727
+
728
+ $original_product_id = apply_filters( 'translate_object_id', $object_id, 'product', true, $this->woocommerce_wpml->products->get_original_product_language( $object_id ) );
729
 
730
  if( $object_id == $original_product_id ){
731
 
732
+ $trid = $this->sitepress->get_element_trid( $object_id, 'post_product' );
733
+ $translations = $this->sitepress->get_element_translations( $trid, 'post_product' );
734
 
735
  foreach ( $translations as $translation ) {
736
 
745
 
746
  }else{
747
 
748
+ $language_code = $this->sitepress->get_language_for_element( $object_id, 'post_product' );
749
 
750
  $this->sync_resource_costs( $original_product_id, $object_id, $meta_key, $language_code );
751
 
805
  }
806
 
807
  function filter_pricing_cost( $cost, $fields, $name, $key ){
808
+ global $product;
809
 
810
+ if( $this->woocommerce_wpml->settings['enable_multi_currency'] == WCML_MULTI_CURRENCIES_INDEPENDENT ){
811
 
812
+ $currency = $this->woocommerce_wpml->multi_currency->get_client_currency();
813
 
814
  if ( $currency == get_option('woocommerce_currency') ) {
815
  return $cost;
827
  }
828
 
829
  if( isset( $booking_id ) ){
830
+ $original_id = apply_filters( 'translate_object_id', $booking_id, 'product', true, $this->woocommerce_wpml->products->get_original_product_language( $booking_id ) );
831
 
832
  if( $booking_id != $original_id ){
833
  $fields = maybe_unserialize( get_post_meta( $original_id, '_wc_booking_pricing', true ) );
838
  if( isset( $fields[ $name.$currency ] ) ){
839
  return $fields[ $name.$currency ];
840
  }else{
841
+ return $this->woocommerce_wpml->multi_currency->prices->convert_price_amount( $cost, $currency );
842
  }
843
 
844
  }
848
  }
849
 
850
  function load_assets( ){
851
+ global $pagenow;
852
+
853
+ $product = $pagenow == 'post.php' && isset( $_GET[ 'post' ] ) ? wc_get_product( $_GET[ 'post' ] ) : false;
854
 
855
+ if( ( $product && $product->product_type == 'booking' ) || $pagenow == 'post-new.php' ){
856
 
857
  wp_register_style( 'wcml-bookings-css', WCML_PLUGIN_URL . '/compatibility/res/css/wcml-bookings.css', array(), WCML_VERSION );
858
  wp_enqueue_style( 'wcml-bookings-css' );
878
  function filter_bundled_product_in_cart_contents( $cart_item, $key, $current_language ){
879
 
880
  if( $cart_item[ 'data' ] instanceof WC_Product_Booking && isset( $cart_item[ 'booking' ] ) ){
881
+
882
 
883
  $current_id = apply_filters( 'translate_object_id', $cart_item[ 'data' ]->id, 'product', true, $current_language );
884
  $cart_product_id = $cart_item['data']->id;
889
 
890
  }
891
 
892
+ if( $this->woocommerce_wpml->settings['enable_multi_currency'] == WCML_MULTI_CURRENCIES_INDEPENDENT || $current_id != $cart_product_id ){
893
 
894
  $booking_info = array(
895
  'wc_bookings_field_start_date_year' => $cart_item[ 'booking' ][ '_year' ],
935
  }
936
 
937
  function booking_currency_dropdown(){
 
938
 
939
+
940
+ if( $this->woocommerce_wpml->settings['enable_multi_currency'] == WCML_MULTI_CURRENCIES_INDEPENDENT ){
941
  $current_booking_currency = $this->get_cookie_booking_currency();
942
 
943
  $wc_currencies = get_woocommerce_currencies();
944
+ $currencies = $this->woocommerce_wpml->multi_currency->get_currencies( $include_default = true );
945
  ?>
946
  <tr valign="top">
947
  <th scope="row"><?php _e( 'Booking currency', 'woocommerce-multilingual' ); ?></th>
1004
  function set_booking_currency( $currency_code = false ){
1005
 
1006
  if( !isset( $_COOKIE [ '_wcml_booking_currency' ]) && !headers_sent()) {
1007
+
1008
 
1009
  $currency_code = get_woocommerce_currency();
1010
 
1011
+ if ( $this->woocommerce_wpml->settings['enable_multi_currency'] == WCML_MULTI_CURRENCIES_INDEPENDENT ){
1012
+ $order_currencies = $this->woocommerce_wpml->multi_currency->orders->get_orders_currencies();
1013
 
1014
  if (!isset($order_currencies[$currency_code])) {
1015
  foreach ($order_currencies as $currency_code => $count) {
1064
  }
1065
 
1066
  function set_order_currency_on_create_booking_page( $order_id ){
 
 
1067
  update_post_meta( $order_id, '_order_currency', $this->get_cookie_booking_currency() );
1068
 
1069
+ update_post_meta( $order_id, 'wpml_language', $this->sitepress->get_current_language() );
1070
 
1071
  }
1072
 
1078
  }
1079
 
1080
  function custom_box_html( $obj, $product_id, $data ){
 
 
1081
  if( wc_get_product($product_id)->product_type != 'booking' ){
1082
  return;
1083
  }
1151
 
1152
  $orig_resources = $this->get_original_resources( $product_id );
1153
 
1154
+ if( $orig_resources && is_array( $orig_resources ) ){
1155
 
1156
  foreach ( $orig_resources as $resource_id => $cost) {
1157
 
1158
+ if ( 'custom_costs' === $resource_id ){
1159
+ continue;
1160
+ }
1161
  $data[ 'bookings-resource_'.$resource_id.'_title' ] = array( 'original' => get_the_title( $resource_id ) );
1162
+ global $sitepress;
1163
  $trns_resource_id = apply_filters('translate_object_id', $resource_id, 'bookable_resource', false, $lang);
1164
  $data[ 'bookings-resource_'.$resource_id.'_title' ][ 'translation' ] = $trns_resource_id ? get_the_title( $trns_resource_id ) : '';
1165
  }
1188
  }
1189
 
1190
  function get_original_persons( $product_id ){
1191
+ $original_persons = $this->wpdb->get_col( $this->wpdb->prepare( "SELECT ID FROM {$this->wpdb->posts} WHERE post_parent = %d AND post_type = 'bookable_person' AND post_status = 'publish'", $product_id ) );
 
1192
  return $original_persons;
1193
  }
1194
 
1220
  }
1221
 
1222
  function wcml_products_tab_sync_resources_and_persons( $original_product_id, $tr_product_id, $data, $language ){
1223
+ global $wpml_post_translations;
1224
 
1225
  remove_action ( 'save_post', array( $wpml_post_translations, 'save_post_actions' ), 100, 2 );
1226
 
1231
  foreach( $orig_resources as $orig_resource_id => $cost ){
1232
 
1233
  $resource_id = apply_filters( 'translate_object_id', $orig_resource_id, 'bookable_resource', false, $language );
1234
+ $orig_resource = $this->wpdb->get_row( $this->wpdb->prepare( "SELECT resource_id, sort_order FROM {$this->wpdb->prefix}wc_booking_relationships WHERE resource_id = %d AND product_id = %d", $orig_resource_id, $original_product_id ), OBJECT );
1235
 
1236
  if( is_null( $resource_id ) ){
1237
 
1244
  }else{
1245
  //update_relationship
1246
 
1247
+ $exist = $this->wpdb->get_var( $this->wpdb->prepare( "SELECT ID FROM {$this->wpdb->prefix}wc_booking_relationships WHERE resource_id = %d AND product_id = %d", $resource_id, $tr_product_id ) );
1248
 
1249
  if( !$exist ){
1250
 
1251
+ $this->wpdb->insert(
1252
+ $this->wpdb->prefix . 'wc_booking_relationships',
1253
  array(
1254
  'product_id' => $tr_product_id,
1255
  'resource_id' => $resource_id,
1263
 
1264
 
1265
 
1266
+ $this->wpdb->update(
1267
+ $this->wpdb->posts,
1268
  array(
1269
  'post_title' => $data[ md5( 'bookings-resource_'.$orig_resource_id.'_title') ]
1270
  ),
1297
 
1298
  }else{
1299
 
1300
+ $this->wpdb->update(
1301
+ $this->wpdb->posts,
1302
  array(
1303
  'post_parent' => $tr_product_id
1304
  ),
1309
 
1310
  }
1311
 
1312
+ $this->wpdb->update(
1313
+ $this->wpdb->posts,
1314
  array(
1315
  'post_title' => $data[ md5 ( 'bookings-person_'.$original_person_id.'_title' ) ],
1316
  'post_excerpt' => $data[ md5( 'bookings-person_'.$original_person_id.'_description' ) ],
1334
  }
1335
 
1336
  function duplicate_booking_for_translations( $booking_id, $lang = false ){
 
 
1337
  $booking_object = get_post( $booking_id );
1338
 
1339
  $booking_data = array(
1344
  'post_parent' => $booking_object->post_parent,
1345
  );
1346
 
1347
+ $active_languages = $this->sitepress->get_active_languages();
1348
 
1349
  foreach( $active_languages as $language ){
1350
 
1351
  $booking_product_id = get_post_meta( $booking_id, '_booking_product_id', true );
1352
 
1353
  if( !$lang ){
1354
+ $booking_language = $this->sitepress->get_element_language_details( $booking_product_id, 'post_product' );
1355
  if ( $booking_language->language_code == $language['code'] ) {
1356
  continue;
1357
  }
1362
  $booking_persons = maybe_unserialize( get_post_meta( $booking_id, '_booking_persons', true ) );
1363
  $trnsl_booking_persons = array();
1364
 
1365
+ if ( is_array( $booking_persons ) && ! empty( $booking_persons ) ) {
1366
+ foreach( $booking_persons as $person_id => $person_count ){
1367
 
1368
+ $trnsl_person_id = apply_filters( 'translate_object_id', $person_id, 'bookable_person', false, $language['code'] );
1369
 
1370
+ if( is_null( $trnsl_person_id ) ){
1371
+ $trnsl_booking_persons[] = $person_count;
1372
+ }else{
1373
+ $trnsl_booking_persons[ $trnsl_person_id ] = $person_count;
1374
+ }
1375
 
1376
+ }
1377
+ }
1378
 
1379
  $trnsl_booking_id = wp_insert_post( $booking_data );
1380
+ $trid = $this->sitepress->get_element_trid( $booking_id );
1381
+ $this->sitepress->set_element_language_details( $trnsl_booking_id, 'post_wc_booking', $trid, $language['code'] );
1382
 
1383
  $meta_args = array(
1384
  '_booking_order_item_id' => get_post_meta( $booking_id, '_booking_order_item_id', true ),
1391
  '_booking_all_day' => intval( get_post_meta( $booking_id, '_booking_all_day', true ) ),
1392
  '_booking_parent_id' => get_post_meta( $booking_id, '_booking_parent_id', true ),
1393
  '_booking_customer_id' => get_post_meta( $booking_id, '_booking_customer_id', true ),
1394
+ '_booking_duplicate_of' => $booking_id,
1395
+ '_language_code' => $language['code'],
1396
  );
1397
 
1398
  foreach ( $meta_args as $key => $value ) {
1409
  function get_translated_booking_product_id( $booking_id, $language ){
1410
 
1411
  $booking_product_id = get_post_meta( $booking_id, '_booking_product_id', true );
1412
+ $trnsl_booking_product_id = '';
1413
 
1414
  if( $booking_product_id ){
1415
  $trnsl_booking_product_id = apply_filters( 'translate_object_id', $booking_product_id, 'product', false, $language );
1443
  $booking_persons = maybe_unserialize( get_post_meta( $booking_id, '_booking_persons', true ) );
1444
  $trnsl_booking_persons = array();
1445
 
1446
+ if ( is_array( $booking_persons ) && ! empty( $booking_persons ) ) {
1447
+ foreach( $booking_persons as $person_id => $person_count ){
1448
 
1449
+ $trnsl_person_id = apply_filters( 'translate_object_id', $person_id, 'bookable_person', false, $language );
1450
 
1451
+ if( is_null( $trnsl_person_id ) ){
1452
+ $trnsl_booking_persons[] = $person_count;
1453
+ }else{
1454
+ $trnsl_booking_persons[ $trnsl_person_id ] = $person_count;
1455
+ }
 
 
1456
 
1457
+ }
1458
+ }
1459
  return $trnsl_booking_persons;
1460
 
1461
  }
1462
 
1463
  function update_status_for_translations( $booking_id ){
 
 
1464
  $translated_bookings = $this->get_translated_bookings( $booking_id );
1465
 
1466
  foreach( $translated_bookings as $booking ){
1467
 
1468
+ $status = $this->wpdb->get_var( $this->wpdb->prepare( "SELECT post_status FROM {$this->wpdb->posts} WHERE ID = %d", $booking_id ) ); //get_post_status( $booking_id );
1469
  $language = get_post_meta( $booking->post_id, '_language_code', true );
1470
 
1471
+ $this->wpdb->update(
1472
+ $this->wpdb->posts,
1473
  array(
1474
  'post_status' => $status,
1475
  'post_parent' => wp_get_post_parent_id( $booking_id ),
1488
  }
1489
 
1490
  function get_translated_bookings($booking_id){
1491
+ $translated_bookings = $this->wpdb->get_results( $this->wpdb->prepare( "SELECT post_id FROM {$this->wpdb->postmeta} WHERE meta_key = '_booking_duplicate_of' AND meta_value = %d", $booking_id ) );
 
 
1492
 
1493
  return $translated_bookings;
1494
  }
1495
 
1496
  public function booking_filters_query( $query ) {
1497
+ global $typenow;
1498
 
1499
  if ( ( isset( $query->query_vars['post_type'] ) && $query->query_vars['post_type'] == 'wc_booking' ) ) {
1500
 
1501
+ $current_lang = $this->sitepress->get_current_language();
1502
 
1503
+ $product_ids = $this->wpdb->get_col( $this->wpdb->prepare(
1504
  "SELECT element_id
1505
+ FROM {$this->wpdb->prefix}icl_translations
1506
  WHERE language_code = %s AND element_type = 'post_product'", $current_lang ) );
1507
 
1508
  $product_ids = array_diff( $product_ids, array( NULL ) );
1523
  );
1524
  }
1525
  }
1526
+
1527
+ return $query;
1528
  }
1529
 
1530
  function bookings_in_date_range_query($booking_ids){
 
 
1531
  foreach ( $booking_ids as $key => $booking_id ) {
1532
 
1533
+ $language_code = $this->sitepress->get_language_for_element( get_post_meta( $booking_id, '_booking_product_id', true ) , 'post_product' );
1534
+ $current_language = $this->sitepress->get_current_language();
1535
 
1536
  if( $language_code != $current_language ){
1537
  unset( $booking_ids[$key] );
1547
 
1548
  if ( isset( $_GET['post_type'] ) && $_GET['post_type'] == 'wc_booking' && isset( $_GET['page'] ) && $_GET['page'] == 'booking_calendar' ) {
1549
 
 
1550
  //delete transient fields
1551
+ $this->wpdb->query("
1552
+ DELETE FROM {$this->wpdb->options}
1553
  WHERE option_name LIKE '%book_dr_%'
1554
  ");
1555
 
1566
  remove_action( 'before_delete_post', array( $this, 'delete_bookings' ) );
1567
 
1568
  foreach( $translated_bookings as $booking ){
1569
+ $this->wpdb->update(
1570
+ $this->wpdb->posts,
 
 
 
1571
  array(
1572
  'post_parent' => 0
1573
  ),
1592
  $translated_bookings = $this->get_translated_bookings( $booking_id );
1593
 
1594
  foreach( $translated_bookings as $booking ){
 
1595
 
1596
+ $this->wpdb->update(
1597
+ $this->wpdb->posts,
1598
  array(
1599
  'post_status' => 'trash'
1600
  ),
1648
  }
1649
 
1650
  function save_person_translation($post_id, $data, $job ){
 
 
1651
  $person_translations = array();
1652
 
1653
  foreach($data as $value){
1669
 
1670
  foreach( $person_translations as $person_id => $pt ){
1671
 
1672
+ $person_trid = $this->sitepress->get_element_trid( $person_id, 'post_bookable_person');
1673
 
1674
 
1675
  $person_id_translated = apply_filters( 'translate_object_id', $person_id, 'bookable_person', false, $job->language_code );
1688
 
1689
  $person_id_translated = wp_insert_post( $person_post );
1690
 
1691
+ $this->sitepress->set_element_language_details( $person_id_translated, 'post_bookable_person', $person_trid, $job->language_code );
1692
 
1693
  } else {
1694
 
1739
  }
1740
 
1741
  function save_resource_translation( $post_id, $data, $job ){
 
 
1742
  $resource_translations = array();
1743
 
1744
  foreach($data as $value){
1760
 
1761
  foreach( $resource_translations as $resource_id => $rt ){
1762
 
1763
+ $resource_trid = $this->sitepress->get_element_trid( $resource_id, 'post_bookable_resource');
1764
 
1765
  $resource_id_translated = apply_filters( 'translate_object_id', $resource_id, 'bookable_resource', false, $job->language_code );
1766
 
1776
 
1777
  $resource_id_translated = wp_insert_post( $resource_post );
1778
 
1779
+ $this->sitepress->set_element_language_details( $resource_id_translated, 'post_bookable_resource', $resource_trid, $job->language_code );
1780
 
1781
+ $sort_order = $this->wpdb->get_var( $this->wpdb->prepare( "SELECT sort_order FROM {$this->wpdb->prefix}wc_booking_relationships WHERE resource_id=%d", $resource_id ) );
1782
  $relationship = array(
1783
  'product_id' => $post_id,
1784
  'resource_id' => $resource_id_translated,
1785
  'sort_order' => $sort_order
1786
  );
1787
+ $this->wpdb->insert( $this->wpdb->prefix . 'wc_booking_relationships', $relationship);
1788
 
1789
  } else {
1790
 
1795
 
1796
  wp_update_post( $resource_post );
1797
 
1798
+ $sort_order = $this->wpdb->get_var( $this->wpdb->prepare( "SELECT sort_order FROM {$this->wpdb->prefix}wc_booking_relationships WHERE resource_id=%d", $resource_id ) );
1799
+ $this->wpdb->update( $this->wpdb->prefix . 'wc_booking_relationships', array( 'sort_order' => $sort_order ),
1800
  array ( 'product_id' => $post_id, 'resource_id' => $resource_id_translated) );
1801
 
1802
 
1842
  return $ids;
1843
  }
1844
 
1845
+ /**
1846
+ * @param array $currencies
1847
+ * @param int $post_id
1848
+ *
1849
+ * @return bool
1850
+ */
1851
+ private function update_booking_costs( $currencies = array(), $post_id = 0 ) {
1852
+ $booking_options = array(
1853
+ 'wcml_wc_booking_cost' => '_wc_booking_cost_',
1854
+ 'wcml_wc_booking_base_cost' => '_wc_booking_base_cost_',
1855
+ 'wcml_wc_display_cost' => '_wc_display_cost_',
1856
+ );
1857
+
1858
+ foreach( $currencies as $code => $currency ) {
1859
+ foreach( $booking_options as $booking_options_post_key => $booking_options_meta_key_prefix ) {
1860
+ if ( isset( $_POST[ $booking_options_post_key ][ $code ] ) && '' !== $_POST[ $booking_options_post_key ][ $code ] ) {
1861
+ update_post_meta( $post_id, $booking_options_meta_key_prefix . $code, sanitize_text_field( $_POST[ $booking_options_post_key ][ $code ] ) );
1862
+ }
1863
+ }
1864
+ }
1865
+
1866
+ return true;
1867
+ }
1868
+
1869
+ /**
1870
+ * @param array $currencies
1871
+ * @param int $post_id
1872
+ *
1873
+ * @return bool
1874
+ */
1875
+ private function update_booking_pricing( $currencies = array(), $post_id = 0 ) {
1876
+ $updated_meta = array();
1877
+ $booking_pricing = get_post_meta( $post_id, '_wc_booking_pricing', true );
1878
+ if ( empty( $booking_pricing ) ) {
1879
+ return false;
1880
+ }
1881
+
1882
+ foreach ( $booking_pricing as $key => $prices) {
1883
+ $updated_meta[ $key ] = $prices;
1884
+ foreach ( $currencies as $code => $currency ) {
1885
+ if ( isset( $_POST['wcml_wc_booking_pricing_base_cost'][ $code ][ $key ] ) ) {
1886
+ $updated_meta[ $key ]['base_cost_' . $code ] = sanitize_text_field( $_POST['wcml_wc_booking_pricing_base_cost'][ $code ][ $key ] );
1887
+ }
1888
+ if ( isset( $_POST['wcml_wc_booking_pricing_cost'][ $code ][ $key ] ) ) {
1889
+ $updated_meta[ $key ]['cost_' . $code ] = sanitize_text_field( $_POST['wcml_wc_booking_pricing_cost'][ $code ][ $key ] );
1890
+ }
1891
+ }
1892
+
1893
+ }
1894
+
1895
+ update_post_meta( $post_id, '_wc_booking_pricing', $updated_meta );
1896
+ return true;
1897
+ }
1898
+
1899
+ /**
1900
+ * @param array $currencies
1901
+ * @param array $person_costs
1902
+ *
1903
+ * @return bool
1904
+ */
1905
+ private function update_booking_person_cost( $currencies = array(), $person_costs = array() ) {
1906
+ if( empty( $person_costs ) ) {
1907
+ return false;
1908
+ }
1909
+
1910
+ foreach( $person_costs as $person_id => $costs ) {
1911
+ foreach ( $currencies as $code => $currency ) {
1912
+ if ( isset( $costs[ $code ] ) ) {
1913
+ update_post_meta( $person_id, 'cost_' . $code, sanitize_text_field( $costs[ $code ] ) );
1914
+ }
1915
+ }
1916
+ }
1917
+ return true;
1918
+ }
1919
+
1920
+ /**
1921
+ * @param array $currencies
1922
+ * @param array $block_costs
1923
+ *
1924
+ * @return bool
1925
+ */
1926
+ private function update_booking_person_block_cost( $currencies = array(), $block_costs = array() ) {
1927
+ if( empty( $block_costs ) ) {
1928
+ return false;
1929
+ }
1930
+
1931
+ foreach( $block_costs as $person_id => $costs ){
1932
+ foreach( $currencies as $code => $currency ){
1933
+ if ( isset( $costs[ $code ] ) ) {
1934
+ update_post_meta( $person_id, 'block_cost_' . $code, sanitize_text_field( $costs[ $code ] ) );
1935
+ }
1936
+ }
1937
+ }
1938
+ return true;
1939
+ }
1940
+
1941
+ /**
1942
+ * @param array $currencies
1943
+ * @param int $post_id
1944
+ * @param array $resource_cost
1945
+ *
1946
+ * @return bool
1947
+ */
1948
+ private function update_booking_resource_cost( $currencies = array(), $post_id = 0, $resource_cost = array() ) {
1949
+ if ( empty( $resource_cost ) ) {
1950
+ return false;
1951
+ }
1952
+
1953
+ $updated_meta = get_post_meta( $post_id, '_resource_base_costs', true );
1954
+ if ( ! is_array( $updated_meta ) ) {
1955
+ $updated_meta = array();
1956
+ }
1957
+
1958
+ $wc_booking_resource_costs = array();
1959
+
1960
+ foreach ( $resource_cost as $resource_id => $costs) {
1961
+
1962
+ foreach ($currencies as $code => $currency) {
1963
+
1964
+ if ( isset( $costs[ $code ] ) ) {
1965
+ $wc_booking_resource_costs[ $code ][ $resource_id ] = sanitize_text_field( $costs[ $code ] );
1966
+ }
1967
+
1968
+ }
1969
+
1970
+ }
1971
+
1972
+ $updated_meta[ 'custom_costs' ] = $wc_booking_resource_costs;
1973
+
1974
+ update_post_meta( $post_id, '_resource_base_costs', $updated_meta );
1975
+
1976
+ $this->sync_resource_costs_with_translations( $post_id, '_resource_base_costs' );
1977
+
1978
+ return true;
1979
+ }
1980
+
1981
+ /**
1982
+ * @param array $currencies
1983
+ * @param int $post_id
1984
+ *
1985
+ * @return bool
1986
+ */
1987
+ private function update_booking_resource_block_cost( $currencies = array(), $post_id = 0, $resource_block_cost = array() ) {
1988
+ if( empty( $resource_block_cost ) ) {
1989
+ return false;
1990
+ }
1991
+
1992
+ $updated_meta = get_post_meta( $post_id, '_resource_block_costs', true );
1993
+
1994
+ $wc_booking_resource_block_costs = array();
1995
+
1996
+ foreach( $resource_block_cost as $resource_id => $costs ){
1997
+
1998
+ foreach( $currencies as $code => $currency ){
1999
+
2000
+ if ( isset( $costs[ $code ] ) ) {
2001
+ $wc_booking_resource_block_costs[ $code ][ $resource_id ] = sanitize_text_field( $costs[ $code ] );
2002
+ }
2003
+
2004
+ }
2005
+
2006
+ }
2007
+
2008
+ $updated_meta[ 'custom_costs' ] = $wc_booking_resource_block_costs;
2009
+
2010
+ update_post_meta( $post_id, '_resource_block_costs', $updated_meta );
2011
+
2012
+ $this->sync_resource_costs_with_translations( $post_id, '_resource_block_costs' );
2013
+
2014
+ return true;
2015
+ }
2016
  }
compatibility/class-wcml-dynamic-pricing.php CHANGED
@@ -8,7 +8,7 @@ class WCML_Dynamic_Pricing{
8
  add_filter('woocommerce_dynamic_pricing_is_applied_to', array($this, 'woocommerce_dynamic_pricing_is_applied_to'),10,5);
9
  add_filter('woocommerce_dynamic_pricing_get_rule_amount',array($this,'woocommerce_dynamic_pricing_get_rule_amount'),10,4);
10
  add_filter('dynamic_pricing_product_rules',array($this,'dynamic_pricing_product_rules'));
11
- add_filter('translate_cart_subtotal_exception',array($this,'translate_cart_subtotal_exception'),10,2);
12
 
13
  }
14
  }
@@ -74,8 +74,8 @@ class WCML_Dynamic_Pricing{
74
  return $rules;
75
  }
76
 
77
- function translate_cart_subtotal_exception( $value, $cart ){
78
- return true;
79
  }
80
 
81
  }
8
  add_filter('woocommerce_dynamic_pricing_is_applied_to', array($this, 'woocommerce_dynamic_pricing_is_applied_to'),10,5);
9
  add_filter('woocommerce_dynamic_pricing_get_rule_amount',array($this,'woocommerce_dynamic_pricing_get_rule_amount'),10,4);
10
  add_filter('dynamic_pricing_product_rules',array($this,'dynamic_pricing_product_rules'));
11
+ add_filter('wcml_calculate_totals_exception', array($this, 'calculate_totals_exception'));
12
 
13
  }
14
  }
74
  return $rules;
75
  }
76
 
77
+ function calculate_totals_exception( ){
78
+ return false;
79
  }
80
 
81
  }
compatibility/class-wcml-product-addons.php CHANGED
@@ -4,24 +4,31 @@ class WCML_Product_Addons{
4
 
5
  function __construct(){
6
 
7
- add_filter('get_product_addons_product_terms',array($this,'addons_product_terms'));
8
- add_filter('get_product_addons_fields',array($this,'product_addons_filter'),10,2);
9
 
10
- add_action('updated_post_meta',array($this,'register_addons_strings'),10,4);
11
- add_action('added_post_meta',array($this,'register_addons_strings'),10,4);
 
12
 
13
  global $pagenow;
14
- if($pagenow == 'edit.php' && isset($_GET['post_type']) && $_GET['post_type']=='product' && isset($_GET['page']) && $_GET['page']=='global_addons' && !isset($_GET['edit'])){
15
- add_action('admin_notices', array($this, 'inf_translate_strings'));
 
 
 
 
 
 
16
  }
17
 
18
  add_action( 'addons_panel_start', array( $this, 'inf_translate_strings' ) );
19
 
20
  if( is_admin() ) {
21
 
22
- add_action('wcml_gui_additional_box_html', array($this, 'custom_box_html'), 10, 3);
23
- add_filter('wcml_gui_additional_box_data', array($this, 'custom_box_html_data'), 10, 4);
24
- add_action('wcml_update_extra_fields',array($this,'addons_update'),10,3);
25
  }
26
  }
27
 
@@ -40,6 +47,32 @@ class WCML_Product_Addons{
40
  }
41
  }
42
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
43
  function product_addons_filter($addons, $object_id){
44
 
45
  foreach($addons as $add_id => $addon){
4
 
5
  function __construct(){
6
 
7
+ add_filter( 'get_product_addons_product_terms', array( $this, 'addons_product_terms' ) );
8
+ add_filter( 'get_product_addons_fields', array( $this, 'product_addons_filter'), 10, 2 );
9
 
10
+ add_action( 'updated_post_meta', array( $this, 'register_addons_strings' ), 10 ,4 );
11
+ add_action( 'added_post_meta', array( $this, 'register_addons_strings' ), 10, 4 );
12
+ add_filter( 'get_post_metadata', array( $this, 'translate_addons_strings' ), 10, 4 );
13
 
14
  global $pagenow;
15
+ if( $pagenow == 'edit.php' &&
16
+ isset( $_GET[ 'post_type' ] ) &&
17
+ $_GET[ 'post_type' ]=='product' &&
18
+ isset( $_GET[ 'page' ] ) &&
19
+ $_GET[ 'page' ]=='global_addons' &&
20
+ !isset( $_GET[ 'edit' ] )
21
+ ){
22
+ add_action( 'admin_notices', array( $this, 'inf_translate_strings' ) );
23
  }
24
 
25
  add_action( 'addons_panel_start', array( $this, 'inf_translate_strings' ) );
26
 
27
  if( is_admin() ) {
28
 
29
+ add_action( 'wcml_gui_additional_box_html', array( $this, 'custom_box_html' ), 10, 3 );
30
+ add_filter( 'wcml_gui_additional_box_data', array( $this, 'custom_box_html_data' ), 10, 4 );
31
+ add_action( 'wcml_update_extra_fields', array( $this,'addons_update' ), 10, 3 );
32
  }
33
  }
34
 
47
  }
48
  }
49
 
50
+ function translate_addons_strings( $null, $object_id, $meta_key, $single ){
51
+
52
+ if( $meta_key == '_product_addons' && get_post_type( $object_id ) == 'global_product_addon' ){
53
+
54
+ remove_filter( 'get_post_metadata', array( $this, 'translate_addons_strings' ), 10, 4 );
55
+ $addons = get_post_meta( $object_id, $meta_key, true);
56
+ add_filter( 'get_post_metadata', array( $this, 'translate_addons_strings' ), 10, 4 );
57
+
58
+ foreach ($addons as $key => $addon) {
59
+ //register name
60
+ $addons[ $key ][ 'name' ] = apply_filters( 'wpml_translate_single_string', $addon['name'], 'wc_product_addons_strings', $object_id . '_addon_' . $addon['type'] . '_' . $addon['position'] . '_name' );
61
+ //register description
62
+ $addons[ $key ][ 'description' ] = apply_filters( 'wpml_translate_single_string', $addon['description'], 'wc_product_addons_strings', $object_id . '_addon_' . $addon['type'] . '_' . $addon['position'] . '_description' );
63
+ //register options labels
64
+ foreach ($addon['options'] as $opt_key => $option) {
65
+ $addons[ $key ][ 'options' ][ $opt_key ][ 'label' ] = apply_filters( 'wpml_translate_single_string', $option['label'], 'wc_product_addons_strings', $object_id . '_addon_' . $addon['type'] . '_' . $addon['position'] . '_option_label_' . $key );
66
+ }
67
+ }
68
+
69
+ return array( 0 => $addons );
70
+ }
71
+
72
+ return $null;
73
+
74
+ }
75
+
76
  function product_addons_filter($addons, $object_id){
77
 
78
  foreach($addons as $add_id => $addon){
compatibility/class-wcml-tab-manager.php CHANGED
@@ -1,535 +1,628 @@
1
  <?php
2
 
3
- class WCML_Tab_Manager{
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4
 
5
- public $tp;
6
-
7
- function __construct(){
8
- add_action( 'wcml_update_extra_fields', array( $this, 'sync_tabs' ), 10, 4 );
9
- add_action( 'wcml_gui_additional_box_html', array( $this, 'custom_box_html'), 10, 3 );
10
- add_filter( 'wcml_gui_additional_box_data', array( $this, 'custom_box_html_data'), 10, 4 );
11
- add_filter( 'wpml_duplicate_custom_fields_exceptions', array( $this, 'duplicate_custom_fields_exceptions' ) );
12
- add_action( 'wcml_after_duplicate_product', array( $this, 'duplicate_product_tabs') , 10, 2 );
13
-
14
- add_filter('wc_tab_manager_tab_id', array($this, 'wc_tab_manager_tab_id'), 10, 1);
15
-
16
- if( version_compare( WCML_VERSION, '3.7.2', '>') ){
17
- add_filter( 'option_wpml_config_files_arr', array($this, 'make__product_tabs_not_translatable_by_default'), 0 );
18
- }
19
-
20
- if( is_admin() ){
21
-
22
- $this->tp = new WPML_Element_Translation_Package;
23
-
24
- add_action( 'save_post', array($this, 'force_set_language_information_on_product_tabs'), 10, 2);
25
-
26
- add_filter( 'wpml_tm_translation_job_data', array( $this, 'append_custom_tabs_to_translation_package' ), 10, 2 );
27
- add_action( 'wpml_translation_job_saved', array( $this, 'save_custom_tabs_translation' ), 10, 3 );
28
-
29
- }
30
-
31
- }
32
-
33
- function make__product_tabs_not_translatable_by_default($wpml_config_array){
34
-
35
- if( isset( $wpml_config_array->plugins['WooCommerce Tab Manager'] ) ){
36
- $wpml_config_array->plugins['WooCommerce Tab Manager'] =
37
- str_replace('<custom-field action="translate">_product_tabs</custom-field>',
38
- '<custom-field action="nothing">_product_tabs</custom-field>',
39
- $wpml_config_array->plugins['WooCommerce Tab Manager'] );
40
- }
41
-
42
- return $wpml_config_array;
43
-
44
- }
45
-
46
- function sync_tabs( $original_product_id, $trnsl_product_id, $data, $lang ){
47
- global $sitepress, $woocommerce, $woocommerce_wpml;
48
-
49
- //check if "duplicate" product
50
- if( ( isset( $_POST['icl_ajx_action'] ) && ( $_POST['icl_ajx_action'] == 'make_duplicates' ) ) || ( get_post_meta( $trnsl_product_id , '_icl_lang_duplicate_of', true ) ) ){
51
- $this->duplicate_tabs( $original_product_id, $trnsl_product_id, $lang );
52
- }
53
-
54
- $orig_prod_tabs = $this->get_product_tabs( $original_product_id );
55
-
56
- if( $orig_prod_tabs ){
57
- $trnsl_product_tabs = array();
58
- $i = 0;
59
- foreach( $orig_prod_tabs as $key => $orig_prod_tab ){
60
- switch( $orig_prod_tab[ 'type' ] ){
61
- case 'core':
62
- $default_language = $woocommerce_wpml->products->get_original_product_language( $original_product_id );
63
- $current_language = $sitepress->get_current_language();
64
- $trnsl_product_tabs[ $key ] = $orig_prod_tabs[ $key ];
65
- $title = '';
66
- $heading = '';
67
-
68
- $title = $data[ md5( 'coretab_'.$orig_prod_tab['id'].'_title' ) ] ? $data[ md5( 'coretab_'.$orig_prod_tab['id'].'_title' ) ] : '';
69
- $heading = $data[ md5( 'coretab_'.$orig_prod_tab['id'].'_heading' ) ] ? $data[ md5( 'coretab_'.$orig_prod_tab['id'].'_heading' ) ] : '';
70
-
71
-
72
- if( $default_language != $lang ){
73
-
74
- $this->refresh_text_domain( $lang );
75
-
76
- if( !$title ){
77
- $title = isset( $_POST['product_tab_title'][ $orig_prod_tab['position'] ] ) ? $_POST['product_tab_title'][ $orig_prod_tab['position'] ] : $orig_prod_tabs[ $key ][ 'title' ];
78
- $title = __( $title, 'woocommerce' );
79
- }
80
-
81
- if( !$heading && ( isset( $orig_prod_tabs[ $key ][ 'heading' ] ) || isset( $_POST['product_tab_heading'][ $orig_prod_tab['position'] ] ) ) ){
82
- $heading = isset( $_POST['product_tab_heading'][ $orig_prod_tab['position'] ] ) ? $_POST['product_tab_heading'][ $orig_prod_tab['position'] ] : $orig_prod_tabs[ $key ][ 'heading' ];
83
- $heading = __( $heading, 'woocommerce' );
84
- }
85
-
86
- $this->refresh_text_domain( $current_language );
87
- }
88
-
89
- $trnsl_product_tabs[ $key ][ 'title' ] = $title;
90
- $trnsl_product_tabs[ $key ][ 'heading' ] = $heading;
91
- break;
92
- case 'global':
93
- $trnsl_product_tabs = $this->set_global_tab( $orig_prod_tab, $trnsl_product_tabs, $lang );
94
- break;
95
- case 'product':
96
- $tab_id = false;
97
-
98
- $title = $data[ md5( 'tab_'.$orig_prod_tab['position'].'_title' ) ];
99
- $content = $data[ md5( 'tab_'.$orig_prod_tab['position'].'_heading' ) ];
100
-
101
- $trnsl_product_tabs = $this->set_product_tab( $orig_prod_tab, $trnsl_product_tabs, $lang, $trnsl_product_id, $tab_id, $title, $content );
102
-
103
- $i++;
104
- break;
105
- }
106
- }
107
- update_post_meta( $trnsl_product_id, '_product_tabs', $trnsl_product_tabs );
108
- }
109
- }
110
-
111
- function duplicate_tabs( $original_product_id, $trnsl_product_id, $lang ){
112
- global $sitepress;
113
- $orig_prod_tabs = maybe_unserialize( get_post_meta( $original_product_id, '_product_tabs', true ) );
114
- $prod_tabs = array();
115
- foreach( $orig_prod_tabs as $key => $orig_prod_tab ){
116
- switch( $orig_prod_tab[ 'type' ] ){
117
- case 'core':
118
- $prod_tabs[ $key ] = $orig_prod_tab;
119
- $this->refresh_text_domain( $lang );
120
- $prod_tabs[ $key ][ 'title' ] = __( $orig_prod_tab[ 'title' ], 'woocommerce' );
121
- if( isset( $orig_prod_tab[ 'heading' ] ) )
122
- $prod_tabs[ $key ][ 'heading' ] = __( $orig_prod_tab[ 'heading' ], 'woocommerce' );
123
- $orig_lang = $sitepress->get_language_for_element( $original_product_id, 'post_product' );
124
- $this->refresh_text_domain( $orig_lang );
125
- break;
126
- case 'global':
127
- $prod_tabs = $this->set_global_tab( $orig_prod_tab, $prod_tabs, $lang );
128
- break;
129
- case 'product':
130
- $original_tab = get_post( $orig_prod_tab[ 'id' ] );
131
- $prod_tabs = $this->set_product_tab( $orig_prod_tab, $prod_tabs, $lang, $trnsl_product_id, false, $original_tab->post_title , $original_tab->post_content );
132
- break;
133
- }
134
- }
135
-
136
- update_post_meta( $trnsl_product_id, '_product_tabs', $prod_tabs );
137
- }
138
-
139
- function refresh_text_domain( $lang ){
140
- global $sitepress, $woocommerce;
141
-
142
- unload_textdomain( 'woocommerce' );
143
- $sitepress->switch_lang( $lang );
144
- $woocommerce->load_plugin_textdomain();
145
- }
146
-
147
- function set_global_tab( $orig_prod_tab, $trnsl_product_tabs, $lang ){
148
- $tr_tab_id = apply_filters( 'translate_object_id', $orig_prod_tab[ 'id' ], 'wc_product_tab', true, $lang );
149
- $trnsl_product_tabs[ $orig_prod_tab[ 'type' ].'_tab_'.$tr_tab_id ] = array(
150
- 'position' => $orig_prod_tab[ 'position' ],
151
- 'type' => $orig_prod_tab[ 'type' ],
152
- 'id' => $tr_tab_id,
153
- 'name' => get_post( $tr_tab_id )->post_name
154
- );
155
- return $trnsl_product_tabs;
156
- }
157
-
158
- function set_product_tab( $orig_prod_tab, $trnsl_product_tabs, $lang, $trnsl_product_id, $tab_id, $title, $content ){
159
- global $wpdb, $sitepress;
160
-
161
- if( !$tab_id ){
162
- $tr_tab_id = apply_filters( 'translate_object_id', $orig_prod_tab[ 'id' ], 'wc_product_tab', false, $lang );
163
-
164
- if( !is_null( $tr_tab_id ) ){
165
- $tab_id = $tr_tab_id;
166
- }
167
- }
168
-
169
- if( $tab_id ){
170
- //update existing tab
171
- $args = array();
172
- $args[ 'post_title' ] = $title;
173
- $args[ 'post_content' ] = $content;
174
- $wpdb->update( $wpdb->posts, $args, array( 'ID' => $tab_id ) );
175
- }else{
176
- //tab not exist creating new
177
- $args = array();
178
- $args[ 'post_title' ] = $title;
179
- $args[ 'post_content' ] = $content;
180
- $args[ 'post_author' ] = get_current_user_id();
181
- $args[ 'post_name' ] = sanitize_title( $title );
182
- $args[ 'post_type' ] = 'wc_product_tab';
183
- $args[ 'post_parent' ] = $trnsl_product_id;
184
- $args[ 'post_status' ] = 'publish';
185
- $wpdb->insert( $wpdb->posts, $args );
186
-
187
- $tab_id = $wpdb->insert_id;
188
- $tab_trid = $sitepress->get_element_trid( $orig_prod_tab[ 'id' ], 'post_wc_product_tab' );
189
- if( !$tab_trid ){
190
- $sitepress->set_element_language_details( $orig_prod_tab[ 'id' ], 'post_wc_product_tab', false, $sitepress->get_default_language() );
191
- $tab_trid = $sitepress->get_element_trid( $orig_prod_tab[ 'id' ], 'post_wc_product_tab' );
192
- }
193
- $sitepress->set_element_language_details( $tab_id, 'post_wc_product_tab', $tab_trid, $lang );
194
- }
195
-
196
- $trnsl_product_tabs[ $orig_prod_tab[ 'type' ].'_tab_'.$tab_id ] = array(
197
- 'position' => $orig_prod_tab[ 'position' ],
198
- 'type' => $orig_prod_tab[ 'type' ],
199
- 'id' => $tab_id,
200
- 'name' => get_post( $tab_id )->post_name
201
- );
202
-
203
- return $trnsl_product_tabs;
204
- }
205
-
206
- function duplicate_custom_fields_exceptions( $exceptions ){
207
- $exceptions[] = '_product_tabs';
208
- return $exceptions;
209
- }
210
-
211
- function custom_box_html( $obj, $product_id, $data ){
212
-
213
- if( get_post_meta( $product_id, '_override_tab_layout', true ) != 'yes' ){
214
- return false;
215
- }
216
-
217
- $orig_prod_tabs = $this->get_product_tabs( $product_id );
218
- if( !$orig_prod_tabs ) return false;
219
-
220
- $tabs_section = new WPML_Editor_UI_Field_Section( __( 'Product tabs', 'woocommerce-multilingual' ) );
221
- end( $orig_prod_tabs );
222
- $last_key = key( $orig_prod_tabs );
223
- $divider = true;
224
- foreach( $orig_prod_tabs as $key => $prod_tab ) {
225
- if( $key == $last_key ){
226
- $divider = false;
227
- }
228
-
229
- if( in_array( $prod_tab['type'], array( 'product', 'core' ) ) ){
230
- if( $prod_tab['type'] == 'core' ){
231
- $group = new WPML_Editor_UI_Field_Group( $prod_tab[ 'title' ], $divider );
232
- $tab_field = new WPML_Editor_UI_Single_Line_Field( 'coretab_'.$prod_tab['id'].'_title', __( 'Title', 'woocommerce-multilingual' ), $data, false );
233
- $group->add_field( $tab_field );
234
- $tab_field = new WPML_Editor_UI_Single_Line_Field( 'coretab_'.$prod_tab['id'].'_heading' , __( 'Heading', 'woocommerce-multilingual' ), $data, false );
235
- $group->add_field( $tab_field );
236
- $tabs_section->add_field( $group );
237
- }else{
238
- $group = new WPML_Editor_UI_Field_Group( ucfirst( str_replace( '-', ' ', $prod_tab[ 'name' ] ) ), $divider );
239
- $tab_field = new WPML_Editor_UI_Single_Line_Field( 'tab_'.$prod_tab['position'].'_title', __( 'Title', 'woocommerce-multilingual' ), $data, false );
240
- $group->add_field( $tab_field );
241
- $tab_field = new WPML_Editor_UI_WYSIWYG_Field( 'tab_'.$prod_tab['position'].'_heading' , null, $data, false );
242
- $group->add_field( $tab_field );
243
- $tabs_section->add_field( $group );
244
- }
245
- }
246
- }
247
- $obj->add_field( $tabs_section );
248
-
249
- }
250
-
251
-
252
- function custom_box_html_data( $data, $product_id, $translation, $lang ){
253
-
254
- $orig_prod_tabs = $this->get_product_tabs( $product_id );
255
-
256
- if( empty($orig_prod_tabs) ){
257
- return $data;
258
- }
259
-
260
- foreach( $orig_prod_tabs as $key => $prod_tab ){
261
- if( in_array( $prod_tab['type'], array( 'product', 'core' ) ) ){
262
- if( $prod_tab['type'] == 'core' ){
263
- $data[ 'coretab_'.$prod_tab['id'].'_title' ] = array( 'original' => $prod_tab['title'] );
264
- $data[ 'coretab_'.$prod_tab['id'].'_heading' ] = array( 'original' => isset ( $prod_tab['heading'] ) ? $prod_tab['heading'] : '' );
265
- }else{
266
- $data[ 'tab_'.$prod_tab['position'].'_title' ] = array( 'original' => get_the_title( $prod_tab['id'] ) );
267
- $data[ 'tab_'.$prod_tab['position'].'_heading' ] = array( 'original' => get_post( $prod_tab['id'] )->post_content );
268
- }
269
- }
270
- }
271
-
272
- if( $translation ){
273
- $tr_product_id = $translation->ID;
274
-
275
- $tr_prod_tabs = $this->get_product_tabs( $translation->ID );
276
-
277
- if( !is_array( $tr_prod_tabs ) ){
278
- return $data; // __('Please update original product','woocommerce-multilingual');
279
- }
280
-
281
- foreach( $tr_prod_tabs as $key => $prod_tab ){
282
- if( in_array( $prod_tab['type'], array( 'product','core' ) ) ){
283
- if($prod_tab['type'] == 'core'){
284
- $data[ 'coretab_'.$prod_tab['id'].'_title' ][ 'translation' ] = $prod_tab['title'];
285
- $data[ 'coretab_'.$prod_tab['id'].'_heading' ][ 'translation' ] = isset ( $prod_tab['heading'] ) ? $prod_tab['heading'] : '';
286
- }else{
287
- $data[ 'tab_'.$prod_tab['position'].'_title' ][ 'translation' ] = get_the_title( $prod_tab['id'] );
288
- $data[ 'tab_'.$prod_tab['position'].'_heading' ][ 'translation' ] = get_post( $prod_tab['id'] )->post_content;
289
- }
290
- }
291
- }
292
- }else{
293
- global $sitepress,$woocommerce;
294
- $current_language = $sitepress->get_current_language();
295
- foreach($orig_prod_tabs as $key=>$prod_tab){
296
- if($prod_tab['type'] == 'core'){
297
- unload_textdomain('woocommerce');
298
- $sitepress->switch_lang($lang);
299
- $woocommerce->load_plugin_textdomain();
300
- $title = __( $prod_tab['title'], 'woocommerce' );
301
- if($prod_tab['title'] != $title){
302
- $data[ 'coretab_'.$prod_tab['id'].'_title' ][ 'translation' ] = $title;
303
-
304
- }
305
-
306
- if(!isset($prod_tab['heading'])){
307
- $data[ 'coretab_'.$prod_tab['id'].'_heading' ][ 'translation' ] = '';
308
- }else{
309
- $heading = __( $prod_tab['heading'], 'woocommerce' );
310
- if($prod_tab['heading'] != $heading){
311
- $data[ 'coretab_'.$prod_tab['id'].'_heading' ][ 'translation' ] = $heading;
312
- }
313
- }
314
-
315
- unload_textdomain('woocommerce');
316
- $sitepress->switch_lang($current_language);
317
- $woocommerce->load_plugin_textdomain();
318
- }
319
- }
320
- }
321
-
322
- return $data;
323
-
324
- }
325
-
326
- function duplicate_product_tabs( $new_id, $original_post ){
327
-
328
- wc_tab_manager_duplicate_product( $new_id, $original_post );
329
-
330
- }
331
-
332
- function force_set_language_information_on_product_tabs($post_id, $post){
333
- global $sitepress;
334
-
335
- if( $post->post_type == 'wc_product_tab' ){
336
-
337
- $language = $sitepress->get_language_for_element($post->ID, 'post_wc_product_tab');
338
- if( empty ($language) && $post->post_parent ) {
339
- $parent_language = $sitepress->get_language_for_element($post->post_parent, 'post_product');
340
- if( $parent_language ){
341
- $sitepress->set_element_language_details($post->ID, 'post_wc_product_tab', null, $parent_language);
342
- }
343
- }
344
-
345
- }
346
-
347
- }
348
-
349
- function append_custom_tabs_to_translation_package($package, $post){
350
-
351
- if( $post->post_type == 'product' ) {
352
-
353
- $override_tab_layout = get_post_meta( $post->ID , '_override_tab_layout', true);
354
-
355
- if( $override_tab_layout == 'yes' ){
356
 
357
- $meta = get_post_meta( $post->ID, '_product_tabs', true );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
358
 
359
- foreach ( (array)$meta as $key => $value ) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
360
 
361
- if ( preg_match( '/product_tab_([0-9]+)/', $key, $matches ) ) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
362
 
363
- $wc_product_tab_id = $matches[1];
364
- $wc_product_tab = get_post( $wc_product_tab_id );
 
 
 
 
 
 
365
 
366
- $package['contents']['product_tabs:product_tab:' . $wc_product_tab_id . ':title'] = array(
367
- 'translate' => 1,
368
- 'data' => $this->tp->encode_field_data( $wc_product_tab->post_title, 'base64' ),
369
- 'format' => 'base64'
370
- );
 
 
 
 
 
 
 
 
 
 
 
 
371
 
372
- $package['contents']['product_tabs:product_tab:' . $wc_product_tab_id . ':description'] = array(
373
- 'translate' => 1,
374
- 'data' => $this->tp->encode_field_data( $wc_product_tab->post_content, 'base64' ),
375
- 'format' => 'base64'
376
- );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
377
 
 
 
 
 
 
 
 
 
 
378
 
379
- } elseif ( preg_match( '/^core_tab_(.+)$/', $key, $matches ) ){
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
380
 
381
- $package['contents']['product_tabs:core_tab_title:' . $matches[1]] = array(
382
- 'translate' => 1,
383
- 'data' => $this->tp->encode_field_data( $value['title'], 'base64' ),
384
- 'format' => 'base64'
385
- );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
386
 
387
- if(isset( $value['heading'] )) {
388
- $package['contents']['product_tabs:core_tab_heading:' . $matches[1]] = array(
389
- 'translate' => 1,
390
- 'data' => $this->tp->encode_field_data( $value['heading'], 'base64' ),
391
- 'format' => 'base64'
392
- );
393
- }
394
 
 
 
 
 
 
 
 
 
 
395
 
396
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
397
 
398
- }
399
- }
400
 
 
 
 
 
 
 
 
401
 
402
- }
403
 
404
- return $package;
405
- }
406
 
407
- function save_custom_tabs_translation( $post_id, $data, $job ){
408
- global $sitepress;
409
 
 
410
 
411
- $translated_product_tabs_updated = false;
412
 
413
- $original_product_tabs = get_post_meta($job->original_doc_id, '_product_tabs', true);
414
 
415
- if( $original_product_tabs ) {
 
416
 
417
- // custom tabs
418
- $product_tab_translations = array();
 
 
 
419
 
420
- foreach ( $data as $value ) {
 
 
 
 
421
 
422
- if ( preg_match( '/product_tabs:product_tab:([0-9]+):(.+)/', $value['field_type'], $matches ) ) {
423
 
424
- $wc_product_tab_id = $matches[1];
425
- $field = $matches[2];
 
 
 
426
 
427
- $product_tab_translations[$wc_product_tab_id][$field] = $value['data'];
428
- }
 
 
 
 
 
 
 
 
 
429
 
430
- }
 
431
 
432
- if ( $product_tab_translations ) {
 
 
 
 
 
 
433
 
434
- $translated_product_tabs = get_post_meta( $post_id, '_product_tabs', true );
435
 
436
- foreach ( $product_tab_translations as $wc_product_tab_id => $value ) {
437
 
438
- $new_wc_product_tab = array(
439
- 'post_type' => 'wp_product_tab',
440
- 'post_title' => $value['title'],
441
- 'post_content' => $value['description'],
442
- 'post_status' => 'publish'
443
- );
444
 
445
- $wc_product_tab_id_translated = wp_insert_post( $new_wc_product_tab );
446
 
447
- if ( $wc_product_tab_id_translated ) {
448
 
449
- $wc_product_tab_trid = $sitepress->get_element_trid( $wc_product_tab_id, 'post_wc_product_tab' );
450
- $sitepress->set_element_language_details( $wc_product_tab_id_translated, 'post_wc_product_tab', $wc_product_tab_trid, $job->language_code );
451
 
452
- $wc_product_tab_translated = get_post( $wc_product_tab_id_translated );
 
 
453
 
454
- $translated_product_tabs['product_tab_' . $wc_product_tab_id_translated] = array(
455
 
456
- 'position' => $original_product_tabs['product_tab_' . $wc_product_tab_id]['position'],
457
- 'type' => 'product',
458
- 'id' => $wc_product_tab_id_translated,
459
- 'name' => $wc_product_tab_translated->post_name
460
 
461
- );
462
 
463
- }
 
 
 
 
 
464
 
465
- }
466
 
 
467
 
468
- $translated_product_tabs_updated = true;
469
- }
470
 
471
- // the other tabs
472
- $product_tab_translations = array();
473
 
474
- foreach ( $data as $value ) {
 
 
 
 
475
 
476
- if ( preg_match( '/product_tabs:core_tab_(.+):(.+)/', $value['field_type'], $matches ) ) {
 
 
477
 
478
- $tab_field = $matches[1];
479
- $tab_id = $matches[2];
480
 
481
- $product_tab_translations[$tab_id][$tab_field] = $value['data'];
 
482
 
483
- }
484
 
485
- }
486
 
487
- if( $product_tab_translations){
488
- foreach( $product_tab_translations as $id => $tab ){
489
 
490
- $translated_product_tabs['core_tab_' . $id] = array(
491
- 'type' => 'core',
492
- 'position' => $original_product_tabs['core_tab_' . $id]['position'],
493
- 'id' => $id,
494
- 'title' => $tab['title']
495
- );
496
 
497
- if( isset( $tab['heading'] ) ){
498
- $translated_product_tabs['core_tab_' . $id]['heading'] = $tab['heading'];
499
- }
500
 
501
- }
 
 
 
 
 
502
 
503
- $translated_product_tabs_updated = true;
504
- }
 
 
505
 
506
- if ( $translated_product_tabs_updated ) {
507
- update_post_meta( $post_id, '_product_tabs', $translated_product_tabs );
508
- }
509
 
510
- }
511
- }
 
 
 
512
 
513
- public function get_product_tabs( $product_id ) {
 
 
 
 
 
514
 
515
- $override_tab_layout = get_post_meta( $product_id, '_override_tab_layout', true );
516
 
517
- if ( 'yes' == $override_tab_layout ) {
518
- // product defines its own tab layout?
519
- $product_tabs = get_post_meta( $product_id, '_product_tabs', true );
520
- } else {
521
- // otherwise, get the default layout if any
522
- $product_tabs = get_option( 'wc_tab_manager_default_layout', false );
523
- }
524
 
525
- return $product_tabs;
526
- }
527
-
528
-
529
- function wc_tab_manager_tab_id($tab_id) {
530
- $tab_id = apply_filters('wpml_object_id', $tab_id, 'wc_product_tab', true);
531
-
532
- return $tab_id;
533
  }
534
 
 
 
 
 
 
 
 
 
535
  }
1
  <?php
2
 
3
+ /**
4
+ * Class WCML_Tab_Manager
5
+ */
6
+ class WCML_Tab_Manager {
7
+ /**
8
+ * @var WPML_Element_Translation_Package
9
+ */
10
+ public $tp;
11
+
12
+ /**
13
+ * @var SitePress
14
+ */
15
+ public $sitepress;
16
+
17
+ /**
18
+ * @var WooCommerce
19
+ */
20
+ public $woocommerce;
21
+
22
+ /**
23
+ * @var woocommerce_wpml
24
+ */
25
+ public $woocommerce_wpml;
26
+
27
+ /**
28
+ * @var wpdb
29
+ */
30
+ public $wpdb;
31
+
32
+ /**
33
+ * WCML_Tab_Manager constructor.
34
+ *
35
+ * @param $sitepress
36
+ * @param $woocommerce
37
+ * @param $woocommerce_wpml
38
+ * @param $wpdb
39
+ */
40
+ function __construct( &$sitepress, &$woocommerce, &$woocommerce_wpml, &$wpdb ) {
41
+ $this->sitepress = $sitepress;
42
+ $this->woocommerce = $woocommerce;
43
+ $this->woocommerce_wpml = $woocommerce_wpml;
44
+ $this->wpdb = $wpdb;
45
+ add_action( 'wcml_update_extra_fields', array( $this, 'sync_tabs' ), 10, 4 );
46
+ add_action( 'wcml_gui_additional_box_html', array( $this, 'custom_box_html' ), 10, 3 );
47
+ add_filter( 'wcml_gui_additional_box_data', array( $this, 'custom_box_html_data' ), 10, 4 );
48
+ add_filter( 'wpml_duplicate_custom_fields_exceptions', array( $this, 'duplicate_custom_fields_exceptions' ) );
49
+ add_action( 'wcml_after_duplicate_product', array( $this, 'duplicate_product_tabs' ) , 10, 2 );
50
+
51
+ add_filter( 'wc_tab_manager_tab_id', array( $this, 'wc_tab_manager_tab_id' ), 10, 1 );
52
+
53
+ if ( version_compare( WCML_VERSION, '3.7.2', '>' ) ) {
54
+ add_filter( 'option_wpml_config_files_arr', array( $this, 'make__product_tabs_not_translatable_by_default' ), 0 );
55
+ }
56
+
57
+ if ( is_admin() ) {
58
+
59
+ $this->tp = new WPML_Element_Translation_Package;
60
+
61
+ add_action( 'save_post', array( $this, 'force_set_language_information_on_product_tabs' ), 10, 2 );
62
+
63
+ add_filter( 'wpml_tm_translation_job_data', array( $this, 'append_custom_tabs_to_translation_package' ), 10, 2 );
64
+ add_action( 'wpml_translation_job_saved', array( $this, 'save_custom_tabs_translation' ), 10, 3 );
65
+
66
+ }
67
 
68
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
69
 
70
+ /**
71
+ * @param $wpml_config_array
72
+ *
73
+ * @return mixed
74
+ */
75
+ function make__product_tabs_not_translatable_by_default( $wpml_config_array ) {
76
+
77
+ if ( isset( $wpml_config_array->plugins['WooCommerce Tab Manager'] ) ) {
78
+ $wpml_config_array->plugins['WooCommerce Tab Manager'] =
79
+ str_replace( '<custom-field action="translate">_product_tabs</custom-field>',
80
+ '<custom-field action="nothing">_product_tabs</custom-field>',
81
+ $wpml_config_array->plugins['WooCommerce Tab Manager']
82
+ );
83
+ }
84
+
85
+ return $wpml_config_array;
86
+ }
87
 
88
+ /**
89
+ * @param $original_product_id
90
+ * @param $trnsl_product_id
91
+ * @param $data
92
+ * @param $lang
93
+ *
94
+ * @return bool
95
+ */
96
+ function sync_tabs( $original_product_id, $trnsl_product_id, $data, $lang ) {
97
+ //check if "duplicate" product
98
+ if ( ( isset( $_POST['icl_ajx_action'] ) && ( 'make_duplicates' === $_POST['icl_ajx_action'] ) ) || ( get_post_meta( $trnsl_product_id , '_icl_lang_duplicate_of', true ) ) ) {
99
+ $this->duplicate_tabs( $original_product_id, $trnsl_product_id, $lang );
100
+ }
101
+
102
+ $orig_prod_tabs = $this->get_product_tabs( $original_product_id );
103
+
104
+ if ( $orig_prod_tabs ) {
105
+ $trnsl_product_tabs = array();
106
+ $i = 0;
107
+ foreach ( $orig_prod_tabs as $key => $orig_prod_tab ) {
108
+ switch ( $orig_prod_tab['type'] ) {
109
+ case 'core':
110
+ $default_language = $this->woocommerce_wpml->products->get_original_product_language( $original_product_id );
111
+ $current_language = $this->sitepress->get_current_language();
112
+ $trnsl_product_tabs[ $key ] = $orig_prod_tabs[ $key ];
113
+ $title = isset( $data[ md5( 'coretab_'.$orig_prod_tab['id'].'_title' ) ] ) ? $data[ md5( 'coretab_'.$orig_prod_tab['id'].'_title' ) ] : '';
114
+ $heading = isset( $data[ md5( 'coretab_'.$orig_prod_tab['id'].'_heading' ) ] ) ? $data[ md5( 'coretab_'.$orig_prod_tab['id'].'_heading' ) ] : '';
115
+
116
+ if ( $default_language !== $lang ) {
117
+
118
+ $this->refresh_text_domain( $lang );
119
+
120
+ if ( ! $title ) {
121
+ $title = isset( $_POST['product_tab_title'][ $orig_prod_tab['position'] ] ) ? $_POST['product_tab_title'][ $orig_prod_tab['position'] ] : $orig_prod_tabs[ $key ]['title'];
122
+ $title = __( $title, 'woocommerce' );
123
+ }
124
+
125
+ if ( ! $heading && ( isset( $orig_prod_tabs[ $key ]['heading'] ) || isset( $_POST['product_tab_heading'][ $orig_prod_tab['position'] ] ) ) ) {
126
+ $heading = isset( $_POST['product_tab_heading'][ $orig_prod_tab['position'] ] ) ? $_POST['product_tab_heading'][ $orig_prod_tab['position'] ] : $orig_prod_tabs[ $key ]['heading'];
127
+ $heading = __( $heading, 'woocommerce' );
128
+ }
129
+
130
+ $this->refresh_text_domain( $current_language );
131
+ }
132
+
133
+ $trnsl_product_tabs[ $key ]['title'] = $title;
134
+ $trnsl_product_tabs[ $key ]['heading'] = $heading;
135
+ break;
136
+ case 'global':
137
+ $trnsl_product_tabs = $this->set_global_tab( $orig_prod_tab, $trnsl_product_tabs, $lang );
138
+ break;
139
+ case 'product':
140
+ $tab_id = false;
141
+ $title_key = md5( 'tab_' . $orig_prod_tab['position'] . '_title' );
142
+ $heading_key = md5( 'tab_' . $orig_prod_tab['position'] . '_heading' );
143
+ $title = isset( $data[ $title_key ] ) ? sanitize_text_field( $data[ $title_key ] ) : '';
144
+ $content = isset( $data[ $heading_key ] ) ? sanitize_text_field( $data[ $heading_key ] ) : '';
145
+
146
+ $trnsl_product_tabs = $this->set_product_tab( $orig_prod_tab, $trnsl_product_tabs, $lang, $trnsl_product_id, $tab_id, $title, $content );
147
+
148
+ $i++;
149
+ break;
150
+ }
151
+ }
152
+ update_post_meta( $trnsl_product_id, '_product_tabs', $trnsl_product_tabs );
153
+
154
+ return true;
155
+ }
156
+
157
+ return false;
158
+ }
159
 
160
+ /**
161
+ * @param $original_product_id
162
+ * @param $trnsl_product_id
163
+ * @param $lang
164
+ */
165
+ function duplicate_tabs( $original_product_id, $trnsl_product_id, $lang ) {
166
+ $orig_prod_tabs = maybe_unserialize( get_post_meta( $original_product_id, '_product_tabs', true ) );
167
+ $prod_tabs = array();
168
+ foreach ( $orig_prod_tabs as $key => $orig_prod_tab ) {
169
+ switch ( $orig_prod_tab['type'] ) {
170
+ case 'core':
171
+ $prod_tabs[ $key ] = $orig_prod_tab;
172
+ $this->refresh_text_domain( $lang );
173
+ $prod_tabs[ $key ]['title'] = __( $orig_prod_tab['title'], 'woocommerce' );
174
+ if ( isset( $orig_prod_tab['heading'] ) ) {
175
+ $prod_tabs[ $key ]['heading'] = __( $orig_prod_tab['heading'], 'woocommerce' );
176
+ }
177
+ $orig_lang = $this->sitepress->get_language_for_element( $original_product_id, 'post_product' );
178
+ $this->refresh_text_domain( $orig_lang );
179
+ break;
180
+ case 'global':
181
+ $prod_tabs = $this->set_global_tab( $orig_prod_tab, $prod_tabs, $lang );
182
+ break;
183
+ case 'product':
184
+ $original_tab = get_post( $orig_prod_tab['id'] );
185
+ $prod_tabs = $this->set_product_tab( $orig_prod_tab, $prod_tabs, $lang, $trnsl_product_id, false, $original_tab->post_title , $original_tab->post_content );
186
+ break;
187
+ }
188
+ }
189
+
190
+ update_post_meta( $trnsl_product_id, '_product_tabs', $prod_tabs );
191
+ }
192
 
193
+ /**
194
+ * @param $lang
195
+ */
196
+ function refresh_text_domain( $lang ) {
197
+ unload_textdomain( 'woocommerce' );
198
+ $this->sitepress->switch_lang( $lang );
199
+ $this->woocommerce->load_plugin_textdomain();
200
+ }
201
 
202
+ /**
203
+ * @param $orig_prod_tab
204
+ * @param $trnsl_product_tabs
205
+ * @param $lang
206
+ *
207
+ * @return mixed
208
+ */
209
+ function set_global_tab( $orig_prod_tab, $trnsl_product_tabs, $lang ) {
210
+ $tr_tab_id = apply_filters( 'translate_object_id', $orig_prod_tab['id'], 'wc_product_tab', true, $lang );
211
+ $trnsl_product_tabs[ $orig_prod_tab['type'].'_tab_'. $tr_tab_id ] = array(
212
+ 'position' => $orig_prod_tab['position'],
213
+ 'type' => $orig_prod_tab['type'],
214
+ 'id' => $tr_tab_id,
215
+ 'name' => get_post( $tr_tab_id )->post_name,
216
+ );
217
+ return $trnsl_product_tabs;
218
+ }
219
 
220
+ /**
221
+ * @param $orig_prod_tab
222
+ * @param $trnsl_product_tabs
223
+ * @param $lang
224
+ * @param $trnsl_product_id
225
+ * @param $tab_id
226
+ * @param $title
227
+ * @param $content
228
+ *
229
+ * @return mixed
230
+ */
231
+ function set_product_tab( $orig_prod_tab, $trnsl_product_tabs, $lang, $trnsl_product_id, $tab_id, $title, $content ) {
232
+ if ( ! $tab_id ) {
233
+ $tr_tab_id = apply_filters( 'translate_object_id', $orig_prod_tab['id'], 'wc_product_tab', false, $lang );
234
+
235
+ if ( ! is_null( $tr_tab_id ) ) {
236
+ $tab_id = $tr_tab_id;
237
+ }
238
+ }
239
+
240
+ if ( $tab_id ) {
241
+ //update existing tab
242
+ $args = array();
243
+ $args['post_title'] = $title;
244
+ $args['post_content'] = $content;
245
+ $this->wpdb->update( $this->wpdb->posts, $args, array( 'ID' => $tab_id ) );
246
+ } else {
247
+ //tab not exist creating new
248
+ $args = array();
249
+ $args['post_title'] = $title;
250
+ $args['post_content'] = $content;
251
+ $args['post_author'] = get_current_user_id();
252
+ $args['post_name'] = sanitize_title( $title );
253
+ $args['post_type'] = 'wc_product_tab';
254
+ $args['post_parent'] = $trnsl_product_id;
255
+ $args['post_status'] = 'publish';
256
+ $this->wpdb->insert( $this->wpdb->posts, $args );
257
+
258
+ $tab_id = $this->wpdb->insert_id;
259
+ $tab_trid = $this->sitepress->get_element_trid( $orig_prod_tab['id'], 'post_wc_product_tab' );
260
+ if ( ! $tab_trid ) {
261
+ $this->sitepress->set_element_language_details( $orig_prod_tab['id'], 'post_wc_product_tab', false, $this->sitepress->get_default_language() );
262
+ $tab_trid = $this->sitepress->get_element_trid( $orig_prod_tab['id'], 'post_wc_product_tab' );
263
+ }
264
+ $this->sitepress->set_element_language_details( $tab_id, 'post_wc_product_tab', $tab_trid, $lang );
265
+ }
266
+
267
+ $trnsl_product_tabs[ $orig_prod_tab['type'] . '_tab_' . $tab_id ] = array(
268
+ 'position' => $orig_prod_tab['position'],
269
+ 'type' => $orig_prod_tab['type'],
270
+ 'id' => $tab_id,
271
+ 'name' => get_post( $tab_id )->post_name,
272
+ );
273
+
274
+ return $trnsl_product_tabs;
275
+ }
276
 
277
+ /**
278
+ * @param $exceptions
279
+ *
280
+ * @return array
281
+ */
282
+ function duplicate_custom_fields_exceptions( $exceptions ) {
283
+ $exceptions[] = '_product_tabs';
284
+ return $exceptions;
285
+ }
286
 
287
+ /**
288
+ * @param $obj
289
+ * @param $product_id
290
+ * @param $data
291
+ *
292
+ * @return bool
293
+ */
294
+ function custom_box_html( $obj, $product_id, $data ) {
295
+
296
+ if ( 'yes' !== get_post_meta( $product_id, '_override_tab_layout', true ) ) {
297
+ return false;
298
+ }
299
+
300
+ $orig_prod_tabs = $this->get_product_tabs( $product_id );
301
+ if ( ! $orig_prod_tabs ) {
302
+ return false;
303
+ }
304
+
305
+ $tabs_section = new WPML_Editor_UI_Field_Section( __( 'Product tabs', 'woocommerce-multilingual' ) );
306
+ end( $orig_prod_tabs );
307
+ $last_key = key( $orig_prod_tabs );
308
+ $divider = true;
309
+ foreach ( $orig_prod_tabs as $key => $prod_tab ) {
310
+ if ( $key === $last_key ) {
311
+ $divider = false;
312
+ }
313
+
314
+ if ( in_array( $prod_tab['type'], array( 'product', 'core' ) ) ) {
315
+ if ( 'core' === $prod_tab['type'] ) {
316
+ $group = new WPML_Editor_UI_Field_Group( $prod_tab['title'], $divider );
317
+ $tab_field = new WPML_Editor_UI_Single_Line_Field( 'coretab_' . $prod_tab['id'].'_title', __( 'Title', 'woocommerce-multilingual' ), $data, false );
318
+ $group->add_field( $tab_field );
319
+ $tab_field = new WPML_Editor_UI_Single_Line_Field( 'coretab_' . $prod_tab['id'].'_heading' , __( 'Heading', 'woocommerce-multilingual' ), $data, false );
320
+ $group->add_field( $tab_field );
321
+ $tabs_section->add_field( $group );
322
+ } else {
323
+ $group = new WPML_Editor_UI_Field_Group( ucfirst( str_replace( '-', ' ', $prod_tab['name'] ) ), $divider );
324
+ $tab_field = new WPML_Editor_UI_Single_Line_Field( 'tab_'.$prod_tab['position'].'_title', __( 'Title', 'woocommerce-multilingual' ), $data, false );
325
+ $group->add_field( $tab_field );
326
+ $tab_field = new WPML_Editor_UI_WYSIWYG_Field( 'tab_'.$prod_tab['position'].'_heading' , null, $data, false );
327
+ $group->add_field( $tab_field );
328
+ $tabs_section->add_field( $group );
329
+ }
330
+ }
331
+ }
332
+ $obj->add_field( $tabs_section );
333
+
334
+ return true;
335
+ }
336
 
337
+ /**
338
+ * @param $data
339
+ * @param $product_id
340
+ * @param $translation
341
+ * @param $lang
342
+ *
343
+ * @return mixed
344
+ */
345
+ function custom_box_html_data( $data, $product_id, $translation, $lang ) {
346
+
347
+ $orig_prod_tabs = $this->get_product_tabs( $product_id );
348
+
349
+ if ( empty( $orig_prod_tabs ) ) {
350
+ return $data;
351
+ }
352
+
353
+ foreach ( $orig_prod_tabs as $key => $prod_tab ) {
354
+ if ( in_array( $prod_tab['type'], array( 'product', 'core' ) ) ) {
355
+ if ( 'core' === $prod_tab['type'] ) {
356
+ $data[ 'coretab_' . $prod_tab['id'] . '_title' ] = array( 'original' => $prod_tab['title'] );
357
+ $data[ 'coretab_' . $prod_tab['id'] . '_heading' ] = array( 'original' => isset( $prod_tab['heading'] ) ? $prod_tab['heading'] : '' );
358
+ } else {
359
+ $data[ 'tab_' . $prod_tab['position'] . '_title' ] = array( 'original' => get_the_title( $prod_tab['id'] ) );
360
+ $data[ 'tab_' . $prod_tab['position'] . '_heading' ] = array( 'original' => get_post( $prod_tab['id'] )->post_content );
361
+ }
362
+ }
363
+ }
364
+
365
+ if ( $translation ) {
366
+ $tr_prod_tabs = $this->get_product_tabs( $translation->ID );
367
+
368
+ if ( ! is_array( $tr_prod_tabs ) ) {
369
+ return $data; // __('Please update original product','woocommerce-multilingual');
370
+ }
371
+
372
+ foreach ( $tr_prod_tabs as $key => $prod_tab ) {
373
+ if ( in_array( $prod_tab['type'], array( 'product', 'core' ) ) ) {
374
+ if ( 'core' === $prod_tab['type'] ) {
375
+ $data[ 'coretab_' . $prod_tab['id'] . '_title' ]['translation'] = $prod_tab['title'];
376
+ $data[ 'coretab_' . $prod_tab['id'] . '_heading' ]['translation'] = isset( $prod_tab['heading'] ) ? $prod_tab['heading'] : '';
377
+ } else {
378
+ $data[ 'tab_'.$prod_tab['position'].'_title' ]['translation'] = get_the_title( $prod_tab['id'] );
379
+ $data[ 'tab_'.$prod_tab['position'].'_heading' ]['translation'] = get_post( $prod_tab['id'] )->post_content;
380
+ }
381
+ }
382
+ }
383
+ } else {
384
+ $current_language = $this->sitepress->get_current_language();
385
+ foreach ( $orig_prod_tabs as $key => $prod_tab ) {
386
+ if ( 'core' === $prod_tab['type'] ) {
387
+ unload_textdomain( 'woocommerce' );
388
+ $this->sitepress->switch_lang( $lang );
389
+ $this->woocommerce->load_plugin_textdomain();
390
+ $title = __( $prod_tab['title'], 'woocommerce' );
391
+ if ( $prod_tab['title'] !== $title ) {
392
+ $data[ 'coretab_' . $prod_tab['id'] . '_title' ]['translation'] = $title;
393
+ }
394
+
395
+ if ( ! isset( $prod_tab['heading'] ) ) {
396
+ $data[ 'coretab_'.$prod_tab['id'].'_heading' ]['translation'] = '';
397
+ } else {
398
+ $heading = __( $prod_tab['heading'], 'woocommerce' );
399
+ if ( $prod_tab['heading'] !== $heading ) {
400
+ $data[ 'coretab_' . $prod_tab['id'] . '_heading' ]['translation'] = $heading;
401
+ }
402
+ }
403
+
404
+ unload_textdomain( 'woocommerce' );
405
+ $this->sitepress->switch_lang( $current_language );
406
+ $this->woocommerce->load_plugin_textdomain();
407
+ }
408
+ }
409
+ }
410
+
411
+ return $data;
412
 
413
+ }
 
 
 
 
 
 
414
 
415
+ /**
416
+ * @param $new_id
417
+ * @param $original_post
418
+ */
419
+ function duplicate_product_tabs( $new_id, $original_post ) {
420
+ if ( function_exists( 'wc_tab_manager_duplicate_product' ) ) {
421
+ wc_tab_manager_duplicate_product( $new_id, $original_post );
422
+ }
423
+ }
424
 
425
+ /**
426
+ * @param $post_id
427
+ * @param $post
428
+ */
429
+ function force_set_language_information_on_product_tabs( $post_id, $post ) {
430
+ if ( 'wc_product_tab' === $post->post_type ) {
431
+
432
+ $language = $this->sitepress->get_language_for_element( $post_id, 'post_wc_product_tab' );
433
+ if ( empty( $language ) && $post->post_parent ) {
434
+ $parent_language = $this->sitepress->get_language_for_element( $post->post_parent, 'post_product' );
435
+ if ( $parent_language ) {
436
+ $this->sitepress->set_element_language_details( $post_id, 'post_wc_product_tab', null, $parent_language );
437
+ }
438
+ }
439
+ }
440
 
441
+ }
 
442
 
443
+ /**
444
+ * @param $package
445
+ * @param $post
446
+ *
447
+ * @return mixed
448
+ */
449
+ function append_custom_tabs_to_translation_package( $package, $post ) {
450
 
451
+ if ( 'product' === $post->post_type ) {
452
 
453
+ $override_tab_layout = get_post_meta( $post->ID , '_override_tab_layout', true );
 
454
 
455
+ if ( 'yes' === $override_tab_layout ) {
 
456
 
457
+ $meta = (array) get_post_meta( $post->ID, '_product_tabs', true );
458
 
459
+ foreach ( $meta as $key => $value ) {
460
 
461
+ if ( preg_match( '/product_tab_([0-9]+)/', $key, $matches ) ) {
462
 
463
+ $wc_product_tab_id = $matches[1];
464
+ $wc_product_tab = get_post( $wc_product_tab_id );
465
 
466
+ $package['contents'][ 'product_tabs:product_tab:' . $wc_product_tab_id . ':title' ] = array(
467
+ 'translate' => 1,
468
+ 'data' => $this->tp->encode_field_data( $wc_product_tab->post_title, 'base64' ),
469
+ 'format' => 'base64',
470
+ );
471
 
472
+ $package['contents'][ 'product_tabs:product_tab:' . $wc_product_tab_id . ':description' ] = array(
473
+ 'translate' => 1,
474
+ 'data' => $this->tp->encode_field_data( $wc_product_tab->post_content, 'base64' ),
475
+ 'format' => 'base64',
476
+ );
477
 
478
+ } elseif ( preg_match( '/^core_tab_(.+)$/', $key, $matches ) ) {
479
 
480
+ $package['contents'][ 'product_tabs:core_tab_title:' . $matches[1] ] = array(
481
+ 'translate' => 1,
482
+ 'data' => $this->tp->encode_field_data( $value['title'], 'base64' ),
483
+ 'format' => 'base64',
484
+ );
485
 
486
+ if ( isset( $value['heading'] ) ) {
487
+ $package['contents'][ 'product_tabs:core_tab_heading:' . $matches[1] ] = array(
488
+ 'translate' => 1,
489
+ 'data' => $this->tp->encode_field_data( $value['heading'], 'base64' ),
490
+ 'format' => 'base64',
491
+ );
492
+ }
493
+ }
494
+ }
495
+ }
496
+ }
497
 
498
+ return $package;
499
+ }
500
 
501
+ /**
502
+ * @param $post_id
503
+ * @param $data
504
+ * @param $job
505
+ */
506
+ function save_custom_tabs_translation( $post_id, $data, $job ) {
507
+ $translated_product_tabs_updated = false;
508
 
509
+ $original_product_tabs = get_post_meta( $job->original_doc_id, '_product_tabs', true );
510
 
511
+ if ( $original_product_tabs ) {
512
 
513
+ // custom tabs
514
+ $product_tab_translations = array();
 
 
 
 
515
 
516
+ foreach ( $data as $value ) {
517
 
518
+ if ( preg_match( '/product_tabs:product_tab:([0-9]+):(.+)/', $value['field_type'], $matches ) ) {
519
 
520
+ $wc_product_tab_id = $matches[1];
521
+ $field = $matches[2];
522
 
523
+ $product_tab_translations[ $wc_product_tab_id ][ $field ] = $value['data'];
524
+ }
525
+ }
526
 
527
+ if ( $product_tab_translations ) {
528
 
529
+ $translated_product_tabs = get_post_meta( $post_id, '_product_tabs', true );
 
 
 
530
 
531
+ foreach ( $product_tab_translations as $wc_product_tab_id => $value ) {
532
 
533
+ $new_wc_product_tab = array(
534
+ 'post_type' => 'wp_product_tab',
535
+ 'post_title' => $value['title'],
536
+ 'post_content' => $value['description'],
537
+ 'post_status' => 'publish',
538
+ );
539
 
540
+ $wc_product_tab_id_translated = wp_insert_post( $new_wc_product_tab );
541
 
542
+ if ( $wc_product_tab_id_translated ) {
543
 
544
+ $wc_product_tab_trid = $this->sitepress->get_element_trid( $wc_product_tab_id, 'post_wc_product_tab' );
545
+ $this->sitepress->set_element_language_details( $wc_product_tab_id_translated, 'post_wc_product_tab', $wc_product_tab_trid, $job->language_code );
546
 
547
+ $wc_product_tab_translated = get_post( $wc_product_tab_id_translated );
 
548
 
549
+ $translated_product_tabs[ 'product_tab_' . $wc_product_tab_id_translated ] = array(
550
+ 'position' => $original_product_tabs[ 'product_tab_' . $wc_product_tab_id ]['position'],
551
+ 'type' => 'product',
552
+ 'id' => $wc_product_tab_id_translated,
553
+ 'name' => $wc_product_tab_translated->post_name,
554
 
555
+ );
556
+ }
557
+ }
558
 
559
+ $translated_product_tabs_updated = true;
560
+ }
561
 
562
+ // the other tabs
563
+ $product_tab_translations = array();
564
 
565
+ foreach ( $data as $value ) {
566
 
567
+ if ( preg_match( '/product_tabs:core_tab_(.+):(.+)/', $value['field_type'], $matches ) ) {
568
 
569
+ $tab_field = $matches[1];
570
+ $tab_id = $matches[2];
571
 
572
+ $product_tab_translations[ $tab_id ][ $tab_field ] = $value['data'];
573
+ }
574
+ }
 
 
 
575
 
576
+ if ( $product_tab_translations ) {
577
+ foreach ( $product_tab_translations as $id => $tab ) {
 
578
 
579
+ $translated_product_tabs[ 'core_tab_' . $id ] = array(
580
+ 'type' => 'core',
581
+ 'position' => $original_product_tabs[ 'core_tab_' . $id ]['position'],
582
+ 'id' => $id,
583
+ 'title' => $tab['title'],
584
+ );
585
 
586
+ if ( isset( $tab['heading'] ) ) {
587
+ $translated_product_tabs[ 'core_tab_' . $id ]['heading'] = $tab['heading'];
588
+ }
589
+ }
590
 
591
+ $translated_product_tabs_updated = true;
592
+ }
 
593
 
594
+ if ( true === $translated_product_tabs_updated && isset( $translated_product_tabs ) ) {
595
+ update_post_meta( $post_id, '_product_tabs', $translated_product_tabs );
596
+ }
597
+ }
598
+ }
599
 
600
+ /**
601
+ * @param $product_id
602
+ *
603
+ * @return mixed|void
604
+ */
605
+ public function get_product_tabs( $product_id ) {
606
 
607
+ $override_tab_layout = get_post_meta( $product_id, '_override_tab_layout', true );
608
 
609
+ if ( 'yes' == $override_tab_layout ) {
610
+ // product defines its own tab layout?
611
+ $product_tabs = get_post_meta( $product_id, '_product_tabs', true );
612
+ } else {
613
+ // otherwise, get the default layout if any
614
+ $product_tabs = get_option( 'wc_tab_manager_default_layout', false );
615
+ }
616
 
617
+ return $product_tabs;
 
 
 
 
 
 
 
618
  }
619
 
620
+ /**
621
+ * @param $tab_id
622
+ *
623
+ * @return mixed|void
624
+ */
625
+ function wc_tab_manager_tab_id( $tab_id ) {
626
+ return apply_filters( 'wpml_object_id', $tab_id, 'wc_product_tab', true );
627
+ }
628
  }
compatibility/class-wcml-table-rate-shipping.php CHANGED
@@ -26,7 +26,7 @@ class WCML_Table_Rate_Shipping{
26
 
27
  public function default_shipping_class_id($args){
28
  global $sitepress, $woocommerce_wpml;
29
- if($sitepress->get_current_language() != $sitepress->get_default_language() && !empty($args['shipping_class_id'])){
30
 
31
  $args['shipping_class_id'] = apply_filters( 'translate_object_id',$args['shipping_class_id'], 'product_shipping_class', false, $sitepress->get_default_language());
32
 
@@ -42,7 +42,7 @@ class WCML_Table_Rate_Shipping{
42
 
43
  public function shipping_class_id_in_default_language( $terms, $post_id, $taxonomy ) {
44
  global $sitepress, $icl_adjust_id_url_filter_off;
45
- if ( isset( $_POST['calc_shipping'] ) && $taxonomy == 'product_shipping_class' ) {
46
 
47
  foreach( $terms as $k => $term ){
48
  $shipping_class_id = apply_filters( 'translate_object_id', $term->term_id, 'product_shipping_class', false, $sitepress->get_default_language());
26
 
27
  public function default_shipping_class_id($args){
28
  global $sitepress, $woocommerce_wpml;
29
+ if( !empty($args['shipping_class_id'])){
30
 
31
  $args['shipping_class_id'] = apply_filters( 'translate_object_id',$args['shipping_class_id'], 'product_shipping_class', false, $sitepress->get_default_language());
32
 
42
 
43
  public function shipping_class_id_in_default_language( $terms, $post_id, $taxonomy ) {
44
  global $sitepress, $icl_adjust_id_url_filter_off;
45
+ if ( !is_admin() && $taxonomy == 'product_shipping_class' ) {
46
 
47
  foreach( $terms as $k => $term ){
48
  $shipping_class_id = apply_filters( 'translate_object_id', $term->term_id, 'product_shipping_class', false, $sitepress->get_default_language());
embedded/autoload_52.php CHANGED
@@ -4,4 +4,4 @@
4
 
5
  require_once dirname(__FILE__) . '/composer'.'/autoload_real_52.php';
6
 
7
- return ComposerAutoloaderInitddf8a94c2f6108e93d177a18dcd16dc9::getLoader();
4
 
5
  require_once dirname(__FILE__) . '/composer'.'/autoload_real_52.php';
6
 
7
+ return ComposerAutoloaderInitf22d2ac5fa5e49381a2eaa0f42a43b81::getLoader();
embedded/composer/autoload_real_52.php CHANGED
@@ -2,7 +2,7 @@
2
 
3
  // autoload_real_52.php generated by xrstf/composer-php52
4
 
5
- class ComposerAutoloaderInitddf8a94c2f6108e93d177a18dcd16dc9 {
6
  private static $loader;
7
 
8
  public static function loadClassLoader($class) {
@@ -19,9 +19,9 @@ class ComposerAutoloaderInitddf8a94c2f6108e93d177a18dcd16dc9 {
19
  return self::$loader;
20
  }
21
 
22
- spl_autoload_register(array('ComposerAutoloaderInitddf8a94c2f6108e93d177a18dcd16dc9', 'loadClassLoader'), true /*, true */);
23
  self::$loader = $loader = new xrstf_Composer52_ClassLoader();
24
- spl_autoload_unregister(array('ComposerAutoloaderInitddf8a94c2f6108e93d177a18dcd16dc9', 'loadClassLoader'));
25
 
26
  $vendorDir = dirname(dirname(__FILE__));
27
  $baseDir = dirname($vendorDir);
2
 
3
  // autoload_real_52.php generated by xrstf/composer-php52
4
 
5
+ class ComposerAutoloaderInitf22d2ac5fa5e49381a2eaa0f42a43b81 {
6
  private static $loader;
7
 
8
  public static function loadClassLoader($class) {
19
  return self::$loader;
20
  }
21
 
22
+ spl_autoload_register(array('ComposerAutoloaderInitf22d2ac5fa5e49381a2eaa0f42a43b81', 'loadClassLoader'), true /*, true */);
23
  self::$loader = $loader = new xrstf_Composer52_ClassLoader();
24
+ spl_autoload_unregister(array('ComposerAutoloaderInitf22d2ac5fa5e49381a2eaa0f42a43b81', 'loadClassLoader'));
25
 
26
  $vendorDir = dirname(dirname(__FILE__));
27
  $baseDir = dirname($vendorDir);
embedded/composer/installed.json CHANGED
@@ -1,17 +1,50 @@
1
  [
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2
  {
3
  "name": "composer/installers",
4
- "version": "v1.0.25",
5
- "version_normalized": "1.0.25.0",
6
  "source": {
7
  "type": "git",
8
  "url": "https://github.com/composer/installers.git",
9
- "reference": "36e5b5843203d7f1cf6ffb0305a97e014387bd8e"
10
  },
11
  "dist": {
12
  "type": "zip",
13
- "url": "https://api.github.com/repos/composer/installers/zipball/36e5b5843203d7f1cf6ffb0305a97e014387bd8e",
14
- "reference": "36e5b5843203d7f1cf6ffb0305a97e014387bd8e",
15
  "shasum": ""
16
  },
17
  "require": {
@@ -25,7 +58,7 @@
25
  "composer/composer": "1.0.*@dev",
26
  "phpunit/phpunit": "4.1.*"
27
  },
28
- "time": "2016-04-13 19:46:30",
29
  "type": "composer-plugin",
30
  "extra": {
31
  "class": "Composer\\Installers\\Plugin",
@@ -60,6 +93,7 @@
60
  "MODX Evo",
61
  "Mautic",
62
  "OXID",
 
63
  "SMF",
64
  "Thelia",
65
  "WolfCMS",
@@ -75,6 +109,7 @@
75
  "dokuwiki",
76
  "drupal",
77
  "elgg",
 
78
  "fuelphp",
79
  "grav",
80
  "installer",
@@ -103,12 +138,12 @@
103
  },
104
  {
105
  "name": "otgs/installer",
106
- "version": "1.7.8",
107
- "version_normalized": "1.7.8.0",
108
  "source": {
109
  "type": "git",
110
  "url": "ssh://git@git.onthegosystems.com:10022/installer/installer.git",
111
- "reference": "4cb8b5d137963fd591fffdbb02357ef95541e66d"
112
  },
113
  "require": {
114
  "composer/installers": "~1.0",
@@ -117,8 +152,8 @@
117
  "require-dev": {
118
  "phpunit/phpunit": "~4.5"
119
  },
120
- "time": "2016-05-23 07:48:35",
121
- "type": "wordpress-plugin",
122
  "extra": {
123
  "branch-alias": {
124
  "dev-master": "1.7.x-dev",
@@ -149,38 +184,5 @@
149
  "update",
150
  "utils"
151
  ]
152
- },
153
- {
154
- "name": "xrstf/composer-php52",
155
- "version": "v1.0.20",
156
- "version_normalized": "1.0.20.0",
157
- "source": {
158
- "type": "git",
159
- "url": "https://github.com/composer-php52/composer-php52.git",
160
- "reference": "bd41459d5e27df8d33057842b32377c39e97a5a8"
161
- },
162
- "dist": {
163
- "type": "zip",
164
- "url": "https://api.github.com/repos/composer-php52/composer-php52/zipball/bd41459d5e27df8d33057842b32377c39e97a5a8",
165
- "reference": "bd41459d5e27df8d33057842b32377c39e97a5a8",
166
- "shasum": ""
167
- },
168
- "time": "2016-04-16 21:52:24",
169
- "type": "library",
170
- "extra": {
171
- "branch-alias": {
172
- "dev-default": "1.x-dev"
173
- }
174
- },
175
- "installation-source": "dist",
176
- "autoload": {
177
- "psr-0": {
178
- "xrstf\\Composer52": "lib/"
179
- }
180
- },
181
- "notification-url": "https://packagist.org/downloads/",
182
- "license": [
183
- "MIT"
184
- ]
185
  }
186
  ]
1
  [
2
+ {
3
+ "name": "xrstf/composer-php52",
4
+ "version": "v1.0.20",
5
+ "version_normalized": "1.0.20.0",
6
+ "source": {
7
+ "type": "git",
8
+ "url": "https://github.com/composer-php52/composer-php52.git",
9
+ "reference": "bd41459d5e27df8d33057842b32377c39e97a5a8"
10
+ },
11
+ "dist": {
12
+ "type": "zip",
13
+ "url": "https://api.github.com/repos/composer-php52/composer-php52/zipball/bd41459d5e27df8d33057842b32377c39e97a5a8",
14
+ "reference": "bd41459d5e27df8d33057842b32377c39e97a5a8",
15
+ "shasum": ""
16
+ },
17
+ "time": "2016-04-16 21:52:24",
18
+ "type": "library",
19
+ "extra": {
20
+ "branch-alias": {
21
+ "dev-default": "1.x-dev"
22
+ }
23
+ },
24
+ "installation-source": "dist",
25
+ "autoload": {
26
+ "psr-0": {
27
+ "xrstf\\Composer52": "lib/"
28
+ }
29
+ },
30
+ "notification-url": "https://packagist.org/downloads/",
31
+ "license": [
32
+ "MIT"
33
+ ]
34
+ },
35
  {
36
  "name": "composer/installers",
37
+ "version": "v1.1.0",
38
+ "version_normalized": "1.1.0.0",
39
  "source": {
40
  "type": "git",
41
  "url": "https://github.com/composer/installers.git",
42
+ "reference": "a3595c5272a6f247228abb20076ed27321e4aae9"
43
  },
44
  "dist": {
45
  "type": "zip",
46
+ "url": "https://api.github.com/repos/composer/installers/zipball/a3595c5272a6f247228abb20076ed27321e4aae9",
47
+ "reference": "a3595c5272a6f247228abb20076ed27321e4aae9",
48
  "shasum": ""
49
  },
50
  "require": {
58
  "composer/composer": "1.0.*@dev",
59
  "phpunit/phpunit": "4.1.*"
60
  },
61
+ "time": "2016-07-05 06:18:20",
62
  "type": "composer-plugin",
63
  "extra": {
64
  "class": "Composer\\Installers\\Plugin",
93
  "MODX Evo",
94
  "Mautic",
95
  "OXID",
96
+ "RadPHP",
97
  "SMF",
98
  "Thelia",
99
  "WolfCMS",
109
  "dokuwiki",
110
  "drupal",
111
  "elgg",
112
+ "expressionengine",
113
  "fuelphp",
114
  "grav",
115
  "installer",
138
  },
139
  {
140
  "name": "otgs/installer",
141
+ "version": "1.7.9",
142
+ "version_normalized": "1.7.9.0",
143
  "source": {
144
  "type": "git",
145
  "url": "ssh://git@git.onthegosystems.com:10022/installer/installer.git",
146
+ "reference": "2efbb75db7daf72bfd6bb5391f61b6155f39c225"
147
  },
148
  "require": {
149
  "composer/installers": "~1.0",
152
  "require-dev": {
153
  "phpunit/phpunit": "~4.5"
154
  },
155
+ "time": "2016-07-05 06:21:57",
156
+ "type": "library",
157
  "extra": {
158
  "branch-alias": {
159
  "dev-master": "1.7.x-dev",
184
  "update",
185
  "utils"
186
  ]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
187
  }
188
  ]
embedded/composer/installers/README.md CHANGED
@@ -38,7 +38,7 @@ is not needed to install packages with these frameworks:
38
  | AGL | `agl-module`
39
  | Bonefish | `bonefish-package`
40
  | AnnotateCms | `annotatecms-module`<br>`annotatecms-component`<br>`annotatecms-service`
41
- | Bitrix | `bitrix-module`<br>`bitrix-component`<br>`bitrix-theme`
42
  | CakePHP 2+ | **`cakephp-plugin`**
43
  | Chef | `chef-cookbook`<br>`chef-role`
44
  | CCFramework | `ccframework-ship`<br>`ccframework-theme`
@@ -46,10 +46,12 @@ is not needed to install packages with these frameworks:
46
  | concrete5 | `concrete5-block`<br>`concrete5-package`<br>`concrete5-theme`<br>`concrete5-update`
47
  | Craft | `craft-plugin`
48
  | Croogo | `croogo-plugin`<br>`croogo-theme`
 
49
  | DokuWiki | `dokuwiki-plugin`<br>`dokuwiki-template`
50
  | Dolibarr | `dolibarr-module`
51
  | Drupal | <b>`drupal-core`<br>`drupal-module`<br>`drupal-theme`</b><br>`drupal-library`<br>`drupal-profile`<br>`drupal-drush`
52
  | Elgg | `elgg-plugin`
 
53
  | FuelPHP v1.x | `fuel-module`<br>`fuel-package`<br/>`fuel-theme`
54
  | FuelPHP v2.x | `fuelphp-component`
55
  | Grav | `grav-plugin`<br>`grav-theme`
@@ -75,6 +77,7 @@ is not needed to install packages with these frameworks:
75
  | Pimcore | `pimcore-plugin`
76
  | PPI | **`ppi-module`**
77
  | Puppet | `puppet-module`
 
78
  | REDAXO | `redaxo-addon`
79
  | Roundcube | `roundcube-plugin`
80
  | shopware | `shopware-backend-plugin`<br/>`shopware-core-plugin`<br/>`shopware-frontend-plugin`<br/>`shopware-theme`
@@ -89,6 +92,7 @@ is not needed to install packages with these frameworks:
89
  | Zend | `zend-library`<br>`zend-extra`<br>`zend-module`
90
  | Zikula | `zikula-module`<br>`zikula-theme`
91
  | Prestashop | `prestashop-module`<br>`prestashop-theme`
 
92
 
93
  ## Example `composer.json` File
94
 
38
  | AGL | `agl-module`
39
  | Bonefish | `bonefish-package`
40
  | AnnotateCms | `annotatecms-module`<br>`annotatecms-component`<br>`annotatecms-service`
41
+ | Bitrix | `bitrix-module` (deprecated) <br>`bitrix-component` (deprecated) <br>`bitrix-theme` (deprecated) <br><br> `bitrix-d7-module` <br> `bitrix-d7-component` <br> `bitrix-d7-template`
42
  | CakePHP 2+ | **`cakephp-plugin`**
43
  | Chef | `chef-cookbook`<br>`chef-role`
44
  | CCFramework | `ccframework-ship`<br>`ccframework-theme`
46
  | concrete5 | `concrete5-block`<br>`concrete5-package`<br>`concrete5-theme`<br>`concrete5-update`
47
  | Craft | `craft-plugin`
48
  | Croogo | `croogo-plugin`<br>`croogo-theme`
49
+ | Decibel | `decibel-app`
50
  | DokuWiki | `dokuwiki-plugin`<br>`dokuwiki-template`
51
  | Dolibarr | `dolibarr-module`
52
  | Drupal | <b>`drupal-core`<br>`drupal-module`<br>`drupal-theme`</b><br>`drupal-library`<br>`drupal-profile`<br>`drupal-drush`
53
  | Elgg | `elgg-plugin`
54
+ | ExpressionEngine 3 | `ee3-addon`<br>`ee3-theme`
55
  | FuelPHP v1.x | `fuel-module`<br>`fuel-package`<br/>`fuel-theme`
56
  | FuelPHP v2.x | `fuelphp-component`
57
  | Grav | `grav-plugin`<br>`grav-theme`
77
  | Pimcore | `pimcore-plugin`
78
  | PPI | **`ppi-module`**
79
  | Puppet | `puppet-module`
80
+ | RadPHP | `radphp-bundle`
81
  | REDAXO | `redaxo-addon`
82
  | Roundcube | `roundcube-plugin`
83
  | shopware | `shopware-backend-plugin`<br/>`shopware-core-plugin`<br/>`shopware-frontend-plugin`<br/>`shopware-theme`
92
  | Zend | `zend-library`<br>`zend-extra`<br>`zend-module`
93
  | Zikula | `zikula-module`<br>`zikula-theme`
94
  | Prestashop | `prestashop-module`<br>`prestashop-theme`
95
+ | Phifty | `phifty-bundle`<br>`phifty-framework`<br>`phifty-library`
96
 
97
  ## Example `composer.json` File
98
 
embedded/composer/installers/src/Composer/Installers/BitrixInstaller.php CHANGED
@@ -6,9 +6,9 @@ use Composer\Util\Filesystem;
6
 
7
  /**
8
  * Installer for Bitrix Framework. Supported types of extensions:
9
- * - `bitrix-module` — copy the module to directory `bitrix/modules/` directory.
10
- * - `bitrix-component` — copy the component to directory `bitrix/components/`.
11
- * - `bitrix-template` — copy the template to directory `bitrix/templates/`.
12
  *
13
  * You can set custom path to directory with Bitrix kernel in `composer.json`:
14
  *
@@ -26,9 +26,12 @@ use Composer\Util\Filesystem;
26
  class BitrixInstaller extends BaseInstaller
27
  {
28
  protected $locations = array(
29
- 'module' => '{$bitrix_dir}/modules/{$name}/',
30
- 'component' => '{$bitrix_dir}/components/{$name}/',
31
- 'theme' => '{$bitrix_dir}/templates/{$name}/',
 
 
 
32
  );
33
 
34
  /**
6
 
7
  /**
8
  * Installer for Bitrix Framework. Supported types of extensions:
9
+ * - `bitrix-d7-module` — copy the module to directory `bitrix/modules/<vendor>.<name>`.
10
+ * - `bitrix-d7-component` — copy the component to directory `bitrix/components/<vendor>/<name>`.
11
+ * - `bitrix-d7-template` — copy the template to directory `bitrix/templates/<vendor>_<name>`.
12
  *
13
  * You can set custom path to directory with Bitrix kernel in `composer.json`:
14
  *
26
  class BitrixInstaller extends BaseInstaller
27
  {
28
  protected $locations = array(
29
+ 'module' => '{$bitrix_dir}/modules/{$name}/', // deprecated, remove on the major release (Backward compatibility will be broken)
30
+ 'component' => '{$bitrix_dir}/components/{$name}/', // deprecated, remove on the major release (Backward compatibility will be broken)
31
+ 'theme' => '{$bitrix_dir}/templates/{$name}/', // deprecated, remove on the major release (Backward compatibility will be broken)
32
+ 'd7-module' => '{$bitrix_dir}/modules/{$vendor}.{$name}/',
33
+ 'd7-component' => '{$bitrix_dir}/components/{$vendor}/{$name}/',
34
+ 'd7-template' => '{$bitrix_dir}/templates/{$vendor}_{$name}/',
35
  );
36
 
37
  /**
embedded/composer/installers/src/Composer/Installers/DecibelInstaller.php ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace Composer\Installers;
3
+
4
+ class DecibelInstaller extends BaseInstaller
5
+ {
6
+ /** @var array */
7
+ protected $locations = array(
8
+ 'app' => 'app/{$name}/',
9
+ );
10
+ }
embedded/composer/installers/src/Composer/Installers/ExpressionEngineInstaller.php ADDED
@@ -0,0 +1,29 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace Composer\Installers;
3
+
4
+ use Composer\Package\PackageInterface;
5
+
6
+ class ExpressionEngineInstaller extends BaseInstaller
7
+ {
8
+
9
+ protected $locations = array();
10
+
11
+ private $ee2Locations = array(
12
+ 'addon' => 'system/expressionengine/third-party/{$name}/',
13
+ 'theme' => 'themes/third-party/{$name}/',
14
+ );
15
+
16
+ private $ee3Locations = array(
17
+ 'addon' => 'system/user/addons/{$name}/',
18
+ 'theme' => 'themes/user/{$name}/',
19
+ );
20
+
21
+ public function getInstallPath(PackageInterface $package, $frameworkType = '')
22
+ {
23
+
24
+ $version = "{$frameworkType}Locations";
25
+ $this->locations = $this->$version;
26
+
27
+ return parent::getInstallPath($package, $frameworkType);
28
+ }
29
+ }
embedded/composer/installers/src/Composer/Installers/Installer.php CHANGED
@@ -29,8 +29,11 @@ class Installer extends LibraryInstaller
29
  'croogo' => 'CroogoInstaller',
30
  'dokuwiki' => 'DokuWikiInstaller',
31
  'dolibarr' => 'DolibarrInstaller',
 
32
  'drupal' => 'DrupalInstaller',
33
  'elgg' => 'ElggInstaller',
 
 
34
  'fuel' => 'FuelInstaller',
35
  'fuelphp' => 'FuelphpInstaller',
36
  'grav' => 'GravInstaller',
@@ -57,6 +60,8 @@ class Installer extends LibraryInstaller
57
  'piwik' => 'PiwikInstaller',
58
  'ppi' => 'PPIInstaller',
59
  'puppet' => 'PuppetInstaller',
 
 
60
  'redaxo' => 'RedaxoInstaller',
61
  'roundcube' => 'RoundcubeInstaller',
62
  'shopware' => 'ShopwareInstaller',
29
  'croogo' => 'CroogoInstaller',
30
  'dokuwiki' => 'DokuWikiInstaller',
31
  'dolibarr' => 'DolibarrInstaller',
32
+ 'decibel' => 'DecibelInstaller',
33
  'drupal' => 'DrupalInstaller',
34
  'elgg' => 'ElggInstaller',
35
+ 'ee3' => 'ExpressionEngineInstaller',
36
+ 'ee2' => 'ExpressionEngineInstaller',
37
  'fuel' => 'FuelInstaller',
38
  'fuelphp' => 'FuelphpInstaller',
39
  'grav' => 'GravInstaller',
60
  'piwik' => 'PiwikInstaller',
61
  'ppi' => 'PPIInstaller',
62
  'puppet' => 'PuppetInstaller',
63
+ 'radphp' => 'RadPHPInstaller',
64
+ 'phifty' => 'PhiftyInstaller',
65
  'redaxo' => 'RedaxoInstaller',
66
  'roundcube' => 'RoundcubeInstaller',
67
  'shopware' => 'ShopwareInstaller',
embedded/composer/installers/src/Composer/Installers/PhiftyInstaller.php ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace Composer\Installers;
3
+
4
+ class PhiftyInstaller extends BaseInstaller
5
+ {
6
+ protected $locations = array(
7
+ 'bundle' => 'bundles/{$name}/',
8
+ 'library' => 'libraries/{$name}/',
9
+ 'framework' => 'frameworks/{$name}/',
10
+ );
11
+ }
embedded/composer/installers/src/Composer/Installers/RadPHPInstaller.php ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace Composer\Installers;
3
+
4
+ class RadPHPInstaller extends BaseInstaller
5
+ {
6
+ protected $locations = array(
7
+ 'bundle' => 'src/{$name}/'
8
+ );
9
+
10
+ /**
11
+ * Format package name to CamelCase
12
+ */
13
+ public function inflectPackageVars($vars)
14
+ {
15
+ $nameParts = explode('/', $vars['name']);
16
+ foreach ($nameParts as &$value) {
17
+ $value = strtolower(preg_replace('/(?<=\\w)([A-Z])/', '_\\1', $value));
18
+ $value = str_replace(array('-', '_'), ' ', $value);
19
+ $value = str_replace(' ', '', ucwords($value));
20
+ }
21
+ $vars['name'] = implode('/', $nameParts);
22
+ return $vars;
23
+ }
24
+ }
embedded/otgs/installer/changelog.txt ADDED
@@ -0,0 +1,136 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ = 1.7.9 =
2
+ * Save the client_id value from the site_key_validation API call response and make it available via WP_Installer_API::get_ts_client_id API call
3
+
4
+ = 1.7.8 =
5
+ * Small fix for hiding the WPML registration notice
6
+
7
+ = 1.7.7 =
8
+ * Fixed js error showing up during registration
9
+ * Styles update for unified WPML messages
10
+
11
+ = 1.7.6 =
12
+ * Updated error messages when validating site keys and stopped removing site keys in case of communication errors
13
+ * Added a note for users who renewed or purchased new subscriptions and who need to revalidate their subscription from their websites
14
+ * Fixed a problem with the registrations for multi-site setups when WordPress was installed in a separate folder
15
+
16
+ = 1.7.5 =
17
+ * Fixed a bug causing registration to not be recognized for the entire network in the multi-site mode
18
+
19
+ = 1.7.4 =
20
+ * Use https for wp-types API
21
+
22
+ = 1.7.3 =
23
+ * Added a dependencies class and check for the windows paths length exception
24
+ * Bug fix: all downloads showed up twice on the plugins list whe upgrading from WPML 3.3
25
+
26
+ = 1.7.2 =
27
+ * Added an exception to handle the case when Types embedded is installer from Toolset Installer and its included Installer version overrides the one running the Toolset setup wizard
28
+
29
+ = 1.7.1 =
30
+ * Added an exception for the case of Types 1.8.9 (Installer 1.7.0) together with older WPML (older Installer)
31
+
32
+ = 1.7.0 =
33
+ * New format for the products data file.
34
+ * Other fixes
35
+
36
+ = 1.6.8 =
37
+ * Sanitized an input that was a potential security issue
38
+
39
+ = 1.6.7 =
40
+ * Fixed a bug causing repeated calls to the Toolset api to validate the user subscription
41
+ * Use https for API urls
42
+
43
+ = 1.6.6 =
44
+ * Fixed the 'Call to undefined function get_plugins()' issue
45
+
46
+ = 1.6.5 =
47
+ * Added configuration file for composer
48
+ * Updated how free plugins are shown on the plugins list (commercial tab)
49
+ * API calls for manipulating translation service preferences
50
+ * Support for hosting custom Installer packages on wpml.org
51
+ * Fixed a warning that was showing when using the OTGS_DISABLE_AUTO_UPDATES constant before any product data was downloaded
52
+ * Changed the frequency with which product updates are checked automatically (24 hours)
53
+ * Improved reporting for version numbers
54
+
55
+ = 1.6.4 =
56
+ * Enabled the OTGS_DISABLE_AUTO_UPDATES constant for theme update checks
57
+ * Fixed a bug that was causing Register links to show for all installed plugins
58
+
59
+ = 1.6.3 =
60
+ * Fixed performance issue related to themes upgrade logic
61
+
62
+ = 1.6 =
63
+ * Improved the way plugins are matched: not just by the folder name (slug) but also by name
64
+ * Added support for installing and upgrading themes from repositories (currently: Toolset themes)
65
+ * Added support for 'alias' plugins on the toolset and wpml repositories (currently: Types)
66
+ * Enhanced the progress animation during plugins downloading
67
+
68
+ = 1.5.6 =
69
+ * Updated the translations
70
+ * Fix for WPML 3.2 conditional upgrade logic
71
+
72
+ = 1.5.5 =
73
+ * Fixed the logic for the high_priority parameter
74
+ * Fixed js bug causing a conflict with NextGen
75
+ * Fixed bug preventing users to install and upgrade Types when they didn't have a Toolset subscription
76
+ * Fixed bug preventing users to upgrade from the embedded Types to the full version
77
+
78
+ = 1.5.4 =
79
+ * Option to disable auto-updates
80
+ * Escaped urls generated with add_query_arg
81
+
82
+ = 1.5.3 =
83
+ * Fixed bug in WP_Installer::custom_plugins_api_call (filter for plugins_api) causing conflicts with other filters for plugins_api
84
+
85
+ = 1.5.2 =
86
+ * More meaningful errors when plugin downloads fail
87
+ * WordPress 4.2 compatibility
88
+ * Performance improvements (will not load in places where it's not needed and not make unnecessary requests to the CDN)
89
+ * Support putting deps.xml config file in the theme folder (root)
90
+ * Included code for importing data for toolset plugins
91
+ * Use CloudFront urls for products list files
92
+
93
+ = 1.5.1 =
94
+ * Fix for allowing embedded plugins to be updated
95
+ * Logic for the migration from embedded plugins to full plugins
96
+
97
+ = 1.5 =
98
+ * Support for embedded plugins
99
+ * Bug fix: When user registers site key with trailing slash, downloads might not work
100
+ * Tweak: Set a higher timeout limit for the http requests to CDN and API
101
+ * API function: link to specific repository
102
+ * API function: get product price
103
+ * New method for defining affiliate info (with backwards compatibility)
104
+
105
+ = 1.4 =
106
+ * Show explicit error in case of connectivity issues while validating a key.
107
+ * Bug fix: Downloading plugins in bulk was broken by plugin that had a redirect after activation
108
+ * Display friendly error message when WordPress does not have permissions to write to the plugins folder
109
+ * Added support for configuration files to auto-download required plugins and theme keys
110
+ * Changed the "Update this info" button to "Check for updates" (it refreshes the subscription info and checks for updates)
111
+ * Support for high_priority parameter that allows setting priority for an Installer instance when more with the same version number exist.
112
+ * Config files from different instances are combined (define repositories in different instances)
113
+ * Updated support for conditional updates display for ICL users
114
+ * More friendly error reporting and handling when using an invalid site key or the plugins archives are not valid.
115
+
116
+
117
+ = 1.3.1 =
118
+ * Support for conditional release notification (ICanLocalize)
119
+
120
+ = 1.3 =
121
+ * Added a new repository: Toolset
122
+ * The product packages can be displayed hierarchically and ordered
123
+ * The link to automatically create site keys will follow through login on the account site (e.g. wpml.org, wp-types.com)
124
+ * Fixed animation issues (not showing in most browsers) when downloading plugins.
125
+ * Created an admin screen on the repository end (icl-mpp) to sho registration stats (site keys, site keys usage, components usage etc..).
126
+ * Bug fix: Renew and Upgrade buttons were not entirely clickable
127
+ * Bug fix: Action buttons (buy, renew, upgrade) were not displayed correctly when WPML was not active (Installer embedded in theme)
128
+ * Support for site-wide registration. Products can be registered on the network instead of on each site separately.
129
+ * Users are able to add either http or https version for any site urls. There will be one site key that will work with both http and https versions.
130
+
131
+ = 1.2 =
132
+ * Added pagination for site keys list of Account -> My Sites
133
+ * Reversed the order in which the site keys are displayed.
134
+ * Fixed problem with WPML registration information (site key) not being saved when the option_value field in the wp_options table used a different charset than the default WordPress charset defined in wp-config.php
135
+ * Allow registering new sites by clicking a link in the WordPress admin instead of copying and pasting the site url in the Account -> My Sites section
136
+ * Display more detailed debug information related to connectivity issues with the WPML repository
embedded/otgs/installer/includes/class-installer-dependencies.php ADDED
@@ -0,0 +1,278 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Installer_Dependencies{
4
+
5
+ private $uploading_allowed = null;
6
+ private $is_win_paths_exception = array();
7
+
8
+
9
+ function __construct(){
10
+
11
+ add_action( 'admin_init', array( $this, 'prevent_plugins_update_on_plugins_page' ), 100);
12
+
13
+
14
+
15
+ global $pagenow;
16
+ if($pagenow == 'update.php'){
17
+ if(isset($_GET['action']) && $_GET['action'] == 'update-selected'){
18
+ add_action('admin_head', array($this, 'prevent_plugins_update_on_updates_screen')); //iframe/bulk
19
+ }else{
20
+ add_action('all_admin_notices', array($this, 'prevent_plugins_update_on_updates_screen')); //regular/singular
21
+ }
22
+ }
23
+ add_action('wp_ajax_update-plugin', array($this, 'prevent_plugins_update_on_updates_screen'), 0); // high priority, before WP
24
+
25
+ }
26
+
27
+ public function is_win_paths_exception($repository_id){
28
+
29
+ if(!isset($this->is_win_paths_exception[$repository_id])) {
30
+
31
+ $this->is_win_paths_exception[$repository_id] = false;
32
+
33
+ if ( strtoupper( substr( PHP_OS, 0, 3 ) ) === 'WIN' ) {
34
+
35
+ $windows_max_path_length = 256;
36
+ $longest_path['wpml'] = 109;
37
+ $longest_path['toolset'] = 99;
38
+
39
+ $margin = 15;
40
+
41
+ $upgrade_path_length = strlen( WP_CONTENT_DIR . '/upgrade' );
42
+
43
+ $installer_settings = WP_Installer()->settings;
44
+
45
+ if ( is_array( $installer_settings['repositories'][$repository_id]['data']['downloads']['plugins'] ) ) {
46
+ $a_plugin = current( $installer_settings['repositories'][$repository_id]['data']['downloads']['plugins'] );
47
+ $url = WP_Installer()->append_site_key_to_download_url( $a_plugin['url'], 'xxxxxx', $repository_id );
48
+ $tmpfname = wp_tempnam( $url );
49
+
50
+ $tmpname_length = strlen( basename( $tmpfname ) ) - 4; // -.tmp
51
+
52
+ if ( $upgrade_path_length + $tmpname_length + $longest_path[$repository_id] + $margin > $windows_max_path_length ) {
53
+
54
+ $this->is_win_paths_exception[$repository_id] = true;
55
+
56
+ }
57
+
58
+ }
59
+
60
+
61
+ }
62
+
63
+ }
64
+
65
+ return $this->is_win_paths_exception[$repository_id];
66
+
67
+ }
68
+
69
+ public function is_uploading_allowed(){
70
+
71
+ if(!isset($this->uploading_allowed)){
72
+ require_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php';
73
+ require_once WP_Installer()->plugin_path() . '/includes/installer-upgrader-skins.php';
74
+
75
+ $upgrader_skins = new Installer_Upgrader_Skins(); //use our custom (mute) Skin
76
+ $upgrader = new Plugin_Upgrader($upgrader_skins);
77
+
78
+ ob_start();
79
+ $res = $upgrader->fs_connect( array(WP_CONTENT_DIR, WP_PLUGIN_DIR) );
80
+ ob_end_clean();
81
+
82
+ if ( ! $res || is_wp_error( $res ) ) {
83
+ $this->uploading_allowed = false;
84
+ }else{
85
+ $this->uploading_allowed = true;
86
+ }
87
+ }
88
+
89
+ return $this->uploading_allowed;
90
+
91
+ }
92
+
93
+ public function cant_download($repository_id){
94
+
95
+ return !$this->is_uploading_allowed() || $this->is_win_paths_exception($repository_id);
96
+
97
+ }
98
+
99
+ public function win_paths_exception_message(){
100
+ return __('Downloading is not possible. WordPress cannot create required folders because of the
101
+ 256 characters limitation of the current Windows environment.', 'installer');
102
+ }
103
+
104
+ public function prevent_plugins_update_on_plugins_page(){
105
+
106
+ $plugins = get_site_transient( 'update_plugins' );
107
+ if ( isset($plugins->response) && is_array($plugins->response) ) {
108
+ $plugins_with_updates = array_keys( $plugins->response );
109
+ }
110
+
111
+ if( !empty($plugins_with_updates) ) {
112
+
113
+ $plugins = get_plugins();
114
+
115
+ $installer_settings = WP_Installer()->settings;
116
+ foreach ($installer_settings['repositories'] as $repository_id => $repository) {
117
+
118
+ if ($this->is_win_paths_exception($repository_id)) {
119
+
120
+ $repositories_plugins = array();
121
+ foreach ($repository['data']['packages'] as $package) {
122
+ foreach ($package['products'] as $product) {
123
+ foreach ($product['plugins'] as $plugin_slug) {
124
+ $download = $installer_settings['repositories'][$repository_id]['data']['downloads']['plugins'][$plugin_slug];
125
+ if ( empty($download['free-on-wporg']) ) {
126
+ $repositories_plugins[$download['slug']] = $download['name'];
127
+ }
128
+ }
129
+ }
130
+ }
131
+
132
+ foreach ($plugins as $plugin_id => $plugin) {
133
+
134
+ if( in_array( $plugin_id, $plugins_with_updates ) ) {
135
+
136
+ $wp_plugin_slug = dirname($plugin_id);
137
+ if (empty($wp_plugin_slug)) {
138
+ $wp_plugin_slug = basename($plugin_id, '.php');
139
+ }
140
+
141
+ foreach ($repositories_plugins as $slug => $name) {
142
+ if ($wp_plugin_slug == $slug || $name == $plugin['Name'] || $name == $plugin['Title']) { //match order: slug, name, title
143
+
144
+ remove_action("after_plugin_row_$plugin_id", 'wp_plugin_update_row', 10, 2);
145
+ add_action("after_plugin_row_$plugin_id", array($this, 'wp_plugin_update_row_win_exception'), 10, 2);
146
+
147
+ }
148
+ }
149
+
150
+ }
151
+
152
+ }
153
+
154
+ }
155
+
156
+
157
+ }
158
+
159
+ }
160
+
161
+ }
162
+
163
+ public function wp_plugin_update_row_win_exception(){
164
+ $wp_list_table = _get_list_table('WP_Plugins_List_Table');
165
+ echo '<tr class="plugin-update-tr">';
166
+ echo '<td class="plugin-update colspanchange" colspan="' . esc_attr( $wp_list_table->get_column_count() ) .
167
+ '"><div class="update-message">' . $this->win_paths_exception_message() . '</div></td>';
168
+ echo '</tr>';
169
+ }
170
+
171
+ public function prevent_plugins_update_on_updates_screen(){
172
+
173
+ if ( isset($_REQUEST['action']) ) {
174
+
175
+ $action = isset($_REQUEST['action']) ? $_REQUEST['action'] : '';
176
+
177
+ $installer_settings = WP_Installer()->settings;
178
+
179
+ //bulk mode
180
+ if('update-selected' == $action) {
181
+
182
+ global $plugins;
183
+
184
+ if(isset($plugins) && is_array($plugins)) {
185
+
186
+ foreach ($plugins as $k => $plugin) {
187
+
188
+ $wp_plugin_slug = dirname($plugin);
189
+
190
+ foreach ($installer_settings['repositories'] as $repository_id => $repository) {
191
+
192
+ if( $this->is_win_paths_exception($repository_id) ){
193
+
194
+ foreach ($repository['data']['packages'] as $package) {
195
+
196
+ foreach ($package['products'] as $product) {
197
+
198
+ foreach ($product['plugins'] as $plugin_slug) {
199
+
200
+ $download = $installer_settings['repositories'][$repository_id]['data']['downloads']['plugins'][$plugin_slug];
201
+
202
+ if ($download['slug'] == $wp_plugin_slug && empty($download['free-on-wporg']) ) {
203
+
204
+ echo '<div class="updated error"><p>' . $this->win_paths_exception_message() .
205
+ ' <strong>(' . $download['name'] . ')</strong>' . '</p></div>';
206
+ unset($plugins[$k]);
207
+
208
+ break(3);
209
+
210
+ }
211
+
212
+ }
213
+
214
+ }
215
+
216
+ }
217
+
218
+
219
+ }
220
+
221
+ }
222
+
223
+ }
224
+
225
+ }
226
+
227
+ }
228
+
229
+
230
+ if( 'upgrade-plugin' == $action || 'update-plugin' == $action ) {
231
+
232
+ $plugin = isset($_REQUEST['plugin']) ? trim($_REQUEST['plugin']) : '';
233
+
234
+ $wp_plugin_slug = dirname($plugin);
235
+
236
+ foreach($installer_settings['repositories'] as $repository_id => $repository){
237
+
238
+ if( $this->is_win_paths_exception( $repository_id ) ) {
239
+ foreach ($repository['data']['packages'] as $package) {
240
+
241
+ foreach($package['products'] as $product) {
242
+
243
+ foreach($product['plugins'] as $plugin_slug) {
244
+ $download = $installer_settings['repositories'][$repository_id]['data']['downloads']['plugins'][$plugin_slug];
245
+
246
+ //match by folder, will change to match by name and folder
247
+ if ( $download['slug'] == $wp_plugin_slug && empty ($download['free-on-wporg'] ) ) {
248
+
249
+ echo '<div class="updated error"><p>' . $this->win_paths_exception_message() . '</p></div>';
250
+
251
+ echo '<div class="wrap">';
252
+ echo '<h2>' . __('Update Plugin') . '</h2>';
253
+ echo '<a href="' . admin_url('update-core.php') . '">' . __('Return to the updates page', 'installer') . '</a>';
254
+ echo '</div>';
255
+ require_once(ABSPATH . 'wp-admin/admin-footer.php');
256
+ exit;
257
+
258
+ }
259
+
260
+ }
261
+
262
+ }
263
+
264
+ }
265
+ }
266
+
267
+ }
268
+
269
+ }
270
+ }
271
+
272
+ }
273
+
274
+
275
+ }
276
+
277
+
278
+
embedded/otgs/installer/includes/class-installer-theme.php ADDED
@@ -0,0 +1,979 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Installer Class for Theme Support
4
+ *
5
+ * Supports automatic updates and installation of Toolset/WPML Themes
6
+ *
7
+ * @class Installer_Theme_Class
8
+ * @version 1.6
9
+ * @category Class
10
+ * @author OnTheGoSystems
11
+ */
12
+
13
+ if ( !defined( 'ABSPATH' ) ) {
14
+ exit;
15
+ }
16
+
17
+ /**
18
+ * Installer_Theme_Class
19
+ */
20
+ class Installer_Theme_Class {
21
+
22
+ /** Theme Repository */
23
+ private $theme_repo;
24
+
25
+ /** Repository API */
26
+ private $repository_api;
27
+
28
+ /** Repository Theme Products */
29
+ private $repository_theme_products;
30
+
31
+ /** Site URL */
32
+ private $installer_site_url;
33
+
34
+ /** Site Key */
35
+ private $installer_site_key;
36
+
37
+ /** The Themes Option */
38
+ protected $installer_themes_option;
39
+
40
+ /** Update settings */
41
+ protected $installer_themes_available_updates;
42
+
43
+ /** The Themes */
44
+ protected $installer_themes = array();
45
+
46
+ /** Repository with themes */
47
+ protected $installer_repo_with_themes;
48
+
49
+ /** Active tab */
50
+ protected $installer_theme_active_tab;
51
+
52
+ /** Theme user registration */
53
+ protected $theme_user_registration;
54
+
55
+ /** Client active subscription */
56
+ protected $installer_theme_subscription_type;
57
+
58
+ public function __construct() {
59
+
60
+ /** Properties */
61
+
62
+ //Get installer repositories
63
+ $installer_repositories = WP_Installer()->get_repositories();
64
+
65
+ //Get repos with themes
66
+ $repos_with_themes = $this->installer_theme_reposities_that_has_themes( $installer_repositories );
67
+
68
+ if ( is_array( $repos_with_themes ) ) {
69
+ //Assign to property
70
+ $this->installer_repo_with_themes = $repos_with_themes;
71
+
72
+ //Let's looped through repos with themes
73
+ foreach ( $repos_with_themes as $k => $repo ) {
74
+
75
+ //$repo could be 'toolset' or 'wpml'
76
+ //Assign each repo with theme to property
77
+ $this->theme_repo[] = $repo;
78
+
79
+ if ( (isset($installer_repositories[$repo]['api-url'])) && (isset($installer_repositories[$repo]['products'])) ) {
80
+
81
+ //Define the rest of the properties based on the given repo
82
+ $this->repository_api[$repo] = $installer_repositories[$repo]['api-url'];
83
+ $this->repository_theme_products[$repo] = $installer_repositories[$repo]['products'];
84
+ $this->installer_site_url[$repo] = WP_Installer()->get_installer_site_url( $repo );
85
+ $this->installer_site_key[$repo] = WP_Installer()->get_site_key( $repo );
86
+ $this->theme_user_registration[$repo] = false;
87
+
88
+ if ( WP_Installer()->repository_has_valid_subscription( $repo ) ) {
89
+
90
+ $this->installer_theme_subscription_type = WP_Installer()->get_subscription_type_for_repository( $repo );
91
+ $this->installer_themes_option[$repo] = 'wp_installer_' . $repo . '_themes';
92
+ $this->installer_themes_available_updates[$repo] = 'wp_installer_' . $repo . '_updated_themes';
93
+ $this->installer_theme_active_tab = '';
94
+
95
+ //We only set themes available to this validated subscription
96
+ $this->installer_theme_available( $repo, $this->installer_theme_subscription_type );
97
+
98
+ add_action( 'installer_themes_support_set_up', array($this, 'installer_theme_sets_active_tab_on_init'), 10 );
99
+ $this->theme_user_registration[$repo] = true;
100
+ }
101
+
102
+ /** We are ready.. let's initialize .... */
103
+ $this->init();
104
+ }
105
+ }
106
+ add_action( 'installer_themes_support_set_up', array($this, 'installer_theme_loaded_hooks') );
107
+ }
108
+ }
109
+
110
+ /** Init */
111
+ public function init() {
112
+ add_action( 'admin_enqueue_scripts', array($this, 'installer_theme_enqueue_scripts') );
113
+ add_filter( 'themes_api', array($this, 'installer_theme_api_override'), 10, 3 );
114
+ add_filter( 'themes_api_result', array($this, 'installer_theme_api_override_response'), 10, 3 );
115
+ add_filter( 'site_transient_update_themes', array($this, 'installer_theme_upgrade_check'), 10, 1 );
116
+ add_action( 'http_api_debug', array($this, 'installer_theme_sync_native_wp_api'), 10, 5 );
117
+ add_filter( 'installer_theme_hook_response_theme', array($this, 'installer_theme_add_num_ratings'), 10, 1 );
118
+ add_filter( 'themes_update_check_locales', array($this, 'installer_theme_sync_call_wp_theme_api'), 10, 1 );
119
+ add_filter( 'admin_url', array($this, 'installer_theme_add_query_arg_tab'), 10, 3 );
120
+ add_filter( 'network_admin_url', array($this, 'installer_theme_add_query_arg_tab'), 10, 2 );
121
+ add_action( 'wp_ajax_installer_theme_frontend_selected_tab', array($this, 'installer_theme_frontend_selected_tab'), 0 );
122
+ add_action( 'wp_loaded', array($this, 'installer_themes_support_set_up_func') );
123
+ }
124
+
125
+ /** Enqueue scripts */
126
+ public function installer_theme_enqueue_scripts() {
127
+ $current_screen = $this->installer_theme_current_screen();
128
+ $commercial_plugin_screen = $this->installer_theme_is_commercial_plugin_screen( $current_screen );
129
+ if ( ('theme-install' == $current_screen) || ($commercial_plugin_screen) || ('theme-install-network' == $current_screen) ) {
130
+ $repo_with_themes = $this->installer_repo_with_themes;
131
+ $js_array = array();
132
+ if ( is_array( $repo_with_themes ) ) {
133
+ foreach ( $repo_with_themes as $k => $v ) {
134
+
135
+ //Hyperlink text
136
+ $theme_repo_name = $this->installer_theme_get_repo_product_name( $v );
137
+ $the_hyperlink_text = esc_js( $theme_repo_name );
138
+
139
+ if ( is_multisite() ) {
140
+ $admin_url_passed = network_admin_url();
141
+ } else {
142
+ $admin_url_passed = admin_url();
143
+ }
144
+
145
+ //Define
146
+ $js_array[$v] = array(
147
+ 'the_hyperlink_text' => $the_hyperlink_text,
148
+ 'registration_status' => $this->theme_user_registration[$v],
149
+ 'is_commercial_plugin_tab' => $commercial_plugin_screen,
150
+ 'registration_url' => $admin_url_passed . 'plugin-install.php?tab=commercial#installer_repo_' . $v
151
+ );
152
+
153
+ }
154
+ }
155
+
156
+ if ( !(empty($js_array)) ) {
157
+ wp_enqueue_script( 'installer-theme-install', WP_Installer()->res_url() . '/res/js/installer_theme_install.js', array('jquery', 'installer-admin'), WP_Installer()->version() );
158
+ $installer_ajax_url = admin_url( 'admin-ajax.php' );
159
+
160
+ if ( is_ssl() ) {
161
+ $installer_ajax_url = str_replace( 'http://', 'https://', $installer_ajax_url );
162
+ } else {
163
+ $installer_ajax_url = str_replace( 'https://', 'http://', $installer_ajax_url );
164
+ }
165
+
166
+ //Case where user is subscribed to a subscription that does not have themes
167
+ $subscription_js_check = $this->installer_theme_subscription_does_not_have_theme( $js_array );
168
+
169
+ wp_localize_script( 'installer-theme-install', 'installer_theme_install_localize',
170
+ array(
171
+ 'js_array_installer' => $js_array,
172
+ 'ajaxurl' => $installer_ajax_url,
173
+ 'no_associated_themes' => $subscription_js_check,
174
+ 'installer_theme_frontend_selected_tab_nonce' => wp_create_nonce( 'installer_theme_frontend_selected_tab' )
175
+ )
176
+ );
177
+ }
178
+ }
179
+ }
180
+
181
+ /** Case where user is subscribed to a subscription that does not have themes */
182
+ protected function installer_theme_subscription_does_not_have_theme( $js_array ) {
183
+
184
+ $any_subscription_has_theme = array();
185
+ $number_of_registrations = array();
186
+
187
+ //Step1, we looped through JS array
188
+ foreach ( $js_array as $repo_slug => $js_details ) {
189
+
190
+ //Step2, checked if user is registered
191
+ if ( isset($this->theme_user_registration[$repo_slug]) ) {
192
+ $registration_status = $this->theme_user_registration[$repo_slug];
193
+ if ( $registration_status ) {
194
+
195
+ //Registered
196
+ $number_of_registrations[] = $repo_slug;
197
+
198
+ //Step3, we checked if the $repo_slug has available theme
199
+ $themes_available = false;
200
+ if ( isset($this->installer_themes[$repo_slug]) ) {
201
+ $themes_available = $this->installer_themes[$repo_slug];
202
+ if ( !(empty($themes_available)) ) {
203
+ //This subscription has theme
204
+ $themes_available = true;
205
+ }
206
+ }
207
+
208
+ if ( $themes_available ) {
209
+ $any_subscription_has_theme[] = $repo_slug;
210
+ }
211
+ }
212
+ }
213
+
214
+ }
215
+
216
+ //Step4, we are done looping, check if there are any repos that have themes
217
+ if ( empty($registration_status) ) {
218
+
219
+ //No registration on any repos
220
+ return FALSE;
221
+
222
+ } elseif ( !(empty($registration_status)) ) {
223
+
224
+ //Has some registration on some repos
225
+ //We then checked if this user has any active subscriptions
226
+ if ( empty($any_subscription_has_theme) ) {
227
+ //No subscription
228
+ return TRUE;
229
+ } else {
230
+ //Has subscription found
231
+ return FALSE;
232
+ }
233
+ }
234
+ }
235
+
236
+ /** Check if its the commercial plugin screen */
237
+ private function installer_theme_is_commercial_plugin_screen( $current_screen ) {
238
+ $commercial = false;
239
+ if ( ('plugin-install' == $current_screen) || ('plugin-install-network' == $current_screen) ) {
240
+ if ( isset($_GET['tab']) ) {
241
+ $tab = $_GET['tab'];
242
+ if ( 'commercial' == $tab ) {
243
+ $commercial = true;
244
+ }
245
+ }
246
+ }
247
+ return $commercial;
248
+ }
249
+
250
+ /** Current screen */
251
+ private function installer_theme_current_screen() {
252
+
253
+ $current_screen_loaded = false;
254
+
255
+ if ( function_exists( 'get_current_screen' ) ) {
256
+
257
+ $screen_output = get_current_screen();
258
+ $current_screen_loaded = $screen_output->id;
259
+
260
+ }
261
+
262
+ return $current_screen_loaded;
263
+
264
+ }
265
+
266
+ /** Override WordPress Themes API */
267
+ public function installer_theme_api_override( $api_boolean, $action, $args ) {
268
+
269
+ //Let's checked if user is browsing our themes
270
+ if ( isset($args->browse) ) {
271
+ $browse = $args->browse;
272
+ if ( in_array( $browse, $this->theme_repo ) ) {
273
+ //Uniquely validated for our Themes
274
+ if ( 'query_themes' == $action ) {
275
+ //User is querying or asking information about our themes, let's override
276
+ $api_boolean = true;
277
+ }
278
+ }
279
+ } elseif ( isset($args->slug) ) {
280
+ //We are installing our themes
281
+ $theme_to_install = $args->slug;
282
+
283
+ //Lets uniquely validate if this belongs to us
284
+ //Check if this is OTGS theme
285
+ $validate_check = $this->installer_themes_belong_to_us( $theme_to_install );
286
+ if ( $validate_check ) {
287
+ //Belongs to us
288
+ if ( !(empty($theme_to_install)) ) {
289
+ $api_boolean = true;
290
+ }
291
+ }
292
+ }
293
+
294
+ return $api_boolean;
295
+ }
296
+
297
+ /** Override WordPress Themes API response with our own themes API*/
298
+ public function installer_theme_api_override_response( $res, $action, $args ) {
299
+
300
+ if ( true === $res ) {
301
+ if ( isset($args->browse) ) {
302
+ $browse = $args->browse;
303
+ if ( in_array( $browse, $this->theme_repo ) ) {
304
+ //Uniquely validated for our themes
305
+ if ( 'query_themes' == $action ) {
306
+ //Client querying OTGS themes
307
+ //Check for registration status
308
+ if ( isset($this->theme_user_registration[$browse]) ) {
309
+ //Set
310
+ if ( !($this->theme_user_registration[$browse]) ) {
311
+ //Not registered yet
312
+ $res = new stdClass();
313
+ $res->info = array();
314
+ $res->themes = array();
315
+ return $res;
316
+ } else {
317
+ //Registered
318
+ $themes = $this->installer_theme_get_themes( '', $browse );
319
+ $res = $this->installer_theme_format_response( $themes, $action );
320
+ }
321
+ }
322
+ }
323
+ }
324
+ } elseif ( isset($args->slug) ) {
325
+ //We are installing theme
326
+ //Lets uniquely validate if this belongs to our theme
327
+ $theme_to_install = $args->slug;
328
+
329
+ //Lets uniquely validate if this belongs to us
330
+ //Check if this is OTGS theme
331
+ $validate_check = $this->installer_themes_belong_to_us( $theme_to_install );
332
+ if ( $validate_check ) {
333
+ //Belongs to us
334
+ if ( ($res) && ('theme_information' == $action) ) {
335
+ $themes = $this->installer_theme_get_themes( '', $this->installer_theme_active_tab );
336
+ $res = $this->installer_theme_format_response( $themes, $action, $args->slug );
337
+ }
338
+ }
339
+ }
340
+ return $res;
341
+ } else {
342
+ //Default WP Themes here
343
+ $client_side_active_tab = get_option( 'wp_installer_clientside_active_tab' );
344
+ if ( $client_side_active_tab ) {
345
+ if ( !(in_array( $client_side_active_tab, $this->theme_repo )) ) {
346
+ //Not OTGS tab
347
+ return $res;
348
+ }
349
+ }
350
+
351
+ }
352
+ }
353
+
354
+ /** Get Themes */
355
+ private function installer_theme_get_themes( $product_url = '', $repo_source = '' ) {
356
+
357
+ //Query API
358
+ if ( empty($product_url) ) {
359
+ //Not set
360
+ if ( isset($this->repository_theme_products[$this->installer_theme_active_tab]) ) {
361
+ $query_remote_url = $this->repository_theme_products[$this->installer_theme_active_tab];
362
+ }
363
+
364
+ } else {
365
+ $query_remote_url = $product_url;
366
+ }
367
+
368
+ //Let's retrieved current installer settings so we won't be querying all the time
369
+ $current_installer_settings = WP_Installer()->get_settings();
370
+
371
+ //Set $themes to FALSE by default
372
+ $themes = false;
373
+
374
+ if ( (is_array( $current_installer_settings )) && (!(empty($current_installer_settings))) ) {
375
+
376
+ //Set and already defined, retrieved $products
377
+ if ( isset($current_installer_settings['repositories'][$repo_source]['data']) ) {
378
+ $products = $current_installer_settings['repositories'][$repo_source]['data'];
379
+ if ( isset($products['downloads']['themes']) ) {
380
+ $themes = $products['downloads']['themes'];
381
+ }
382
+ }
383
+
384
+ } else {
385
+
386
+ //Call API
387
+ $response = wp_remote_get( $query_remote_url );
388
+
389
+ if ( is_wp_error( $response ) ) {
390
+ //Error detected: http fallback
391
+ $query_remote_url = preg_replace( "@^https://@", 'http://', $query_remote_url );
392
+ $response = wp_remote_get( $query_remote_url );
393
+ }
394
+
395
+ if ( !(is_wp_error( $response )) ) {
396
+ //Not WP error
397
+ //Evaluate response
398
+ if ( $response && isset($response['response']['code']) && $response['response']['code'] == 200 ) {
399
+ //In this case, response is set and defined, proceed...
400
+ $body = wp_remote_retrieve_body( $response );
401
+ if ( $body ) {
402
+ $products = json_decode( $body, true );
403
+ if ( isset($products['downloads']['themes']) ) {
404
+ $themes = $products['downloads']['themes'];
405
+ }
406
+ }
407
+
408
+ }
409
+ }
410
+ }
411
+
412
+ //Return themes, can be filtered by user subscription type
413
+ return apply_filters( 'installer_theme_get_themes', $themes, $this->installer_theme_active_tab );
414
+ }
415
+
416
+ /** Format response in compatibility with WordPress Theme API response */
417
+ private function installer_theme_format_response( $themes, $action, $slug = '' ) {
418
+
419
+ //Let's append download link only when retrieving theme information for installation
420
+ if ( ('theme_information' == $action) && (!(empty($slug))) ) {
421
+
422
+ //Only return one result -> the theme to be installed
423
+ foreach ( $themes as $k => $theme ) {
424
+ if ( $slug == $theme['basename'] ) {
425
+ $theme['download_link'] = WP_Installer()->append_site_key_to_download_url( $theme['url'], $this->installer_site_key[$this->installer_theme_active_tab], $this->installer_theme_active_tab );
426
+ $theme = json_decode( json_encode( $theme ), FALSE );
427
+ return $theme;
428
+ }
429
+ }
430
+
431
+ } else {
432
+
433
+ $res = new stdClass();
434
+ $res->info = array();
435
+ $res->themes = array();
436
+
437
+ //Define info
438
+ $res->info['page'] = 1;
439
+ $res->info['pages'] = 10;
440
+
441
+ //Let's count available themes ;
442
+ $res->info['results'] = count( $themes );
443
+
444
+ //Let's saved themes for easy access later on
445
+ $this->installer_theme_savethemes_by_slug( $themes );
446
+
447
+ //Let's defined available themes
448
+ if ( isset($this->installer_theme_subscription_type) ) {
449
+ //Has subscription type defined, let's saved what is associated with this subscription
450
+ $this->installer_theme_available( $this->installer_theme_active_tab, $this->installer_theme_subscription_type );
451
+ } else {
452
+ $this->installer_theme_available( $this->installer_theme_active_tab );
453
+ }
454
+
455
+ //Let's add themes to the overriden WordPress API Theme response
456
+ /** Installer 1.7.6: Update to compatible data format response from WP Theme API */
457
+ $theme_compatible_array=array();
458
+ if ((is_array($themes))) {
459
+ foreach ($themes as $k=>$v) {
460
+ $theme_compatible_array[]=(object)($v);
461
+ }
462
+ }
463
+ $res->themes = $theme_compatible_array;
464
+ $res->themes = apply_filters( 'installer_theme_hook_response_theme', $res->themes );
465
+ return $res;
466
+ }
467
+ }
468
+
469
+ /** Let's save all available themes by its slug after any latest API query */
470
+ private function installer_theme_savethemes_by_slug( $themes, $doing_query = false ) {
471
+
472
+ if ( !($doing_query) ) {
473
+ $this->installer_themes[$this->installer_theme_active_tab] = array();
474
+ }
475
+
476
+ if ( !(empty($themes)) ) {
477
+ $themes_for_saving = array();
478
+ foreach ( $themes as $k => $theme ) {
479
+ if ( !($doing_query) ) {
480
+ if ( isset($theme['slug']) ) {
481
+ $theme_slug = $theme['slug'];
482
+ if ( !(empty($theme_slug)) ) {
483
+ $themes_for_saving[] = $theme_slug;
484
+ }
485
+ }
486
+ } else {
487
+
488
+ if ( ((isset($theme['slug'])) && (isset($theme['version'])) &&
489
+ (isset($theme['theme_page_url']))) && (isset($theme['url']))
490
+ ) {
491
+ $theme_slug = $theme['slug'];
492
+ $theme_version = $theme['version'];
493
+ $theme_page_url = $theme['theme_page_url'];
494
+ $theme_url = $theme['url'];
495
+ if ( (!(empty($theme_slug))) && (!(empty($theme_version))) &&
496
+ (!(empty($theme_page_url))) && (!(empty($theme_url)))
497
+ ) {
498
+ //$theme_slug is unique for every theme
499
+ $themes_for_saving[$theme_slug] = array(
500
+ 'version' => $theme_version,
501
+ 'theme_page_url' => $theme_page_url,
502
+ 'url' => $theme_url
503
+ );
504
+
505
+ }
506
+ }
507
+ }
508
+
509
+ }
510
+
511
+ if ( !(empty($themes_for_saving)) ) {
512
+ //Has themes for saving
513
+ if ( !($doing_query) ) {
514
+ //Not doing query
515
+ $existing_themes = get_option( $this->installer_themes_option[$this->installer_theme_active_tab] );
516
+ if ( !($existing_themes) ) {
517
+ //Does not yet exists
518
+ delete_option( $this->installer_themes_option[$this->installer_theme_active_tab] );
519
+ update_option( $this->installer_themes_option[$this->installer_theme_active_tab], $themes_for_saving );
520
+ } else {
521
+ //exists, check if we need to update
522
+ if ( $existing_themes == $themes_for_saving ) {
523
+ //Equal, no need to update here
524
+ } else {
525
+ //Update
526
+ delete_option( $this->installer_themes_option[$this->installer_theme_active_tab] );
527
+ update_option( $this->installer_themes_option[$this->installer_theme_active_tab], $themes_for_saving );
528
+ }
529
+ }
530
+ } else {
531
+ //Used for query purposes only, don't save anything
532
+ return $themes_for_saving;
533
+ }
534
+ }
535
+ }
536
+ }
537
+
538
+ /** Available themes */
539
+ private function installer_theme_available( $repo, $subscription_type = '' ) {
540
+
541
+ $subscription_type = intval( $subscription_type );
542
+ if ( $subscription_type > 0 ) {
543
+
544
+ //Here we have a case of validated subscription
545
+ //We need to set themes that is available to this subscription
546
+ $themes_associated_with_subscription = $this->installer_themes[$repo] = $this->installer_theme_get_themes_by_subscription( $subscription_type, $repo );
547
+ if ( !(empty($themes_associated_with_subscription)) ) {
548
+ //Has themes
549
+ $this->installer_themes[$repo] = $themes_associated_with_subscription;
550
+ }
551
+ } else {
552
+
553
+ //Get themes
554
+ $this->installer_themes[$repo] = get_option( $this->installer_themes_option[$repo] );
555
+ }
556
+ }
557
+
558
+ /** Theme upgrade check */
559
+ public function installer_theme_upgrade_check( $the_value ) {
560
+
561
+ //Step1: Let's looped through repos with themes and check if we have updates available for them.
562
+ if ( (is_array( $this->installer_repo_with_themes )) && (!(empty($this->installer_repo_with_themes))) ) {
563
+ foreach ( $this->installer_repo_with_themes as $k => $repo_slug ) {
564
+ //Step2: Let's checked if we have update for this theme
565
+ $update_available = get_option( $this->installer_themes_available_updates[$repo_slug] );
566
+ if ( $update_available ) {
567
+ if ( (is_array( $update_available )) && (!(empty($update_available))) ) {
568
+ //Has updates available coming from this specific theme repo
569
+ //Let's loop through the themes that needs update
570
+ foreach ( $update_available as $theme_slug => $v ) {
571
+ //Add to response API
572
+ $the_value->response [$theme_slug] = array(
573
+ 'theme' => $theme_slug,
574
+ 'new_version' => $v['new_version'],
575
+ 'url' => $v['url'],
576
+ 'package' => $v['package']
577
+ );
578
+ }
579
+ }
580
+ }
581
+ }
582
+ }
583
+ //Return
584
+ return $the_value;
585
+ }
586
+
587
+ /** Return repositories that has themes */
588
+ private function installer_theme_reposities_that_has_themes( $repositories, $ret_value = true, $doing_api_query = false ) {
589
+
590
+ $repositories_with_themes = array();
591
+
592
+ if ( (is_array( $repositories )) && (!(empty($repositories))) ) {
593
+
594
+ //Let's checked if we have something before
595
+ $themes = get_option( 'installer_repositories_with_theme' );
596
+
597
+ if ( (!($themes)) || ($doing_api_query) ) {
598
+ //Not yet defined
599
+ //Loop through each repositories and check whether they have themes
600
+ foreach ( $repositories as $k => $v ) {
601
+ if ( isset($v['products']) ) {
602
+ $products_url = $v['products'];
603
+ $themes = $this->installer_theme_get_themes( $products_url, $k );
604
+ if ( (is_array( $themes )) && (!(empty($themes))) ) {
605
+ //Repo has themes
606
+ $repositories_with_themes[] = $k;
607
+ }
608
+ }
609
+ }
610
+ } else {
611
+ //Already set
612
+ $repositories_with_themes = $themes;
613
+ }
614
+
615
+ if ( (((is_array( $repositories_with_themes )) && (!(empty($repositories_with_themes)))) && (!($themes))) || ($doing_api_query) ) {
616
+ //Save to db
617
+ update_option( 'installer_repositories_with_theme', $repositories_with_themes );
618
+ }
619
+ }
620
+
621
+ if ( $ret_value ) {
622
+ return $repositories_with_themes;
623
+ }
624
+
625
+ }
626
+
627
+ /** When WordPress queries its own Themes API, we sync with our own */
628
+ public function installer_theme_sync_native_wp_api( $response, $responsetext, $class, $args, $url ) {
629
+
630
+ $api_native_string = 'api.wordpress.org/themes/';
631
+ if ( (strpos( $url, $api_native_string ) !== false) ) {
632
+ //WordPress is querying its own themes API
633
+ $installer_repositories = WP_Installer()->get_repositories();
634
+
635
+ //Query our own API and update repository values too
636
+ $this->installer_theme_reposities_that_has_themes( $installer_repositories, false, true );
637
+ }
638
+ }
639
+
640
+ /** Returns product name by theme repo slug */
641
+ private function installer_theme_get_repo_product_name( $theme_repo ) {
642
+
643
+ $theme_repo_name = false;
644
+
645
+ if ( isset(WP_Installer()->settings['repositories'][$theme_repo]['data']['product-name']) ) {
646
+ //Set
647
+ $prod_name = WP_Installer()->settings['repositories'][$theme_repo]['data']['product-name'];
648
+ if ( !(empty($prod_name)) ) {
649
+ $theme_repo_name = $prod_name;
650
+ }
651
+ } else {
652
+ //Not yet
653
+ if ( $theme_repo == $this->theme_repo ) {
654
+ $result = $this->installer_theme_general_api_query();
655
+ if ( isset($result['product-name']) ) {
656
+ $product_name = $result['product-name'];
657
+ if ( !(empty($product_name)) ) {
658
+ $theme_repo_name = $product_name;
659
+ }
660
+ }
661
+ }
662
+ }
663
+
664
+ return $theme_repo_name;
665
+ }
666
+
667
+ /** General query API method, returns $products */
668
+ private function installer_theme_general_api_query() {
669
+ $products = false;
670
+ $response = wp_remote_get( $this->repository_theme_products );
671
+ if ( !(is_wp_error( $response )) ) {
672
+ //Not WP error
673
+ //Evaluate response
674
+ if ( $response && isset($response['response']['code']) && $response['response']['code'] == 200 ) {
675
+ //In this case, response is set and defined, proceed...
676
+ $body = wp_remote_retrieve_body( $response );
677
+ if ( $body ) {
678
+ $result = json_decode( $body, true );
679
+ if ( (is_array( $result )) && (!(empty($result))) ) {
680
+ $products = $result;
681
+ }
682
+ }
683
+
684
+ }
685
+ }
686
+
687
+ return $products;
688
+ }
689
+
690
+ /** General method to check if themes are OTGS themes based on its slug*/
691
+ private function installer_themes_belong_to_us( $theme_slug ) {
692
+
693
+ $found = false;
694
+ $theme_slug = trim( $theme_slug );
695
+
696
+ foreach ( $this->installer_themes as $repo_with_theme => $themes ) {
697
+ foreach ( $themes as $k => $otgs_theme_slug ) {
698
+ if ( $theme_slug == $otgs_theme_slug ) {
699
+ //match found! Theme belongs to otgs
700
+ return true;
701
+ }
702
+ }
703
+ }
704
+ return $found;
705
+
706
+ }
707
+
708
+ /** Sets active tab on init */
709
+ public function installer_theme_sets_active_tab_on_init() {
710
+
711
+ if ( isset ($_SERVER ['REQUEST_URI']) ) {
712
+ $request_uri = $_SERVER ['REQUEST_URI'];
713
+ if ( isset ($_GET ['browse']) ) {
714
+ $active_tab = trim( $_GET ['browse'] );
715
+ $this->installer_theme_active_tab = $active_tab;
716
+ } elseif ( isset ($_POST ['request'] ['browse']) ) {
717
+ $active_tab = trim( $_POST ['request'] ['browse'] );
718
+ $this->installer_theme_active_tab = $active_tab;
719
+ } elseif ( (isset ($_GET ['theme_repo'])) && (isset ($_GET ['action'])) ) {
720
+ $theme_repo = trim( $_GET ['theme_repo'] );
721
+ $the_action = trim( $_GET ['action'] );
722
+ if ( ('install-theme' == $the_action) && (!(empty($theme_repo))) ) {
723
+ $this->installer_theme_active_tab = $theme_repo;
724
+ }
725
+ } elseif ( wp_get_referer() ) {
726
+ $referer = wp_get_referer();
727
+ $parts = parse_url( $referer );
728
+ if ( isset($parts['query']) ) {
729
+ parse_str( $parts['query'], $query );
730
+ if ( isset($query['browse']) ) {
731
+ $this->installer_theme_active_tab = $query['browse'];
732
+ }
733
+ }
734
+ }
735
+ }
736
+ }
737
+
738
+ /** WP Theme API compatibility- added num ratings */
739
+ /** Installer 1.7.6+ Added updated 'rating' field */
740
+ public function installer_theme_add_num_ratings( $themes ) {
741
+
742
+ if ( (is_array( $themes )) && (!(empty($themes))) ) {
743
+ foreach ( $themes as $k => $v ) {
744
+ if ( !(isset($v->num_ratings)) ) {
745
+ $themes[$k]->num_ratings = 100;
746
+ }
747
+ if ( !(isset($v->rating)) ) {
748
+ $themes[$k]->rating = 100;
749
+ }
750
+ }
751
+ }
752
+
753
+ return $themes;
754
+ }
755
+
756
+ /** When WordPress.org makes a call to its repository, let's run our own upgrade checks too */
757
+ public function installer_theme_sync_call_wp_theme_api( $locales ) {
758
+
759
+ $this->installer_theme_upgrade_theme_check();
760
+
761
+ return $locales;
762
+ }
763
+
764
+ /** Upgrade theme check */
765
+ private function installer_theme_upgrade_theme_check() {
766
+
767
+ // Step1-> we get all installed themes in clients local themes directory
768
+ $installed_themes = wp_get_themes();
769
+
770
+ // Step2: We need to loop through each repository with themes
771
+ foreach ( $this->installer_repo_with_themes as $k => $repo_slug ) {
772
+
773
+ // We then need to retrieved the products URL for each of this repo
774
+ $products_url = $this->repository_theme_products [$repo_slug];
775
+
776
+ // Step3-> we get all available themes in our repository via API based on this URL
777
+ $available_themes = $this->installer_theme_get_themes( $products_url, $repo_slug );
778
+
779
+ if ( !($available_themes) ) {
780
+
781
+ // API is not available as of the moment, return..
782
+ return;
783
+ } else {
784
+
785
+ // We have available themes here...
786
+ // Step4->let's simplify available themes data by slugs
787
+ $simplified_available_themes = $this->installer_theme_savethemes_by_slug( $available_themes, true );
788
+
789
+ // Step5->Let's loop through installed themes
790
+ if ( (is_array( $installed_themes )) && (!(empty ($installed_themes))) ) {
791
+ $otgs_theme_updates_available = array();
792
+ foreach ( $installed_themes as $theme_slug => $theme_object ) {
793
+ if ( array_key_exists( $theme_slug, $simplified_available_themes ) ) {
794
+
795
+ // This is our theme
796
+ // Step6->Let's get version of the local theme installed
797
+ $local_version = $theme_object->get( 'Version' );
798
+
799
+ // Step7->Let's get the latest version of this theme, page URL and download URL from our repository
800
+ $repository_version = $simplified_available_themes [$theme_slug] ['version'];
801
+ $theme_page_url = $simplified_available_themes [$theme_slug] ['theme_page_url'];
802
+ $theme_download_url = $simplified_available_themes [$theme_slug] ['url'];
803
+
804
+ // Step8->Let's compare the version
805
+ if ( version_compare( $repository_version, $local_version, '>' ) ) {
806
+
807
+ // Update available for this theme
808
+ // Step9-> Define download URL with site key
809
+ $package_url = WP_Installer()->append_site_key_to_download_url( $theme_download_url, $this->installer_site_key [$repo_slug], $repo_slug );
810
+
811
+ //Step10-> Assign to updates array for later accessing.
812
+ $otgs_theme_updates_available[$theme_slug] = array(
813
+ 'theme' => $theme_slug,
814
+ 'new_version' => $repository_version,
815
+ 'url' => $theme_page_url,
816
+ 'package' => $package_url
817
+ );
818
+ }
819
+ }
820
+ }
821
+ //Exited the upgrade loop for this specific theme repository
822
+ if ( !(empty($otgs_theme_updates_available)) ) {
823
+ //Has updates
824
+ update_option( $this->installer_themes_available_updates[$repo_slug], $otgs_theme_updates_available );
825
+ } else {
826
+ //No updates
827
+ delete_option( $this->installer_themes_available_updates[$repo_slug] );
828
+ }
829
+
830
+ }
831
+ }
832
+ }
833
+ }
834
+
835
+ /** When the user is on Themes install page OTG themes repository, let's the currently selected tab */
836
+ public function installer_theme_add_query_arg_tab( $url, $path, $blog_id = null ) {
837
+
838
+ $wp_install_string = 'update.php?action=install-theme';
839
+ if ( $path == $wp_install_string ) {
840
+ if ( isset($this->installer_theme_active_tab) ) {
841
+ if ( !(empty($this->installer_theme_active_tab)) ) {
842
+ $url = add_query_arg( array(
843
+ 'theme_repo' => $this->installer_theme_active_tab
844
+ ), $url );
845
+ }
846
+ }
847
+ }
848
+ return $url;
849
+ }
850
+
851
+ /** Save frontend theme tab selected */
852
+ public function installer_theme_frontend_selected_tab() {
853
+ if ( isset($_POST["frontend_tab_selected"]) ) {
854
+ check_ajax_referer( 'installer_theme_frontend_selected_tab', 'installer_theme_frontend_selected_tab_nonce' );
855
+
856
+ //Client_side_active_tab
857
+ $frontend_tab_selected = filter_input( INPUT_POST, 'frontend_tab_selected', FILTER_SANITIZE_FULL_SPECIAL_CHARS, FILTER_NULL_ON_FAILURE );
858
+ if ( !(empty($frontend_tab_selected)) ) {
859
+ //Front end tab selected
860
+ update_option( 'wp_installer_clientside_active_tab', $frontend_tab_selected, false );
861
+
862
+ //Check for registration status
863
+ if ( isset($this->theme_user_registration[$frontend_tab_selected]) ) {
864
+ //Set
865
+ if ( !($this->theme_user_registration[$frontend_tab_selected]) ) {
866
+ //Not registered yet
867
+
868
+ if ( is_multisite() ) {
869
+ $admin_url_passed = network_admin_url();
870
+ } else {
871
+ $admin_url_passed = admin_url();
872
+ }
873
+
874
+ $registration_url = $admin_url_passed . 'plugin-install.php?tab=commercial#installer_repo_' . $frontend_tab_selected;
875
+
876
+ //Message and link
877
+ $theme_repo_name = $this->installer_theme_get_repo_product_name( $frontend_tab_selected );;
878
+ $response['unregistered_messages'] = sprintf( __( 'To install and update %s, please %sregister%s %s for this site.', 'installer' ),
879
+ $theme_repo_name, '<a href="' . $registration_url . '">', '</a>', $theme_repo_name );
880
+
881
+ }
882
+ }
883
+
884
+ $response['output'] = $frontend_tab_selected;
885
+ echo json_encode( $response );
886
+ }
887
+ die();
888
+ }
889
+ die();
890
+ }
891
+
892
+ /** Installer loaded aux hooks */
893
+ public function installer_theme_loaded_hooks() {
894
+
895
+ if ( isset($this->installer_theme_subscription_type) ) {
896
+ $subscription_type = intval( $this->installer_theme_subscription_type );
897
+ if ( $subscription_type > 0 ) {
898
+ //Client is subscribed
899
+ add_filter( 'installer_theme_get_themes', array($this, 'installer_theme_filter_themes_by_subscription'), 10, 2 );
900
+ }
901
+ }
902
+
903
+ }
904
+
905
+ /** Get themes by subscription type */
906
+ protected function installer_theme_get_themes_by_subscription( $subscription_type, $repo ) {
907
+
908
+ $themes_associated_with_subscription = array();
909
+ if ( isset(WP_Installer()->settings['repositories'][$repo]['data']['packages']) ) {
910
+ //Set
911
+ $packages = WP_Installer()->settings['repositories'][$repo]['data']['packages'];
912
+ $available_themes_subscription = array();
913
+ foreach ( $packages as $package_id => $package_details ) {
914
+ if ( isset($package_details['products']) ) {
915
+ $the_products = $package_details['products'];
916
+ foreach ( $the_products as $product_slug => $product_details ) {
917
+ if ( isset($product_details['subscription_type']) ) {
918
+ $subscription_type_from_settings = intval( $product_details['subscription_type'] );
919
+ if ( $subscription_type_from_settings == $subscription_type ) {
920
+ //We found the subscription
921
+ if ( isset($product_details['themes']) ) {
922
+ $themes_associated_with_subscription = $product_details['themes'];
923
+ return $themes_associated_with_subscription;
924
+ }
925
+ }
926
+ }
927
+
928
+ }
929
+ }
930
+ }
931
+ }
932
+ return $themes_associated_with_subscription;
933
+ }
934
+
935
+ /** Filter API theme response according to user subscription */
936
+ public function installer_theme_filter_themes_by_subscription( $themes, $active_tab ) {
937
+
938
+ //Step1, we only filter OTGS themes
939
+ $orig = count( $themes );
940
+ if ( in_array( $active_tab, $this->theme_repo ) ) {
941
+ //OTGS Theme
942
+ //Step2, we retrieved the available themes based on client subscription
943
+ if ( isset($this->installer_themes[$active_tab]) ) {
944
+ $available_themes = $this->installer_themes[$active_tab];
945
+ //Step3, we filter $themes based on this info
946
+ if ( (is_array( $themes )) && (!(empty($themes))) ) {
947
+ foreach ( $themes as $k => $theme ) {
948
+ //Step4, get theme slug
949
+ if ( isset($theme['slug']) ) {
950
+ $theme_slug = $theme['slug'];
951
+ if ( !(empty($theme_slug)) ) {
952
+ if ( !(in_array( $theme_slug, $available_themes )) ) {
953
+ //This theme is not in available themes
954
+ unset($themes[$k]);
955
+ }
956
+ }
957
+ }
958
+ }
959
+ }
960
+ }
961
+ }
962
+ $new = count( $themes );
963
+ if ( $orig != $new ) {
964
+ //It is filtered
965
+ $themes = array_values( $themes );
966
+ }
967
+
968
+ return $themes;
969
+ }
970
+
971
+ /** Hook to wp_loaded, fires when all Installer theme class is ready */
972
+ public function installer_themes_support_set_up_func() {
973
+ do_action( 'installer_themes_support_set_up' );
974
+ }
975
+
976
+ }
977
+
978
+ /** Instantiate Installer Theme Class */
979
+ new Installer_Theme_Class;
embedded/otgs/installer/includes/installer-api.php ADDED
@@ -0,0 +1,116 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class WP_Installer_API{
4
+
5
+ public static function get_product_installer_link($repository_id, $package_id = false){
6
+
7
+ $menu_url = WP_Installer()->menu_url();
8
+
9
+ $url = $menu_url . '#' . $repository_id;
10
+ if($package_id){
11
+ $url .= '/' . $package_id;
12
+ }
13
+
14
+ return $url;
15
+
16
+ }
17
+
18
+ public static function get_product_price($repository_id, $package_id, $product_id, $incl_discount = false){
19
+
20
+ $price = WP_Installer()->get_product_price($repository_id, $package_id, $product_id, $incl_discount);
21
+
22
+ return $price;
23
+ }
24
+
25
+ /**
26
+ * Retrieve the preferred translation service.
27
+ *
28
+ * @since 1.6.5
29
+ *
30
+ * @param string The repository id (e.g. wpml)
31
+ * @return string The translation service id
32
+ */
33
+ public static function get_preferred_ts($repository_id = 'wpml'){
34
+
35
+ if(isset(WP_Installer()->settings['repositories'][$repository_id]['ts_info']['preferred'])){
36
+ return WP_Installer()->settings['repositories'][$repository_id]['ts_info']['preferred'];
37
+ }
38
+
39
+ return false;
40
+
41
+ }
42
+
43
+ /**
44
+ * Set the preferred translation service.
45
+ *
46
+ * @since 1.6.5
47
+ *
48
+ * @param string The translation service id
49
+ * @param string The repository id (e.g. wpml)
50
+ */
51
+ public static function set_preferred_ts( $value, $repository_id = 'wpml' ){
52
+
53
+ if( isset( WP_Installer()->settings['repositories'][$repository_id]['ts_info']['preferred'] ) ){
54
+
55
+ WP_Installer()->settings['repositories'][$repository_id]['ts_info']['preferred'] = $value;
56
+
57
+ WP_Installer()->save_settings();
58
+
59
+ }
60
+
61
+ }
62
+
63
+ /**
64
+ * Retrieve the referring translation service (if any)
65
+ *
66
+ * @since 1.6.5
67
+ *
68
+ * @param string The repository id (e.g. wpml)
69
+ * @return string The translation service id or false
70
+ */
71
+ public static function get_ts_referal($repository_id = 'wpml'){
72
+
73
+ if(isset(WP_Installer()->settings['repositories'][$repository_id]['ts_info']['referal'])){
74
+ return WP_Installer()->settings['repositories'][$repository_id]['ts_info']['referal'];
75
+ }
76
+
77
+ return false;
78
+
79
+ }
80
+
81
+ /**
82
+ * Retrieve the translation services client id for a specific repository (if any)
83
+ *
84
+ * @since 1.7.9
85
+ *
86
+ * @param string The repository id (e.g. wpml)
87
+ * @return string The client id or false
88
+ */
89
+ public static function get_ts_client_id( $repository_id = 'wpml' ){
90
+
91
+ if(isset(WP_Installer()->settings['repositories'][$repository_id]['ts_info']['client_id'])){
92
+ return WP_Installer()->settings['repositories'][$repository_id]['ts_info']['client_id'];
93
+ }
94
+
95
+ return false;
96
+
97
+ }
98
+
99
+ /**
100
+ * Retrieve the site key corresponding to a repository.
101
+ * This is a wrapper of WP_Installer::get_site_key()
102
+ * @see WP_Installer::get_site_key()
103
+ *
104
+ * @since 1.7.9
105
+ *
106
+ * @param string The repository id (e.g. wpml)
107
+ * @return string The site key (or false)
108
+ */
109
+ public static function get_site_key( $repository_id = 'wpml' ){
110
+
111
+ return WP_Installer()->get_site_key( $repository_id );
112
+
113
+ }
114
+
115
+
116
+ }
embedded/otgs/installer/includes/installer-upgrader-skins.php ADDED
@@ -0,0 +1,37 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class Installer_Upgrader_Skins extends WP_Upgrader_Skin{
3
+
4
+ function __construct($args = array()){
5
+ $defaults = array( 'url' => '', 'nonce' => '', 'title' => '', 'context' => false );
6
+ $this->options = wp_parse_args($args, $defaults);
7
+ }
8
+
9
+ function header(){
10
+
11
+ }
12
+
13
+ function footer(){
14
+
15
+ }
16
+
17
+ function error($error){
18
+ $this->installer_error = $error;
19
+ }
20
+
21
+ function add_strings(){
22
+
23
+ }
24
+
25
+ function feedback($string){
26
+
27
+ }
28
+
29
+ function before(){
30
+
31
+ }
32
+
33
+ function after(){
34
+
35
+ }
36
+
37
+ }
embedded/otgs/installer/includes/installer.class.php ADDED
@@ -0,0 +1,2559 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ final class WP_Installer{
4
+ protected static $_instance = null;
5
+
6
+ public $settings = array();
7
+
8
+ private $repositories = array();
9
+
10
+ protected $api_debug = '';
11
+
12
+ private $config = array();
13
+
14
+ protected $_plugins_renew_warnings = array();
15
+
16
+ protected $_gz_on = false;
17
+
18
+ private $admin_messages = array();
19
+
20
+ private $_using_icl = false;
21
+ private $_wpml_version = false;
22
+
23
+ private $package_source = array();
24
+
25
+ const SITE_KEY_VALIDATION_SOURCE_OTHER = 0;
26
+ const SITE_KEY_VALIDATION_SOURCE_DOWNLOAD_SPECIFIC = 1;
27
+ const SITE_KEY_VALIDATION_SOURCE_DOWNLOAD_REPORT = 2;
28
+ const SITE_KEY_VALIDATION_SOURCE_REGISTRATION = 3;
29
+ const SITE_KEY_VALIDATION_SOURCE_REVALIDATION = 4;
30
+ const SITE_KEY_VALIDATION_SOURCE_UPDATES_CHECK = 5;
31
+
32
+ public $dependencies;
33
+
34
+ public static function instance() {
35
+
36
+ if ( is_null( self::$_instance ) ) {
37
+ self::$_instance = new self();
38
+ }
39
+
40
+ return self::$_instance;
41
+ }
42
+
43
+ public function __construct(){
44
+
45
+ if(!is_admin() || !is_user_logged_in()) return; //Only for admin
46
+
47
+ $this->_gz_on = function_exists('gzuncompress') && function_exists('gzcompress');
48
+ $this->settings = $this->get_settings();
49
+
50
+ add_action('admin_notices', array($this, 'show_site_key_nags'));
51
+
52
+ add_action('admin_notices', array($this, 'show_admin_messages'));
53
+
54
+ add_action('admin_init', array($this, 'load_embedded_plugins'), 0);
55
+
56
+ add_action('admin_menu', array($this, 'menu_setup'));
57
+ add_action('network_admin_menu', array($this, 'menu_setup'));
58
+
59
+ if(defined('DOING_AJAX') && isset($_POST['action']) && $_POST['action'] == 'installer_download_plugin'){
60
+ add_filter( 'site_transient_update_plugins', array( $this, 'plugins_upgrade_check') );
61
+ }
62
+ add_filter('plugins_api', array( $this, 'custom_plugins_api_call'), 10, 3);
63
+ add_filter('pre_set_site_transient_update_plugins', array( $this, 'plugins_upgrade_check'));
64
+
65
+ // register repositories
66
+ $this->load_repositories_list();
67
+
68
+ if( empty($this->settings['last_repositories_update']) || time() - $this->settings['last_repositories_update'] > 86400
69
+ || ( isset($_GET['force-check']) && $_GET['force-check'] == 1 ) ){
70
+ $this->refresh_repositories_data();
71
+ }
72
+
73
+ // default config
74
+ $this->config['plugins_install_tab'] = false;
75
+
76
+ add_action('init', array($this, 'init'));
77
+
78
+ //add_filter('wp_installer_buy_url', array($this, 'append_parameters_to_buy_url'));
79
+
80
+ add_action('init', array($this,'load_locale'));
81
+
82
+ }
83
+
84
+ public function get_repositories() {
85
+
86
+ return $this->repositories;
87
+
88
+ }
89
+
90
+ public function set_config($key, $value){
91
+
92
+ $this->config[$key] = $value;
93
+
94
+ }
95
+
96
+ public function init(){
97
+ global $pagenow;
98
+
99
+ $this->dependencies = new Installer_Dependencies;
100
+
101
+ if(empty($this->settings['_pre_1_0_clean_up'])) {
102
+ $this->_pre_1_0_clean_up();
103
+ }
104
+
105
+ $this->settings = $this->_old_products_format_backwards_compatibility($this->settings);
106
+
107
+ if ( !function_exists( 'get_plugins' ) ) {
108
+ require_once ABSPATH . 'wp-admin/includes/plugin.php';
109
+ }
110
+
111
+ $this->_using_icl = function_exists('wpml_site_uses_icl') && wpml_site_uses_icl();
112
+ $this->_wpml_version = defined('ICL_SITEPRESS_VERSION') ? ICL_SITEPRESS_VERSION : '';
113
+
114
+ wp_enqueue_script('installer-admin', $this->res_url() . '/res/js/admin.js', array('jquery'), $this->version());
115
+ wp_enqueue_style('installer-admin', $this->res_url() . '/res/css/admin.css', array(), $this->version());
116
+
117
+ $translation_array = array(
118
+ 'installing' => __( 'Installing %s', 'installer' ),
119
+ 'updating' => __( 'Updating %s', 'installer' ),
120
+ 'activating' => __( 'Activating %s', 'installer' )
121
+ );
122
+
123
+ wp_localize_script( 'installer-admin', 'installer_strings', $translation_array );
124
+
125
+ if($pagenow == 'plugins.php'){
126
+ add_action('admin_notices', array($this, 'setup_plugins_page_notices'));
127
+ add_action('admin_notices', array($this, 'setup_plugins_renew_warnings'), 10);
128
+ add_action('admin_notices', array($this, 'queue_plugins_renew_warnings'), 20);
129
+
130
+ add_action('admin_init', array($this, 'setup_plugins_action_links'));
131
+
132
+ }
133
+
134
+ if($this->is_repositories_page()){
135
+ add_action('admin_init', array($this, 'validate_repository_subscription'));
136
+ }
137
+
138
+ if(defined('DOING_AJAX')){
139
+ add_action('wp_ajax_save_site_key', array($this, 'save_site_key'));
140
+ add_action('wp_ajax_remove_site_key', array($this, 'remove_site_key'));
141
+ add_action('wp_ajax_update_site_key', array($this, 'update_site_key'));
142
+
143
+ add_action('wp_ajax_installer_download_plugin', array($this, 'download_plugin_ajax_handler'));
144
+ add_action('wp_ajax_installer_activate_plugin', array($this, 'activate_plugin'));
145
+
146
+ add_action('wp_ajax_installer_dismiss_nag', array($this, 'dismiss_nag'));
147
+ }
148
+
149
+ if($pagenow == 'update.php'){
150
+ if(isset($_GET['action']) && $_GET['action'] == 'update-selected'){
151
+ add_action('admin_head', array($this, 'plugin_upgrade_custom_errors')); //iframe/bulk
152
+ }else{
153
+ add_action('all_admin_notices', array($this, 'plugin_upgrade_custom_errors')); //regular/singular
154
+ }
155
+ }
156
+
157
+ // WP 4.2
158
+ if(defined('DOING_AJAX')){
159
+ add_action('wp_ajax_update-plugin', array($this, 'plugin_upgrade_custom_errors'), 0); // high priority, before WP
160
+ }
161
+
162
+ //Include theme support
163
+ include_once $this->plugin_path() . '/includes/class-installer-theme.php';
164
+
165
+ // Extra information about the source of Installer
166
+ $package_source_file = $this->plugin_path() . '/installer-source.json';
167
+ if( file_exists( $package_source_file ) ){
168
+ $this->package_source = json_decode( file_get_contents( $package_source_file ) );
169
+ }
170
+ }
171
+
172
+ protected function log($message){
173
+ if( defined('WPML_INSTALLER_LOGGING') && WPML_INSTALLER_LOGGING ){
174
+ if($fh = @fopen( $this->plugin_path() . '/installer.log', 'a' )){
175
+ fwrite($fh, current_time( 'mysql' ) . "\t" . $message . "\n");
176
+ }
177
+ }
178
+ }
179
+
180
+ public function register_admin_message($text, $type = 'updated'){
181
+ $this->admin_messages[] = array('text' => $text, 'type' => $type);
182
+ }
183
+
184
+ public function show_admin_messages(){
185
+ if(!empty($this->admin_messages)){
186
+ $types = array( 'error', 'updated', 'notice' );
187
+ foreach($this->admin_messages as $message){
188
+ $class = in_array( $message['type'], $types ) ? $message['type'] : 'updated';
189
+ ?>
190
+ <div class="<?php echo $class ?>">
191
+ <p>
192
+ <?php echo $message['text'] ?>
193
+ </p>
194
+ </div>
195
+ <?php
196
+ }
197
+ }
198
+ }
199
+
200
+ public function load_locale(){
201
+ $locale = get_locale();
202
+ $locale = apply_filters( 'plugin_locale', $locale, 'installer' );
203
+ $mo_file = $this->plugin_path() . '/locale/installer-' . $locale . '.mo';
204
+ if(file_exists($mo_file)){
205
+ load_textdomain( 'installer', $mo_file );
206
+ }
207
+ }
208
+
209
+ public function load_embedded_plugins(){
210
+ if(file_exists($this->plugin_path() . '/embedded-plugins' )) {
211
+ include_once $this->plugin_path() . '/embedded-plugins/embedded-plugins.class.php';
212
+ $this->installer_embedded_plugins = new Installer_Embedded_Plugins();
213
+ }
214
+ }
215
+
216
+ public function menu_setup(){
217
+ global $pagenow;
218
+
219
+ if(is_multisite() && !is_network_admin()){
220
+ $this->menu_multisite_redirect();
221
+ add_options_page(__('Installer', 'installer'), __('Installer', 'installer'), 'manage_options', 'installer', array($this, 'show_products')) ;
222
+ }else{
223
+ if($this->config['plugins_install_tab'] && is_admin() && $pagenow == 'plugin-install.php'){
224
+ // Default GUI, under Plugins -> Install
225
+ add_filter('install_plugins_tabs', array($this, 'add_install_plugins_tab'));
226
+ add_action('install_plugins_commercial', array($this, 'show_products'));
227
+ }
228
+ }
229
+
230
+ }
231
+
232
+ public function menu_url(){
233
+ if(is_multisite()){
234
+ if(is_network_admin()){
235
+ $url = network_admin_url('plugin-install.php?tab=commercial');
236
+ }else{
237
+ $url = admin_url('options-general.php?page=installer');
238
+ }
239
+ }else{
240
+ $url = admin_url('plugin-install.php?tab=commercial');
241
+ }
242
+ return $url;
243
+ }
244
+
245
+ private function menu_multisite_redirect(){
246
+ global $pagenow;
247
+
248
+ if($pagenow == 'plugin-install.php' && isset($_GET['tab']) && $_GET['tab'] == 'commercial'){
249
+ wp_redirect($this->menu_url());
250
+ exit;
251
+ }
252
+
253
+ }
254
+
255
+ private function _pre_1_0_clean_up(){
256
+ global $wpdb;
257
+
258
+ if(!defined('WPRC_VERSION')){
259
+ $old_tables = array(
260
+ $wpdb->prefix . 'wprc_cached_requests',
261
+ $wpdb->prefix . 'wprc_extension_types',
262
+ $wpdb->prefix . 'wprc_extensions',
263
+ $wpdb->prefix . 'wprc_repositories',
264
+ $wpdb->prefix . 'wprc_repositories_relationships',
265
+ );
266
+
267
+ foreach($old_tables as $table){
268
+ $wpdb->query(sprintf("DROP TABLE IF EXISTS %s", $table));
269
+ }
270
+
271
+ }
272
+
273
+ $this->settings['_pre_1_0_clean_up'] = true;
274
+ $this->save_settings();
275
+ }
276
+
277
+ public function setup_plugins_action_links(){
278
+
279
+ $plugins = get_plugins();
280
+
281
+ $repositories_plugins = array();
282
+
283
+ if( !empty($this->settings['repositories']) ) {
284
+
285
+ foreach ( $this->settings['repositories'] as $repository_id => $repository ) {
286
+
287
+ foreach ( $repository['data']['packages'] as $package ) {
288
+
289
+ foreach ( $package['products'] as $product ) {
290
+
291
+ foreach ( $product['plugins'] as $plugin_slug ) {
292
+
293
+ $download = $this->settings['repositories'][$repository_id]['data']['downloads']['plugins'][$plugin_slug];
294
+
295
+ if ( !isset($repositories_plugins[$repository_id][$download['slug']]) ) {
296
+ $repositories_plugins[$repository_id][$download['slug']] = array(
297
+ 'name' => $download['name'],
298
+ 'registered' => $this->plugin_is_registered( $repository_id, $download['slug'] ) ? 1 : 0
299
+ );
300
+ }
301
+
302
+ }
303
+
304
+ }
305
+
306
+ }
307
+
308
+ foreach ( $plugins as $plugin_id => $plugin ) {
309
+
310
+ $wp_plugin_slug = dirname( $plugin_id );
311
+ if ( empty($wp_plugin_slug) ) {
312
+ $wp_plugin_slug = basename( $plugin_id, '.php' );
313
+ }
314
+
315
+ foreach ( $repositories_plugins as $repository_id => $r_plugins ) {
316
+
317
+ foreach ( $r_plugins as $slug => $r_plugin ) {
318
+
319
+ if ( $wp_plugin_slug == $slug || $r_plugin['name'] == $plugin['Name'] || $r_plugin['name'] == $plugin['Title'] ) { //match order: slug, name, title
320
+
321
+ if ( $r_plugin['registered'] ) {
322
+ add_filter( 'plugin_action_links_' . $plugin_id, array($this, 'plugins_action_links_registered') );
323
+ } else {
324
+ add_filter( 'plugin_action_links_' . $plugin_id, array($this, 'plugins_action_links_not_registered') );
325
+ }
326
+
327
+ }
328
+
329
+ }
330
+
331
+ }
332
+
333
+
334
+ }
335
+
336
+ }
337
+ }
338
+
339
+ }
340
+
341
+ public function plugins_action_links_registered($links){
342
+ $links[] = '<a href="' . $this->menu_url() . '">' . __('Registered', 'installer') . '</a>';
343
+ return $links;
344
+ }
345
+
346
+ public function plugins_action_links_not_registered($links){
347
+ $links[] = '<a href="' . $this->menu_url() . '">' . __('Register', 'installer') . '</a>';
348
+ return $links;
349
+ }
350
+
351
+ public function plugin_is_registered($repository_id, $slug){
352
+
353
+ $registered = false;
354
+
355
+ if( $this->repository_has_valid_subscription($repository_id) ){
356
+
357
+ $subscription_type = $this->get_subscription_type_for_repository($repository_id);
358
+ $r_plugins = array();
359
+
360
+ foreach($this->settings['repositories'][$repository_id]['data']['packages'] as $package){
361
+
362
+ foreach($package['products'] as $product){
363
+
364
+ if( $product['subscription_type'] == $subscription_type || $this->have_superior_subscription($subscription_type, $product) ) {
365
+
366
+ foreach ($product['plugins'] as $plugin_slug) {
367
+
368
+ $download = $this->settings['repositories'][$repository_id]['data']['downloads']['plugins'][$plugin_slug];
369
+
370
+ if (!isset($rep_plugins[$download['slug']])) {
371
+ $r_plugins[$download['slug']] = $download['slug'];
372
+ }
373
+
374
+ }
375
+
376
+ }
377
+
378
+ }
379
+
380
+ }
381
+
382
+ $registered = isset($r_plugins[$slug]);
383
+
384
+ }
385
+
386
+
387
+ return $registered;
388
+
389
+ }
390
+
391
+ public function version(){
392
+ return WP_INSTALLER_VERSION;
393
+ }
394
+
395
+ public function plugin_path() {
396
+ return untrailingslashit( plugin_dir_path( dirname(__FILE__) ) );
397
+ }
398
+
399
+ public function plugin_url() {
400
+ if(isset($this->config['in_theme_folder']) && !empty($this->config['in_theme_folder'])){
401
+ $url = untrailingslashit(get_template_directory_uri() . '/' . $this->config['in_theme_folder']);
402
+ }else{
403
+ $url = untrailingslashit( plugins_url( '/', dirname(__FILE__) ) );
404
+ }
405
+
406
+ return $url;
407
+ }
408
+
409
+ public function is_repositories_page(){
410
+ global $pagenow;
411
+
412
+ return $pagenow == 'plugin-install.php' && isset($_GET['tab']) && $_GET['tab'] == 'commercial';
413
+ }
414
+
415
+ public function res_url(){
416
+ if(isset($this->config['in_theme_folder']) && !empty($this->config['in_theme_folder'])){
417
+ $url = untrailingslashit(get_template_directory_uri() . '/' . $this->config['in_theme_folder']);
418
+ }else{
419
+ $url = $this->plugin_url();
420
+ }
421
+ return $url;
422
+ }
423
+
424
+ public function save_settings(){
425
+
426
+ $_settings = serialize($this->settings);
427
+ if($this->_gz_on){
428
+ $_settings = gzcompress($_settings);
429
+ }
430
+ $_settings = base64_encode($_settings);
431
+
432
+ update_option( 'wp_installer_settings', $_settings );
433
+
434
+ if( is_multisite() && is_main_site() && isset($this->settings['repositories']) ){
435
+ $network_settings = array();
436
+
437
+ foreach( $this->settings['repositories'] as $rep_id => $repository ){
438
+ if( isset($repository['subscription']) )
439
+ $network_settings[$rep_id] = $repository['subscription'];
440
+ }
441
+
442
+ update_site_option( 'wp_installer_network', $network_settings );
443
+
444
+
445
+ }
446
+
447
+ }
448
+
449
+ public function get_settings($refresh = false){
450
+
451
+ if($refresh || empty($this->settings)){
452
+
453
+ $_settings = get_option('wp_installer_settings');
454
+
455
+
456
+ if (is_array($_settings) || empty($_settings)) { //backward compatibility 1.1
457
+ $this->settings = $_settings;
458
+
459
+ } else {
460
+ $_settings = base64_decode($_settings);
461
+ if ($this->_gz_on) {
462
+ $_settings = gzuncompress($_settings);
463
+ }
464
+ $this->settings = unserialize($_settings);
465
+ }
466
+
467
+ if (is_multisite() && isset($this->settings['repositories'])) {
468
+ $network_settings = maybe_unserialize(get_site_option('wp_installer_network'));
469
+ if ($network_settings) {
470
+ foreach ($this->settings['repositories'] as $rep_id => $repository) {
471
+ if (isset($network_settings[$rep_id])) {
472
+ $this->settings['repositories'][$rep_id]['subscription'] = $network_settings[$rep_id];
473
+ }
474
+ }
475
+ }
476
+ }
477
+
478
+
479
+ $this->settings = $this->_pre_1_6_backwards_compatibility($this->settings);
480
+
481
+ $this->settings = $this->_old_products_format_backwards_compatibility($this->settings);
482
+
483
+ }
484
+
485
+
486
+ return $this->settings;
487
+ }
488
+
489
+ //backward compatibility, will remove 'basename' in version 1.8
490
+ private function _pre_1_6_backwards_compatibility($settings){
491
+
492
+ if( version_compare($this->version(), '1.8', '<') && !empty($settings['repositories']) ){
493
+
494
+ foreach ($settings['repositories'] as $repository_id => $repository) {
495
+
496
+ foreach ($repository['data']['downloads']['plugins'] as $slug => $download) {
497
+
498
+ $settings['repositories'][$repository_id]['data']['downloads']['plugins'][$slug]['slug'] = $download['basename'];
499
+
500
+ }
501
+ }
502
+
503
+ }
504
+
505
+ return $settings;
506
+
507
+ }
508
+
509
+ //backward compatibility - support old products list format (downloads under products instead of global downloads list)
510
+ private function _old_products_format_backwards_compatibility($settings){
511
+
512
+ if( version_compare($this->version(), '1.8', '<') && !empty($settings['repositories']) && empty($this->_old_products_format_backwards_compatibility) ) {
513
+
514
+ foreach ($settings['repositories'] as $repository_id => $repository) {
515
+
516
+ $populate_downloads = false;
517
+
518
+ foreach ($repository['data']['packages'] as $package_id => $package) {
519
+
520
+ foreach ($package['products'] as $product_id => $product) {
521
+
522
+ if (!isset($product['plugins'])) {
523
+
524
+ $populate_downloads = true;
525
+
526
+ foreach ($product['downloads'] as $download_id => $download) {
527
+
528
+ $settings['repositories'][$repository_id]['data']['packages'][$package_id]['products'][$product_id]['plugins'][] = $download['slug'];
529
+
530
+ }
531
+
532
+ }
533
+
534
+ }
535
+
536
+ }
537
+
538
+ if ($populate_downloads) {
539
+
540
+ // Add downloads branch
541
+ foreach ($repository['data']['packages'] as $package_id => $package) {
542
+
543
+ foreach ($package['products'] as $product_id => $product) {
544
+
545
+ foreach ($product['downloads'] as $download_id => $download) {
546
+
547
+ if (!isset($settings['repositories'][$repository_id]['data']['downloads']['plugins'][$download['slug']])) {
548
+ $settings['repositories'][$repository_id]['data']['downloads']['plugins'][$download['slug']] = $download;
549
+ }
550
+
551
+ $settings['repositories'][$repository_id]['data']['packages'][$package_id]['products'][$product_id]['plugins'][] = $download['slug'];
552
+ }
553
+
554
+ unset($settings['repositories'][$repository_id]['data']['packages'][$package_id]['products'][$product_id]['downloads']);
555
+
556
+ }
557
+
558
+ }
559
+
560
+ }
561
+
562
+ }
563
+
564
+ $this->_old_products_format_backwards_compatibility = true;
565
+
566
+ }
567
+
568
+ return $settings;
569
+
570
+ }
571
+
572
+ public function get_installer_site_url( $repository_id = false ){
573
+ global $current_site;
574
+
575
+ $site_url = get_site_url();
576
+
577
+ if( $repository_id && is_multisite() && isset( $this->settings['repositories'] ) ){
578
+ $network_settings = maybe_unserialize( get_site_option('wp_installer_network') );
579
+
580
+ if ( isset( $network_settings[$repository_id] ) ) {
581
+ $site_url = get_site_url( $current_site->blog_id );
582
+ }
583
+
584
+ }
585
+
586
+ return $site_url;
587
+ }
588
+
589
+ public function show_site_key_nags(){
590
+ $screen = get_current_screen();
591
+
592
+ if($screen->base == 'settings_page_installer' || ($screen->base == 'plugin-install' && isset($_GET['tab']) && $_GET['tab'] == 'commercial')){
593
+ return;
594
+ }
595
+
596
+ if(!empty($this->config['site_key_nags'])){
597
+
598
+ foreach($this->config['site_key_nags'] as $nag){
599
+
600
+ if(!$this->repository_has_subscription($nag['repository_id'] )){
601
+ $show = true;
602
+ if(!empty($nag['condition_cb'])){
603
+ $show = call_user_func($nag['condition_cb']);
604
+ }
605
+
606
+ if(empty($this->settings['dismissed_nags'][$nag['repository_id']]) && $show){
607
+ echo '<div class="updated error otgs-is-dismissible"><p>';
608
+ printf(__("To get automatic updates, you need to register %s for this site. %sRegister %s%s", 'sitepress'),
609
+ $nag['product_name'], '<a class="button-primary" href="' . $this->menu_url() . '">', $nag['product_name'], '</a>');
610
+
611
+ echo '</p>';
612
+ echo '<span class="installer-dismiss-nag notice-dismiss" data-repository="' . $nag['repository_id'] . '"><span class="screen-reader-text">' . __('Dismiss', 'sitepress') . '</span></span>';
613
+ echo '</div>';
614
+ }
615
+ }
616
+
617
+ }
618
+
619
+ }
620
+
621
+ }
622
+
623
+ public function dismiss_nag(){
624
+ $this->settings['dismissed_nags'][$_POST['repository']] = 1;
625
+
626
+ $this->save_settings();
627
+
628
+ echo json_encode(array());
629
+ exit;
630
+ }
631
+
632
+ public function add_install_plugins_tab($tabs){
633
+
634
+ $tabs['commercial'] = __('Commercial', 'installer');
635
+
636
+ return $tabs;
637
+ }
638
+
639
+ public function load_repositories_list(){
640
+ global $wp_installer_instances;
641
+
642
+ foreach ($wp_installer_instances as $instance) {
643
+
644
+ if (file_exists(dirname($instance['bootfile']) . '/repositories.xml')) {
645
+ $config_file = dirname($instance['bootfile']) . '/repositories.xml';
646
+
647
+ if (file_exists(dirname($instance['bootfile']) . '/repositories.sandbox.xml')) {
648
+ $config_file = dirname($instance['bootfile']) . '/repositories.sandbox.xml';
649
+ add_filter('https_ssl_verify', '__return_false');
650
+ }
651
+
652
+ $repos = simplexml_load_file($config_file);
653
+
654
+ if($repos) {
655
+ foreach ($repos as $repo) {
656
+ $id = strval($repo->id);
657
+
658
+ $data['api-url'] = strval($repo->apiurl);
659
+ $data['products'] = strval($repo->products);
660
+
661
+ // excludes rule;
662
+ if (isset($this->config['repositories_exclude']) && in_array($id, $this->config['repositories_exclude'])) {
663
+ continue;
664
+ }
665
+
666
+ // includes rule;
667
+ if (isset($this->config['repositories_include']) && !in_array($id, $this->config['repositories_include'])) {
668
+ continue;
669
+ }
670
+
671
+ $this->repositories[$id] = $data;
672
+
673
+ }
674
+ }
675
+
676
+ }
677
+ }
678
+
679
+ }
680
+
681
+ public function filter_repositories_list(){
682
+
683
+ if(!empty($this->settings['repositories'])) {
684
+ foreach ($this->settings['repositories'] as $id => $repo_data) {
685
+
686
+ // excludes rule;
687
+ if (isset($this->config['repositories_exclude']) && in_array($id, $this->config['repositories_exclude'])) {
688
+ unset($this->settings['repositories'][$id]);
689
+ }
690
+
691
+ // includes rule;
692
+ if (isset($this->config['repositories_include']) && !in_array($id, $this->config['repositories_include'])) {
693
+ unset($this->settings['repositories'][$id]);
694
+ }
695
+
696
+
697
+ }
698
+ }
699
+
700
+
701
+ }
702
+
703
+ public function refresh_repositories_data(){
704
+ static $checked = false;
705
+
706
+ if( defined('OTGS_DISABLE_AUTO_UPDATES') && OTGS_DISABLE_AUTO_UPDATES && empty($_GET['force-check']) || $checked ){
707
+
708
+ if(empty($this->settings['repositories']) && $this->is_repositories_page()){
709
+
710
+ foreach($this->repositories as $id => $data) {
711
+ $repository_names[] = $id;
712
+
713
+ }
714
+
715
+ $error = sprintf(__("Installer cannot display the products information because the automatic updating for %s was explicitly disabled with the configuration below (usually in wp-config.php):", 'installer'), strtoupper( join(', ', $repository_names) ));
716
+ $error .= '<br /><br /><code>define("OTGS_DISABLE_AUTO_UPDATES", true);</code><br /><br />';
717
+ $error .= sprintf(__("In order to see the products information, please run the %smanual updates check%s to initialize the products list or (temporarily) remove the above code.", 'installer'), '<a href="' . admin_url('update-core.php') . '">', '</a>');
718
+
719
+ $this->register_admin_message($error, 'error');
720
+
721
+
722
+ }
723
+
724
+ return;
725
+ }
726
+
727
+ $checked = true;
728
+
729
+ foreach($this->repositories as $id => $data){
730
+
731
+ $response = wp_remote_get($data['products']);
732
+
733
+ if(is_wp_error($response)){
734
+ // http fallback
735
+ $data['products'] = preg_replace("@^https://@", 'http://', $data['products']);
736
+ $response = wp_remote_get($data['products']);
737
+ }
738
+
739
+ if(is_wp_error($response)){
740
+
741
+ $error = sprintf(__("Installer cannot contact our updates server to get information about the available products and check for new versions. If you are seeing this message for the first time, you can ignore it, as it may be a temporary communication problem. If the problem persists and your WordPress admin is slowing down, you can disable automated version checks. Add the following line to your wp-config.php file:", 'installer'), strtoupper($id));
742
+ $error .= '<br /><br /><code>define("OTGS_DISABLE_AUTO_UPDATES", true);</code>';
743
+
744
+ $this->register_admin_message($error, 'error');
745
+
746
+ continue;
747
+ }
748
+
749
+ if($response && isset($response['response']['code']) && $response['response']['code'] == 200){
750
+ $body = wp_remote_retrieve_body($response);
751
+ if($body){
752
+ $products = json_decode($body, true);
753
+
754
+ if(is_array($products)){
755
+ $this->settings['repositories'][$id]['data'] = $products;
756
+ $this->settings = $this->_pre_1_6_backwards_compatibility($this->settings);
757
+ }
758
+ }
759
+
760
+ }
761
+
762
+ $this->log( sprintf("Checked for %s updates: %s", $id, $data['products']) );
763
+
764
+
765
+ }
766
+
767
+ // cleanup
768
+ if(empty($this->settings['repositories'])){
769
+ $this->settings['repositories'] = array();
770
+ }
771
+ foreach($this->settings['repositories'] as $id => $data){
772
+ if(!in_array($id, array_keys($this->repositories))){
773
+ unset($this->settings['repositories'][$id]);
774
+ }
775
+ }
776
+
777
+ $this->settings['last_repositories_update']= time();
778
+
779
+ $this->save_settings();
780
+
781
+ }
782
+
783
+ public function show_products($args = array()){
784
+
785
+ $screen = get_current_screen();
786
+
787
+ if($screen->base == 'settings_page_installer'){ // settings page
788
+ echo '<div class="wrap">';
789
+ echo '<h2>' . __('Installer', 'installer') . '</h2>';
790
+ echo '<br />';
791
+ }
792
+
793
+ if(!is_array($args)) $args = array();
794
+ if(empty($args['template'])) $args['template'] = 'default';
795
+
796
+ $this->filter_repositories_list();
797
+
798
+ if(!empty($this->settings['repositories'])){
799
+
800
+ $this->localize_strings();
801
+ $this->set_filtered_prices($args);
802
+ $this->set_hierarchy_and_order();
803
+
804
+ foreach($this->settings['repositories'] as $repository_id => $repository){
805
+
806
+ if($args['template'] == 'compact'){
807
+
808
+ if(isset($args['repository']) && $args['repository'] == $repository_id){
809
+ include $this->plugin_path() . '/templates/products-compact.php';
810
+ }
811
+
812
+ }else{
813
+
814
+ include $this->plugin_path() . '/templates/repository-listing.php';
815
+
816
+ }
817
+
818
+ unset($site_key, $subscription_type, $expired, $upgrade_options, $products_avaliable);
819
+
820
+ }
821
+
822
+ }else{
823
+
824
+ echo '<center>' . __('No repositories defined.', 'installer') . '</center>';
825
+
826
+ }
827
+
828
+ if($screen->base == 'settings_page_installer'){ // settings page
829
+ echo '</div>';
830
+ }
831
+
832
+
833
+ }
834
+
835
+ public function get_product_price($repository_id, $package_id, $product_id, $incl_discount = false){
836
+
837
+ $price = false;
838
+
839
+ foreach($this->settings['repositories'][$repository_id]['data']['packages'] as $package ){
840
+
841
+ if($package['id'] == $package_id){
842
+ if(isset($package['products'][$product_id])){
843
+ if($incl_discount && isset($package['products'][$product_id]['price_disc'])){
844
+ $price = $package['products'][$product_id]['price_disc'];
845
+ }elseif(isset($package['products'][$product_id]['price'])){
846
+ $price = $package['products'][$product_id]['price'];
847
+ }
848
+ }
849
+ break;
850
+ }
851
+ }
852
+
853
+ return $price;
854
+ }
855
+
856
+ private function _render_product_packages($packages, $subscription_type, $expired, $upgrade_options, $repository_id){
857
+
858
+ $data = array();
859
+
860
+ foreach($packages as $package_id => $package){
861
+
862
+ $row = array('products' => array(), 'downloads' => array());
863
+ foreach($package['products'] as $product){
864
+
865
+ // filter out free subscriptions from being displayed as buying options
866
+ if( empty($product['price']) && (empty($subscription_type) || $expired) ){
867
+ continue;
868
+ }
869
+
870
+ // buy base
871
+ if(empty($subscription_type) || $expired) {
872
+
873
+ $p['url'] = $this->append_parameters_to_buy_url($product['url'], $repository_id);
874
+ if (!empty($product['price_disc'])) {
875
+ $p['label'] = $product['call2action'] . ' - ' . sprintf('$%s %s$%d%s (USD)', $product['price_disc'], '&nbsp;&nbsp;<del>', $product['price'], '</del>');
876
+ } else {
877
+ $p['label'] = $product['call2action'] . ' - ' . sprintf('$%d (USD)', $product['price']);
878
+ }
879
+ $row['products'][] = $p;
880
+
881
+ // renew
882
+ } elseif(isset($subscription_type) && $product['subscription_type'] == $subscription_type){
883
+
884
+ if($product['renewals']) {
885
+ foreach ($product['renewals'] as $renewal) {
886
+ $p['url'] = $this->append_parameters_to_buy_url($renewal['url'], $repository_id);
887
+ $p['label'] = $renewal['call2action'] . ' - ' . sprintf('$%d (USD)', $renewal['price']);
888
+ }
889
+
890
+ $row['products'][] = $p;
891
+ }
892
+
893
+ }
894
+
895
+ // upgrades
896
+ if(!empty($upgrade_options[$product['subscription_type']])){
897
+
898
+ foreach($upgrade_options[$product['subscription_type']] as $stype => $upgrade){
899
+ if($stype != $subscription_type) continue;
900
+
901
+ $p['url'] = $this->append_parameters_to_buy_url($upgrade['url'], $repository_id);
902
+ if (!empty($upgrade['price_disc'])) {
903
+ $p['label'] = $upgrade['call2action'] . ' - ' . sprintf('$%s %s$%d%s (USD)', $upgrade['price_disc'], '&nbsp;&nbsp;<del>', $upgrade['price'], '</del>');
904
+ } else {
905
+ $p['label'] = $upgrade['call2action'] . ' - ' . sprintf('$%d (USD)', $upgrade['price']);
906
+ }
907
+ $row['products'][] = $p;
908
+
909
+ }
910
+
911
+ }
912
+
913
+ // downloads
914
+ if(isset($subscription_type) && !$expired && $product['subscription_type'] == $subscription_type){
915
+ foreach($product['plugins'] as $plugin_slug){
916
+
917
+ $row['downloads'][] = $this->settings['repositories'][$repository_id]['data']['downloads']['plugins'][$plugin_slug];
918
+
919
+ }
920
+
921
+ }
922
+
923
+ //subpackages
924
+ if(!empty($package['sub-packages'])){
925
+ $row['sub-packages'] = $package['sub-packages'];
926
+ }
927
+
928
+ }
929
+
930
+ $row['id'] = $package['id'];
931
+ $row['image_url'] = $package['image_url'];
932
+ $row['name'] = $package['name'];
933
+ $row['description'] = $package['description'];
934
+
935
+ if(!empty($row['products']) || !empty($row['downloads']) || !empty($row['sub-packages'])){
936
+ $data[] = $row;
937
+ }
938
+
939
+
940
+ }
941
+
942
+ return $data;
943
+
944
+ }
945
+
946
+ public function get_extra_url_parameters(){
947
+
948
+ $parameters = array();
949
+
950
+ if(!empty($this->package_source)){
951
+ foreach($this->package_source as $key => $val){
952
+ $parameters[$key] = $val;
953
+ }
954
+ }
955
+
956
+ $parameters['installer_version'] = WP_INSTALLER_VERSION;
957
+ $parameters['theme'] = wp_get_theme()->get( 'Name' );
958
+ $parameters['site_name'] = get_bloginfo( 'name' );
959
+
960
+ return $parameters;
961
+ }
962
+
963
+ public function append_parameters_to_buy_url($url, $repository_id, $args = array()){
964
+
965
+ $url = add_query_arg( array('icl_site_url' => $this->get_installer_site_url( $repository_id ) ), $url );
966
+
967
+ $affiliate_id = false;
968
+ $affiliate_key = false;
969
+
970
+ // Add extra parameters for custom Installer packages
971
+ if( !empty($this->package_source) ){
972
+ $extra = $this->get_extra_url_parameters();
973
+
974
+ if( !empty($extra['repository']) && $extra['repository'] == $repository_id ) {
975
+
976
+ if( !empty($extra['affiliate_key']) && !empty($extra['user_id']) ){
977
+ $this->config['affiliate_id:' . $repository_id] = $extra['user_id'];
978
+ $this->config['affiliate_key:' . $repository_id] = $extra['affiliate_key'];
979
+ unset($extra['affiliate_key'], $extra['user_id'], $extra['repository']); // no need to include these ones
980
+ }
981
+
982
+ $url = add_query_arg($extra, $url);
983
+ }
984
+
985
+ }
986
+
987
+ if(isset($this->config['affiliate_id:' . $repository_id]) && isset($this->config['affiliate_key:' . $repository_id])){
988
+
989
+ $affiliate_id = $this->config['affiliate_id:' . $repository_id];
990
+ $affiliate_key = $this->config['affiliate_key:' . $repository_id];
991
+
992
+ }elseif(isset($args['affiliate_id:' . $repository_id]) && isset($args['affiliate_key:' . $repository_id])){
993
+
994
+ $affiliate_id = $args['affiliate_id:' . $repository_id];
995
+ $affiliate_key = $args['affiliate_key:' . $repository_id];
996
+
997
+ }elseif(defined('ICL_AFFILIATE_ID') && defined('ICL_AFFILIATE_KEY')){ //support for 1 repo
998
+
999
+ $affiliate_id = ICL_AFFILIATE_ID;
1000
+ $affiliate_key = ICL_AFFILIATE_KEY;
1001
+
1002
+ }elseif(isset($this->config['affiliate_id']) && isset($this->config['affiliate_key'])) {
1003
+ // BACKWARDS COMPATIBILITY
1004
+ $affiliate_id = $this->config['affiliate_id'];
1005
+ $affiliate_key = $this->config['affiliate_key'];
1006
+ }
1007
+
1008
+ if($affiliate_id && $affiliate_key){
1009
+ $url = add_query_arg(array('aid' => $affiliate_id, 'affiliate_key' => $affiliate_key), $url);
1010
+ }
1011
+
1012
+ if($repository_id == 'wpml'){
1013
+ $url = add_query_arg(array('using_icl' => $this->_using_icl, 'wpml_version' => $this->_wpml_version), $url);
1014
+ }
1015
+
1016
+ $url = apply_filters('wp_installer_buy_url', $url);
1017
+
1018
+ $url = esc_url($url);
1019
+
1020
+ return $url;
1021
+
1022
+ }
1023
+
1024
+ public function save_site_key($args = array()){
1025
+
1026
+ $error = '';
1027
+
1028
+ $repository_id = isset($args['repository_id']) ? $args['repository_id'] : (isset($_POST['repository_id']) ? $_POST['repository_id'] : false);
1029
+ $nonce = isset($args['nonce']) ? $args['nonce'] : (isset($_POST['nonce']) ? $_POST['nonce'] : '');
1030
+ $site_key = isset($args['site_key']) ? $args['site_key'] : $_POST['site_key_' . $repository_id];
1031
+
1032
+ $site_key = preg_replace("/[^A-Za-z0-9]/", '', $site_key);
1033
+
1034
+ if($repository_id && $nonce && wp_create_nonce('save_site_key_' . $repository_id) == $nonce){
1035
+
1036
+ try {
1037
+ $subscription_data = $this->fetch_subscription_data( $repository_id, $site_key, self::SITE_KEY_VALIDATION_SOURCE_REGISTRATION );
1038
+
1039
+ if ( $subscription_data ) {
1040
+ $this->settings['repositories'][$repository_id]['subscription'] = array('key' => $site_key, 'data' => $subscription_data);
1041
+ $this->save_settings();
1042
+ } else {
1043
+ $error = __( 'Invalid site key for the current site.', 'installer' );
1044
+ }
1045
+
1046
+ } catch (Exception $e ){
1047
+ $error = $e->getMessage();
1048
+ if( preg_match('#Could not resolve host: (.*)#', $error, $matches) || preg_match('#Couldn\'t resolve host \'(.*)\'#', $error, $matches) ){
1049
+ $error = sprintf(__("%s cannot access %s to register. Try again to see if it's a temporary problem. If the problem continues, make sure that this site has access to the Internet. You can still use the plugin without registration, but you will not receive automated updates.", 'installer'),
1050
+ '<strong><i>' . $this->get_generic_product_name($repository_id) . '</i></strong>',
1051
+ '<strong><i>' . $matches[1]. '</i></strong>'
1052
+ ) ;
1053
+ }
1054
+ }
1055
+
1056
+ }
1057
+
1058
+ $return = array('error' => $error);
1059
+
1060
+ if($this->api_debug){
1061
+ $return['debug'] = $this->api_debug;
1062
+ }
1063
+
1064
+ if(!empty($args['return'])){
1065
+ return $return;
1066
+ }else{
1067
+ echo json_encode($return);
1068
+ exit;
1069
+ }
1070
+
1071
+ }
1072
+
1073
+ /**
1074
+ * Alias for WP_Installer::get_repository_site_key
1075
+ * @see WP_Installer::get_repository_site_key()
1076
+ *
1077
+ * @param string $repository_id
1078
+ * @return string (site key) or bool
1079
+ */
1080
+ public function get_site_key($repository_id){
1081
+ return WP_Installer::get_repository_site_key( $repository_id );
1082
+ }
1083
+
1084
+ public function remove_site_key(){
1085
+ if($_POST['nonce'] == wp_create_nonce('remove_site_key_' . $_POST['repository_id'])){
1086
+ unset($this->settings['repositories'][$_POST['repository_id']]['subscription']);
1087
+ $this->save_settings();
1088
+
1089
+ $this->refresh_repositories_data();
1090
+ }
1091
+ exit;
1092
+ }
1093
+
1094
+ public function validate_repository_subscription(){
1095
+ $repository_id = isset($_GET['validate_repository']) ? $_GET['validate_repository'] : false;
1096
+ if($repository_id){
1097
+
1098
+ $site_key = $this->get_site_key($repository_id);
1099
+ if($site_key) {
1100
+ $subscription_data = $this->fetch_subscription_data( $repository_id, $site_key, self::SITE_KEY_VALIDATION_SOURCE_REVALIDATION);
1101
+ if(empty($subscription_data)){
1102
+ unset($this->settings['repositories'][$repository_id]['subscription']);
1103
+ delete_site_transient('update_plugins');
1104
+ $this->save_settings();
1105
+ }
1106
+ }
1107
+
1108
+ wp_redirect($this->menu_url() . '#repository-' . $repository_id);
1109
+ exit;
1110
+
1111
+ }
1112
+
1113
+ }
1114
+
1115
+ public function update_site_key(){
1116
+
1117
+ $error = '';
1118
+
1119
+ if($_POST['nonce'] == wp_create_nonce('update_site_key_' . $_POST['repository_id'])){
1120
+
1121
+ $repository_id = $_POST['repository_id'];
1122
+ $site_key = $this->get_site_key($_POST['repository_id']);
1123
+
1124
+ if($site_key){
1125
+ try {
1126
+ $subscription_data = $this->fetch_subscription_data( $repository_id, $site_key, self::SITE_KEY_VALIDATION_SOURCE_UPDATES_CHECK );
1127
+
1128
+ if ( $subscription_data ) {
1129
+ $this->settings['repositories'][$repository_id]['subscription'] = array('key' => $site_key, 'data' => $subscription_data);
1130
+
1131
+ //also refresh products information
1132
+ $this->refresh_repositories_data();
1133
+
1134
+ $this->save_settings();
1135
+
1136
+ } else {
1137
+ unset($this->settings['repositories'][$repository_id]['subscription']);
1138
+ $error = __( 'Invalid site key for the current site. If the error persists, try to unregister first and then register again with the same site key.', 'installer' );
1139
+ }
1140
+
1141
+
1142
+ } catch (Exception $e ){
1143
+ $error = $e->getMessage();
1144
+ if( preg_match('#Could not resolve host: (.*)#', $error, $matches) || preg_match('#Couldn\'t resolve host \'(.*)\'#', $error, $matches) ){
1145
+ $error = sprintf(__("%s cannot access %s to register. Try again to see if it's a temporary problem. If the problem continues, make sure that this site has access to the Internet. You can still use the plugin without registration, but you will not receive automated updates.", 'installer'),
1146
+ '<strong><i>' . $this->get_generic_product_name($repository_id) . '</i></strong>',
1147
+ '<strong><i>' . $matches[1]. '</i></strong>'
1148
+ ) ;
1149
+ }
1150
+ }
1151
+
1152
+ }
1153
+
1154
+ }
1155
+
1156
+ echo json_encode(array('error' => $error));
1157
+
1158
+ exit;
1159
+ }
1160
+
1161
+ public function api_debug_log($text){
1162
+
1163
+ if(defined('WPML_DEBUG_INSTALLER') && WPML_DEBUG_INSTALLER){
1164
+
1165
+ if(!is_scalar($text)){
1166
+ $text = print_r($text, 1);
1167
+ }
1168
+
1169
+ $this->api_debug .= $text . "\n";
1170
+
1171
+ }
1172
+
1173
+ }
1174
+
1175
+ public function fetch_subscription_data( $repository_id, $site_key, $source = self::SITE_KEY_VALIDATION_SOURCE_OTHER ){
1176
+
1177
+ $subscription_data = false;
1178
+
1179
+ $args['body'] = array(
1180
+ 'action' => 'site_key_validation',
1181
+ 'site_key' => $site_key,
1182
+ 'site_url' => $this->get_installer_site_url( $repository_id ),
1183
+ 'source' => $source
1184
+ );
1185
+
1186
+ if($repository_id == 'wpml'){
1187
+ $args['body']['using_icl'] = $this->_using_icl;
1188
+ $args['body']['wpml_version'] = $this->_wpml_version;
1189
+ }
1190
+
1191
+ $args['body']['installer_version'] = WP_INSTALLER_VERSION;
1192
+ $args['body']['theme'] = wp_get_theme()->get( 'Name' );
1193
+ $args['body']['site_name'] = get_bloginfo( 'name' );
1194
+
1195
+ $args['body']['versions'] = $this->get_local_product_versions( $repository_id );
1196
+
1197
+ $args['timeout'] = 45;
1198
+
1199
+ // Add extra parameters for custom Installer packages
1200
+ if( !empty($this->package_source) ){
1201
+ $extra = $this->get_extra_url_parameters();
1202
+ if( !empty($extra['repository']) && $extra['repository'] == $repository_id ) {
1203
+ unset($extra['repository']);
1204
+ foreach($extra as $key => $val){
1205
+ $args['body'][$key] = $val;
1206
+ }
1207
+ }
1208
+ }
1209
+
1210
+ $response = wp_remote_post($this->repositories[$repository_id]['api-url'], $args);
1211
+
1212
+ $this->api_debug_log("POST {$this->repositories[$repository_id]['api-url']}");
1213
+ $this->api_debug_log($args);
1214
+
1215
+ $this->log("POST {$this->repositories[$repository_id]['api-url']} - fetch subscription data");
1216
+
1217
+ if( !is_wp_error($response) ){
1218
+ $datas = wp_remote_retrieve_body($response);
1219
+
1220
+ if(is_serialized($datas)){
1221
+ $data = unserialize($datas);
1222
+ $this->api_debug_log($data);
1223
+ }else{
1224
+ $this->api_debug_log($datas);
1225
+ }
1226
+
1227
+ if(!empty($data->subscription_data)){
1228
+ $subscription_data = $data->subscription_data;
1229
+ }
1230
+
1231
+ do_action( 'installer_fetched_subscription_data', $data, $repository_id);
1232
+
1233
+ }else{
1234
+
1235
+ $this->api_debug_log($response);
1236
+ throw new Exception( $response->get_error_message() );
1237
+ }
1238
+
1239
+ return $subscription_data;
1240
+
1241
+ }
1242
+
1243
+ function get_local_product_versions( $repository_id ){
1244
+
1245
+ $versions = array();
1246
+
1247
+ foreach( $this->settings['repositories'][$repository_id]['data']['packages'] as $package_id => $package ){
1248
+
1249
+ foreach( $package['products'] as $product_id => $product ){
1250
+
1251
+ foreach( $product['plugins'] as $plugin_slug ){
1252
+
1253
+ $download = $this->settings['repositories'][$repository_id]['data']['downloads']['plugins'][$plugin_slug];
1254
+
1255
+ if( empty( $versions[$download['slug']] ) ) {
1256
+ $v = $this->get_plugin_installed_version($download['name'], $download['slug']);
1257
+ if($v){
1258
+ $versions[$download['slug']] = $v;
1259
+ }
1260
+ }
1261
+
1262
+ }
1263
+
1264
+ }
1265
+
1266
+ }
1267
+
1268
+ return $versions;
1269
+ }
1270
+
1271
+ public function get_repository_site_key($repository_id){
1272
+ $site_key = false;
1273
+
1274
+ if(!empty($this->settings['repositories'][$repository_id]['subscription']['key'])){
1275
+ $site_key = $this->settings['repositories'][$repository_id]['subscription']['key'];
1276
+ }
1277
+
1278
+ return $site_key;
1279
+ }
1280
+
1281
+ public function repository_has_valid_subscription($repository_id){
1282
+
1283
+ $valid = false;
1284
+
1285
+ if(!empty($this->settings['repositories'][$repository_id]['subscription'])){
1286
+
1287
+ $subscription = $this->settings['repositories'][$repository_id]['subscription']['data'];
1288
+ $valid = ( $subscription->status == 1 && (strtotime($subscription->expires) > time() || empty($subscription->expires)) ) || $subscription->status == 4;
1289
+
1290
+ }
1291
+ return $valid;
1292
+
1293
+ }
1294
+
1295
+ public function repository_has_subscription($repository_id){
1296
+ $key = false;
1297
+ if(!empty($this->settings['repositories'][$repository_id]['subscription']['key'])){
1298
+ $key = $this->settings['repositories'][$repository_id]['subscription']['key'];
1299
+ }
1300
+
1301
+ return $key;
1302
+
1303
+ }
1304
+
1305
+ public function repository_has_expired_subscription($repository_id){
1306
+
1307
+ return $this->repository_has_subscription($repository_id) && !$this->repository_has_valid_subscription($repository_id);
1308
+
1309
+ }
1310
+
1311
+ public function get_generic_product_name($repository_id){
1312
+
1313
+ return $this->settings['repositories'][$repository_id]['data']['product-name'];
1314
+
1315
+ }
1316
+
1317
+ public function show_subscription_renew_warning($repository_id, $subscription_id){
1318
+
1319
+ $show = false;
1320
+
1321
+ $data = $this->settings['repositories'][$repository_id]['data'];
1322
+ if(!empty($data['subscriptions_meta'])){
1323
+ if(isset($data['subscriptions_meta']['expiration'])){
1324
+
1325
+ if(!empty($data['subscriptions_meta']['expiration'][$subscription_id])){
1326
+
1327
+ $days = $data['subscriptions_meta']['expiration'][$subscription_id]['days_warning'];
1328
+ $message = $data['subscriptions_meta']['expiration'][$subscription_id]['warning_message'];
1329
+
1330
+ }else{
1331
+
1332
+ //defaults
1333
+ $days = 30;
1334
+ $message = __('You will have to renew your subscription in order to continue getting the updates and support.', 'installer');
1335
+
1336
+ }
1337
+
1338
+ if(!empty($this->settings['repositories'][$repository_id]['subscription'])){
1339
+ $subscription = $this->settings['repositories'][$repository_id]['subscription'];
1340
+
1341
+ if($subscription['data']->subscription_type == $subscription_id && !empty($subscription['data']->expires)){
1342
+
1343
+ if(strtotime($subscription['data']->expires) < strtotime(sprintf("+%d day", $days))){
1344
+
1345
+ $days_to_expiration = ceil((strtotime($subscription['data']->expires) - time()) / 86400);
1346
+
1347
+ echo '<div><p class="installer-warn-box">' .
1348
+ sprintf(_n('Your subscription expires in %d day.', 'Your subscription expires in %d days.', $days_to_expiration, 'installer'), $days_to_expiration) .
1349
+ '<br />' . $message .
1350
+ '</p></div>';
1351
+
1352
+ $show = true;
1353
+
1354
+ }
1355
+
1356
+ }
1357
+
1358
+ }
1359
+
1360
+
1361
+ }
1362
+ }
1363
+
1364
+
1365
+ return $show;
1366
+
1367
+ }
1368
+
1369
+ public function setup_plugins_renew_warnings(){
1370
+
1371
+ $plugins = get_plugins();
1372
+
1373
+ $subscriptions_with_warnings = array();
1374
+ foreach($this->settings['repositories'] as $repository_id => $repository){
1375
+
1376
+ if($this->repository_has_valid_subscription($repository_id)){
1377
+ $subscription_type = $this->settings['repositories'][$repository_id]['subscription']['data']->subscription_type;
1378
+ $expires = $this->settings['repositories'][$repository_id]['subscription']['data']->expires;
1379
+
1380
+ $never_expires = isset($this->settings['repositories'][$repository_id]['subscription'])
1381
+ && empty($this->settings['repositories'][$repository_id]['subscription']['data']->expires)
1382
+ && (
1383
+ $this->settings['repositories'][$repository_id]['subscription']['data']->status == 4 ||
1384
+ $this->settings['repositories'][$repository_id]['subscription']['data']->status == 1
1385
+ );
1386
+
1387
+ if(!$never_expires){
1388
+ if(isset($this->settings['repositories'][$repository_id]['data']['subscriptions_meta']['expiration'][$subscription_type])){
1389
+
1390
+ $days_warning = $this->settings['repositories'][$repository_id]['data']['subscriptions_meta']['expiration'][$subscription_type]['days_warning'];
1391
+ $custom_message = $this->settings['repositories'][$repository_id]['data']['subscriptions_meta']['expiration'][$subscription_type]['warning_message'];
1392
+
1393
+ }else{
1394
+ //defaults
1395
+ $days_warning = 30;
1396
+ $custom_message = __('You will have to renew your subscription in order to continue getting the updates and support.', 'installer');
1397
+ }
1398
+
1399
+ if(strtotime($expires) < strtotime(sprintf('+%d day', $days_warning)) ){
1400
+
1401
+ $days_to_expiration = ceil((strtotime($expires) - time()) / 86400);
1402
+
1403
+ $message = sprintf(_n('Your subscription expires in %d day.', 'Your subscription expires in %d days.', $days_to_expiration, 'installer'), $days_to_expiration);
1404
+ $subscriptions_with_warnings[$subscription_type] = $message . ' ' . $custom_message;
1405
+
1406
+ }
1407
+ }
1408
+
1409
+ }
1410
+
1411
+ }
1412
+
1413
+
1414
+
1415
+ foreach($plugins as $plugin_id => $plugin){
1416
+
1417
+ $slug = dirname($plugin_id);
1418
+ if(empty($slug)) continue;
1419
+
1420
+ foreach($this->settings['repositories'] as $repository_id => $repository){
1421
+
1422
+ if($this->repository_has_valid_subscription($repository_id)){
1423
+
1424
+ foreach($repository['data']['packages'] as $package){
1425
+
1426
+ foreach($package['products'] as $product){
1427
+
1428
+ foreach($product['plugins'] as $plugin_slug){
1429
+
1430
+ $download = $this->settings['repositories'][$repository_id]['data']['downloads']['plugins'][$plugin_slug];
1431
+
1432
+ if($download['slug'] == $slug || $download['name'] == $plugin['Name'] || $download['name'] == $plugin['Title']){ //match order: slug, name, title
1433
+
1434
+ if(isset($subscriptions_with_warnings[$product['subscription_type']])){
1435
+
1436
+ $this->_plugins_renew_warnings[$plugin_id] = $subscriptions_with_warnings[$product['subscription_type']];
1437
+
1438
+ }
1439
+
1440
+ }
1441
+
1442
+ }
1443
+
1444
+ }
1445
+
1446
+ }
1447
+
1448
+ }
1449
+
1450
+ }
1451
+
1452
+ }
1453
+
1454
+ }
1455
+
1456
+ public function queue_plugins_renew_warnings() {
1457
+
1458
+ if(!empty($this->_plugins_renew_warnings)){
1459
+
1460
+ foreach($this->_plugins_renew_warnings as $plugin_id => $message){
1461
+
1462
+ add_action( "after_plugin_row_" . $plugin_id, array($this, 'plugins_renew_warning'), 10, 3 );
1463
+ }
1464
+
1465
+ }
1466
+
1467
+ }
1468
+
1469
+ public function plugins_renew_warning($plugin_file, $plugin_data, $status){
1470
+
1471
+ if(empty($this->_plugins_renew_warnings[$plugin_file])) return;
1472
+
1473
+ $wp_list_table = _get_list_table('WP_Plugins_List_Table');
1474
+ ?>
1475
+
1476
+ <tr class="plugin-update-tr"><td colspan="<?php echo $wp_list_table->get_column_count(); ?>" class="plugin-update colspanchange">
1477
+ <div class="update-message">
1478
+ <?php
1479
+ echo $this->_plugins_renew_warnings[$plugin_file]. ' ';
1480
+ printf(__('%sRenew here%s.', 'installer'),
1481
+ '<a href="' . $this->menu_url() . '">', '</a>');
1482
+ ?>
1483
+ </div>
1484
+ </tr>
1485
+
1486
+ <?php
1487
+
1488
+ }
1489
+
1490
+ public function get_subscription_type_for_repository($repository_id){
1491
+
1492
+ $subscription_type = false;
1493
+
1494
+ if(!empty($this->settings['repositories'][$repository_id]['subscription'])){
1495
+ $subscription_type = $this->settings['repositories'][$repository_id]['subscription']['data']->subscription_type;
1496
+ }
1497
+
1498
+ return $subscription_type;
1499
+
1500
+ }
1501
+
1502
+ public function have_superior_subscription($subscription_type, $product){
1503
+
1504
+ $have = false;
1505
+
1506
+ if(is_array($product['upgrades'])){
1507
+ foreach($product['upgrades'] as $u){
1508
+ if($u['subscription_type'] == $subscription_type){
1509
+ $have = true;
1510
+ break;
1511
+ }
1512
+ }
1513
+ }
1514
+
1515
+ return $have;
1516
+ }
1517
+
1518
+ public function is_product_available_for_download($product_name, $repository_id){
1519
+
1520
+ $available = false;
1521
+
1522
+ $subscription_type = $this->get_subscription_type_for_repository($repository_id);
1523
+ $expired = $this->repository_has_expired_subscription($repository_id);
1524
+
1525
+ if($this->repository_has_subscription($repository_id) && !$expired){
1526
+
1527
+ $this->set_hierarchy_and_order();
1528
+
1529
+ foreach($this->settings['repositories'][$repository_id]['data']['packages'] as $package_id => $package){
1530
+
1531
+ $has_top_package = false;
1532
+
1533
+ foreach($package['products'] as $product){
1534
+
1535
+ if($subscription_type == $product['subscription_type']){
1536
+ $has_top_package = true;
1537
+ if($product['name'] == $product_name){
1538
+ return $available = true;
1539
+ }
1540
+ }
1541
+
1542
+ }
1543
+
1544
+ if(!empty($package['sub-packages'])){
1545
+ foreach($package['sub-packages'] as $sub_package){
1546
+ foreach($sub_package['products'] as $product){
1547
+ if($product['name'] == $product_name && ($subscription_type == $product['subscription_type'] || $has_top_package)){
1548
+ return $available = true;
1549
+ }
1550
+ }
1551
+ }
1552
+ }
1553
+
1554
+ }
1555
+ }
1556
+
1557
+ return $available;
1558
+
1559
+ }
1560
+
1561
+ public function get_upgrade_options($repository_id){
1562
+ $all_upgrades = array();
1563
+
1564
+ //get all products: packages and subpackages
1565
+ $all_products = array();
1566
+ foreach($this->settings['repositories'][$repository_id]['data']['packages'] as $package){
1567
+ foreach($package['products'] as $product) {
1568
+ $all_products[] = $product;
1569
+ }
1570
+ if(!empty($package['sub-packages'])){
1571
+ foreach($package['sub-packages'] as $subpackage){
1572
+ foreach($subpackage['products'] as $product) {
1573
+ $all_products[] = $product;
1574
+ }
1575
+
1576
+ }
1577
+
1578
+ }
1579
+
1580
+ }
1581
+
1582
+ foreach($all_products as $product) {
1583
+ if ($product['upgrades']) {
1584
+ foreach ($product['upgrades'] as $upgrade) {
1585
+ if ($this->repository_has_valid_subscription($repository_id) || ($this->repository_has_subscription($repository_id) && $upgrade['including_expired'])) {
1586
+ $all_upgrades[$upgrade['subscription_type']][$product['subscription_type']] = $upgrade;
1587
+ }
1588
+ }
1589
+ }
1590
+ }
1591
+
1592
+ return $all_upgrades;
1593
+
1594
+ }
1595
+
1596
+ public function append_site_key_to_download_url($url, $key, $repository_id){
1597
+
1598
+ $url_params['site_key'] = $key;
1599
+ $url_params['site_url'] = $this->get_installer_site_url( $repository_id );
1600
+
1601
+
1602
+ // Add extra parameters for custom Installer packages
1603
+ if( !empty($this->package_source) ){
1604
+ $extra = $this->get_extra_url_parameters();
1605
+ if( !empty($extra['repository']) && $extra['repository'] == $repository_id ) {
1606
+ unset($extra['repository']);
1607
+ foreach($extra as $key => $val){
1608
+ $url_params[$key] = $val;
1609
+ }
1610
+ }
1611
+ }
1612
+
1613
+ $url = add_query_arg($url_params, $url);
1614
+
1615
+ if($repository_id == 'wpml'){
1616
+ $url = add_query_arg(array('using_icl' => $this->_using_icl, 'wpml_version' => $this->_wpml_version), $url);
1617
+ }
1618
+
1619
+ return $url;
1620
+
1621
+ }
1622
+
1623
+ public function plugin_is_installed($name, $slug, $version = null){
1624
+
1625
+ $is = false;
1626
+
1627
+ $plugins = get_plugins();
1628
+
1629
+ foreach($plugins as $plugin_id => $plugin){
1630
+
1631
+ $wp_plugin_slug = dirname($plugin_id);
1632
+
1633
+ // Exception: embedded plugins
1634
+ if( $wp_plugin_slug == $slug || $plugin['Name'] == $name || $plugin['Title'] == $name || ( $wp_plugin_slug == $slug . '-embedded' || $plugin['Name'] == $name . ' Embedded' ) ){
1635
+ if($version){
1636
+ if(version_compare($plugin['Version'], $version, '>=')){
1637
+ $is = $plugin['Version'];
1638
+ }
1639
+ }else{
1640
+ $is = $plugin['Version'];
1641
+ }
1642
+
1643
+ break;
1644
+ }
1645
+
1646
+ }
1647
+
1648
+ //exception: Types name difference
1649
+ if(!$is && $name == 'Types'){
1650
+ return $this->plugin_is_installed('Types - Complete Solution for Custom Fields and Types', $slug, $version);
1651
+ }
1652
+
1653
+ return $is;
1654
+ }
1655
+
1656
+ public function plugin_is_embedded_version($name, $slug){
1657
+ $is = false;
1658
+
1659
+ $plugins = get_plugins();
1660
+
1661
+ //false if teh full version is also installed
1662
+ $is_full_installed = false;
1663
+ foreach($plugins as $plugin_id => $plugin){
1664
+
1665
+ if(($plugin['Name'] == $name && !preg_match("#-embedded$#", $slug)) ){
1666
+ $is_full_installed = true;
1667
+ break;
1668
+ }
1669
+
1670
+ }
1671
+
1672
+ if($is_full_installed){
1673
+ return false;
1674
+ }
1675
+
1676
+ foreach($plugins as $plugin_id => $plugin){
1677
+
1678
+ // TBD
1679
+ $wp_plugin_slug = dirname($plugin_id);
1680
+ if( $wp_plugin_slug == $slug . '-embedded' && $plugin['Name'] == $name . ' Embedded'){
1681
+ $is = true;
1682
+ break;
1683
+ }
1684
+
1685
+ }
1686
+
1687
+ return $is;
1688
+
1689
+ }
1690
+
1691
+ //Alias for plugin_is_installed
1692
+ public function get_plugin_installed_version($name, $slug){
1693
+
1694
+ return $this->plugin_is_installed($name, $slug);
1695
+
1696
+ }
1697
+
1698
+ public function get_plugin_repository_version($repository_id, $slug){
1699
+ $version = false;
1700
+
1701
+ if(!empty($this->settings['repositories'][$repository_id]['data']['packages'])){
1702
+ foreach($this->settings['repositories'][$repository_id]['data']['packages'] as $package){
1703
+ foreach($package['products'] as $product) {
1704
+
1705
+ foreach($product['plugins'] as $plugin_slug){
1706
+
1707
+ $download = $this->settings['repositories'][$repository_id]['data']['downloads']['plugins'][$plugin_slug];
1708
+
1709
+ if($download['slug'] == $slug){
1710
+ $version = $download['version'];
1711
+ break (3);
1712
+ }
1713
+
1714
+ }
1715
+
1716
+ }
1717
+ }
1718
+ }
1719
+
1720
+ return $version;
1721
+ }
1722
+
1723
+ public function is_uploading_allowed(){
1724
+
1725
+ //_deprecated_function ( __FUNCTION__, '1.7.3', 'Installer_Dependencies::' . __FUNCTION__ );
1726
+ return $this->dependencies->is_uploading_allowed();
1727
+
1728
+ }
1729
+
1730
+ public function download_plugin_ajax_handler(){
1731
+
1732
+ require_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php';
1733
+ require_once $this->plugin_path() . '/includes/installer-upgrader-skins.php';
1734
+
1735
+ if(isset($_POST['data'])){
1736
+
1737
+ $data = json_decode( base64_decode( $_POST['data'] ), true );
1738
+
1739
+ }
1740
+
1741
+ $ret = false;
1742
+ $plugin_id = false;
1743
+ $message = '';
1744
+
1745
+ //validate subscription
1746
+ $site_key = $this->get_repository_site_key($data['repository_id']);
1747
+ $subscription_data = $this->fetch_subscription_data( $data['repository_id'], $site_key , self::SITE_KEY_VALIDATION_SOURCE_DOWNLOAD_REPORT);
1748
+
1749
+ if($subscription_data && !is_wp_error($subscription_data) && $this->repository_has_valid_subscription($data['repository_id'])){
1750
+
1751
+ if($data['nonce'] == wp_create_nonce('install_plugin_' . $data['url'])){
1752
+
1753
+ $upgrader_skins = new Installer_Upgrader_Skins(); //use our custom (mute) Skin
1754
+ $upgrader = new Plugin_Upgrader($upgrader_skins);
1755
+
1756
+ remove_action( 'upgrader_process_complete', array( 'Language_Pack_Upgrader', 'async_upgrade' ), 20 );
1757
+
1758
+ $plugins = get_plugins();
1759
+
1760
+ //upgrade or install?
1761
+ foreach($plugins as $id => $plugin){
1762
+ $wp_plugin_slug = dirname($id);
1763
+ $is_embedded = $this->plugin_is_embedded_version(preg_replace('/ Embedded$/', '', $plugin['Name']), preg_replace('/-embedded$/', '', $wp_plugin_slug));
1764
+
1765
+ if($wp_plugin_slug == $data['slug'] || $is_embedded && preg_replace('/-embedded$/', '', $wp_plugin_slug) == $data['slug']){
1766
+ $plugin_id = $id;
1767
+ break;
1768
+ }
1769
+ }
1770
+
1771
+ if($plugin_id && empty($is_embedded)){ //upgrade
1772
+ $response['upgrade'] = 1;
1773
+
1774
+ $plugin_is_active = is_plugin_active($plugin_id);
1775
+
1776
+ $ret = $upgrader->upgrade($plugin_id);
1777
+
1778
+ if(!$ret && !empty($upgrader->skin->installer_error)){
1779
+ if(is_wp_error($upgrader->skin->installer_error)){
1780
+ $message = $upgrader->skin->installer_error->get_error_message() .
1781
+ ' (' . $upgrader->skin->installer_error->get_error_data() . ')';
1782
+ }
1783
+ }
1784
+
1785
+ if($plugin_is_active){
1786
+ //prevent redirects
1787
+ add_filter('wp_redirect', '__return_false');
1788
+ activate_plugin($plugin_id);
1789
+ }
1790
+
1791
+ }else{ //install
1792
+
1793
+ if($is_embedded){
1794
+ delete_plugins(array($plugin_id));
1795
+ }
1796
+
1797
+ $response['install'] = 1;
1798
+ $ret = $upgrader->install($data['url']);
1799
+ if(!$ret && !empty($upgrader->skin->installer_error)){
1800
+ if(is_wp_error($upgrader->skin->installer_error)){
1801
+ $message = $upgrader->skin->installer_error->get_error_message() .
1802
+ ' (' . $upgrader->skin->installer_error->get_error_data() . ')';
1803
+ }
1804
+ }
1805
+ }
1806
+
1807
+ $plugins = get_plugins(); //read again
1808
+
1809
+ if($ret && !empty($_POST['activate'])){
1810
+ foreach($plugins as $id => $plugin){
1811
+ $wp_plugin_slug = dirname($id);
1812
+ if($wp_plugin_slug == $data['slug']){
1813
+ $plugin_version = $plugin['Version'];
1814
+ $plugin_id = $id;
1815
+ break;
1816
+ }
1817
+ }
1818
+
1819
+ }
1820
+
1821
+ }
1822
+
1823
+ } else { //subscription not valid
1824
+
1825
+ $ret = false;
1826
+ $message = __('Your subscription appears to no longer be valid. Please try to register again using a valid site key.', 'installer');
1827
+ }
1828
+
1829
+ $response['version'] = isset($plugin_version) ? $plugin_version : 0;
1830
+ $response['plugin_id'] = $plugin_id;
1831
+ $response['nonce'] = wp_create_nonce('activate_' . $plugin_id);
1832
+ $response['success'] = $ret;
1833
+ $response['message'] = $message;
1834
+
1835
+ echo json_encode( $response );
1836
+ exit;
1837
+
1838
+ }
1839
+
1840
+ public function download_plugin($slug, $url){
1841
+
1842
+ require_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php';
1843
+ require_once $this->plugin_path() . '/includes/installer-upgrader-skins.php';
1844
+
1845
+ $upgrader_skins = new Installer_Upgrader_Skins(); //use our custom (mute) Skin
1846
+ $upgrader = new Plugin_Upgrader($upgrader_skins);
1847
+
1848
+ remove_action( 'upgrader_process_complete', array( 'Language_Pack_Upgrader', 'async_upgrade' ), 20 );
1849
+
1850
+ $plugins = get_plugins();
1851
+
1852
+ $plugin_id = false;
1853
+
1854
+ //upgrade or install?
1855
+ foreach($plugins as $id => $plugin){
1856
+ $wp_plugin_slug = dirname($id);
1857
+ if($wp_plugin_slug == $slug){
1858
+ $plugin_id = $id;
1859
+ break;
1860
+ }
1861
+ }
1862
+
1863
+ if($plugin_id){ //upgrade
1864
+
1865
+ $plugin_is_active = is_plugin_active($plugin_id);
1866
+
1867
+ $ret = $upgrader->upgrade($plugin_id);
1868
+
1869
+ if($plugin_is_active){
1870
+ activate_plugin($plugin_id);
1871
+ }
1872
+
1873
+ }else{ //install
1874
+ $ret = $upgrader->install($url);
1875
+ }
1876
+
1877
+ return $ret;
1878
+
1879
+ }
1880
+
1881
+ public function activate_plugin(){
1882
+
1883
+ $error = '';
1884
+
1885
+ if(isset($_POST['nonce']) && isset($_POST['plugin_id']) && $_POST['nonce'] == wp_create_nonce('activate_' . $_POST['plugin_id'])){
1886
+
1887
+ $plugin_id = $_POST['plugin_id'];
1888
+
1889
+ // Deactivate any embedded version
1890
+ $plugin_slug = dirname($plugin_id);
1891
+ $active_plugins = get_option('active_plugins');
1892
+ foreach($active_plugins as $plugin){
1893
+ $wp_plugin_slug = dirname($plugin);
1894
+ if($wp_plugin_slug == $plugin_slug . '-embedded'){
1895
+ deactivate_plugins(array($plugin));
1896
+ break;
1897
+ }
1898
+ }
1899
+
1900
+ //prevent redirects
1901
+ add_filter('wp_redirect', '__return_false', 10000);
1902
+
1903
+ $return = activate_plugin($plugin_id);
1904
+
1905
+ if(is_wp_error($return)){
1906
+ $error = $return->get_error_message();
1907
+ }
1908
+
1909
+ }else{
1910
+ $error = 'error';
1911
+ }
1912
+
1913
+ $ret = array('error' => $error);
1914
+
1915
+ echo json_encode($ret);
1916
+ exit;
1917
+
1918
+ }
1919
+
1920
+ public function custom_plugins_api_call($false, $action, $args){
1921
+
1922
+ if($action == 'plugin_information'){
1923
+
1924
+ $slug = $args->slug;
1925
+
1926
+ foreach($this->settings['repositories'] as $repository_id => $repository){
1927
+
1928
+ if(!$this->repository_has_valid_subscription($repository_id)){
1929
+ $site_key = false;
1930
+ }else{
1931
+ $site_key = $repository['subscription']['key'];
1932
+ }
1933
+
1934
+ foreach($repository['data']['packages'] as $package){
1935
+
1936
+ foreach($package['products'] as $product){
1937
+
1938
+ foreach($product['plugins'] as $plugin_slug){
1939
+
1940
+ $download = $this->settings['repositories'][$repository_id]['data']['downloads']['plugins'][$plugin_slug];
1941
+
1942
+ if($download['slug'] == $slug){
1943
+
1944
+ $res = new stdClass();
1945
+ $res->external = true;
1946
+
1947
+ $res->name = $download['name'];
1948
+ $res->slug = $slug;
1949
+ $res->version = $download['version'];
1950
+ $res->author = '';
1951
+ $res->author_profile = '';
1952
+ $res->last_updated = $download['date'];
1953
+ //$res->homepage = $download['url'];
1954
+
1955
+ if($site_key){
1956
+ $res->download_link = $this->append_site_key_to_download_url($download['url'], $site_key, $repository_id);
1957
+ }else{
1958
+ // if(!empty($download['free-on-wporg'])
1959
+ return false; //try somewhere else. e.g. wordpress.org
1960
+ }
1961
+
1962
+ $res->homepage = $repository['data']['url'];
1963
+ $res->sections = array('Description' => $download['description'], 'Changelog' => $download['changelog']);
1964
+
1965
+ return $res;
1966
+
1967
+ }
1968
+
1969
+ }
1970
+
1971
+ }
1972
+
1973
+ }
1974
+
1975
+ }
1976
+
1977
+ }
1978
+
1979
+ return $false;
1980
+
1981
+ }
1982
+
1983
+ public function plugins_upgrade_check($update_plugins){
1984
+
1985
+ if(!empty($this->settings['repositories'])){
1986
+
1987
+ $plugins = get_plugins();
1988
+
1989
+ foreach($plugins as $plugin_id => $plugin){
1990
+
1991
+ $slug = dirname($plugin_id);
1992
+ if(empty($slug)) continue;
1993
+
1994
+ $version = $plugin['Version'];
1995
+ $name = $plugin['Name'];
1996
+
1997
+ foreach($this->settings['repositories'] as $repository_id => $repository){
1998
+
1999
+
2000
+ if(!$this->repository_has_valid_subscription($repository_id)){
2001
+ $site_key = false;
2002
+ }else{
2003
+ $site_key = $repository['subscription']['key'];
2004
+ //$subscription_type = $this->get_subscription_type_for_repository($repository_id);
2005
+ }
2006
+
2007
+ foreach($repository['data']['packages'] as $package){
2008
+
2009
+ foreach($package['products'] as $product){
2010
+
2011
+ foreach($product['plugins'] as $plugin_slug){
2012
+
2013
+ $download = $this->settings['repositories'][$repository_id]['data']['downloads']['plugins'][$plugin_slug];
2014
+
2015
+ if(!empty($download['free-on-wporg'])) {
2016
+ continue;
2017
+ }
2018
+
2019
+ if(empty($update_plugins->response[$plugin_id]) && ($download['slug'] == $slug || $download['name'] == $name ) && version_compare($download['version'], $version, '>')){
2020
+
2021
+ $response = new stdClass();
2022
+ $response->id = 0;
2023
+ $response->slug = $slug;
2024
+ $response->plugin = $plugin_id;
2025
+ $response->new_version = $download['version'];
2026
+ $response->upgrade_notice = '';
2027
+ $response->url = $download['url'];
2028
+ if($site_key){
2029
+ $response->package = $this->append_site_key_to_download_url($download['url'], $site_key, $repository_id);
2030
+ }
2031
+ $update_plugins->checked[$plugin_id] = $version;
2032
+ $update_plugins->response[$plugin_id] = $response;
2033
+
2034
+ }
2035
+
2036
+ }
2037
+
2038
+ }
2039
+
2040
+ }
2041
+
2042
+ }
2043
+
2044
+ }
2045
+
2046
+ }
2047
+
2048
+ return $update_plugins;
2049
+
2050
+ }
2051
+
2052
+ public function setup_plugins_page_notices(){
2053
+
2054
+ $plugins = get_plugins();
2055
+
2056
+ foreach($plugins as $plugin_id => $plugin){
2057
+
2058
+ $slug = dirname($plugin_id);
2059
+ if(empty($slug)) continue;
2060
+
2061
+ $name = $plugin['Name'];
2062
+
2063
+ foreach($this->settings['repositories'] as $repository_id => $repository){
2064
+
2065
+ if(!$this->repository_has_valid_subscription($repository_id)){
2066
+ $site_key = false;
2067
+ }else{
2068
+ $site_key = $repository['subscription']['key'];
2069
+ }
2070
+
2071
+ foreach($repository['data']['packages'] as $package){
2072
+
2073
+ foreach($package['products'] as $product){
2074
+
2075
+ foreach($product['plugins'] as $plugin_slug){
2076
+
2077
+ $download = $this->settings['repositories'][$repository_id]['data']['downloads']['plugins'][$plugin_slug];
2078
+
2079
+ if(!empty($download['free-on-wporg'])) {
2080
+ continue;
2081
+ }
2082
+
2083
+ if( $download['slug'] == $slug || $download['name'] == $name ){
2084
+
2085
+ if( !$site_key || !$this->plugin_is_registered($repository_id, $download['slug']) ){
2086
+ add_action( "after_plugin_row_" . $plugin_id, array($this, 'show_purchase_notice_under_plugin'), 10, 3 );
2087
+ }
2088
+
2089
+ }
2090
+
2091
+ }
2092
+
2093
+ }
2094
+
2095
+ }
2096
+
2097
+ }
2098
+
2099
+ }
2100
+
2101
+ }
2102
+
2103
+ public function show_purchase_notice_under_plugin($plugin_file, $plugin_data, $status){
2104
+
2105
+ $wp_list_table = _get_list_table('WP_Plugins_List_Table');
2106
+ ?>
2107
+
2108
+ <tr class="plugin-update-tr"><td colspan="<?php echo $wp_list_table->get_column_count(); ?>" class="plugin-update colspanchange">
2109
+ <div class="update-message installer-q-icon">
2110
+ <?php
2111
+ printf(__('You need to have a valid subscription in order to get upgrades or support for this plugin. %sPurchase a subscription or enter an existing site key%s.', 'installer'),
2112
+ '<a href="' . $this->menu_url() . '">', '</a>');
2113
+ ?>
2114
+ </div>
2115
+ </tr>
2116
+
2117
+ <?php
2118
+
2119
+ }
2120
+
2121
+ public function localize_strings(){
2122
+
2123
+ if(!empty($this->settings['repositories'])){
2124
+ foreach($this->settings['repositories'] as $repository_id => $repository){
2125
+ //set name as call2action when don't have any
2126
+ //products
2127
+ foreach($repository['data']['packages'] as $package_id => $package){
2128
+ foreach($package['products'] as $product_id => $product){
2129
+ if(empty($product['call2action'])){
2130
+ $this->settings['repositories'][$repository_id]['data']['packages'][$package_id]['products'][$product_id]['call2action'] = $product['name'];
2131
+ }
2132
+
2133
+ foreach($product['upgrades'] as $idx => $upg){
2134
+ if(empty($upg['call2action'])){
2135
+ $this->settings['repositories'][$repository_id]['data']['packages'][$package_id]['products'][$product_id]['upgrades'][$idx]['call2action'] = $upg['name'];
2136
+ }
2137
+ }
2138
+
2139
+ foreach($product['renewals'] as $idx => $rnw){
2140
+ if(empty($rnw['call2action'])){
2141
+ $this->settings['repositories'][$repository_id]['data']['packages'][$package_id]['products'][$product_id]['renewals'][$idx]['call2action'] = $rnw['name'];
2142
+ }
2143
+
2144
+ }
2145
+
2146
+ }
2147
+ }
2148
+ }
2149
+ }
2150
+
2151
+ global $sitepress;
2152
+ if(is_null($sitepress)){
2153
+ return;
2154
+ }
2155
+
2156
+ // default strings are always in English
2157
+ $user_admin_language = $sitepress->get_admin_language();
2158
+
2159
+ if($user_admin_language != 'en'){
2160
+ foreach($this->settings['repositories'] as $repository_id => $repository){
2161
+
2162
+ $localization = $repository['data']['localization'];
2163
+
2164
+ //packages
2165
+ foreach($repository['data']['packages'] as $package_id => $package){
2166
+
2167
+ if( isset($localization['packages'][$package_id]['name'][$user_admin_language]) ){
2168
+ $this->settings['repositories'][$repository_id]['data']['packages'][$package_id]['name'] = $localization['packages'][$package_id]['name'][$user_admin_language];
2169
+ }
2170
+ if( isset($localization['packages'][$package_id]['description'][$user_admin_language]) ){
2171
+ $this->settings['repositories'][$repository_id]['data']['packages'][$package_id]['description'] = $localization['packages'][$package_id]['description'][$user_admin_language];
2172
+ }
2173
+
2174
+ }
2175
+
2176
+ //products
2177
+ foreach($repository['data']['packages'] as $package_id => $package){
2178
+ foreach($package['products'] as $product_id => $product){
2179
+
2180
+ if( isset($localization['products'][$product_id]['name'][$user_admin_language]) ){
2181
+ $this->settings['repositories'][$repository_id]['data']['packages'][$package_id]['products'][$product_id]['name']
2182
+ = $localization['products'][$product_id]['name'][$user_admin_language];
2183
+ }
2184
+ if( isset($localization['products'][$product_id]['description'][$user_admin_language]) ){
2185
+ $this->settings['repositories'][$repository_id]['data']['packages'][$package_id]['products'][$product_id]['description']
2186
+ = $localization['products'][$product_id]['description'][$user_admin_language];
2187
+ }
2188
+ if( isset($localization['products'][$product_id]['call2action'][$user_admin_language]) ){
2189
+ $this->settings['repositories'][$repository_id]['data']['packages'][$package_id]['products'][$product_id]['name']
2190
+ = $localization['products'][$product_id]['call2action'][$user_admin_language];
2191
+ }
2192
+
2193
+
2194
+ }
2195
+ }
2196
+
2197
+ //subscription info
2198
+ if(isset($repository['data']['subscriptions_meta']['expiration'])){
2199
+ foreach($repository['data']['subscriptions_meta']['expiration'] as $subscription_id => $note){
2200
+ if(isset($localization['subscriptions-notes'][$subscription_id]['expiration-warning'][$user_admin_language])){
2201
+ $this->settings['repositories'][$repository_id]['data']['subscriptions_meta']['expiration'][$subscription_id]['warning_message']
2202
+ = $localization['subscriptions-notes'][$subscription_id]['expiration-warning'][$user_admin_language];
2203
+ }
2204
+ }
2205
+ }
2206
+
2207
+ }
2208
+ }
2209
+
2210
+ }
2211
+
2212
+ public function get_matching_cp($repository, $args = array()){
2213
+ $match = false;
2214
+
2215
+
2216
+ $cp_name = $cp_author = false;
2217
+
2218
+ if(isset($this->config['src_name']) && isset($this->config['src_author'])){
2219
+
2220
+ $cp_name = $this->config['src_name'];
2221
+ $cp_author = $this->config['src_author'];
2222
+
2223
+ }elseif(isset($args['src_name']) && isset($args['src_author'])){
2224
+
2225
+ $cp_name = $args['src_name'];
2226
+ $cp_author = $args['src_author'];
2227
+
2228
+ }
2229
+
2230
+ if(isset($repository['data']['marketing_cp'])){
2231
+
2232
+ foreach($repository['data']['marketing_cp'] as $cp){
2233
+
2234
+ if(!empty($cp['exp']) && time() > $cp['exp']){
2235
+ continue;
2236
+ }
2237
+
2238
+ //Use theme_name for plugins too
2239
+ if(!empty($cp['theme_name'])){
2240
+ if($cp['author_name'] == $cp_author && $cp['theme_name'] == $cp_name){
2241
+ $match = $cp;
2242
+ continue;
2243
+ }
2244
+ }else{
2245
+ if($cp['author_name'] == $cp_author){
2246
+ $match = $cp;
2247
+ continue;
2248
+ }
2249
+ }
2250
+
2251
+ }
2252
+
2253
+ }
2254
+
2255
+ return $match;
2256
+ }
2257
+
2258
+ public function set_filtered_prices($args = array()){
2259
+
2260
+ foreach($this->settings['repositories'] as $repository_id => $repository){
2261
+
2262
+ $match = $this->get_matching_cp($repository, $args);
2263
+
2264
+ if(empty($match)) continue;
2265
+
2266
+ foreach($repository['data']['packages'] as $package_id => $package){
2267
+
2268
+ foreach($package['products'] as $product_id => $product){
2269
+
2270
+ if($match['dtp'] == '%'){
2271
+ $fprice = round( $product['price'] * (1 - $match['amt']/100), 2 );
2272
+ $fprice = $fprice != round($fprice) ? sprintf('%.2f', $fprice) : round($fprice, 0);
2273
+ }elseif($match['dtp'] == '-'){
2274
+ $fprice = $product['price'] - $match['amt'];
2275
+ }else{
2276
+ $fprice = $product['price'];
2277
+ }
2278
+
2279
+ if($fprice){
2280
+ $this->settings['repositories'][$repository_id]['data']['packages'][$package_id]['products'][$product_id]['price_disc'] = $fprice;
2281
+
2282
+ $url_glue = false !== strpos($this->settings['repositories'][$repository_id]['data']['packages'][$package_id]['products'][$product_id]['url'], '?') ? '&' : '?';
2283
+ $cpndata = base64_encode(json_encode(array('theme_author' => $match['author_name'], 'theme_name' => $match['theme_name'], 'vlc' => $match['vlc'])));
2284
+ $this->settings['repositories'][$repository_id]['data']['packages'][$package_id]['products'][$product_id]['url'] .= $url_glue . 'cpn=' . $cpndata;
2285
+
2286
+ foreach($product['upgrades'] as $upgrade_id => $upgrade){
2287
+
2288
+ $fprice = false;
2289
+ if($match['dtp'] == '%'){
2290
+ $fprice = round( $upgrade['price'] * (1 - $match['amt']/100), 2 );
2291
+ $fprice = $fprice != round($fprice) ? sprintf('%.2f', $fprice) : round($fprice, 0);
2292
+ }elseif($match['dtp'] == '-'){
2293
+ $fprice = $upgrade['price'] - $match['amt'];
2294
+ }
2295
+ if($fprice){
2296
+ $this->settings['repositories'][$repository_id]['data']['packages'][$package_id]['products'][$product_id]['upgrades'][$upgrade_id]['price_disc'] = $fprice;
2297
+ $this->settings['repositories'][$repository_id]['data']['packages'][$package_id]['products'][$product_id]['upgrades'][$upgrade_id]['url'] .= $url_glue . 'cpn=' . $cpndata;
2298
+ }
2299
+
2300
+
2301
+ }
2302
+
2303
+ }
2304
+
2305
+ }
2306
+
2307
+ }
2308
+
2309
+ }
2310
+
2311
+ }
2312
+
2313
+ public function set_hierarchy_and_order(){
2314
+
2315
+ //2 levels
2316
+ if(!empty($this->settings['repositories'])) {
2317
+ foreach ($this->settings['repositories'] as $repository_id => $repository) {
2318
+
2319
+ if( empty( $repository['data']['packages'] ) ) continue;
2320
+
2321
+ $all_packages = $repository['data']['packages'];
2322
+ $ordered_packages = array();
2323
+
2324
+ //backward compatibility - 'order'
2325
+ foreach($all_packages as $k => $v){
2326
+ if(!isset($v['order'])){
2327
+ $all_packages[$k]['order'] = 0;
2328
+ }
2329
+ }
2330
+
2331
+ //select parents
2332
+ foreach ($all_packages as $package_id => $package) {
2333
+ if(empty($package['parent'])){
2334
+ $ordered_packages[$package_id] = $package;
2335
+ }
2336
+ }
2337
+
2338
+ //add sub-packages
2339
+ foreach($all_packages as $package_id => $package){
2340
+ if(!empty($package['parent'])) {
2341
+ if(isset($ordered_packages[$package['parent']])){
2342
+ $ordered_packages[$package['parent']]['sub-packages'][$package_id] = $package;
2343
+ }
2344
+ }
2345
+ }
2346
+
2347
+ // order parents
2348
+ usort($ordered_packages, array($this, '_order_packages_callback'));
2349
+ //order sub-packages
2350
+ foreach($ordered_packages as $package_id => $package){
2351
+ if(!empty($package['sub-packages'])) {
2352
+ usort($ordered_packages[$package_id]['sub-packages'], create_function('$a, $b', 'return $a[\'order\'] > $b[\'order\'];'));
2353
+ }
2354
+ }
2355
+
2356
+ $this->settings['repositories'][$repository_id]['data']['packages'] = $ordered_packages;
2357
+
2358
+
2359
+ }
2360
+ }
2361
+
2362
+
2363
+ }
2364
+
2365
+ public function _order_packages_callback($a, $b){
2366
+ return $a['order'] > $b['order'];
2367
+ }
2368
+
2369
+ public function get_support_tag_by_name( $name, $repository ){
2370
+
2371
+ if( is_array($this->settings['repositories'][$repository]['data']['support_tags'] )){
2372
+ foreach( $this->settings['repositories'][$repository]['data']['support_tags'] as $support_tag){
2373
+ if( $support_tag['name'] == $name ){
2374
+ return $support_tag['url'];
2375
+ }
2376
+ }
2377
+ }
2378
+
2379
+ return false;
2380
+ }
2381
+
2382
+ public function plugin_upgrade_custom_errors(){
2383
+
2384
+ if ( isset($_REQUEST['action']) ) {
2385
+
2386
+ $action = isset($_REQUEST['action']) ? $_REQUEST['action'] : '';
2387
+
2388
+ //bulk mode
2389
+ if('update-selected' == $action) {
2390
+
2391
+ global $plugins;
2392
+
2393
+ if(isset($plugins) && is_array($plugins)) {
2394
+
2395
+ foreach ($plugins as $k => $plugin) {
2396
+ $plugin_repository = false;
2397
+
2398
+ $wp_plugin_slug = dirname($plugin);
2399
+
2400
+ foreach ($this->settings['repositories'] as $repository_id => $repository) {
2401
+
2402
+ foreach ($repository['data']['packages'] as $package) {
2403
+
2404
+ foreach ($package['products'] as $product) {
2405
+
2406
+ foreach ($product['plugins'] as $plugin_slug) {
2407
+
2408
+ $download = $this->settings['repositories'][$repository_id]['data']['downloads']['plugins'][$plugin_slug];
2409
+
2410
+ if ($download['slug'] == $wp_plugin_slug) {
2411
+ $plugin_repository = $repository_id;
2412
+ $product_name = $repository['data']['product-name'];
2413
+ $plugin_name = $download['name'];
2414
+ $free_on_wporg = !empty($download['free-on-wporg']);
2415
+ break;
2416
+ }
2417
+
2418
+ }
2419
+
2420
+ }
2421
+
2422
+ }
2423
+
2424
+ }
2425
+
2426
+ if ($plugin_repository) {
2427
+
2428
+ //validate subscription
2429
+ static $sub_cache = array();
2430
+
2431
+ if(empty($sub_cache[$plugin_repository])){
2432
+ $site_key = $this->get_repository_site_key($plugin_repository);
2433
+ if ($site_key) {
2434
+ $subscription_data = $this->fetch_subscription_data( $plugin_repository, $site_key, self::SITE_KEY_VALIDATION_SOURCE_REVALIDATION );
2435
+ }
2436
+
2437
+ $sub_cache[$plugin_repository]['site_key'] = $site_key;
2438
+ $sub_cache[$plugin_repository]['subscription_data'] = isset($subscription_data) ? $subscription_data : false;
2439
+ }else{
2440
+
2441
+ $site_key = $sub_cache[$plugin_repository]['site_key'];
2442
+ $subscription_data = $sub_cache[$plugin_repository]['subscription_data'];
2443
+
2444
+ }
2445
+
2446
+ if(!$site_key && !empty($free_on_wporg)){ // allow the download from wp.org
2447
+ continue;
2448
+ }
2449
+
2450
+ if (empty($site_key) || empty($subscription_data)) {
2451
+
2452
+
2453
+ $error_message = sprintf(__("%s cannot update because your site's registration is not valid. Please %sregister %s%s again for this site first.", 'installer'),
2454
+ '<strong>' . $plugin_name . '</strong>', '<a target="_top" href="' . $this->menu_url() . '&validate_repository=' . $plugin_repository .
2455
+ '#repository-' . $plugin_repository . '">', $product_name, '</a>');
2456
+
2457
+ echo '<div class="updated error"><p>' . $error_message . '</p></div>';
2458
+
2459
+ unset($plugins[$k]);
2460
+
2461
+
2462
+ }
2463
+
2464
+ }
2465
+
2466
+ }
2467
+
2468
+ }
2469
+
2470
+ }
2471
+
2472
+
2473
+ if( 'upgrade-plugin' == $action || 'update-plugin' == $action ) {
2474
+
2475
+ $plugin = isset($_REQUEST['plugin']) ? trim($_REQUEST['plugin']) : '';
2476
+
2477
+ $wp_plugin_slug = dirname($plugin);
2478
+
2479
+ $plugin_repository = false;
2480
+
2481
+ foreach($this->settings['repositories'] as $repository_id => $repository){
2482
+
2483
+ foreach($repository['data']['packages'] as $package){
2484
+
2485
+ foreach($package['products'] as $product){
2486
+
2487
+ foreach($product['plugins'] as $plugin_slug){
2488
+ $download = $this->settings['repositories'][$repository_id]['data']['downloads']['plugins'][$plugin_slug];
2489
+
2490
+ //match by folder, will change to match by name and folder
2491
+ if($download['slug'] == $wp_plugin_slug) {
2492
+ $plugin_repository = $repository_id;
2493
+ $product_name = $repository['data']['product-name'];
2494
+ $plugin_name = $download['name'];
2495
+ $free_on_wporg = !empty($download['free-on-wporg']);
2496
+ break;
2497
+ }
2498
+
2499
+ }
2500
+
2501
+ }
2502
+
2503
+ }
2504
+
2505
+ }
2506
+
2507
+ if($plugin_repository) {
2508
+
2509
+ //validate subscription
2510
+ $site_key = $this->get_repository_site_key($plugin_repository);
2511
+ if ($site_key) {
2512
+ $subscription_data = $this->fetch_subscription_data( $plugin_repository, $site_key, self::SITE_KEY_VALIDATION_SOURCE_REVALIDATION );
2513
+ }
2514
+
2515
+ if ( (empty($site_key) || empty($subscription_data)) && empty($free_on_wporg)) {
2516
+
2517
+ $error_message = sprintf(__("%s cannot update because your site's registration is not valid. Please %sregister %s%s again for this site first.", 'installer'),
2518
+ '<strong>'.$plugin_name . '</strong>', '<a href="' . $this->menu_url() . '&validate_repository=' . $plugin_repository .
2519
+ '#repository-' . $plugin_repository . '">', $product_name, '</a>');
2520
+
2521
+ if(defined('DOING_AJAX')){ //WP 4.2
2522
+
2523
+ $status = array(
2524
+ 'update' => 'plugin',
2525
+ 'plugin' => $plugin,
2526
+ 'slug' => sanitize_key( $_POST['slug'] ),
2527
+ 'oldVersion' => '',
2528
+ 'newVersion' => '',
2529
+ );
2530
+
2531
+ $status['errorCode'] = 'wp_installer_invalid_subscription';
2532
+ $status['error'] = $error_message;
2533
+
2534
+ wp_send_json_error( $status );
2535
+
2536
+ } else { // WP 4.1.1
2537
+ echo '<div class="updated error"><p>' . $error_message . '</p></div>';
2538
+
2539
+
2540
+ echo '<div class="wrap">';
2541
+ echo '<h2>' . __('Update Plugin') . '</h2>';
2542
+ echo '<a href="' . admin_url('plugins.php') . '">' . __('Return to the plugins page') . '</a>';
2543
+ echo '</div>';
2544
+ require_once(ABSPATH . 'wp-admin/admin-footer.php');
2545
+ exit;
2546
+
2547
+ }
2548
+
2549
+ }
2550
+
2551
+
2552
+ }
2553
+
2554
+ }
2555
+ }
2556
+
2557
+ }
2558
+
2559
+ }
embedded/otgs/installer/includes/translation-service-info.class.php ADDED
@@ -0,0 +1,40 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class TranslationServiceInfo{
4
+
5
+ function __construct(){
6
+
7
+ add_action('installer_fetched_subscription_data',array($this, 'save_info'), 10, 2);
8
+
9
+ }
10
+
11
+ function save_info($data, $repository_id) {
12
+
13
+ $ts_info = isset( WP_Installer()->settings['repositories'][$repository_id]['ts_info'] ) ?
14
+ WP_Installer()->settings['repositories'][$repository_id]['ts_info'] : false;
15
+
16
+ $save_settings = false;
17
+ if(isset($data->ts_info['preferred']) && empty($ts_info['preferred'])){
18
+ WP_Installer()->settings['repositories'][$repository_id]['ts_info']['preferred'] = $data->ts_info['preferred'];
19
+ $save_settings = true;
20
+ }
21
+
22
+ if(isset($data->ts_info['referal']) && empty($ts_info['referal'])){
23
+ WP_Installer()->settings['repositories'][$repository_id]['ts_info']['referal'] = $data->ts_info['referal'];
24
+ $save_settings = true;
25
+ }
26
+
27
+ if ( !empty( $data->ts_info['client_id'] ) ) { // can be updated
28
+ WP_Installer()->settings['repositories'][$repository_id]['ts_info']['client_id'] = $data->ts_info['client_id'];
29
+ $save_settings = true;
30
+ }
31
+
32
+ if($save_settings){
33
+ WP_Installer()->save_settings();
34
+ }
35
+
36
+ }
37
+
38
+ }
39
+
40
+ new TranslationServiceInfo();
embedded/otgs/installer/installer.php ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ define('WP_INSTALLER_VERSION', '1.7.9');
3
+
4
+ include_once dirname(__FILE__) . '/includes/installer.class.php';
5
+
6
+ function WP_Installer() {
7
+ return WP_Installer::instance();
8
+ }
9
+
10
+
11
+ WP_Installer();
12
+
13
+ include_once WP_Installer()->plugin_path() . '/includes/installer-api.php';
14
+ include_once WP_Installer()->plugin_path() . '/includes/translation-service-info.class.php';
15
+ include_once WP_Installer()->plugin_path() . '/includes/class-installer-dependencies.php';
16
+
17
+ // Ext function
18
+ function WP_Installer_Show_Products($args = array()){
19
+
20
+ WP_Installer()->show_products($args);
21
+
22
+ }
embedded/otgs/installer/loader.php ADDED
@@ -0,0 +1,151 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ if ( ! defined( 'ABSPATH' ) ) {
4
+ exit; // Exit if accessed directly
5
+ }
6
+
7
+ //It should only be loaded on the admin side
8
+ if( !is_admin() ){
9
+ if(!function_exists('WP_Installer_Setup')){ function WP_Installer_Setup(){} }
10
+ $wp_installer_instance = null;
11
+ return;
12
+ }
13
+
14
+
15
+ $wp_installer_instance = dirname(__FILE__) . '/installer.php';
16
+
17
+
18
+ // Global stack of instances
19
+ global $wp_installer_instances;
20
+ $wp_installer_instances[$wp_installer_instance] = array(
21
+ 'bootfile' => $wp_installer_instance,
22
+ 'version' => '1.7.9'
23
+ );
24
+
25
+
26
+ /* EXCEPTIONS ********************************************************************************************/
27
+ // Exception: When WPML prior 3.2 is used, that instance must be used regardless of another newer instance
28
+ // Case 1: WPML loaded before Types - eliminate other instances
29
+ if( defined('ICL_SITEPRESS_VERSION') && version_compare(ICL_SITEPRESS_VERSION, '3.2', '<') ) {
30
+ foreach($wp_installer_instances as $key => $instance) {
31
+ if(isset($instance['args']['site_key_nags'])){
32
+ $wp_installer_instances[$key]['version'] = '9.9';
33
+ }else{
34
+ $wp_installer_instances[$key]['version'] = '0';
35
+ }
36
+ }
37
+ }
38
+
39
+ // Exception: Types 1.8.9 (Installer 1.7.0) with WPML before 3.3 (Installer before 1.7.0)
40
+ // New products file http://d2salfytceyqoe.cloudfront.net/wpml-products33.json overrides the old one
41
+ // while the WPML's instance is being used
42
+ // => Force using the new Installer Instance
43
+ if( defined('ICL_SITEPRESS_VERSION') && version_compare(ICL_SITEPRESS_VERSION, '3.3.1', '<') ) {
44
+
45
+ // if Installer 1.7.0+ is present, unregister Installer from old WPML
46
+ // Force Installer 1.7.0+ being used over older Installer versions
47
+ $installer_171_plus_on = false;
48
+ foreach($wp_installer_instances as $key => $instance) {
49
+ if( version_compare( $instance['version'], '1.7.1', '>=' ) ){
50
+ $installer_171_plus_on = true;
51
+ break;
52
+ }
53
+ }
54
+
55
+ if( $installer_171_plus_on ){
56
+ foreach($wp_installer_instances as $key => $instance) {
57
+
58
+ if( version_compare( $instance['version'], '1.7.0', '<' ) ){
59
+ unset( $wp_installer_instances[$key] );
60
+ }
61
+
62
+ }
63
+ }
64
+
65
+ }
66
+
67
+ // Exception: When using the embedded plugins module allow the set up to run completely with the
68
+ // Installer instance that triggers it
69
+ if( isset( $_POST['installer_instance'] ) && isset( $wp_installer_instances[$_POST['installer_instance']] ) ){
70
+ $wp_installer_instances[$_POST['installer_instance']]['version'] = '999';
71
+ }
72
+ /* EXCEPTIONS ********************************************************************************************/
73
+
74
+
75
+ // Only one of these in the end
76
+ remove_action('after_setup_theme', 'wpml_installer_instance_delegator', 1);
77
+ add_action('after_setup_theme', 'wpml_installer_instance_delegator', 1);
78
+
79
+ // When all plugins load pick the newest version
80
+ if(!function_exists('wpml_installer_instance_delegator')){
81
+ function wpml_installer_instance_delegator(){
82
+ global $wp_installer_instances;
83
+
84
+ // version based election
85
+ foreach($wp_installer_instances as $instance){
86
+
87
+ if(!isset($delegate)){
88
+ $delegate = $instance;
89
+ continue;
90
+ }
91
+
92
+ if(version_compare($instance['version'], $delegate['version'], '>')){
93
+ $delegate = $instance;
94
+ }
95
+ }
96
+
97
+ // priority based election
98
+ $highest_priority = null;
99
+ foreach($wp_installer_instances as $instance) {
100
+ if(isset($instance['args']['high_priority'])){
101
+ if(is_null($highest_priority) || $instance['args']['high_priority'] <= $highest_priority){
102
+ $highest_priority = $instance['args']['high_priority'];
103
+ $delegate = $instance;
104
+ }
105
+ }
106
+ }
107
+
108
+ // Exception: When WPML prior 3.2 is used, that instance must be used regardless of another newer instance
109
+ // Case 2: WPML loaded after Types
110
+ if( defined('ICL_SITEPRESS_VERSION') && version_compare(ICL_SITEPRESS_VERSION, '3.2', '<') ) {
111
+ foreach($wp_installer_instances as $key => $instance) {
112
+ if(isset($instance['args']['site_key_nags'])){
113
+ $delegate = $instance;
114
+ $wp_installer_instances = array($key => $delegate); //Eliminate other instances
115
+ break;
116
+ }
117
+ }
118
+ }
119
+
120
+ include_once $delegate['bootfile'];
121
+
122
+ // set configuration
123
+ if(strpos(realpath($delegate['bootfile']), realpath(TEMPLATEPATH)) === 0){
124
+ $delegate['args']['in_theme_folder'] = dirname(ltrim(str_replace(realpath(TEMPLATEPATH), '', realpath($delegate['bootfile'])), '\\/'));
125
+ }
126
+ if(isset($delegate['args']) && is_array($delegate['args'])){
127
+ foreach($delegate['args'] as $key => $value){
128
+ WP_Installer()->set_config($key, $value);
129
+ }
130
+ }
131
+
132
+ }
133
+ }
134
+
135
+ if(!function_exists('WP_Installer_Setup')){
136
+
137
+ // $args:
138
+ // plugins_install_tab = true|false (default: true)
139
+ // repositories_include = array() (default: all)
140
+ // repositories_exclude = array() (default: none)
141
+ // template = name (default: default)
142
+ //
143
+ // Ext function
144
+ function WP_Installer_Setup($wp_installer_instance, $args = array()){
145
+ global $wp_installer_instances;
146
+
147
+ $wp_installer_instances[$wp_installer_instance]['args'] = $args;
148
+
149
+ }
150
+
151
+ }
embedded/otgs/installer/locale/installer-ar.mo ADDED
Binary file
embedded/otgs/installer/locale/installer-de_DE.mo ADDED
Binary file
embedded/otgs/installer/locale/installer-el.mo ADDED
Binary file
embedded/otgs/installer/locale/installer-es_ES.mo ADDED
Binary file
embedded/otgs/installer/locale/installer-fr_FR.mo ADDED
Binary file
embedded/otgs/installer/locale/installer-he_IL.mo ADDED
Binary file
embedded/otgs/installer/locale/installer-it_IT.mo ADDED
Binary file
embedded/otgs/installer/locale/installer-ja.mo ADDED
Binary file
embedded/otgs/installer/locale/installer-ko_KR.mo ADDED
Binary file
embedded/otgs/installer/locale/installer-nl_NL.mo ADDED
Binary file
embedded/otgs/installer/locale/installer-pl_PL.mo ADDED
Binary file
embedded/otgs/installer/locale/installer-pt_BR.mo ADDED
Binary file
embedded/otgs/installer/locale/installer-pt_PT.mo ADDED
Binary file
embedded/otgs/installer/locale/installer-ru_RU.mo ADDED
Binary file
embedded/otgs/installer/locale/installer-sv_SE.mo ADDED
Binary file
embedded/otgs/installer/locale/installer-uk_UA.mo ADDED
Binary file
embedded/otgs/installer/locale/installer-vi.mo ADDED
Binary file
embedded/otgs/installer/locale/installer-zh_CN.mo ADDED
Binary file
embedded/otgs/installer/locale/installer-zh_TW.mo ADDED
Binary file
embedded/otgs/installer/locale/orig/installer.po ADDED
@@ -0,0 +1,230 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # This file was generated by WPML
2
+ # WPML is a WordPress plugin that can turn any WordPress site into a full featured multilingual content management system.
3
+ # https://wpml.org
4
+ msgid ""
5
+ msgstr ""
6
+ "Content-Type: text/plain; charset=utf-8\n"
7
+ "Content-Transfer-Encoding: 8bit\n"
8
+ "Project-Id-Version:WPML_EXPORT\n"
9
+ "POT-Creation-Date: \n"
10
+ "PO-Revision-Date: \n"
11
+ "Last-Translator: \n"
12
+ "Language-Team: \n"
13
+ "Language:en\n"
14
+ "MIME-Version: 1.0\n"
15
+
16
+ msgid "Installer"
17
+ msgstr ""
18
+
19
+ msgid "Registered"
20
+ msgstr ""
21
+
22
+ msgid "Register"
23
+ msgstr ""
24
+
25
+ msgid "To get automatic updates, you need to register %s for this site. %sRegister %s%s"
26
+ msgstr ""
27
+
28
+ msgid "Dismiss"
29
+ msgstr ""
30
+
31
+ msgid "Commercial"
32
+ msgstr ""
33
+
34
+ msgid "Installer cannot contact our updates server to get information about the available products and check for new versions. If you are seeing this message for the first time, you can ignore it, as it may be a temporary communication problem. If the problem persists and your WordPress admin is slowing down, you can disable automated version checks. Add the following line to your wp-config.php file:"
35
+ msgstr ""
36
+
37
+ msgid "No repositories defined."
38
+ msgstr ""
39
+
40
+ msgid "%s cannot access %s to register. Try again to see if it's a temporary problem. If the problem continues, make sure that this site has access to the Internet. You can still use the plugin without registration, but you will not receive automated updates."
41
+ msgstr ""
42
+
43
+ msgid "Invalid site key for the current site."
44
+ msgstr ""
45
+
46
+ msgid "You will have to renew your subscription in order to continue getting the updates and support."
47
+ msgstr ""
48
+
49
+ msgid "%sRenew here%s."
50
+ msgstr ""
51
+
52
+ msgid "Your subscription appears to no longer be valid. Please try to register again using a valid site key."
53
+ msgstr ""
54
+
55
+ msgid "You need to have a valid subscription in order to get upgrades or support for this plugin. %sPurchase a subscription or enter an existing site key%s."
56
+ msgstr ""
57
+
58
+ msgid "%s cannot update because your site's registration is not valid. Please %sregister %s%s again for this site first."
59
+ msgstr ""
60
+
61
+ msgid "Update Plugin"
62
+ msgstr ""
63
+
64
+ msgid "Return to the plugins page"
65
+ msgstr ""
66
+
67
+ msgid "Your subscription expires in %d day."
68
+ msgstr ""
69
+
70
+ msgid "Your subscription expires in %d days."
71
+ msgstr ""
72
+
73
+ msgid "Downloading is not possible because WordPress cannot write into the plugins folder. %sHow to fix%s."
74
+ msgstr ""
75
+
76
+ msgid "Plugin"
77
+ msgstr ""
78
+
79
+ msgid "downloading..."
80
+ msgstr ""
81
+
82
+ msgid "failed!"
83
+ msgstr ""
84
+
85
+ msgid "downloaded"
86
+ msgstr ""
87
+
88
+ msgid "activating"
89
+ msgstr ""
90
+
91
+ msgid "activated"
92
+ msgstr ""
93
+
94
+ msgid "Activate after download"
95
+ msgstr ""
96
+
97
+ msgid "Operation complete!"
98
+ msgstr ""
99
+
100
+ msgid "Download failed!\n\nClick OK to revalidate your subscription or CANCEL to try again."
101
+ msgstr ""
102
+
103
+ msgid "Available"
104
+ msgstr ""
105
+
106
+ msgid "Installed"
107
+ msgstr ""
108
+
109
+ msgid "Downloading"
110
+ msgstr ""
111
+
112
+ msgid "Activate"
113
+ msgstr ""
114
+
115
+ msgid "Download"
116
+ msgstr ""
117
+
118
+ msgid "Downloads:"
119
+ msgstr ""
120
+
121
+ msgid "Current version"
122
+ msgstr ""
123
+
124
+ msgid "Released"
125
+ msgstr ""
126
+
127
+ msgid "Installed version"
128
+ msgstr ""
129
+
130
+ msgid "(embedded)"
131
+ msgstr ""
132
+
133
+ msgid "installing..."
134
+ msgstr ""
135
+
136
+ msgid "updating..."
137
+ msgstr ""
138
+
139
+ msgid "installed"
140
+ msgstr ""
141
+
142
+ msgid "updated"
143
+ msgstr ""
144
+
145
+ msgid "Download failed!\n\nPlease refresh the page and try again."
146
+ msgstr ""
147
+
148
+ msgid "Incorrect setup"
149
+ msgstr ""
150
+
151
+ msgid "Invalid product"
152
+ msgstr ""
153
+
154
+ msgid "Unknown repository"
155
+ msgstr ""
156
+
157
+ msgid " Your current site key (%s) does not match the selected product (%s)."
158
+ msgstr ""
159
+
160
+ msgid "Buy %s"
161
+ msgstr ""
162
+
163
+ msgid "Already bought %s?"
164
+ msgstr ""
165
+
166
+ msgid "Renew %s"
167
+ msgstr ""
168
+
169
+ msgid "Remove current site key (%s)"
170
+ msgstr ""
171
+
172
+ msgid "%s support on wpml.org"
173
+ msgstr ""
174
+
175
+ msgid "Enter site key"
176
+ msgstr ""
177
+
178
+ msgid "Subscription is expired."
179
+ msgstr ""
180
+
181
+ msgid "Add"
182
+ msgstr ""
183
+
184
+ msgid "Are you sure you want to remove this site key?"
185
+ msgstr ""
186
+
187
+ msgid "Register %s"
188
+ msgstr ""
189
+
190
+ msgid "1. Go to your %s%s account%s and add this site URL: %s"
191
+ msgstr ""
192
+
193
+ msgid "Unregister %s from this site"
194
+ msgstr ""
195
+
196
+ msgid "%s is registered on this site. You will receive automatic updates until %s"
197
+ msgstr ""
198
+
199
+ msgid "%s is registered on this site. Your Lifetime account gives you updates for life."
200
+ msgstr ""
201
+
202
+ msgid "This page lets you install plugins and update existing plugins. To remove any of these plugins, go to the %splugins%s page and if you have the permission to remove plugins you should be able to do this."
203
+ msgstr ""
204
+
205
+ msgid "Already bought?"
206
+ msgstr ""
207
+
208
+ msgid "2. Enter your site key"
209
+ msgstr ""
210
+
211
+ msgid "Subscription is expired. You need to either purchase a new subscription or upgrade if available."
212
+ msgstr ""
213
+
214
+ msgid "Check for updates"
215
+ msgstr ""
216
+
217
+ msgid "Individual components"
218
+ msgstr ""
219
+
220
+ msgid "OK"
221
+ msgstr ""
222
+
223
+ msgid "Cancel"
224
+ msgstr ""
225
+
226
+ msgid "Are you sure you want to unregister?"
227
+ msgstr ""
228
+
229
+ msgid "Click to see individual components options."
230
+ msgstr ""
embedded/otgs/installer/repositories.xml ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0" encoding="utf-8"?>
2
+ <repositories>
3
+ <repository>
4
+ <id>wpml</id>
5
+ <apiurl>https://api.wpml.org/</apiurl>
6
+ <products>http://d2salfytceyqoe.cloudfront.net/wpml33-products.json</products>
7
+ </repository>
8
+ <repository>
9
+ <id>toolset</id>
10
+ <apiurl>https://api.wp-types.com/</apiurl>
11
+ <products>http://d7j863fr5jhrr.cloudfront.net/toolset33-products.json</products>
12
+ </repository>
13
+ </repositories>
embedded/otgs/installer/res/css/admin.css ADDED
@@ -0,0 +1,186 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ .otgsi_site_key_form{
2
+ display:none;
3
+ /*display:inline;*/
4
+ }
5
+
6
+ .installer-status-installing, .installer-status-installed, .installer-status-updating, .installer-status-updated, .installer-status-activating, .installer-status-activated, .installer-status-success{
7
+ display: none;
8
+ }
9
+ .installer-status-installing{color: #FF9900; }
10
+ .installer-status-installed{color: #003300; font-weight: bold; }
11
+ .installer-status-updating{color: #FF9900; }
12
+ .installer-status-updated{color: #003300; font-weight: bold; }
13
+
14
+ .installer-status-activating{color: #996666 }
15
+ .installer-status-activated{color: #333366; font-weight: bold; }
16
+
17
+ .js-status-success p{
18
+ color: #FF9900;
19
+ padding: 4px;
20
+ }
21
+
22
+ .installer-green-text{
23
+ color:#006600;
24
+ font-weight:bold;
25
+ }
26
+
27
+ .installer-red-text{
28
+ color:#b22121;
29
+ font-weight:bold;
30
+ }
31
+
32
+ .installer-products-list li{
33
+ display: inline;
34
+ margin-right: 20px;
35
+ }
36
+
37
+ .otgs_wp_installer_table a.disabled{
38
+ color:#888;
39
+ }
40
+
41
+ .otgs_wp_installer_subtable{
42
+ clear: both;
43
+ margin-left:-20px;
44
+ }
45
+ .otgs_wp_installer_subtable td p{
46
+ font-size: 92%;
47
+ }
48
+
49
+ .installer-status-error{
50
+ color: #f00;
51
+ }
52
+
53
+ .installer-status-note{
54
+ color: #6F6E6D;
55
+ font-style: italic;
56
+ }
57
+
58
+ .installer-warn-box{
59
+ -webkit-border-radius: 5px;-moz-border-radius: 5px;border-radius: 5px;border:1px solid #962722;background-color:#F5C8C6;
60
+ color: #333;
61
+ padding: 5px;
62
+ }
63
+ .installer-warn-box span.details{
64
+ font-style: italic;
65
+ color:#777;
66
+ }
67
+
68
+ .installer-error-box{
69
+ color:#962722;
70
+ margin-top: 10px;
71
+ }
72
+ .installer-error-box p{
73
+ margin: 10px 0 10px 0;
74
+ -webkit-border-radius: 5px;-moz-border-radius: 5px;border-radius: 5px;border:1px solid #962722;background-color:#F5C8C6;
75
+ color: #333;
76
+ padding: 5px;
77
+ text-align: center;
78
+ }
79
+
80
+ .spinner-inline{
81
+ float: none;
82
+ display: inline-block;
83
+ visibility: visible;
84
+ }
85
+
86
+ .installer-q-icon:before{
87
+ content: '\f223' !important;
88
+ }
89
+
90
+ .otgsi_yellow_bg{
91
+ background-color: #f2f46b;
92
+ }
93
+
94
+ .otgs_wp_installer_table_compact{
95
+ width:480px;
96
+ border: solid 1px #999;
97
+ padding:10px;
98
+ border-radius: 5px;
99
+ }
100
+
101
+ .installer-plugins-list-compact{
102
+ background-color: #fff;
103
+ border-collapse: collapse;
104
+ border:solid 1px #C1DAD7;
105
+ width:100%;
106
+ }
107
+
108
+ .installer-plugins-list-compact tr th{
109
+ padding-top:3px;
110
+ background-color: #ccc;
111
+ }
112
+
113
+ .installer-plugins-list-compact tr{
114
+ background-color: #ddd;
115
+ }
116
+
117
+ .installer-plugins-list-compact tr.even{
118
+ background-color: #eee;
119
+ }
120
+
121
+ .installer-plugins-list-compact td{
122
+ padding:2px 5px 2px 5px;
123
+ border-right: 1px solid #C1DAD7;
124
+ border-bottom: 1px solid #C1DAD7;
125
+ }
126
+
127
+ .installer-plugins-list-compact td.twelve{
128
+ width:16px;
129
+ }
130
+
131
+ .otgs_wp_installer_table_compact .installer-status-downloading,
132
+ .otgs_wp_installer_table_compact .installer-status-downloaded,
133
+ .otgs_wp_installer_table_compact .installer-status-activating,
134
+ .otgs_wp_installer_table_compact .installer-status-activated{
135
+ display: none;
136
+ color:transparent; width: 12px; padding:2px;
137
+ }
138
+
139
+ .otgs_wp_installer_table_compact .installer-status-success,
140
+ .otgs_wp_installer_table_compact .installer-status-fail{
141
+ display: none;
142
+ }
143
+
144
+ .installer-status-success{
145
+ float: right;
146
+ color: #006600;
147
+ }
148
+
149
+ .otgs_wp_installer_table_compact .installer-status-downloading{background: url(../img/dn.gif) no-repeat center; }
150
+ .otgs_wp_installer_table_compact .installer-status-downloaded{background: url(../img/complete.png) no-repeat center;}
151
+ .otgs_wp_installer_table_compact .installer-status-activating{background: url(../img/dn.gif) no-repeat center; }
152
+ .otgs_wp_installer_table_compact .installer-status-activated{background: url(../img/complete.png) no-repeat center; }
153
+ .otgs_wp_installer_table_compact .installer-status-error{background: url(../img/icon_error.gif) no-repeat center; }
154
+
155
+ .installer_highlight{
156
+ color:#c5510b;
157
+ }
158
+
159
+ .installer_highlight_package{
160
+ background-color: #fff9c0;
161
+ }
162
+
163
+ .plugin_progress{
164
+ font-style: italic;
165
+ color: #777
166
+ }
167
+
168
+ .installer-download-progress-status{
169
+ display: none;
170
+ float:right;
171
+ color: #006600;
172
+ font-style: italic;
173
+ background: url('../img/spinner.gif') no-repeat;
174
+ padding-left:24px;
175
+ }
176
+
177
+ .otgs-is-dismissible {
178
+ position: relative;
179
+ padding-right: 38px;
180
+ }
181
+ .otgs-is-dismissible .notice-dismiss {
182
+ text-decoration: none;
183
+ }
184
+ .otgs-is-dismissible p [class*="button-"] {
185
+ margin: -5px 5px;
186
+ }
embedded/otgs/installer/res/img/complete.png ADDED
Binary file
embedded/otgs/installer/res/img/computer.png ADDED
Binary file
embedded/otgs/installer/res/img/dn.gif ADDED
Binary file
embedded/otgs/installer/res/img/dn2.gif ADDED
Binary file
embedded/otgs/installer/res/img/globe.png ADDED
Binary file
embedded/otgs/installer/res/img/icon_error.gif ADDED
Binary file
embedded/otgs/installer/res/img/on.png ADDED
Binary file
embedded/otgs/installer/res/img/spinner.gif ADDED
Binary file
embedded/otgs/installer/res/js/admin.js ADDED
@@ -0,0 +1,403 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ var otgs_wp_installer = {
2
+
3
+ init: function(){
4
+
5
+ jQuery('.otgs_wp_installer_table').on('click', '.enter_site_key_js', otgs_wp_installer.show_site_key_form);
6
+ jQuery('.otgs_wp_installer_table').on('click', '.cancel_site_key_js', otgs_wp_installer.hide_site_key_form);
7
+
8
+ jQuery('.otgs_wp_installer_table').on('click', '.remove_site_key_js', otgs_wp_installer.remove_site_key);
9
+ jQuery('.otgs_wp_installer_table').on('click', '.update_site_key_js', otgs_wp_installer.update_site_key);
10
+
11
+ jQuery('.otgs_wp_installer_table').on('submit', '.otgsi_site_key_form', otgs_wp_installer.save_site_key);
12
+ jQuery('.otgs_wp_installer_table').on('submit', '.otgsi_downloads_form', otgs_wp_installer.download_downloads);
13
+ jQuery('.otgs_wp_installer_table').on('change', '.otgsi_downloads_form :checkbox[name="downloads[]"]', otgs_wp_installer.update_downloads_form);
14
+
15
+ jQuery('.installer-dismiss-nag').click(otgs_wp_installer.dismiss_nag);
16
+
17
+ jQuery('.otgs_wp_installer_table').on('click', '.installer_expand_button', otgs_wp_installer.toggle_subpackages);
18
+
19
+ otgs_wp_installer.scroll_to_repository();
20
+
21
+ if( typeof pagenow != 'undefined' && pagenow == 'plugins'){
22
+
23
+ jQuery(document).ajaxSuccess(function(event, xhr, settings) {
24
+ var data = otgs_wp_installer.getQueryParameters(settings.data);
25
+ if(typeof data.action != 'undefined' && data.action == 'update-plugin'){
26
+ response = xhr.responseJSON.data;
27
+ console.log(typeof response.error);
28
+ if(typeof response.error != 'undefined'){
29
+ var default_error = jQuery('#' + response.slug + '-update .update-message').html();
30
+ jQuery('#' + response.slug + '-update .update-message').html(default_error + ' &raquo;<span class="installer-red-text"> ' + response.error + '</span>');
31
+ }
32
+ }
33
+ return false;
34
+ });
35
+
36
+ }
37
+
38
+ },
39
+
40
+ getQueryParameters : function(str) {
41
+ return (str || document.location.search).replace(/(^\?)/,'').split("&").map(function(n){return n = n.split("="),this[n[0]] = n[1],this}.bind({}))[0];
42
+ },
43
+
44
+ reset_errors: function(){
45
+ jQuery('.installer-error-box').html('').hide();
46
+ },
47
+
48
+ show_error: function(repo, text){
49
+ jQuery('#installer_repo_' + repo).find('.installer-error-box').html(text).show();
50
+ },
51
+
52
+ show_site_key_form: function(){
53
+ otgs_wp_installer.reset_errors();
54
+
55
+ var form = jQuery(this).parent().find('form.otgsi_site_key_form');
56
+ jQuery(this).prev().hide();
57
+ jQuery(this).hide();
58
+ form.css('display', 'inline');
59
+ form.find('input[name^=site_key_]').focus().val('');
60
+ form.find('input').removeAttr('disabled');
61
+
62
+ form.closest('.otgsi_register_product_wrap').addClass('otgsi_yellow_bg');
63
+
64
+ return false;
65
+ },
66
+
67
+ hide_site_key_form: function(){
68
+ var form = jQuery(this).closest('form');
69
+ form.hide();
70
+ form.parent().find('.enter_site_key_js').show();
71
+ form.parent().find('.enter_site_key_js').prev().show();
72
+
73
+ form.closest('.otgsi_register_product_wrap').removeClass('otgsi_yellow_bg');
74
+ otgs_wp_installer.reset_errors();
75
+ return false;
76
+ },
77
+
78
+ save_site_key: function(){
79
+
80
+ var thisf = jQuery(this);
81
+ var data = jQuery(this).serialize();
82
+ jQuery(this).find('input').attr('disabled', 'disabled');
83
+
84
+ var spinner = jQuery('<span class="spinner"></span>');
85
+ spinner.css({display: 'inline-block', float: 'none'}).prependTo(jQuery(this));
86
+
87
+ otgs_wp_installer.reset_errors();
88
+
89
+ jQuery.ajax({url: ajaxurl, type: 'POST', dataType:'json', data: data, success:
90
+ function(ret){
91
+ if(!ret.error){
92
+ otgs_wp_installer.saved_site_key();
93
+ }else{
94
+ otgs_wp_installer.show_error(thisf.find('[name=repository_id]').val(), ret.error);
95
+ thisf.find('input').removeAttr('disabled');
96
+ }
97
+
98
+ if(typeof ret.debug != 'undefined'){
99
+ thisf.append('<textarea style="width:100%" rows="20">' + ret.debug + '</textarea>');
100
+ }
101
+
102
+ spinner.remove();
103
+ }
104
+ });
105
+
106
+ return false;
107
+
108
+ },
109
+
110
+ saved_site_key: function(){
111
+ location.reload();
112
+ },
113
+
114
+ remove_site_key: function(){
115
+
116
+ if(confirm(jQuery(this).data('confirmation'))){
117
+
118
+ jQuery('<span class="spinner"></span>').css({visibility: 'visible', float: 'none'}).prependTo(jQuery(this).parent());
119
+ data = {action: 'remove_site_key', repository_id: jQuery(this).data('repository'), nonce: jQuery(this).data('nonce')}
120
+ jQuery.ajax({url: ajaxurl, type: 'POST', data: data, success: otgs_wp_installer.removed_site_key});
121
+ }
122
+
123
+ return false;
124
+ },
125
+
126
+ removed_site_key: function(){
127
+ location.reload();
128
+ },
129
+
130
+ update_site_key: function(){
131
+ var error_wrap = jQuery(this).closest('.otgsi_register_product_wrap').find('.installer-error-box');
132
+ error_wrap.html('');
133
+
134
+ var spinner = jQuery('<span class="spinner"></span>');
135
+
136
+ spinner.css({visibility: 'visible', float: 'none'}).prependTo(jQuery(this).parent());
137
+ data = {action: 'update_site_key', repository_id: jQuery(this).data('repository'), nonce: jQuery(this).data('nonce')}
138
+ jQuery.ajax({
139
+ url: ajaxurl,
140
+ type: 'POST',
141
+ data: data,
142
+ dataType: 'json',
143
+ complete: function( event, xhr, settings ){
144
+ var error = '';
145
+ if(xhr == 'success') {
146
+ var ret = event.responseJSON;
147
+ if(ret.error){
148
+ error = ret.error;
149
+ }else{
150
+ otgs_wp_installer.updated_site_key(ret);
151
+ }
152
+ }else{
153
+ error = 'Error processing request (' + xhr + '). Please try again!';
154
+ }
155
+
156
+ if( error ){
157
+ error_wrap.html('<p>' + error + '</p>').show();
158
+ spinner.remove();
159
+ }
160
+
161
+ }
162
+ });
163
+
164
+ return false;
165
+
166
+ },
167
+
168
+ updated_site_key: function(ret){
169
+ location.reload();
170
+ },
171
+
172
+ update_downloads_form: function(){
173
+
174
+ var checked = jQuery('.otgsi_downloads_form :checkbox:checked[name="downloads[]"]').length;
175
+
176
+ if(checked){
177
+ jQuery(this).closest('form').find(':submit, :checkbox[name=activate]').removeAttr('disabled');
178
+ }else{
179
+ jQuery(this).closest('form').find(':submit, :checkbox[name=activate]').attr('disabled', 'disabled');
180
+ }
181
+
182
+
183
+ },
184
+
185
+ download_downloads: function(){
186
+
187
+ var activate = jQuery(this).find(":checkbox:checked[name=activate]").val(),
188
+ action_button = jQuery(this).find('input[type="submit"]');
189
+ downloads_form = jQuery(this),
190
+ idx = 0,
191
+ checkboxes = [];
192
+
193
+ jQuery(this).find(':checkbox:checked[name="downloads[]"]').each(function(){
194
+ if(jQuery(this).attr('disabled')) return;
195
+ checkboxes[idx] = jQuery(this);
196
+ idx++;
197
+ jQuery(this).attr('disabled', 'disabled');
198
+ });
199
+
200
+ idx = 0;
201
+
202
+ if( typeof checkboxes[idx] != 'undefined' ){
203
+ download_and_activate( checkboxes[idx] );
204
+ action_button.attr('disabled', 'disabled');
205
+ }
206
+
207
+ function download_and_activate( elem ){
208
+
209
+ var this_tr = elem.closest('tr');
210
+ var is_update = this_tr.find('.installer-red-text').length;
211
+ if(is_update){
212
+ var installing = this_tr.find('.installer-status-updating');
213
+ var installed = this_tr.find('.installer-status-updated');
214
+ }else{
215
+ var installing = this_tr.find('.installer-status-installing');
216
+ var installed = this_tr.find('.installer-status-installed');
217
+
218
+ }
219
+ if(activate){
220
+ var activating = this_tr.find('.installer-status-activating');
221
+ var activated = this_tr.find('.installer-status-activated');
222
+ }
223
+
224
+ if( this_tr.find('.for_spinner_js .spinner').length > 0 ){
225
+ var spinner = this_tr.find('.for_spinner_js .spinner');
226
+ }else{
227
+ var spinner = this_tr.find('.installer-status-downloading');
228
+ }
229
+
230
+ otgs_wp_installer.reset_errors();
231
+ downloads_form.find('div.installer-status-success').hide();
232
+ spinner.css('visibility', 'visible');
233
+ installing.show();
234
+
235
+ var plugin_name = this_tr.find('.installer_plugin_name').html();
236
+ if(is_update){
237
+ otgs_wp_installer.show_download_progress_status(downloads_form, installer_strings.updating.replace('%s', plugin_name));
238
+ }else{
239
+ otgs_wp_installer.show_download_progress_status(downloads_form, installer_strings.installing.replace('%s', plugin_name));
240
+ }
241
+
242
+
243
+ data = {action: 'installer_download_plugin', data: elem.val(), activate: activate}
244
+
245
+ jQuery.ajax({
246
+ url: ajaxurl,
247
+ type: 'POST',
248
+ dataType: 'json',
249
+ data: data,
250
+ success: function(ret){
251
+ installing.hide();
252
+
253
+ if(!ret.success){
254
+ installed.addClass('installer-status-error');
255
+ installed.html(installed.data('fail'));
256
+
257
+ if(ret.message){
258
+ installed.closest('.otgs_wp_installer_table').find('.installer-error-box').html('<p>' + ret.message + '</p>').show();
259
+ }else{
260
+ installed.closest('.otgs_wp_installer_table').find('.installer-error-box').html('<p>' + downloads_form.find('.installer-revalidate-message').html() + '</p>').show();
261
+ }
262
+
263
+
264
+ }
265
+
266
+ installed.show();
267
+ spinner.fadeOut();
268
+
269
+ if(ret.version){
270
+ this_tr.find('.installer_version_installed').html('<span class="installer-green-text">' + ret.version + '</span>');
271
+ }
272
+
273
+ if(ret.success && activate){
274
+
275
+ otgs_wp_installer.show_download_progress_status(downloads_form, installer_strings.activating.replace('%s', plugin_name));
276
+ activating.show();
277
+ spinner.show();
278
+ this_tr.find('.installer-red-text').removeClass('installer-red-text').addClass('installer-green-text').html(ret.version);
279
+
280
+ jQuery.ajax({
281
+ url: ajaxurl,
282
+ type: 'POST',
283
+ dataType: 'json',
284
+ data: {action: 'installer_activate_plugin', plugin_id: ret.plugin_id, nonce: ret.nonce},
285
+ success: function(ret){
286
+ activating.hide();
287
+ if(!ret.error ){
288
+ activated.show();
289
+ }
290
+
291
+ spinner.fadeOut();
292
+
293
+ idx++;
294
+ if( typeof checkboxes[idx] != 'undefined' ){
295
+ download_and_activate( checkboxes[idx] );
296
+ }else{
297
+ otgs_wp_installer.hide_download_progress_status(downloads_form);
298
+ downloads_form.find('div.installer-status-success').show();
299
+ action_button.removeAttr('disabled');
300
+ }
301
+ }
302
+ });
303
+ }else{
304
+ idx++;
305
+ if( typeof checkboxes[idx] != 'undefined' ){
306
+ download_and_activate( checkboxes[idx] );
307
+ }else{
308
+ otgs_wp_installer.hide_download_progress_status(downloads_form);
309
+ downloads_form.find('div.installer-status-success').show();
310
+ action_button.removeAttr('disabled');
311
+ }
312
+ }
313
+ }
314
+
315
+ });
316
+
317
+ };
318
+
319
+ return false;
320
+ },
321
+
322
+
323
+ show_download_progress_status: function(downloads_form, text){
324
+
325
+ downloads_form.find('.installer-download-progress-status').html(text).fadeIn();
326
+
327
+ },
328
+
329
+ hide_download_progress_status: function(downloads_form){
330
+
331
+ downloads_form.find('.installer-download-progress-status').html('').fadeOut();
332
+
333
+ },
334
+
335
+ dismiss_nag: function(){
336
+
337
+ var thisa = jQuery(this);
338
+
339
+ data = {action: 'installer_dismiss_nag', repository: jQuery(this).data('repository')}
340
+
341
+ jQuery.ajax({url: ajaxurl, type: 'POST', dataType:'json', data: data, success:
342
+ function(ret){
343
+ thisa.closest('.otgs-is-dismissible').remove();
344
+ }
345
+ });
346
+
347
+ return false;
348
+ },
349
+
350
+ toggle_subpackages: function(){
351
+ var list = jQuery(this).closest('td').find('.otgs_wp_installer_subtable');
352
+
353
+ if(list.is(':visible')){
354
+ list.slideUp('fast');
355
+ }else{
356
+ list.slideDown('fast');
357
+ }
358
+
359
+
360
+ return false;
361
+
362
+ },
363
+
364
+ scroll_to_repository: function(){
365
+
366
+ var ref = window.location.hash.replace('#', '');
367
+
368
+ if(ref) {
369
+ var split = ref.split('/');
370
+ var repo = split[0];
371
+
372
+ if(typeof split[1] != 'undefined'){
373
+ var package = split[1];
374
+ var repo_element = jQuery('#repository-' + repo);
375
+
376
+
377
+
378
+ if(repo_element.length){
379
+
380
+ jQuery('html, body').animate({
381
+ scrollTop: repo_element.offset().top
382
+ }, 1000);
383
+
384
+ var package_element = jQuery('#repository-' + repo +'_' + package);
385
+
386
+ if(package_element.length && !package_element.is(':visible')){
387
+ package_element.parents('.otgs_wp_installer_subtable').slideDown();
388
+ package_element.addClass('installer_highlight_package');
389
+ }
390
+
391
+ package_element.find('.button-secondary').removeClass('button-secondary').addClass('button-primary');
392
+ }
393
+ }
394
+
395
+ }
396
+
397
+ }
398
+
399
+
400
+ }
401
+
402
+
403
+ jQuery(document).ready(otgs_wp_installer.init);
embedded/otgs/installer/res/js/iframeResizer.min.js ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
1
+ /*! iFrame Resizer (iframeSizer.min.js ) - v2.6.1 - 2014-09-03
2
+ * Desc: Force cross domain iframes to size to content.
3
+ * Requires: iframeResizer.contentWindow.min.js to be loaded into the target frame.
4
+ * Copyright: (c) 2014 David J. Bradshaw - dave@bradshaw.net
5
+ * License: MIT
6
+ */
7
+
8
+ !function(){"use strict";function a(a,b,c){"addEventListener"in window?a.addEventListener(b,c,!1):"attachEvent"in window&&a.attachEvent("on"+b,c)}function b(){var a,b=["moz","webkit","o","ms"];for(a=0;a<b.length&&!w;a+=1)w=window[b[a]+"RequestAnimationFrame"];w||c(" RequestAnimationFrame not supported")}function c(a){y.log&&"object"==typeof console&&console.log(s+"[Host page"+u+"]"+a)}function d(a){function b(){function a(){h(z),f(),y.resizedCallback(z)}i(a,z,"resetPage")}function d(a){var b=a.id;c(" Removing iFrame: "+b),a.parentNode.removeChild(a),y.closedCallback(b),c(" --")}function e(){var a=x.substr(t).split(":");return{iframe:document.getElementById(a[0]),id:a[0],height:a[1],width:a[2],type:a[3]}}function j(a){var b=Number(y["max"+a]),d=Number(y["min"+a]),e=a.toLowerCase(),f=Number(z[e]);if(d>b)throw new Error("Value for min"+a+" can not be greater than max"+a);c(" Checking "+e+" is in range "+d+"-"+b),d>f&&(f=d,c(" Set "+e+" to min value")),f>b&&(f=b,c(" Set "+e+" to max value")),z[e]=""+f}function k(){var b=a.origin,d=z.iframe.src.split("/").slice(0,3).join("/");if(y.checkOrigin&&(c(" Checking connection is from: "+d),""+b!="null"&&b!==d))throw new Error("Unexpected message received from: "+b+" for "+z.iframe.id+". Message was: "+a.data+". This error can be disabled by adding the checkOrigin: false option.");return!0}function l(){return s===(""+x).substr(0,t)}function m(){var a=z.type in{"true":1,"false":1};return a&&c(" Ignoring init message from meta parent page"),a}function n(){var a=x.substr(x.indexOf(":")+r+6);c(" MessageCallback passed: {iframe: "+z.iframe.id+", message: "+a+"}"),y.messageCallback({iframe:z.iframe,message:a}),c(" --")}function o(){if(null===z.iframe)throw new Error("iFrame ("+z.id+") does not exist on "+u);return!0}function q(){c(" Reposition requested from iFrame"),v={x:z.width,y:z.height},f()}function w(){switch(z.type){case"close":d(z.iframe),y.resizedCallback(z);break;case"message":n();break;case"scrollTo":q();break;case"reset":g(z);break;case"init":b(),y.initCallback(z.iframe);break;default:b()}}var x=a.data,z={};l()&&(c(" Received: "+x),z=e(),j("Height"),j("Width"),!m()&&o()&&k()&&(w(),p=!1))}function e(){null===v&&(v={x:void 0!==window.pageXOffset?window.pageXOffset:document.documentElement.scrollLeft,y:void 0!==window.pageYOffset?window.pageYOffset:document.documentElement.scrollTop},c(" Get position: "+v.x+","+v.y))}function f(){null!==v&&(window.scrollTo(v.x,v.y),c(" Set position: "+v.x+","+v.y),v=null)}function g(a){function b(){h(a),j("reset","reset",a.iframe)}c(" Size reset requested by "+("init"===a.type?"host page":"iFrame")),e(),i(b,a,"init")}function h(a){function b(b){a.iframe.style[b]=a[b]+"px",c(" IFrame ("+a.iframe.id+") "+b+" set to "+a[b]+"px")}y.sizeHeight&&b("height"),y.sizeWidth&&b("width")}function i(a,b,d){d!==b.type&&w?(c(" Requesting animation frame"),w(a)):a()}function j(a,b,d){c("["+a+"] Sending msg to iframe ("+b+")"),d.contentWindow.postMessage(s+b,"*")}function k(){function b(){function a(a){1/0!==y[a]&&0!==y[a]&&(k.style[a]=y[a]+"px",c(" Set "+a+" = "+y[a]+"px"))}a("maxHeight"),a("minHeight"),a("maxWidth"),a("minWidth")}function d(a){return""===a&&(k.id=a="iFrameResizer"+o++,c(" Added missing iframe ID: "+a+" ("+k.src+")")),a}function e(){c(" IFrame scrolling "+(y.scrolling?"enabled":"disabled")+" for "+l),k.style.overflow=!1===y.scrolling?"hidden":"auto",k.scrolling=!1===y.scrolling?"no":"yes"}function f(){("number"==typeof y.bodyMargin||"0"===y.bodyMargin)&&(y.bodyMarginV1=y.bodyMargin,y.bodyMargin=""+y.bodyMargin+"px")}function h(){return l+":"+y.bodyMarginV1+":"+y.sizeWidth+":"+y.log+":"+y.interval+":"+y.enablePublicMethods+":"+y.autoResize+":"+y.bodyMargin+":"+y.heightCalculationMethod+":"+y.bodyBackground+":"+y.bodyPadding+":"+y.tolerance}function i(b){a(k,"load",function(){var a=p;j("iFrame.onload",b,k),!a&&y.heightCalculationMethod in x&&g({iframe:k,height:0,width:0,type:"init"})}),j("init",b,k)}var k=this,l=d(k.id);e(),b(),f(),i(h())}function l(a){if("object"!=typeof a)throw new TypeError("Options is not an object.")}function m(){function a(a){if("IFRAME"!==a.tagName.toUpperCase())throw new TypeError("Expected <IFRAME> tag, found <"+a.tagName+">.");k.call(a)}function b(a){a=a||{},l(a);for(var b in z)z.hasOwnProperty(b)&&(y[b]=a.hasOwnProperty(b)?a[b]:z[b])}return function(c,d){b(c),Array.prototype.forEach.call(document.querySelectorAll(d||"iframe"),a)}}function n(a){a.fn.iFrameResize=function(b){return b=b||{},l(b),y=a.extend({},z,b),this.filter("iframe").each(k).end()}}var o=0,p=!0,q="message",r=q.length,s="[iFrameSizer]",t=s.length,u="",v=null,w=window.requestAnimationFrame,x={max:1,scroll:1,bodyScroll:1,documentElementScroll:1},y={},z={autoResize:!0,bodyBackground:null,bodyMargin:null,bodyMarginV1:8,bodyPadding:null,checkOrigin:!0,enablePublicMethods:!1,heightCalculationMethod:"offset",interval:32,log:!1,maxHeight:1/0,maxWidth:1/0,minHeight:0,minWidth:0,scrolling:!1,sizeHeight:!0,sizeWidth:!1,tolerance:0,closedCallback:function(){},initCallback:function(){},messageCallback:function(){},resizedCallback:function(){}};b(),a(window,"message",d),"jQuery"in window&&n(jQuery),"function"==typeof define&&define.amd?define(function(){return m()}):window.iFrameResize=m()}();
9
+ //# sourceMappingURL=../src/iframeResizer.map
10
+
embedded/otgs/installer/res/js/installer_theme_install.js ADDED
@@ -0,0 +1,97 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ jQuery( document ).ready( function( $ ) {
2
+
3
+ /** Append OTGS Theme tab */
4
+ var js_array= installer_theme_install_localize.js_array_installer;
5
+
6
+ if (!($.isEmptyObject(js_array))) {
7
+ //Unempty
8
+ for(var key in js_array) {
9
+ //Dont append if we are on commercial plugins tab page and if there are no themes
10
+ if ((!(js_array[key]['is_commercial_plugin_tab'])) && (!(installer_theme_install_localize.no_associated_themes))) {
11
+ $('div.wp-filter ul.filter-links').append('<li><a data-sort="'+key+'" href="#">'+ js_array[key]['the_hyperlink_text'] +'</a></li>');
12
+ }
13
+ }
14
+ }
15
+
16
+ /** Page load event tab selected identifier */
17
+ var loaded_browsing_tab=installer_theme_extended_object.getParameterByName('browse');
18
+ if (loaded_browsing_tab.length > 0) {
19
+
20
+ var frontend_tab_selected_tab = loaded_browsing_tab;
21
+
22
+ } else if (0 == loaded_browsing_tab.length){
23
+
24
+ //WordPress defaults to 'Featured' when theme install is loaded without the browse parameter
25
+ var frontend_tab_selected_tab = 'featured';
26
+ }
27
+
28
+ /** Prepare data on page load event for AJAX */
29
+ var data = {
30
+ action: 'installer_theme_frontend_selected_tab',
31
+ installer_theme_frontend_selected_tab_nonce: installer_theme_install_localize.installer_theme_frontend_selected_tab_nonce,
32
+ frontend_tab_selected :frontend_tab_selected_tab
33
+ };
34
+
35
+ //Call AJAX
36
+ installer_theme_extended_object.doAJAX(data,frontend_tab_selected_tab,js_array);
37
+
38
+ /** When user clicks on any tab */
39
+ $(document).on('click','.filter-links li > a',function () {
40
+
41
+ //Get data_sort
42
+ var data_sort =$(this).attr('data-sort');
43
+
44
+ if (data_sort) {
45
+ //data_sort is set, prepare data
46
+ var data = {
47
+ action: 'installer_theme_frontend_selected_tab',
48
+ installer_theme_frontend_selected_tab_nonce: installer_theme_install_localize.installer_theme_frontend_selected_tab_nonce,
49
+ frontend_tab_selected : data_sort
50
+ };
51
+
52
+ //Call AJAX
53
+ installer_theme_extended_object.doAJAX(data,data_sort,js_array);
54
+
55
+ }
56
+ });
57
+
58
+ var fullhash = window.location.hash;
59
+ if (fullhash.length > 0) {
60
+ var product_selector=fullhash+' '+'.enter_site_key_js';
61
+ if ($(product_selector).length ) {
62
+ $(product_selector).click();
63
+ }
64
+ }
65
+ });
66
+
67
+ //Installer theme extended JS object for methods
68
+ var installer_theme_extended_object = {
69
+
70
+ getParameterByName: function(name) {
71
+ name = name.replace(/[\[]/, "\\[").replace(/[\]]/, "\\]");
72
+ var regex = new RegExp("[\\?&]" + name + "=([^&#]*)"),
73
+ results = regex.exec(location.search);
74
+ return results === null ? "" : decodeURIComponent(results[1].replace(/\+/g, " "));
75
+ },
76
+
77
+ doAJAX: function(data,data_sort,js_array) {
78
+
79
+ //We only want to post to AJAX if its an OTGS tab
80
+ jQuery.post(installer_theme_install_localize.ajaxurl, data, function(response) {
81
+ //AJAX response
82
+ var myObject = jQuery.parseJSON(response);
83
+ if (typeof myObject != "undefined") {
84
+ if(myObject.hasOwnProperty("output")){
85
+ var tab_selected= myObject.output;
86
+ if (data_sort in js_array) {
87
+ if (!(installer_theme_install_localize.js_array_installer[tab_selected]['registration_status'])) {
88
+ //Not registered, no theme response
89
+ var unregistered_message= myObject.unregistered_messages;
90
+ jQuery('.no-themes').html(unregistered_message);
91
+ }
92
+ }
93
+ }
94
+ }
95
+ });
96
+ }
97
+ };
embedded/otgs/installer/templates/downloads-list-compact.php ADDED
@@ -0,0 +1,80 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ <form method="post" class="otgsi_downloads_form">
3
+
4
+ <table class="installer-plugins-list-compact">
5
+ <thead>
6
+ <tr>
7
+ <th>&nbsp;</th>
8
+ <th><?php _e('Plugin', 'installer') ?></th>
9
+ <th><img src="<?php echo $this->plugin_url() ?>/res/img/globe.png" alt="<?php esc_attr_e('Available', 'installer') ?>" width="16" height="16"></th>
10
+ <th><img src="<?php echo $this->plugin_url() ?>/res/img/computer.png" alt="<?php esc_attr_e('Installed', 'installer') ?>" width="16" height="16"></th>
11
+ <th><img src="<?php echo $this->plugin_url() ?>/res/img/dn2.gif" alt="<?php esc_attr_e('Downloading', 'installer') ?>" width="16" height="16"></th>
12
+ <th><img src="<?php echo $this->plugin_url() ?>/res/img/on.png" alt="<?php esc_attr_e('Activate', 'installer') ?>" width="16" height="16"></th>
13
+ </tr>
14
+ </thead>
15
+ <tbody>
16
+ <?php foreach($product['downloads'] as $download): ?>
17
+ <?php if(empty($tr_oddeven) || $tr_oddeven == 'even') $tr_oddeven = 'odd'; else $tr_oddeven = 'even'; ?>
18
+ <tr class="<?php echo $tr_oddeven ?>">
19
+ <td>
20
+ <label>
21
+ <?php
22
+ $url = $this->append_site_key_to_download_url($download['url'], $site_key, $repository_id );
23
+
24
+ $download_data = array(
25
+ 'url' => $url,
26
+ 'slug' => $download['slug'],
27
+ 'nonce' => wp_create_nonce('install_plugin_' . $url),
28
+ 'repository_id' => $repository_id
29
+ );
30
+
31
+ $disabled = $expired ||
32
+ (
33
+ $this->plugin_is_installed($download['name'], $download['slug'], $download['version']) &&
34
+ !$this->plugin_is_embedded_version($download['name'], $download['slug'])
35
+ ) || WP_Installer()->dependencies->cant_download( $repository_id );
36
+
37
+ ?>
38
+ <input type="checkbox" name="downloads[]" value="<?php echo base64_encode(json_encode($download_data)); ?>" <?php
39
+ if($disabled): ?>disabled="disabled"<?php endif; ?> />&nbsp;
40
+
41
+ </label>
42
+ </td>
43
+ <td class="installer_plugin_name"><?php echo $download['name'] ?></td>
44
+ <td><?php echo $download['version'] ?></td>
45
+ <td class="installer_version_installed">
46
+ <?php if($v = $this->plugin_is_installed($download['name'], $download['slug'])):
47
+ $class = version_compare($v, $download['version'], '>=') ? 'installer-green-text' : 'installer-red-text'; ?>
48
+ <span class="<?php echo $class ?>"><?php echo $v; ?></span>
49
+ <?php endif; ?>
50
+ </td>
51
+ <td class="twelve">
52
+ <div class="installer-status-downloading"><?php _e('downloading...', 'installer') ?></div>
53
+ <div class="installer-status-downloaded" data-fail="<?php _e('failed!', 'installer') ?>"><?php _e('downloaded', 'installer') ?></div>
54
+ </td>
55
+ <td class="twelve">
56
+ <div class="installer-status-activating"><?php _e('activating', 'installer') ?></div>
57
+ <div class="installer-status-activated"><?php _e('activated', 'installer') ?></div>
58
+ </td>
59
+ </tr>
60
+ <?php endforeach; ?>
61
+ </tbody>
62
+ </table>
63
+
64
+ <?php if( !WP_Installer()->dependencies->is_uploading_allowed() ): ?>
65
+ <p class="installer-error-box"><?php printf(__('Downloading is not possible because WordPress cannot write into the plugins folder. %sHow to fix%s.', 'installer'),
66
+ '<a href="http://codex.wordpress.org/Changing_File_Permissions">', '</a>') ?></p>
67
+ <?php elseif( WP_Installer()->dependencies->is_win_paths_exception($repository_id) ): ?>
68
+ <p><?php echo WP_Installer()->dependencies->win_paths_exception_message() ?></p>
69
+ <?php endif;?>
70
+
71
+ <br />
72
+ <input type="submit" class="button-secondary" value="<?php esc_attr_e('Download', 'installer') ?>" disabled="disabled" />
73
+ &nbsp;
74
+ <label><input name="activate" type="checkbox" value="1" disabled="disabled" />&nbsp;<?php _e('Activate after download', 'installer') ?></label>
75
+
76
+ <div class="installer-download-progress-status"></div>
77
+ <div class="installer-status-success"><?php _e('Operation complete!', 'installer') ?></div>
78
+
79
+ <span class="installer-revalidate-message hidden"><?php _e("Download failed!\n\nClick OK to revalidate your subscription or CANCEL to try again.", 'installer') ?></span>
80
+ </form>
embedded/otgs/installer/templates/downloads-list.php ADDED
@@ -0,0 +1,85 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <br clear="all" /><br />
2
+ <strong><?php _e('Downloads:', 'installer') ?></strong>
3
+
4
+ <form method="post" class="otgsi_downloads_form">
5
+
6
+ <table class="widefat">
7
+ <thead>
8
+ <tr>
9
+ <th>&nbsp;</th>
10
+ <th><?php _e('Plugin', 'installer') ?></th>
11
+ <th><?php _e('Current version', 'installer') ?></th>
12
+ <th><?php _e('Released', 'installer') ?></th>
13
+ <th><?php _e('Installed version', 'installer') ?></th>
14
+ <th>&nbsp;</th>
15
+ <th>&nbsp;</th>
16
+ <th>&nbsp;</th>
17
+ </tr>
18
+ </thead>
19
+ <tbody>
20
+ <?php
21
+ foreach($package['downloads'] as $download): ?>
22
+ <tr>
23
+ <td>
24
+ <label>
25
+ <?php
26
+ $url = $this->append_site_key_to_download_url($download['url'], $site_key, $repository_id);
27
+
28
+ $download_data = array(
29
+ 'url' => $url,
30
+ 'slug' => $download['slug'],
31
+ 'nonce' => wp_create_nonce('install_plugin_' . $url),
32
+ 'repository_id' => $repository_id
33
+ );
34
+ ?>
35
+ <input type="checkbox" name="downloads[]" value="<?php echo base64_encode(json_encode($download_data)); ?>" <?php
36
+ if($this->plugin_is_installed($download['name'], $download['slug'], $download['version']) && !$this->plugin_is_embedded_version($download['name'], $download['slug']) || WP_Installer()->dependencies->cant_download($repository_id) ): ?>disabled="disabled"<?php endif; ?> />&nbsp;
37
+
38
+ </label>
39
+ </td>
40
+ <td class="installer_plugin_name"><?php echo $download['name'] ?></td>
41
+ <td><?php echo $download['version'] ?></td>
42
+ <td><?php echo date_i18n('F j, Y', strtotime($download['date'])) ?></td>
43
+ <td class="installer_version_installed">
44
+ <?php if($v = $this->plugin_is_installed($download['name'], $download['slug'])): $class = version_compare($v, $download['version'], '>=') ? 'installer-green-text' : 'installer-red-text'; ?>
45
+ <span class="<?php echo $class ?>"><?php echo $v; ?></span>
46
+ <?php if($this->plugin_is_embedded_version($download['name'], $download['slug'])): ?>&nbsp;<?php _e('(embedded)', 'installer'); ?><?php endif; ?>
47
+ <?php endif; ?>
48
+ </td>
49
+ <td>
50
+ <span class="installer-status-installing"><?php _e('installing...', 'installer') ?></span>
51
+ <span class="installer-status-updating"><?php _e('updating...', 'installer') ?></span>
52
+ <span class="installer-status-installed" data-fail="<?php _e('failed!', 'installer') ?>"><?php _e('installed', 'installer') ?></span>
53
+ <span class="installer-status-updated" data-fail="<?php _e('failed!', 'installer') ?>"><?php _e('updated', 'installer') ?></span>
54
+ </td>
55
+ <td>
56
+ <span class="installer-status-activating"><?php _e('activating', 'installer') ?></span>
57
+ <span class="installer-status-activated"><?php _e('activated', 'installer') ?></span>
58
+ </td>
59
+ <td class="for_spinner_js"><span class="spinner"></span></td>
60
+ </tr>
61
+ <?php endforeach; ?>
62
+ </tbody>
63
+ </table>
64
+
65
+ <br />
66
+
67
+ <div class="installer-error-box">
68
+ <?php if( !WP_Installer()->dependencies->is_uploading_allowed() ): ?>
69
+ <p><?php printf(__('Downloading is not possible because WordPress cannot write into the plugins folder. %sHow to fix%s.', 'installer'),
70
+ '<a href="http://codex.wordpress.org/Changing_File_Permissions">', '</a>') ?></p>
71
+ <?php elseif( WP_Installer()->dependencies->is_win_paths_exception($repository_id) ): ?>
72
+ <p><?php echo WP_Installer()->dependencies->win_paths_exception_message() ?></p>
73
+ <?php endif; ?>
74
+ </div>
75
+
76
+ <input type="submit" class="button-secondary" value="<?php esc_attr_e('Download', 'installer') ?>" disabled="disabled" />
77
+ &nbsp;
78
+ <label><input name="activate" type="checkbox" value="1" disabled="disabled" />&nbsp;<?php _e('Activate after download', 'installer') ?></label>
79
+
80
+ <div class="installer-download-progress-status"></div>
81
+
82
+ <div class="installer-status-success"><?php _e('Operation complete!', 'installer') ?></div>
83
+
84
+ <span class="installer-revalidate-message hidden"><?php _e("Download failed!\n\nPlease refresh the page and try again.", 'installer') ?></span>
85
+ </form>
embedded/otgs/installer/templates/products-compact.php ADDED
@@ -0,0 +1,129 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <h3><?php echo $args['box_title'] ?></h3>
2
+
3
+ <?php
4
+ if(empty($args['repository']) || empty($args['package']) || empty($args['product'])){
5
+ echo __('Incorrect setup', 'installer');
6
+ return;
7
+ }
8
+
9
+ $product = false;
10
+ foreach($this->settings['repositories'][$repository_id]['data']['packages'] as $package_idx => $package){
11
+
12
+ //pre 1.3 backwardds compatibility
13
+ if(!isset($package['id'])){
14
+ $package['id'] = sanitize_title_with_dashes($package['name']);
15
+ }
16
+
17
+ if($package['id'] == $args['package']){
18
+ $product = $this->settings['repositories'][$repository_id]['data']['packages'][$package_idx]['products'][$args['product']];
19
+ break;
20
+ }
21
+ }
22
+
23
+
24
+ if(!$product){
25
+ echo __('Invalid product', 'installer');
26
+ return;
27
+ }
28
+
29
+ if(isset($this->settings['repositories'][$repository_id])){
30
+ if(isset($this->settings['repositories'][$repository_id]['subscription']['key'])){
31
+ $site_key = $this->settings['repositories'][$repository_id]['subscription']['key'];
32
+ }else{
33
+ $site_key = false;
34
+ }
35
+ }else{
36
+ echo __('Unknown repository', 'installer');
37
+ return;
38
+ }
39
+
40
+ $subscription_type = $this->get_subscription_type_for_repository($repository_id);
41
+ $expired = false;
42
+
43
+ if($subscription_type != $product['subscription_type'] && !$this->have_superior_subscription($subscription_type, $product) && $site_key){
44
+ $subscription_no_match = sprintf(__(' Your current site key (%s) does not match the selected product (%s).', 'installer'), $site_key, $product['name']);
45
+ }
46
+
47
+ if(!isset($args['product_name'])) $args['product_name'] = $product['name'];
48
+
49
+ ?>
50
+
51
+ <div class="otgs_wp_installer_table otgs_wp_installer_table_compact">
52
+
53
+ <p><?php echo $args['box_description'] ?></p>
54
+
55
+
56
+ <?php if(!$this->repository_has_subscription($repository_id) || !empty($subscription_no_match)): ?>
57
+
58
+ <?php if(!empty($subscription_no_match)): ?>
59
+ <div class="installer-warn-box">
60
+ <?php echo $subscription_no_match; ?>
61
+ </div>
62
+ <br />
63
+ <?php endif; ?>
64
+
65
+ <a class="button-primary" href="<?php echo $this->append_parameters_to_buy_url($product['url'], $repository_id, $args) ?>"><?php printf(__('Buy %s', 'installer'), $args['product_name']) ?></a>
66
+
67
+ <div>
68
+ <br />
69
+ <?php printf(__('Already bought %s?', 'installer'), $args['product_name']) ?>
70
+ <a class="enter_site_key_js" href="#"><?php _e('Enter site key', 'installer') ?></a>&nbsp;&nbsp;
71
+
72
+ <form class="otgsi_site_key_form" method="post">
73
+ <input type="hidden" name="action" value="save_site_key" />
74
+ <input type="hidden" name="nonce" value="<?php echo wp_create_nonce('save_site_key_' . $repository_id) ?>" />
75
+ <input type="hidden" name="repository_id" value="<?php echo $repository_id ?>">
76
+ <input type="text" size="10" name="site_key_<?php echo $repository_id ?>" />
77
+ <input class="button-secondary" type="submit" value="<?php esc_attr_e('Add', 'installer') ?>" />
78
+ </form>
79
+ <div class="installer-error-box hidden" style="margin-top:10px;"></div>
80
+ </div>
81
+
82
+ <?php else: ?>
83
+
84
+ <?php if($this->repository_has_expired_subscription($repository_id)): $expired = true; ?>
85
+
86
+ <div><p class="installer-warn-box"><?php _e('Subscription is expired.', 'installer') ?></p></div>
87
+
88
+ <?php else: ?>
89
+
90
+ <?php if($this->show_subscription_renew_warning($repository_id, $subscription_type)): ?>
91
+
92
+ <ul class="installer-products-list">
93
+ <?php foreach($product['renewals'] as $renewal): ?>
94
+ <li>
95
+ <a href="<?php echo $this->append_parameters_to_buy_url($renewal['url'], $repository_id, $args) ?>"><?php printf(__('Renew %s', 'installer'), $args['product_name']) ?></a>
96
+ </li>
97
+ <?php endforeach; ?>
98
+ </ul>
99
+
100
+ <?php endif; ?>
101
+
102
+ <?php endif; ?>
103
+
104
+ <center>
105
+ <a class="remove_site_key_js" href="#" data-repository=<?php echo $repository_id ?> data-confirmation="<?php esc_attr_e('Are you sure you want to remove this site key?', 'installer') ?>" data-nonce="<?php echo wp_create_nonce('remove_site_key_' . $repository_id) ?>"><?php printf(__("Remove current site key (%s)", 'installer'), $site_key) ?></a>
106
+ </center>
107
+ <br />
108
+
109
+ <?php include $this->plugin_path() . '/templates/downloads-list-compact.php'; ?>
110
+
111
+
112
+
113
+ <?php endif; ?>
114
+
115
+ <?php
116
+ if( isset( $args[ 'name' ] ) ):
117
+ $support_link = $this->get_support_tag_by_name($args['name'], $args['repository']); ?>
118
+
119
+ <?php if($support_link): ?>
120
+ <p><a href="<?php echo $support_link ?>" target="_blank"><?php printf(__('%s support on wpml.org', 'installer'), $args['name'] ) ?></a></p>
121
+
122
+ <?php endif; ?>
123
+ <?php
124
+ // compatibility for installer 1.1
125
+ elseif( isset( $args[ 'support_link' ] ) ): ?>
126
+ <p><?php echo $args[ 'support_link' ]; ?></p>
127
+ <?php endif; ?>
128
+
129
+ </div>
embedded/otgs/installer/templates/repository-listing.php ADDED
@@ -0,0 +1,179 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php if((!$this->repository_has_subscription($repository_id) && $match = $this->get_matching_cp($repository)) && $match['exp']): ?>
2
+ <p class="alignright installer_highlight"><strong><?php printf('Price offers available until %s', date_i18n(get_option( 'date_format' ), $match['exp'])) ?></strong></p>
3
+ <?php endif; ?>
4
+
5
+ <h3 id="repository-<?php echo $repository_id ?>"><?php echo $repository['data']['name'] ?></h3>
6
+ <?php
7
+ $generic_product_name = $this->settings['repositories'][$repository_id]['data']['product-name'];
8
+ ?>
9
+ <table class="widefat otgs_wp_installer_table" id="installer_repo_<?php echo $repository_id ?>">
10
+
11
+ <tr>
12
+ <td>&nbsp;</td>
13
+ <td class="otgsi_register_product_wrap" align="center" valign="top">
14
+ <?php // IF NO SUBSCRIPTION ?>
15
+ <?php if(!$this->repository_has_subscription($repository_id)): ?>
16
+
17
+ <div style="text-align: right;">
18
+ <span><?php _e('Already bought?', 'installer'); ?>&nbsp;</span>
19
+ <a class="enter_site_key_js button-primary" href="#"><?php printf(__('Register %s', 'installer'), $generic_product_name); ?></a>&nbsp;&nbsp;
20
+ <form class="otgsi_site_key_form" method="post">
21
+ <input type="hidden" name="action" value="save_site_key" />
22
+ <input type="hidden" name="nonce" value="<?php echo wp_create_nonce('save_site_key_' . $repository_id) ?>" />
23
+ <input type="hidden" name="repository_id" value="<?php echo $repository_id ?>">
24
+ <?php _e('2. Enter your site key', 'installer'); ?>
25
+ <input type="text" size="10" name="site_key_<?php echo $repository_id ?>" placeholder="<?php echo esc_attr('site key') ?>" />
26
+ <input class="button-primary" type="submit" value="<?php esc_attr_e('OK', 'installer') ?>" />
27
+ <input class="button-secondary cancel_site_key_js" type="button" value="<?php esc_attr_e('Cancel', 'installer') ?>" />
28
+
29
+ <div class="alignleft" style="margin-top:6px;"><?php printf(__('1. Go to your %s%s account%s and add this site URL: %s', 'installer'),
30
+ '<a href="' . $this->settings['repositories'][$repository_id]['data']['site_keys_management_url'] . '?add='.urlencode($this->get_installer_site_url( $repository_id )).'">',
31
+ $generic_product_name, '</a>', $this->get_installer_site_url( $repository_id )); ?></div>
32
+ </form>
33
+
34
+
35
+ </div>
36
+
37
+ <?php
38
+ $site_key = false;
39
+
40
+ // IF SUBSCRIPTION
41
+ else:
42
+
43
+ $site_key = $this->settings['repositories'][$repository_id]['subscription']['key'];
44
+ $subscription_type = $this->get_subscription_type_for_repository($repository_id);
45
+
46
+ $upgrade_options = $this->get_upgrade_options($repository_id);
47
+ $expired = false;
48
+
49
+ ?>
50
+
51
+ <?php if($this->repository_has_expired_subscription($repository_id)): $expired = true; ?>
52
+ <div>
53
+ <p class="installer-warn-box">
54
+ <?php _e('Subscription expired. You need to either purchase a new subscription or upgrade if available.', 'installer') ?>
55
+ <span class="alignright">
56
+ <a class="update_site_key_js button-secondary" href="#" data-repository=<?php echo $repository_id ?> data-nonce="<?php echo wp_create_nonce('update_site_key_' . $repository_id) ?>">
57
+ <?php _e('Revalidate subscription', 'installer'); ?>
58
+ </a>
59
+ </span>
60
+ <br />
61
+ <span class="details"><?php _e("If you have already purchased or renewed your subscription and you can still see this message, please revalidate your subscription", 'installer') ?></span>
62
+ </p>
63
+ </div>
64
+ <?php else: ?>
65
+ <?php $this->show_subscription_renew_warning($repository_id, $subscription_type); ?>
66
+ <?php endif; ?>
67
+
68
+ <div class="alignright">
69
+ <a class="remove_site_key_js button-secondary" href="#" data-repository=<?php echo $repository_id ?> data-confirmation="<?php esc_attr_e('Are you sure you want to unregister?', 'installer') ?>" data-nonce="<?php echo wp_create_nonce('remove_site_key_' . $repository_id) ?>"><?php printf(__("Unregister %s from this site", 'installer'), $generic_product_name) ?></a>&nbsp;
70
+ <a class="update_site_key_js button-secondary" href="#" data-repository=<?php echo $repository_id ?> data-nonce="<?php echo wp_create_nonce('update_site_key_' . $repository_id) ?>">
71
+ <?php _e('Check for updates', 'installer'); ?>
72
+ </a>
73
+ </div>
74
+
75
+ <?php if(empty($expired)): ?>
76
+ <div class="alignleft">
77
+ <?php if($expires = $this->settings['repositories'][$repository_id]['subscription']['data']->expires): ?>
78
+ <?php printf(__('%s is registered on this site. You will receive automatic updates until %s', 'installer'), $generic_product_name, date_i18n('F j, Y', strtotime($expires))); ?>
79
+ <?php else: ?>
80
+ <?php printf(__('%s is registered on this site. Your Lifetime account gives you updates for life.', 'installer'), $generic_product_name); ?>
81
+ <?php endif; ?>
82
+ </div>
83
+ <?php endif; //if(empty($expired)) ?>
84
+
85
+ <?php endif; // if(!repository_has_subscription) ?>
86
+ <br clear="all" />
87
+ <div class="installer-error-box hidden"></div>
88
+
89
+ </td>
90
+ </tr>
91
+
92
+ <?php
93
+
94
+ $subscription_type = isset($subscription_type) ? $subscription_type : null;
95
+ $expired = isset($expired) ? $expired : null;
96
+ $upgrade_options = isset($upgrade_options) ? $upgrade_options : null;
97
+ $packages = $this->_render_product_packages($repository['data']['packages'], $subscription_type, $expired, $upgrade_options, $repository_id);
98
+ if(empty($subscription_type) || $expired){
99
+ $subpackages_expandable = true;
100
+ }else{
101
+ $subpackages_expandable = false;
102
+ }
103
+
104
+ ?>
105
+
106
+ <?php foreach($packages as $package): ?>
107
+ <tr id="repository-<?php echo $repository_id ?>_<?php echo $package['id'] ?>">
108
+ <td><img width="140" height="140" src="<?php echo $package['image_url'] ?>" /></td>
109
+ <td>
110
+ <p><strong><?php echo $package['name'] ?></strong></p>
111
+ <p><?php echo $package['description'] ?></p>
112
+
113
+ <?php if($package['products']): ?>
114
+ <?php foreach($package['products'] as $product): ?>
115
+ <ul class="installer-products-list" style="display:inline">
116
+ <li>
117
+ <a class="button-secondary" href="<?php echo $product['url'] ?>"><?php echo $product['label'] ?></a>
118
+ </li>
119
+ </ul>
120
+ <?php endforeach; ?>
121
+ <?php endif; ?>
122
+
123
+ <?php if($package['downloads']): ?>
124
+ <?php include $this->plugin_path() . '/templates/downloads-list.php'; ?>
125
+ <?php endif; ?>
126
+
127
+ <?php if(!empty($package['sub-packages'])): ?>
128
+
129
+ <?php $subpackages = $this->_render_product_packages($package['sub-packages'], $subscription_type, $expired, $upgrade_options, $repository_id); ?>
130
+
131
+ <?php if($subpackages): ?>
132
+
133
+ <?php if($subpackages_expandable): ?>
134
+ <h5><a class="installer_expand_button" href="#" title="<?php esc_attr_e('Click to see individual components options.', 'installer') ?>"><?php _e('Individual components', 'installer') ?></a></h5>
135
+ <?php endif; ?>
136
+
137
+ <table class="otgs_wp_installer_subtable" style="<?php if($subpackages_expandable) echo 'display:none' ?>">
138
+ <?php foreach($subpackages as $package): ?>
139
+ <tr id="repository-<?php echo $repository_id ?>_<?php echo $package['id'] ?>">
140
+ <td><img width="70" height="70" src="<?php echo $package['image_url'] ?>" /></td>
141
+ <td>
142
+ <p><strong><?php echo $package['name'] ?></strong></p>
143
+ <p><?php echo $package['description'] ?></p>
144
+
145
+ <?php if($package['products']): ?>
146
+ <?php foreach($package['products'] as $product): ?>
147
+ <ul class="installer-products-list" style="display:inline">
148
+ <li>
149
+ <a class="button-secondary" href="<?php echo $product['url'] ?>"><?php echo $product['label'] ?></a>
150
+ </li>
151
+ </ul>
152
+ <?php endforeach; ?>
153
+ <?php endif; ?>
154
+
155
+ <?php if($package['downloads']): ?>
156
+ <?php include $this->plugin_path() . '/templates/downloads-list.php'; ?>
157
+ <?php endif; ?>
158
+ </td>
159
+ </tr>
160
+ <?php endforeach; ?>
161
+ </table>
162
+ <?php endif; ?>
163
+
164
+ <?php endif; ?>
165
+
166
+
167
+ </td>
168
+ </tr>
169
+
170
+ <?php endforeach; ?>
171
+
172
+ </table>
173
+
174
+
175
+ <p><i><?php printf(__('This page lets you install plugins and update existing plugins. To remove any of these plugins, go to the %splugins%s page and if you have the permission to remove plugins you should be able to do this.', 'installer'), '<a href="' . admin_url('plugins.php') . '">' , '</a>'); ?></i></p>
176
+
177
+
178
+
179
+ <br />
inc/class-wcml-cart.php CHANGED
@@ -17,7 +17,7 @@ class WCML_Cart
17
  add_action( 'wp_ajax_nopriv_woocommerce_add_to_cart', array( $this, 'wcml_refresh_fragments' ), 0 );
18
 
19
  //cart
20
- add_action( 'woocommerce_before_calculate_totals', array( $this, 'woocommerce_calculate_totals' ) );
21
  add_action( 'woocommerce_get_cart_item_from_session', array( $this, 'translate_cart_contents' ), 10, 3 );
22
  add_action( 'woocommerce_cart_loaded_from_session', array( $this, 'translate_cart_subtotal' ) );
23
  add_action( 'woocommerce_before_checkout_process', array( $this, 'wcml_refresh_cart_total' ) );
@@ -186,9 +186,6 @@ class WCML_Cart
186
 
187
  public function translate_cart_subtotal( $cart ) {
188
 
189
- if ( apply_filters( 'translate_cart_subtotal_exception', false, $cart ) ){
190
- return;
191
- }
192
  if( apply_filters( 'wcml_calculate_totals_exception', true ) ){
193
  $cart->calculate_totals();
194
  }
17
  add_action( 'wp_ajax_nopriv_woocommerce_add_to_cart', array( $this, 'wcml_refresh_fragments' ), 0 );
18
 
19
  //cart
20
+ add_action( 'woocommerce_before_calculate_totals', array( $this, 'woocommerce_calculate_totals' ), 100 );
21
  add_action( 'woocommerce_get_cart_item_from_session', array( $this, 'translate_cart_contents' ), 10, 3 );
22
  add_action( 'woocommerce_cart_loaded_from_session', array( $this, 'translate_cart_subtotal' ) );
23
  add_action( 'woocommerce_before_checkout_process', array( $this, 'wcml_refresh_cart_total' ) );
186
 
187
  public function translate_cart_subtotal( $cart ) {
188
 
 
 
 
189
  if( apply_filters( 'wcml_calculate_totals_exception', true ) ){
190
  $cart->calculate_totals();
191
  }
inc/class-wcml-compatibility.php CHANGED
@@ -1,20 +1,37 @@
1
  <?php
2
 
3
  class WCML_Compatibility {
4
-
5
- function __construct(){
6
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7
  $this->init();
8
 
9
  }
10
 
11
  function init(){
12
-
13
  //hardcoded list of extensions and check which ones the user has and then include the corresponding file from the ‘compatibility’ folder
14
 
15
  //WooCommerce Tab Manager plugin
16
  if(class_exists('WC_Tab_Manager')){
17
- $this->tab_manager = new WCML_Tab_Manager();
 
18
  }
19
 
20
  //WooCommerce Table Rate Shipping plugin
@@ -78,7 +95,7 @@ class WCML_Compatibility {
78
 
79
  // WooCommerce Bookings
80
  if(defined( 'WC_BOOKINGS_VERSION' ) && version_compare(WC_BOOKINGS_VERSION, '1.7.8', '>=') ){
81
- $this->bookings = new WCML_Bookings();
82
 
83
  // WooCommerce Accommodation Bookings
84
  if( defined( 'WC_ACCOMMODATION_BOOKINGS_VERSION' ) ){
1
  <?php
2
 
3
  class WCML_Compatibility {
 
 
4
 
5
+ /**
6
+ * @var SitePress
7
+ */
8
+ public $sitepress;
9
+
10
+ /**
11
+ * @var woocommerce_wpml
12
+ */
13
+ public $woocommerce_wpml;
14
+
15
+ /**
16
+ * @var wpdb
17
+ */
18
+ public $wpdb;
19
+
20
+ function __construct( &$sitepress, &$woocommerce_wpml, &$wpdb ) {
21
+ $this->sitepress = $sitepress;
22
+ $this->woocommerce_wpml = $woocommerce_wpml;
23
+ $this->wpdb = $wpdb;
24
  $this->init();
25
 
26
  }
27
 
28
  function init(){
 
29
  //hardcoded list of extensions and check which ones the user has and then include the corresponding file from the ‘compatibility’ folder
30
 
31
  //WooCommerce Tab Manager plugin
32
  if(class_exists('WC_Tab_Manager')){
33
+ global $woocommerce;
34
+ $this->tab_manager = new WCML_Tab_Manager( $this->sitepress, $woocommerce, $this->woocommerce_wpml, $this->wpdb );
35
  }
36
 
37
  //WooCommerce Table Rate Shipping plugin
95
 
96
  // WooCommerce Bookings
97
  if(defined( 'WC_BOOKINGS_VERSION' ) && version_compare(WC_BOOKINGS_VERSION, '1.7.8', '>=') ){
98
+ $this->bookings = new WCML_Bookings( $this->sitepress, $this->woocommerce_wpml, $this->wpdb );
99
 
100
  // WooCommerce Accommodation Bookings
101
  if( defined( 'WC_ACCOMMODATION_BOOKINGS_VERSION' ) ){
inc/class-wcml-endpoints.php CHANGED
@@ -14,8 +14,9 @@ class WCML_Endpoints{
14
 
15
  if( !is_admin() ){
16
  //endpoints hooks
17
- $this->register_endpoints_translations();
18
  $this->maybe_flush_rules();
 
 
19
 
20
  add_filter('pre_get_posts', array($this, 'check_if_endpoint_exists'));
21
  }
@@ -106,9 +107,9 @@ class WCML_Endpoints{
106
  }
107
 
108
  function update_rewrite_rules( $value, $old_value ){
109
- remove_filter( 'pre_update_option_rewrite_rules', array( $this, 'update_rewrite_rules' ), 100, 2 );
110
  $this->add_endpoints();
111
- flush_rewrite_rules();
 
112
  return $value;
113
  }
114
 
14
 
15
  if( !is_admin() ){
16
  //endpoints hooks
 
17
  $this->maybe_flush_rules();
18
+ $this->register_endpoints_translations();
19
+
20
 
21
  add_filter('pre_get_posts', array($this, 'check_if_endpoint_exists'));
22
  }
107
  }
108
 
109
  function update_rewrite_rules( $value, $old_value ){
 
110
  $this->add_endpoints();
111
+ $this->flush_rules_for_endpoints_translations();
112
+
113
  return $value;
114
  }
115
 
inc/class-wcml-resources.php CHANGED
@@ -8,11 +8,13 @@ class WCML_Resources {
8
  private static $pagenow;
9
 
10
  private static $woocommerce_wpml;
 
11
 
12
- public static function set_up_resources( &$woocommerce_wpml ) {
13
  global $pagenow;
14
 
15
  self::$woocommerce_wpml =& $woocommerce_wpml;
 
16
 
17
  self::$page = isset($_GET['page']) ? $_GET['page'] : null;
18
  self::$tab = isset($_GET['tab']) ? $_GET['tab'] : null;
@@ -100,8 +102,14 @@ class WCML_Resources {
100
  }
101
 
102
  if ( !is_admin() ) {
 
 
103
  wp_register_script( 'cart-widget', WCML_PLUGIN_URL . '/res/js/cart_widget' . WCML_JS_MIN . '.js', array('jquery'), WCML_VERSION );
104
  wp_enqueue_script( 'cart-widget' );
 
 
 
 
105
  } else {
106
  wp_register_script( 'wcml-messages', WCML_PLUGIN_URL . '/res/js/wcml-messages' . WCML_JS_MIN . '.js', array('jquery'), WCML_VERSION );
107
  wp_enqueue_script( 'wcml-messages' );
8
  private static $pagenow;
9
 
10
  private static $woocommerce_wpml;
11
+ private static $sitepress;
12
 
13
+ public static function set_up_resources( &$woocommerce_wpml, &$sitepress ) {
14
  global $pagenow;
15
 
16
  self::$woocommerce_wpml =& $woocommerce_wpml;
17
+ self::$sitepress =& $sitepress;
18
 
19
  self::$page = isset($_GET['page']) ? $_GET['page'] : null;
20
  self::$tab = isset($_GET['tab']) ? $_GET['tab'] : null;
102
  }
103
 
104
  if ( !is_admin() ) {
105
+ $referer = isset( $_SERVER[ 'HTTP_REFERER' ] ) ? $_SERVER[ 'HTTP_REFERER' ] : '';
106
+
107
  wp_register_script( 'cart-widget', WCML_PLUGIN_URL . '/res/js/cart_widget' . WCML_JS_MIN . '.js', array('jquery'), WCML_VERSION );
108
  wp_enqueue_script( 'cart-widget' );
109
+ wp_localize_script( 'cart-widget', 'actions', array(
110
+ 'is_lang_switched' => self::$sitepress->get_language_from_url( $referer ) != self::$sitepress->get_current_language() ? 1 : 0,
111
+ 'is_currency_switched' => isset( $_GET[ 'wcmlc' ] ) ? 1 : 0
112
+ ) );
113
  } else {
114
  wp_register_script( 'wcml-messages', WCML_PLUGIN_URL . '/res/js/wcml-messages' . WCML_JS_MIN . '.js', array('jquery'), WCML_VERSION );
115
  wp_enqueue_script( 'wcml-messages' );
inc/class-wcml-terms.php CHANGED
@@ -51,13 +51,7 @@ class WCML_Terms{
51
  add_filter('get_terms',array($this,'filter_coupons_terms'),10,3);
52
  add_filter('get_terms',array($this,'filter_shipping_classes_terms'),10,3);
53
 
54
-
55
  add_filter( 'woocommerce_get_product_terms', array( $this, 'get_product_terms_filter' ), 10, 4 );
56
-
57
- add_filter( 'pre_update_option_woocommerce_flat_rate_settings', array( $this, 'update_woocommerce_shipping_settings_for_class_costs' ) );
58
- add_filter( 'pre_update_option_woocommerce_international_delivery_settings', array( $this, 'update_woocommerce_shipping_settings_for_class_costs' ) );
59
- add_action('wp_ajax_woocommerce_shipping_zone_methods_save_settings', array( $this, 'update_woocommerce_shipping_settings_for_class_costs_from_ajax'), 9);
60
-
61
  add_action( 'created_term_translation', array( $this, 'set_flag_to_sync'), 10, 3 );
62
  }
63
 
@@ -99,21 +93,6 @@ class WCML_Terms{
99
  }
100
 
101
  }
102
-
103
- //update flat rate options for shipping classes
104
- if( $original_tax->taxonomy == 'product_shipping_class' ){
105
-
106
- $settings = get_option( 'woocommerce_flat_rate_settings' );
107
- if( is_array( $settings ) ){
108
- update_option( 'woocommerce_flat_rate_settings', $this->update_woocommerce_shipping_settings_for_class_costs( $settings ) );
109
- }
110
-
111
- $settings = get_option( 'woocommerce_international_delivery_settings' );
112
- if( is_array( $settings ) ){
113
- update_option( 'woocommerce_international_delivery_settings', $this->update_woocommerce_shipping_settings_for_class_costs( $settings ) );
114
- }
115
-
116
- }
117
  }
118
 
119
  function show_term_translation_screen_notices(){
@@ -947,66 +926,7 @@ class WCML_Terms{
947
  return $filtered_terms;
948
  }
949
 
950
- function update_woocommerce_shipping_settings_for_class_costs( $settings ){
951
-
952
- remove_filter( 'get_term', array( $this->sitepress, 'get_term_adjust_id' ), 1 );
953
- foreach( $settings as $setting_key => $value ){
954
 
955
- if( substr($setting_key, 0, 11) == 'class_cost_' ){
956
-
957
- $shipp_class_key = substr($setting_key, 11 );
958
-
959
- if( is_numeric( $shipp_class_key ) ){
960
- $shipp_class = get_term( $shipp_class_key, 'product_shipping_class' );
961
- }else{
962
- $shipp_class = get_term_by( 'slug', $shipp_class_key, 'product_shipping_class' );
963
- }
964
-
965
- $trid = $this->sitepress->get_element_trid( $shipp_class->term_taxonomy_id, 'tax_product_shipping_class' );
966
-
967
- $translations = $this->sitepress->get_element_translations( $trid, 'tax_product_shipping_class' );
968
-
969
- foreach( $translations as $translation ){
970
-
971
- $tr_shipp_class = get_term_by( 'term_taxonomy_id', $translation->element_id, 'product_shipping_class' );
972
-
973
- if( is_numeric( $shipp_class_key ) ){
974
- $settings[ 'class_cost_'.$tr_shipp_class->term_id ] = $value;
975
- }else{
976
- $settings[ 'class_cost_'.$tr_shipp_class->slug ] = $value;
977
- }
978
-
979
- }
980
-
981
- }
982
-
983
- }
984
- add_filter( 'get_term', array( $this->sitepress, 'get_term_adjust_id' ), 1 );
985
-
986
- return $settings;
987
- }
988
-
989
- function update_woocommerce_shipping_settings_for_class_costs_from_ajax(){
990
-
991
- if (isset($_POST['data']['woocommerce_flat_rate_type']) && $_POST['data']['woocommerce_flat_rate_type'] == 'class') {
992
-
993
- $settings = array();
994
- foreach ($_POST['data'] as $key => $value) {
995
- if (substr($key, 0, 33) == 'woocommerce_flat_rate_class_cost_') {
996
- $settings[substr($key, 22)] = $value;
997
- }
998
- }
999
-
1000
- $updated_costs_settings = $this->update_woocommerce_shipping_settings_for_class_costs($settings);
1001
-
1002
- $flat_rate_setting_id = 'woocommerce_flat_rate_' . $_POST['data']['instance_id'] . '_settings';
1003
- $settings = get_option($flat_rate_setting_id, true);
1004
-
1005
- $settings = array_replace($settings, $updated_costs_settings);
1006
-
1007
- update_option($flat_rate_setting_id, $settings);
1008
- }
1009
- }
1010
 
1011
 
1012
  function set_flag_to_sync( $taxonomy, $el_id, $language_code ){
51
  add_filter('get_terms',array($this,'filter_coupons_terms'),10,3);
52
  add_filter('get_terms',array($this,'filter_shipping_classes_terms'),10,3);
53
 
 
54
  add_filter( 'woocommerce_get_product_terms', array( $this, 'get_product_terms_filter' ), 10, 4 );
 
 
 
 
 
55
  add_action( 'created_term_translation', array( $this, 'set_flag_to_sync'), 10, 3 );
56
  }
57
 
93
  }
94
 
95
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
96
  }
97
 
98
  function show_term_translation_screen_notices(){
926
  return $filtered_terms;
927
  }
928
 
 
 
 
 
929
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
930
 
931
 
932
  function set_flag_to_sync( $taxonomy, $el_id, $language_code ){
inc/class-wcml-upgrade.php CHANGED
@@ -319,35 +319,43 @@ class WCML_Upgrade{
319
 
320
  $woocommerce_permalinks = maybe_unserialize( get_option('woocommerce_permalinks') );
321
 
322
- foreach($woocommerce_permalinks as $base_key => $base){
323
-
324
- $base_key = trim($base_key, '/');
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
325
 
326
- if($base) {
327
- $taxonomy = false;
 
 
 
 
 
 
 
 
 
 
328
 
329
- switch( $base_key ){
330
- case 'category_base': $taxonomy = 'product_cat'; break;
331
- case 'tag_base': $taxonomy = 'product_tag'; break;
332
- case 'attribute_base':$taxonomy = 'attribute'; break;
333
  }
334
 
335
- if($taxonomy) {
336
- $wpdb->update(
337
- $wpdb->prefix . 'icl_strings',
338
- array(
339
- 'context' => 'WordPress',
340
- 'name' => sprintf('URL %s tax slug', $taxonomy)
341
- ),
342
- array(
343
- 'context' => sprintf('URL %s slugs - %s', $taxonomy, $base),
344
- 'name' => sprintf('Url %s slug: %s', $taxonomy, $base)
345
- )
346
- );
347
-
348
- }
349
  }
350
-
351
  }
352
 
353
  $endpoint_keys = array( 'order-pay', 'order-received', 'view-order', 'edit-account', 'edit-address', 'lost-password', 'customer-logout', 'add-payment-method' );
@@ -379,6 +387,10 @@ class WCML_Upgrade{
379
 
380
  }
381
 
 
 
 
 
382
  $woocommerce_wpml->terms->check_if_sync_terms_needed();
383
 
384
  $wcml_settings = get_option('_wcml_settings');
319
 
320
  $woocommerce_permalinks = maybe_unserialize( get_option('woocommerce_permalinks') );
321
 
322
+ if( is_array( $woocommerce_permalinks ) ) {
323
+ foreach ( $woocommerce_permalinks as $base_key => $base ) {
324
+
325
+ $base_key = trim( $base_key, '/' );
326
+
327
+ if ( $base ) {
328
+ $taxonomy = false;
329
+
330
+ switch ( $base_key ) {
331
+ case 'category_base':
332
+ $taxonomy = 'product_cat';
333
+ break;
334
+ case 'tag_base':
335
+ $taxonomy = 'product_tag';
336
+ break;
337
+ case 'attribute_base':
338
+ $taxonomy = 'attribute';
339
+ break;
340
+ }
341
 
342
+ if ( $taxonomy ) {
343
+ $wpdb->update(
344
+ $wpdb->prefix . 'icl_strings',
345
+ array(
346
+ 'context' => 'WordPress',
347
+ 'name' => sprintf( 'URL %s tax slug', $taxonomy )
348
+ ),
349
+ array(
350
+ 'context' => sprintf( 'URL %s slugs - %s', $taxonomy, $base ),
351
+ 'name' => sprintf( 'Url %s slug: %s', $taxonomy, $base )
352
+ )
353
+ );
354
 
355
+ }
 
 
 
356
  }
357
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
358
  }
 
359
  }
360
 
361
  $endpoint_keys = array( 'order-pay', 'order-received', 'view-order', 'edit-account', 'edit-address', 'lost-password', 'customer-logout', 'add-payment-method' );
387
 
388
  }
389
 
390
+ if( !isset($woocommerce_wpml->terms) ){
391
+ global $sitepress;
392
+ $woocommerce_wpml->terms = new WCML_Terms( $woocommerce_wpml, $sitepress, $wpdb );
393
+ }
394
  $woocommerce_wpml->terms->check_if_sync_terms_needed();
395
 
396
  $wcml_settings = get_option('_wcml_settings');
inc/class-wcml-url-translation.php CHANGED
@@ -4,13 +4,17 @@ class WCML_Url_Translation {
4
 
5
  public $default_product_base;
6
  public $default_product_category_base;
 
7
  public $default_product_tag_base;
 
8
 
9
  function __construct() {
10
 
11
  $this->default_product_base = 'product';
12
  $this->default_product_category_base = 'product-category';
13
  $this->default_product_tag_base = 'product-tag';
 
 
14
 
15
  $this->wc_permalinks = get_option( 'woocommerce_permalinks' );
16
 
@@ -473,7 +477,7 @@ class WCML_Url_Translation {
473
 
474
  if ( $term_language ) {
475
 
476
- $slug_details = $this->get_translated_tax_slug( $taxonomy, $term_language );
477
 
478
  $base = $slug_details['slug'];
479
  $base_translated = $slug_details['translated_slug'];
@@ -501,26 +505,42 @@ class WCML_Url_Translation {
501
  return $termlink;
502
  }
503
 
504
- function get_translated_tax_slug( $taxonomy, $language = false ) {
505
  global $sitepress, $woocommerce_wpml;
506
 
507
  switch ( $taxonomy ) {
508
  case 'product_tag':
509
- $slug = !empty( $this->wc_permalinks['tag_base'] ) ? trim( $this->wc_permalinks['tag_base'], '/' ) : 'product-tag';
 
 
 
 
 
 
 
 
510
 
511
  $string_language = $woocommerce_wpml->strings->get_string_language( $slug, $this->url_strings_context(), $this->url_string_name( $taxonomy ) );
512
 
513
  break;
514
 
515
  case 'product_cat':
516
- $slug = !empty( $this->wc_permalinks['category_base'] ) ? trim( $this->wc_permalinks['category_base'], '/' ) : 'product-category';
 
 
 
 
 
 
 
 
517
 
518
  $string_language = $woocommerce_wpml->strings->get_string_language( $slug, $this->url_strings_context(), $this->url_string_name( $taxonomy ) );
519
 
520
  break;
521
 
522
  default:
523
- $slug = trim( $this->wc_permalinks['attribute_base'], '/' );
524
 
525
  $string_language = $woocommerce_wpml->strings->get_string_language( $slug, $this->url_strings_context(), $this->url_string_name( 'attribute' ) );
526
 
@@ -537,10 +557,10 @@ class WCML_Url_Translation {
537
 
538
  $slug_translation = apply_filters( 'wpml_translate_single_string', $slug, $this->url_strings_context(), $this->url_string_name( $taxonomy ), $language, false );
539
 
540
- return array( 'slug' => $slug, 'translated_slug' => $slug_translation );
541
  }
542
 
543
- return array( 'slug' => $slug, 'translated_slug' => $slug );
544
 
545
  }
546
 
4
 
5
  public $default_product_base;
6
  public $default_product_category_base;
7
+ public $default_product_category_gettext_base;
8
  public $default_product_tag_base;
9
+ public $default_product_tag_gettext_base;
10
 
11
  function __construct() {
12
 
13
  $this->default_product_base = 'product';
14
  $this->default_product_category_base = 'product-category';
15
  $this->default_product_tag_base = 'product-tag';
16
+ $this->default_product_category_gettext_base = _x( 'product-category', 'slug', 'woocommerce' );
17
+ $this->default_product_tag_gettext_base = _x( 'product-tag', 'slug', 'woocommerce' );
18
 
19
  $this->wc_permalinks = get_option( 'woocommerce_permalinks' );
20
 
477
 
478
  if ( $term_language ) {
479
 
480
+ $slug_details = $this->get_translated_tax_slug( $taxonomy, $term_language, true );
481
 
482
  $base = $slug_details['slug'];
483
  $base_translated = $slug_details['translated_slug'];
505
  return $termlink;
506
  }
507
 
508
+ function get_translated_tax_slug( $taxonomy, $language = false, $return_gettext_slug = false ) {
509
  global $sitepress, $woocommerce_wpml;
510
 
511
  switch ( $taxonomy ) {
512
  case 'product_tag':
513
+
514
+ if( !empty( $this->wc_permalinks['tag_base'] ) ) {
515
+ $slug = $gettext_slug = trim($this->wc_permalinks['tag_base'], '/');
516
+ }else{
517
+ $slug = 'product-tag';
518
+ if( $return_gettext_slug ){
519
+ $gettext_slug = $this->default_product_tag_gettext_base;
520
+ }
521
+ }
522
 
523
  $string_language = $woocommerce_wpml->strings->get_string_language( $slug, $this->url_strings_context(), $this->url_string_name( $taxonomy ) );
524
 
525
  break;
526
 
527
  case 'product_cat':
528
+
529
+ if( !empty( $this->wc_permalinks['category_base'] ) ) {
530
+ $slug = $gettext_slug = trim( $this->wc_permalinks['category_base'], '/' );
531
+ }else{
532
+ $slug = 'product-category';
533
+ if( $return_gettext_slug ){
534
+ $gettext_slug = $this->default_product_category_gettext_base;
535
+ }
536
+ }
537
 
538
  $string_language = $woocommerce_wpml->strings->get_string_language( $slug, $this->url_strings_context(), $this->url_string_name( $taxonomy ) );
539
 
540
  break;
541
 
542
  default:
543
+ $slug = $gettext_slug = trim( $this->wc_permalinks['attribute_base'], '/' );
544
 
545
  $string_language = $woocommerce_wpml->strings->get_string_language( $slug, $this->url_strings_context(), $this->url_string_name( 'attribute' ) );
546
 
557
 
558
  $slug_translation = apply_filters( 'wpml_translate_single_string', $slug, $this->url_strings_context(), $this->url_string_name( $taxonomy ), $language, false );
559
 
560
+ return array( 'slug' => $return_gettext_slug ? $gettext_slug : $slug, 'translated_slug' => $slug_translation );
561
  }
562
 
563
+ return array( 'slug' => $return_gettext_slug ? $gettext_slug : $slug, 'translated_slug' => $return_gettext_slug && $language != $string_language ? $gettext_slug : $slug );
564
 
565
  }
566
 
inc/class-wcml-wc-shipping.php CHANGED
@@ -3,9 +3,12 @@
3
  class WCML_WC_Shipping{
4
 
5
  private $current_language;
 
6
 
7
  function __construct( &$sitepress ){
8
 
 
 
9
  add_filter('woocommerce_package_rates', array($this, 'translate_shipping_methods_in_package'));
10
  add_action('woocommerce_tax_rate_added', array($this, 'register_tax_rate_label_string'), 10, 2 );
11
  add_filter('woocommerce_rate_label',array($this,'translate_woocommerce_rate_label'));
@@ -13,10 +16,17 @@ class WCML_WC_Shipping{
13
  $this->shipping_methods_filters();
14
  add_action('wp_ajax_woocommerce_shipping_zone_methods_save_settings', array( $this, 'save_shipping_zone_method_from_ajax'), 9 );
15
 
16
- $this->current_language = $sitepress->get_current_language();
17
  if( $this->current_language == 'all' ){
18
- $this->current_language = $sitepress->get_default_language();
19
  }
 
 
 
 
 
 
 
20
  }
21
 
22
  function shipping_methods_filters(){
@@ -55,6 +65,8 @@ class WCML_WC_Shipping{
55
  function register_zone_shipping_strings( $instance_settings, $object ){
56
  if( !empty( $instance_settings['title'] ) ){
57
  $this->register_shipping_title( $object->id.$object->instance_id, $instance_settings['title'] );
 
 
58
  }
59
 
60
  return $instance_settings;
@@ -128,4 +140,88 @@ class WCML_WC_Shipping{
128
 
129
  }
130
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
131
  }
3
  class WCML_WC_Shipping{
4
 
5
  private $current_language;
6
+ private $sitepress;
7
 
8
  function __construct( &$sitepress ){
9
 
10
+ $this->sitepress = $sitepress;
11
+
12
  add_filter('woocommerce_package_rates', array($this, 'translate_shipping_methods_in_package'));
13
  add_action('woocommerce_tax_rate_added', array($this, 'register_tax_rate_label_string'), 10, 2 );
14
  add_filter('woocommerce_rate_label',array($this,'translate_woocommerce_rate_label'));
16
  $this->shipping_methods_filters();
17
  add_action('wp_ajax_woocommerce_shipping_zone_methods_save_settings', array( $this, 'save_shipping_zone_method_from_ajax'), 9 );
18
 
19
+ $this->current_language = $this->sitepress->get_current_language();
20
  if( $this->current_language == 'all' ){
21
+ $this->current_language = $this->sitepress->get_default_language();
22
  }
23
+
24
+ add_action( 'icl_save_term_translation', array( $this, 'sync_class_costs_for_new_shipping_classes' ), 100, 2 );
25
+
26
+
27
+ add_filter( 'pre_update_option_woocommerce_flat_rate_settings', array( $this, 'update_woocommerce_shipping_settings_for_class_costs' ) );
28
+ add_filter( 'pre_update_option_woocommerce_international_delivery_settings', array( $this, 'update_woocommerce_shipping_settings_for_class_costs' ) );
29
+ add_action( 'wp_ajax_woocommerce_shipping_zone_methods_save_settings', array( $this, 'update_woocommerce_shipping_settings_for_class_costs_from_ajax'), 9);
30
  }
31
 
32
  function shipping_methods_filters(){
65
  function register_zone_shipping_strings( $instance_settings, $object ){
66
  if( !empty( $instance_settings['title'] ) ){
67
  $this->register_shipping_title( $object->id.$object->instance_id, $instance_settings['title'] );
68
+
69
+ $instance_settings = $this->sync_flat_rate_class_cost( $object->get_post_data(), $instance_settings );
70
  }
71
 
72
  return $instance_settings;
140
 
141
  }
142
 
143
+ function sync_class_costs_for_new_shipping_classes( $original_tax, $result ){
144
+ //update flat rate options for shipping classes
145
+ if( $original_tax->taxonomy == 'product_shipping_class' ){
146
+
147
+ $settings = get_option( 'woocommerce_flat_rate_settings' );
148
+ if( is_array( $settings ) ){
149
+ update_option( 'woocommerce_flat_rate_settings', $this->update_woocommerce_shipping_settings_for_class_costs( $settings ) );
150
+ }
151
+
152
+ $settings = get_option( 'woocommerce_international_delivery_settings' );
153
+ if( is_array( $settings ) ){
154
+ update_option( 'woocommerce_international_delivery_settings', $this->update_woocommerce_shipping_settings_for_class_costs( $settings ) );
155
+ }
156
+
157
+ }
158
+ }
159
+
160
+ function update_woocommerce_shipping_settings_for_class_costs( $settings ){
161
+
162
+ remove_filter( 'get_term', array( $this->sitepress, 'get_term_adjust_id' ), 1 );
163
+ foreach( $settings as $setting_key => $value ){
164
+
165
+ if( substr($setting_key, 0, 11) == 'class_cost_' ){
166
+
167
+ $shipp_class_key = substr($setting_key, 11 );
168
+
169
+ if( is_numeric( $shipp_class_key ) ){
170
+ $shipp_class = get_term( $shipp_class_key, 'product_shipping_class' );
171
+ }else{
172
+ $shipp_class = get_term_by( 'slug', $shipp_class_key, 'product_shipping_class' );
173
+ }
174
+
175
+ $trid = $this->sitepress->get_element_trid( $shipp_class->term_taxonomy_id, 'tax_product_shipping_class' );
176
+
177
+ $translations = $this->sitepress->get_element_translations( $trid, 'tax_product_shipping_class' );
178
+
179
+ foreach( $translations as $translation ){
180
+
181
+ $tr_shipp_class = get_term_by( 'term_taxonomy_id', $translation->element_id, 'product_shipping_class' );
182
+
183
+ if( is_numeric( $shipp_class_key ) ){
184
+ $settings[ 'class_cost_'.$tr_shipp_class->term_id ] = $value;
185
+ }else{
186
+ $settings[ 'class_cost_'.$tr_shipp_class->slug ] = $value;
187
+ }
188
+
189
+ }
190
+
191
+ }
192
+
193
+ }
194
+ add_filter( 'get_term', array( $this->sitepress, 'get_term_adjust_id' ), 1 );
195
+
196
+ return $settings;
197
+ }
198
+
199
+ function update_woocommerce_shipping_settings_for_class_costs_from_ajax(){
200
+
201
+ if (isset($_POST['data']['woocommerce_flat_rate_type']) && $_POST['data']['woocommerce_flat_rate_type'] == 'class') {
202
+
203
+ $flat_rate_setting_id = 'woocommerce_flat_rate_' . $_POST['data']['instance_id'] . '_settings';
204
+ $settings = get_option( $flat_rate_setting_id, true );
205
+
206
+ $settings = $this->sync_flat_rate_class_cost( $_POST['data'], $settings );
207
+
208
+ update_option($flat_rate_setting_id, $settings);
209
+ }
210
+ }
211
+
212
+ function sync_flat_rate_class_cost( $data, $inst_settings ){
213
+
214
+ $settings = array();
215
+ foreach ( $data as $key => $value ) {
216
+ if ( substr( $key, 0, 33) == 'woocommerce_flat_rate_class_cost_' ) {
217
+ $settings[ substr( $key, 22 ) ] = $value;
218
+ }
219
+ }
220
+
221
+ $updated_costs_settings = $this->update_woocommerce_shipping_settings_for_class_costs( $settings );
222
+ $inst_settings = array_replace( $inst_settings, $updated_costs_settings );
223
+
224
+ return $inst_settings;
225
+ }
226
+
227
  }
inc/class-woocommerce-wpml.php CHANGED
@@ -114,7 +114,7 @@ class woocommerce_wpml {
114
  return false;
115
  }
116
 
117
- $this->compatibility = new WCML_Compatibility();
118
 
119
  $actions_that_need_mc = array(
120
  'save-mc-options',
@@ -171,7 +171,7 @@ class woocommerce_wpml {
171
 
172
  WCML_Install::initialize( $this, $sitepress );
173
 
174
- WCML_Resources::set_up_resources( $this );
175
 
176
  add_filter('woocommerce_get_checkout_payment_url', array('WCML_Links', 'filter_woocommerce_redirect_location'));
177
  add_filter('woocommerce_get_cancel_order_url', array('WCML_Links', 'filter_woocommerce_redirect_location'));
114
  return false;
115
  }
116
 
117
+ $this->compatibility = new WCML_Compatibility( $sitepress, $this, $wpdb );
118
 
119
  $actions_that_need_mc = array(
120
  'save-mc-options',
171
 
172
  WCML_Install::initialize( $this, $sitepress );
173
 
174
+ WCML_Resources::set_up_resources( $this, $sitepress );
175
 
176
  add_filter('woocommerce_get_checkout_payment_url', array('WCML_Links', 'filter_woocommerce_redirect_location'));
177
  add_filter('woocommerce_get_cancel_order_url', array('WCML_Links', 'filter_woocommerce_redirect_location'));
inc/currencies/class-wcml-custom-prices.php CHANGED
@@ -4,15 +4,12 @@ class WCML_Custom_Prices{
4
 
5
  private $woocommerce_wpml;
6
 
7
- public function __construct(){
8
- add_filter('init', array($this, 'custom_prices_init') );
 
9
  }
10
 
11
  public function custom_prices_init(){
12
- global $woocommerce_wpml;
13
-
14
- $this->woocommerce_wpml =& $woocommerce_wpml;
15
-
16
  if ( is_admin() ) {
17
  add_action( 'woocommerce_variation_options', array($this, 'add_individual_variation_nonce'), 10, 3 );
18
 
@@ -228,6 +225,8 @@ class WCML_Custom_Prices{
228
 
229
  }
230
 
 
 
231
  return $custom_prices;
232
  }
233
 
4
 
5
  private $woocommerce_wpml;
6
 
7
+ public function __construct( &$woocommerce_wpml ){
8
+ add_filter( 'init', array( $this, 'custom_prices_init' ) );
9
+ $this->woocommerce_wpml = $woocommerce_wpml;
10
  }
11
 
12
  public function custom_prices_init(){
 
 
 
 
13
  if ( is_admin() ) {
14
  add_action( 'woocommerce_variation_options', array($this, 'add_individual_variation_nonce'), 10, 3 );
15
 
225
 
226
  }
227
 
228
+ $custom_prices = apply_filters( 'wcml_product_custom_prices', $custom_prices, $product_id, $currency );
229
+
230
  return $custom_prices;
231
  }
232
 
inc/currencies/class-wcml-multi-currency-shipping.php CHANGED
@@ -25,14 +25,19 @@ class WCML_Multi_Currency_Shipping{
25
  foreach($methods as $k => $method){
26
 
27
  // exceptions
 
 
 
 
28
  if(
29
- isset($shipping_methods[$method->id]) && isset($shipping_methods[$method->id]->settings['type']) && $shipping_methods[$method->id]->settings['type'] == 'percent'
30
- || preg_match('/^table_rate-[0-9]+ : [0-9]+$/', $k)
 
 
31
  ){
32
  continue;
33
  }
34
 
35
-
36
  foreach($method->taxes as $j => $tax){
37
 
38
  $methods[$k]->taxes[$j] = apply_filters('wcml_shipping_price_amount', $methods[$k]->taxes[$j]);
25
  foreach($methods as $k => $method){
26
 
27
  // exceptions
28
+ $is_old_table_rate = defined('TABLE_RATE_SHIPPING_VERSION' ) &&
29
+ version_compare( TABLE_RATE_SHIPPING_VERSION, '3.0', '<' ) &&
30
+ preg_match('/^table_rate-[0-9]+ : [0-9]+$/', $k);
31
+
32
  if(
33
+ isset($shipping_methods[$method->id]) &&
34
+ isset($shipping_methods[$method->id]->settings['type']) &&
35
+ $shipping_methods[$method->id]->settings['type'] == 'percent'
36
+ || $is_old_table_rate
37
  ){
38
  continue;
39
  }
40
 
 
41
  foreach($method->taxes as $j => $tax){
42
 
43
  $methods[$k]->taxes[$j] = apply_filters('wcml_shipping_price_amount', $methods[$k]->taxes[$j]);
inc/currencies/class-wcml-multi-currency-table-rate-shipping.php CHANGED
@@ -1,10 +1,16 @@
1
  <?php
2
 
 
 
 
 
 
 
3
  class WCML_Multi_Currency_Table_Rate_Shipping{
4
 
5
  public static function set_up(){
6
  // table rate shipping support
7
- if(defined('TABLE_RATE_SHIPPING_VERSION')){
8
  add_filter('woocommerce_table_rate_query_rates', array(__CLASS__, 'table_rate_shipping_rates'));
9
  add_filter('woocommerce_table_rate_instance_settings', array(__CLASS__, 'table_rate_instance_settings'));
10
  }
1
  <?php
2
 
3
+ /**
4
+ * Class WCML_Multi_Currency_Table_Rate_Shipping
5
+ *
6
+ * This is only required for versions of WooCommerce Table Rating older than 3.0
7
+ */
8
+
9
  class WCML_Multi_Currency_Table_Rate_Shipping{
10
 
11
  public static function set_up(){
12
  // table rate shipping support
13
+ if( defined('TABLE_RATE_SHIPPING_VERSION' ) && version_compare( TABLE_RATE_SHIPPING_VERSION, '3.0', '<' ) ){
14
  add_filter('woocommerce_table_rate_query_rates', array(__CLASS__, 'table_rate_shipping_rates'));
15
  add_filter('woocommerce_table_rate_instance_settings', array(__CLASS__, 'table_rate_instance_settings'));
16
  }
inc/currencies/class-wcml-multi-currency.php CHANGED
@@ -74,7 +74,7 @@ class WCML_Multi_Currency{
74
  $this->reports = new WCML_Multi_Currency_Reports();
75
  $this->orders = new WCML_Multi_Currency_Orders( $this );
76
  $this->admin_currency_selector = new WCML_Admin_Currency_Selector();
77
- $this->custom_prices = new WCML_Custom_Prices();
78
  $this->currency_switcher = new WCML_Currency_Switcher;
79
 
80
 
74
  $this->reports = new WCML_Multi_Currency_Reports();
75
  $this->orders = new WCML_Multi_Currency_Orders( $this );
76
  $this->admin_currency_selector = new WCML_Admin_Currency_Selector();
77
+ $this->custom_prices = new WCML_Custom_Prices( $woocommerce_wpml );
78
  $this->currency_switcher = new WCML_Currency_Switcher;
79
 
80
 
inc/translation-editor/class-wcml-editor-ui-product-job.php CHANGED
@@ -131,6 +131,9 @@ class WCML_Editor_UI_Product_Job extends WPML_Editor_UI_Job {
131
  }
132
 
133
  $custom_fields = $this->get_product_custom_fields_to_translate( $this->product->id );
 
 
 
134
 
135
  if( $custom_fields ) {
136
  $custom_fields_section = new WPML_Editor_UI_Field_Section( __( 'Custom Fields', 'woocommerce-multilingual' ) );
@@ -195,6 +198,13 @@ class WCML_Editor_UI_Product_Job extends WPML_Editor_UI_Job {
195
  }
196
  }
197
 
 
 
 
 
 
 
 
198
  do_action( 'wcml_gui_additional_box_html', $this, $this->product->id, $this->data );
199
 
200
  }
131
  }
132
 
133
  $custom_fields = $this->get_product_custom_fields_to_translate( $this->product->id );
134
+ if( $this->product->product_type === 'external' ){
135
+ $custom_fields = array_diff( $custom_fields, array( '_product_url', '_button_text' ) );
136
+ }
137
 
138
  if( $custom_fields ) {
139
  $custom_fields_section = new WPML_Editor_UI_Field_Section( __( 'Custom Fields', 'woocommerce-multilingual' ) );
198
  }
199
  }
200
 
201
+ if( $this->product->product_type === 'external' ){
202
+ $external_product_section = new WPML_Editor_UI_Field_Section( __( 'External Product', 'woocommerce-multilingual' ) );
203
+ $external_product_section->add_field( new WPML_Editor_UI_Single_Line_Field( '_product_url', __( 'Product url', 'woocommerce-multilingual' ), $this->data, true ) );
204
+ $external_product_section->add_field( new WPML_Editor_UI_Single_Line_Field( '_button_text', __( 'Button text', 'woocommerce-multilingual' ), $this->data, true ) );
205
+ $this->add_field( $external_product_section );
206
+ }
207
+
208
  do_action( 'wcml_gui_additional_box_html', $this, $this->product->id, $this->data );
209
 
210
  }
inc/translation-editor/class-wcml-synchronize-product-data.php CHANGED
@@ -137,13 +137,15 @@ class WCML_Synchronize_Product_Data{
137
  // synchronize post variations
138
  $this->woocommerce_wpml->sync_variations_data->sync_product_variations( $original_product_id, $translated_product_id, $lang );
139
  $this->sync_linked_products( $original_product_id, $translated_product_id, $lang );
 
 
 
140
  }
141
  if( $this->woocommerce_wpml->settings['enable_multi_currency'] == WCML_MULTI_CURRENCIES_INDEPENDENT ) {
142
  //save custom prices
143
  $this->woocommerce_wpml->multi_currency->custom_prices->save_custom_prices( $duplicated_post_id );
144
  $this->woocommerce_wpml->multi_currency->custom_prices->sync_product_variations_custom_prices($original_product_id);
145
  }
146
-
147
  }
148
 
149
  public function sync_product_data( $original_product_id, $tr_product_id, $lang ){
@@ -174,6 +176,9 @@ class WCML_Synchronize_Product_Data{
174
  $this->woocommerce_wpml->sync_variations_data->sync_product_variations( $original_product_id, $tr_product_id, $lang );
175
 
176
  $this->sync_linked_products( $original_product_id, $tr_product_id, $lang );
 
 
 
177
  }
178
 
179
  public function sync_product_taxonomies( $original_product_id, $tr_product_id, $lang ){
@@ -294,8 +299,8 @@ class WCML_Synchronize_Product_Data{
294
  $trid = $this->sitepress->get_element_trid( $id, 'post_'.$type );
295
  $translations = $this->sitepress->get_element_translations( $trid, 'post_'.$type, true);
296
 
297
- foreach ($translations as $translation) {
298
- if ( $translation->element_id != $id ) {
299
  update_post_meta( $translation->element_id, '_stock_status', $status );
300
  }
301
  }
137
  // synchronize post variations
138
  $this->woocommerce_wpml->sync_variations_data->sync_product_variations( $original_product_id, $translated_product_id, $lang );
139
  $this->sync_linked_products( $original_product_id, $translated_product_id, $lang );
140
+
141
+ // Clear any unwanted data
142
+ wc_delete_product_transients( $translated_product_id );
143
  }
144
  if( $this->woocommerce_wpml->settings['enable_multi_currency'] == WCML_MULTI_CURRENCIES_INDEPENDENT ) {
145
  //save custom prices
146
  $this->woocommerce_wpml->multi_currency->custom_prices->save_custom_prices( $duplicated_post_id );
147
  $this->woocommerce_wpml->multi_currency->custom_prices->sync_product_variations_custom_prices($original_product_id);
148
  }
 
149
  }
150
 
151
  public function sync_product_data( $original_product_id, $tr_product_id, $lang ){
176
  $this->woocommerce_wpml->sync_variations_data->sync_product_variations( $original_product_id, $tr_product_id, $lang );
177
 
178
  $this->sync_linked_products( $original_product_id, $tr_product_id, $lang );
179
+
180
+ // Clear any unwanted data
181
+ wc_delete_product_transients( $tr_product_id );
182
  }
183
 
184
  public function sync_product_taxonomies( $original_product_id, $tr_product_id, $lang ){
299
  $trid = $this->sitepress->get_element_trid( $id, 'post_'.$type );
300
  $translations = $this->sitepress->get_element_translations( $trid, 'post_'.$type, true);
301
 
302
+ foreach ( $translations as $translation ) {
303
+ if ( !$translation->original ) {
304
  update_post_meta( $translation->element_id, '_stock_status', $status );
305
  }
306
  }
readme.txt CHANGED
@@ -1,11 +1,11 @@
1
  === WooCommerce Multilingual - run WooCommerce with WPML ===
2
- Contributors: AmirHelzer, dominykasgel, dgwatkins, adelval, sergey.r, mihaimihai
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.9
7
- Tested up to: 4.5.1
8
- Stable tag: 3.8
9
 
10
  Allows running fully multilingual e-commerce sites using WooCommerce and WPML.
11
 
@@ -131,6 +131,20 @@ WooCommerce Multilingual is compatible with all major WooCommerce extensions. We
131
 
132
  == Changelog ==
133
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
134
  = 3.8.1 =
135
  * Fixed one compatibility issue with WooCommerce Ajax Cart: cart quantities were not updating
136
  * Fixed one compatibility issue with WooCommerce Bookings: incorrect bookings were shown in the backend when toggling between admin languages
@@ -142,8 +156,6 @@ WooCommerce Multilingual is compatible with all major WooCommerce extensions. We
142
  * Made translation controls on the WooCommerce products page disabled by default
143
  * Optimized autoloading of PHP classes for better performance
144
 
145
-
146
-
147
  = 3.8 =
148
  * A new design, a new look and feel complementing the new WPML 3.4
149
  * A new translation editor for the products
1
  === WooCommerce Multilingual - run WooCommerce with WPML ===
2
+ Contributors: AmirHelzer, sergey.r, mihaimihai, EduardMaghakyan
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.9
7
+ Tested up to: 4.5.3
8
+ Stable tag: 3.8.2
9
 
10
  Allows running fully multilingual e-commerce sites using WooCommerce and WPML.
11
 
131
 
132
  == Changelog ==
133
 
134
+ = 3.8.2 =
135
+ * Bug fix: cart strings not displaying in the correct language in some conditions
136
+ * Bug fix: prices in secondary currencies were not updated on the front end after changing the price (the cache was not invalidated)
137
+ * Bug fix: shipping classes were not synchronized for translated products in some circumstances
138
+ * Bug fix: translated endpoints were missing from the rewrite rules after updating the permalinks
139
+ * Bug fix: stock status was sometimes not synchronized correctly when changing the stock manually
140
+ * Bug fix: when using the default category base the language switcher did not show translated urls on the front end
141
+ * Updated the cart cache hashes logic according to new WooCommerce logic
142
+ * Added a new filter: 'wcml_product_custom_prices'
143
+ * Added separate section for translatable fields for external products in the translations editor
144
+ * Fixed compatibility issues with WooCommerce Table Rate Shipping 3.0+
145
+ * Fixed one compatibility issue with WooCommerce Dynamic Pricing: the discount was not shown on the mini-cart
146
+ * Fixed compatibility with Product Add-ons: strings were not translated
147
+
148
  = 3.8.1 =
149
  * Fixed one compatibility issue with WooCommerce Ajax Cart: cart quantities were not updating
150
  * Fixed one compatibility issue with WooCommerce Bookings: incorrect bookings were shown in the backend when toggling between admin languages
156
  * Made translation controls on the WooCommerce products page disabled by default
157
  * Optimized autoloading of PHP classes for better performance
158
 
 
 
159
  = 3.8 =
160
  * A new design, a new look and feel complementing the new WPML 3.4
161
  * A new translation editor for the products
res/js/cart_widget.js CHANGED
@@ -1,7 +1,9 @@
1
  jQuery(document).ready(function($){
2
  try {
3
- if (sessionStorage.getItem('wc_cart_hash') == '') {
4
- sessionStorage.removeItem('wc_fragments');
 
 
5
  }
6
  } catch(err){
7
  //console.log(err.message);
1
  jQuery(document).ready(function($){
2
  try {
3
+ var cart_hash_key = wc_cart_fragments_params.ajax_url.toString() + '-wc_cart_hash';
4
+
5
+ if (sessionStorage.getItem( 'woocommerce_cart_hash' ) == '' || actions.is_lang_switched == 1 || actions.is_currency_switched == 1 ) {
6
+ sessionStorage.removeItem( 'wc_fragments' );
7
  }
8
  } catch(err){
9
  //console.log(err.message);
res/js/cart_widget.min.js CHANGED
@@ -1 +1 @@
1
- jQuery(document).ready(function(a){try{""==sessionStorage.getItem("wc_cart_hash")&&sessionStorage.removeItem("wc_fragments")}catch(b){}});
1
+ jQuery(document).ready(function(a){try{wc_cart_fragments_params.ajax_url.toString()+"-wc_cart_hash";(""==sessionStorage.getItem("woocommerce_cart_hash")||1==actions.is_lang_switched||1==actions.is_currency_switched)&&sessionStorage.removeItem("wc_fragments")}catch(b){}});
res/js/lock_fields.js CHANGED
@@ -39,7 +39,6 @@ jQuery(document).ready(function($){
39
  'add_attribute',
40
  'select_all_attributes',
41
  'select_no_attributes',
42
- 'edit-post-status',
43
  'edit-visibility'
44
  ];
45
  buttons = buttons.concat( non_standard_fields.classes );
@@ -60,7 +59,7 @@ jQuery(document).ready(function($){
60
  $('.'+buttons[i]).after($('.wcml_lock_img').clone().removeClass('wcml_lock_img').show());
61
  }
62
 
63
- $('a.edit-post-status span,#visibility .edit-visibility span').bind({
64
  click: function(e) {
65
  return false;
66
  }
39
  'add_attribute',
40
  'select_all_attributes',
41
  'select_no_attributes',
 
42
  'edit-visibility'
43
  ];
44
  buttons = buttons.concat( non_standard_fields.classes );
59
  $('.'+buttons[i]).after($('.wcml_lock_img').clone().removeClass('wcml_lock_img').show());
60
  }
61
 
62
+ $('#visibility .edit-visibility span').bind({
63
  click: function(e) {
64
  return false;
65
  }
res/js/lock_fields.min.js CHANGED
@@ -1 +1 @@
1
- jQuery(document).ready(function(a){var b,c=["_virtual","_downloadable","product-type","_backorders","_manage_stock","_stock","_stock_status","_sold_individually","comment_status","_tax_status","_tax_class","parent_id","crosssell_ids","upsell_ids"];for(1==unlock_fields.file_paths&&c.push("_download_type"),c=c.concat(non_standard_fields.ids),a(".wcml_prod_hidden_notice").prependTo("#woocommerce-product-data"),b=0;b<c.length;b++)a("#"+c[b]).attr("disabled","disabled"),a("#"+c[b]).after(a(".wcml_lock_img").clone().removeClass("wcml_lock_img").show());var d=["add_variation","link_all_variations","attribute_taxonomy","save_attributes","add_new_attribute","product_attributes .remove_row","add_attribute","select_all_attributes","select_no_attributes","edit-post-status","edit-visibility"];for(d=d.concat(non_standard_fields.classes),1==unlock_fields.file_paths&&(d.push("upload_file_button"),d.push("insert"),d.push("delete"),a(".upload_file_button,.insert,.delete").bind({click:function(a){return!1}})),b=0;b<d.length;b++)a("."+d[b]).attr("disabled","disabled"),a("."+d[b]).after(a(".wcml_lock_img").clone().removeClass("wcml_lock_img").show());a("a.edit-post-status span,#visibility .edit-visibility span").bind({click:function(a){return!1}}),a(".remove_variation").each(function(){a(this).attr("disabled","disabled"),a(this).after(a(".wcml_lock_img").clone().removeClass("wcml_lock_img").show().css("float","right"))});var e=["_width","_height","_sku","_length","_weight","product_length","_regular_price","_sale_price","_sale_price_dates_from","_sale_price_dates_to"];for(1==unlock_fields.file_paths&&(e.push("_download_limit"),e.push("_download_expiry"),e.push("_wc_file_names[]"),e.push("_wc_file_urls[]")),e=e.concat(non_standard_fields.input_names),1==unlock_fields.menu_order&&e.push("menu_order"),b=0;b<e.length;b++)a('input[name="'+e[b]+'"]').attr("readonly","readonly"),a(".dimensions_field span.wrap").css("float","left"),"_width"!=e[b]&&"_height"!=e[b]&&"_length"!=e[b]||(a('input[name="'+e[b]+'"]').css("margin-right",0),a('input[name="'+e[b]+'"]').css("float","none"),a('input[name="'+e[b]+'"]').css("width","29%")),"_sale_price_dates_to"==e[b]?a('input[name="'+e[b]+'"]').after(a(".wcml_lock_img").clone().removeClass("wcml_lock_img").css("float","left").show()):a('input[name="'+e[b]+'"]').after(a(".wcml_lock_img").clone().removeClass("wcml_lock_img").show());a('#product_attributes td textarea,#product_attributes input[type="text"]').each(function(){a(this).attr("readonly","readonly"),a(this).after(a(".wcml_lock_img").clone().removeClass("wcml_lock_img").show())}),a('#product_attributes input[type="checkbox"]').each(function(){a(this).attr("disabled","disabled"),a(this).after(a(".wcml_lock_img").clone().removeClass("wcml_lock_img").show())}),a('form#post input[type="submit"]').click(function(){for(b=0;b<c.length;b++)a("#"+c[b]).removeAttr("disabled");a('.woocommerce_variation select,#variable_product_options .toolbar select,.woocommerce_variation input[type="checkbox"],#product_attributes input[type="checkbox"]').each(function(){a(this).removeAttr("disabled")})})});var wcml_lock_variation_fields=function(){var a=jQuery(".woocommerce_variation>h3 select").attr("disabled");if("undefined"==typeof a||a===!1){jQuery(".woocommerce_variation>h3 select, #variable_product_options .toolbar select, .show_if_variation_manage_stock select").each(function(){jQuery(this).attr("disabled","disabled"),jQuery(this).parent().append('<input type="hidden" name="'+jQuery(this).attr("name")+'" value="'+jQuery(this).val()+'" />'),jQuery(this).after(jQuery(".wcml_lock_img").clone().removeClass("wcml_lock_img").show())});var b=0,c=["_width","_height","_sku","_length","_weight","product_length","_regular_price","_sale_price","_sale_price_dates_from","_sale_price_dates_to","_stock","_download_limit","_download_expiry"];for(b=0;b<c.length;b++)jQuery('input[name^="variable'+c[b]+'"]').each(function(){jQuery(this).attr("readonly","readonly"),jQuery(this).after(jQuery(".wcml_lock_img").clone().removeClass("wcml_lock_img").show())});var d=["_enabled","_is_downloadable","_is_virtual","_manage_stock"];for(b=0;b<d.length;b++)jQuery('input[name^="variable'+d[b]+'"]').each(function(){jQuery(this).attr("disabled","disabled"),jQuery(this).after(jQuery(".wcml_lock_img").clone().removeClass("wcml_lock_img").show())});var e=["_stock_status","_shipping_class","_tax_class"];for(b=0;b<e.length;b++)jQuery('select[name^="variable'+e[b]+'"]').each(function(){jQuery(this).attr("disabled","disabled"),jQuery(this).parent().append('<input type="hidden" name="'+jQuery(this).attr("name")+'" value="'+jQuery(this).val()+'" />'),jQuery(this).after(jQuery(".wcml_lock_img").clone().removeClass("wcml_lock_img").show())});if(1==unlock_fields.file_paths){var f=["_wc_variation_file_names","_wc_variation_file_urls"];for(b=0;b<f.length;b++)jQuery('input[name^="'+f[b]+'"]').each(function(){jQuery(this).attr("readonly","readonly"),jQuery(this).after(jQuery(".wcml_lock_img").clone().removeClass("wcml_lock_img").show())});var g=["upload_file_button","insert","delete"];for(b=0;b<g.length;b++)jQuery("."+g[b]).attr("disabled","disabled"),jQuery("."+g[b]).after(jQuery(".wcml_lock_img").clone().removeClass("wcml_lock_img").show().css("float","right"))}}};
1
+ jQuery(document).ready(function(a){var b,c=["_virtual","_downloadable","product-type","_backorders","_manage_stock","_stock","_stock_status","_sold_individually","comment_status","_tax_status","_tax_class","parent_id","crosssell_ids","upsell_ids"];for(1==unlock_fields.file_paths&&c.push("_download_type"),c=c.concat(non_standard_fields.ids),a(".wcml_prod_hidden_notice").prependTo("#woocommerce-product-data"),b=0;b<c.length;b++)a("#"+c[b]).attr("disabled","disabled"),a("#"+c[b]).after(a(".wcml_lock_img").clone().removeClass("wcml_lock_img").show());var d=["add_variation","link_all_variations","attribute_taxonomy","save_attributes","add_new_attribute","product_attributes .remove_row","add_attribute","select_all_attributes","select_no_attributes","edit-visibility"];for(d=d.concat(non_standard_fields.classes),1==unlock_fields.file_paths&&(d.push("upload_file_button"),d.push("insert"),d.push("delete"),a(".upload_file_button,.insert,.delete").bind({click:function(a){return!1}})),b=0;b<d.length;b++)a("."+d[b]).attr("disabled","disabled"),a("."+d[b]).after(a(".wcml_lock_img").clone().removeClass("wcml_lock_img").show());a("#visibility .edit-visibility span").bind({click:function(a){return!1}}),a(".remove_variation").each(function(){a(this).attr("disabled","disabled"),a(this).after(a(".wcml_lock_img").clone().removeClass("wcml_lock_img").show().css("float","right"))});var e=["_width","_height","_sku","_length","_weight","product_length","_regular_price","_sale_price","_sale_price_dates_from","_sale_price_dates_to"];for(1==unlock_fields.file_paths&&(e.push("_download_limit"),e.push("_download_expiry"),e.push("_wc_file_names[]"),e.push("_wc_file_urls[]")),e=e.concat(non_standard_fields.input_names),1==unlock_fields.menu_order&&e.push("menu_order"),b=0;b<e.length;b++)a('input[name="'+e[b]+'"]').attr("readonly","readonly"),a(".dimensions_field span.wrap").css("float","left"),("_width"==e[b]||"_height"==e[b]||"_length"==e[b])&&(a('input[name="'+e[b]+'"]').css("margin-right",0),a('input[name="'+e[b]+'"]').css("float","none"),a('input[name="'+e[b]+'"]').css("width","29%")),"_sale_price_dates_to"==e[b]?a('input[name="'+e[b]+'"]').after(a(".wcml_lock_img").clone().removeClass("wcml_lock_img").css("float","left").show()):a('input[name="'+e[b]+'"]').after(a(".wcml_lock_img").clone().removeClass("wcml_lock_img").show());a('#product_attributes td textarea,#product_attributes input[type="text"]').each(function(){a(this).attr("readonly","readonly"),a(this).after(a(".wcml_lock_img").clone().removeClass("wcml_lock_img").show())}),a('#product_attributes input[type="checkbox"]').each(function(){a(this).attr("disabled","disabled"),a(this).after(a(".wcml_lock_img").clone().removeClass("wcml_lock_img").show())}),a('form#post input[type="submit"]').click(function(){for(b=0;b<c.length;b++)a("#"+c[b]).removeAttr("disabled");a('.woocommerce_variation select,#variable_product_options .toolbar select,.woocommerce_variation input[type="checkbox"],#product_attributes input[type="checkbox"]').each(function(){a(this).removeAttr("disabled")})})});var wcml_lock_variation_fields=function(){var a=jQuery(".woocommerce_variation>h3 select").attr("disabled");if("undefined"==typeof a||a===!1){jQuery(".woocommerce_variation>h3 select, #variable_product_options .toolbar select, .show_if_variation_manage_stock select").each(function(){jQuery(this).attr("disabled","disabled"),jQuery(this).parent().append('<input type="hidden" name="'+jQuery(this).attr("name")+'" value="'+jQuery(this).val()+'" />'),jQuery(this).after(jQuery(".wcml_lock_img").clone().removeClass("wcml_lock_img").show())});var b=0,c=["_width","_height","_sku","_length","_weight","product_length","_regular_price","_sale_price","_sale_price_dates_from","_sale_price_dates_to","_stock","_download_limit","_download_expiry"];for(b=0;b<c.length;b++)jQuery('input[name^="variable'+c[b]+'"]').each(function(){jQuery(this).attr("readonly","readonly"),jQuery(this).after(jQuery(".wcml_lock_img").clone().removeClass("wcml_lock_img").show())});var d=["_enabled","_is_downloadable","_is_virtual","_manage_stock"];for(b=0;b<d.length;b++)jQuery('input[name^="variable'+d[b]+'"]').each(function(){jQuery(this).attr("disabled","disabled"),jQuery(this).after(jQuery(".wcml_lock_img").clone().removeClass("wcml_lock_img").show())});var e=["_stock_status","_shipping_class","_tax_class"];for(b=0;b<e.length;b++)jQuery('select[name^="variable'+e[b]+'"]').each(function(){jQuery(this).attr("disabled","disabled"),jQuery(this).parent().append('<input type="hidden" name="'+jQuery(this).attr("name")+'" value="'+jQuery(this).val()+'" />'),jQuery(this).after(jQuery(".wcml_lock_img").clone().removeClass("wcml_lock_img").show())});if(1==unlock_fields.file_paths){var f=["_wc_variation_file_names","_wc_variation_file_urls"];for(b=0;b<f.length;b++)jQuery('input[name^="'+f[b]+'"]').each(function(){jQuery(this).attr("readonly","readonly"),jQuery(this).after(jQuery(".wcml_lock_img").clone().removeClass("wcml_lock_img").show())});var g=["upload_file_button","insert","delete"];for(b=0;b<g.length;b++)jQuery("."+g[b]).attr("disabled","disabled"),jQuery("."+g[b]).after(jQuery(".wcml_lock_img").clone().removeClass("wcml_lock_img").show().css("float","right"))}}};
wpml-woocommerce.php CHANGED
@@ -6,12 +6,12 @@
6
  Author: OnTheGoSystems
7
  Author URI: http://www.onthegosystems.com/
8
  Text Domain: woocommerce-multilingual
9
- Version: 3.8.1
10
  */
11
 
12
  if( defined( 'WCML_VERSION' ) ) return;
13
 
14
- define( 'WCML_VERSION', '3.8.1' );
15
  define( 'WCML_PLUGIN_PATH', dirname( __FILE__ ) );
16
  define( 'WCML_PLUGIN_FOLDER', basename( WCML_PLUGIN_PATH ) );
17
  define( 'WCML_LOCALE_PATH', WCML_PLUGIN_PATH . '/locale' );
6
  Author: OnTheGoSystems
7
  Author URI: http://www.onthegosystems.com/
8
  Text Domain: woocommerce-multilingual
9
+ Version: 3.8.2
10
  */
11
 
12
  if( defined( 'WCML_VERSION' ) ) return;
13
 
14
+ define( 'WCML_VERSION', '3.8.2' );
15
  define( 'WCML_PLUGIN_PATH', dirname( __FILE__ ) );
16
  define( 'WCML_PLUGIN_FOLDER', basename( WCML_PLUGIN_PATH ) );
17
  define( 'WCML_LOCALE_PATH', WCML_PLUGIN_PATH . '/locale' );