MailChimp for WooCommerce - Version 2.1.15

Version Description

  • adds optional feedback survey on deactivate
  • updates syncing engine to use REST API
  • fixes edited orders syncing old and new products into Mailchimp
  • adds support for remove_action
Download this release

Release Info

Developer ryanhungate
Plugin Icon wp plugin MailChimp for WooCommerce
Version 2.1.15
Comparing to
See all releases

Code changes from version 2.1.14 to 2.1.15

Files changed (29) hide show
  1. README.txt +11 -5
  2. admin/class-mailchimp-woocommerce-admin.php +111 -35
  3. admin/partials/mailchimp-woocommerce-admin-tabs.php +12 -1
  4. admin/partials/tabs/campaign_defaults.php +2 -2
  5. admin/partials/tabs/logs.php +3 -3
  6. admin/partials/tabs/newsletter_settings.php +4 -4
  7. admin/partials/tabs/store_info.php +1 -1
  8. admin/partials/tabs/store_sync.php +12 -6
  9. bootstrap.php +80 -62
  10. includes/api/assets/class-mailchimp-order.php +11 -0
  11. includes/api/class-mailchimp-api.php +29 -3
  12. includes/api/class-mailchimp-woocommerce-transform-orders-wc3.php +1 -1
  13. includes/class-mailchimp-woocommerce-deactivation-survey.php +398 -0
  14. includes/class-mailchimp-woocommerce-newsletter.php +17 -0
  15. includes/class-mailchimp-woocommerce-options.php +5 -5
  16. includes/class-mailchimp-woocommerce-queue.php +226 -0
  17. includes/class-mailchimp-woocommerce-rest-api.php +296 -0
  18. includes/class-mailchimp-woocommerce-service.php +27 -0
  19. includes/class-mailchimp-woocommerce.php +11 -29
  20. includes/processes/class-mailchimp-woocommerce-abstract-sync.php +1 -1
  21. includes/processes/class-mailchimp-woocommerce-process-coupons-initial-sync.php +21 -0
  22. includes/processes/class-mailchimp-woocommerce-process-products.php +1 -1
  23. includes/processes/class-mailchimp-woocommerce-rest-queue.php +244 -0
  24. includes/vendor/queue/classes/worker/wp-http-worker.php +1 -1
  25. includes/vendor/queue/classes/worker/wp-worker.php +1 -1
  26. mailchimp-woocommerce.php +2 -2
  27. public/class-mailchimp-woocommerce-public.php +6 -2
  28. public/js/mailchimp-woocommerce-public.js +17 -0
  29. public/js/mailchimp-woocommerce-public.min.js +1 -1
README.txt CHANGED
@@ -3,8 +3,8 @@ Contributors: ryanhungate, Mailchimp
3
  Tags: ecommerce,email,workflows,mailchimp
4
  Donate link: https://mailchimp.com
5
  Requires at least: 4.3
6
- Tested up to: 5.0.3
7
- Stable tag: 2.1.14
8
  Requires PHP: 7.0
9
  WC tested up to: 3.5.4
10
  License: GPLv2 or later
@@ -24,10 +24,11 @@ With Mailchimp for WooCommerce, you’ll have the power to:
24
  - Add discount codes created in WooCommerce to your emails and automations with a Promo Code content block
25
  - Create beautiful landing pages that make it easy to highlight your products, promote a sale or giveaway, and grow your list.
26
  ###Important Notes
27
- This plugin supports our most powerful API 3.0 features, and is intended for users who have not yet integrated their WooCommerce stores with Mailchimp.
28
- You can run this new integration at the same time as your current WooCommerce integration for Mailchimp. However, data from the older integration will display separately in subscriber profiles, and can’t be used with e-commerce features that require API 3.0.
29
  WordPress.com compatibility is limited to Business tier users only.
30
- At this time, the synchronization of product categories from WooCommerce to Mailchimp is not supported.
 
31
  == Installation ==
32
  ###Before You Start
33
  Here are some things to know before you begin this process.
@@ -62,6 +63,11 @@ The Mailchimp for WooCommerce supports Wordpress Multi Sites and below are a few
62
  - Deleting removes the connection between Mailchimp and WooCommerce, and uninstalls the plugin from your site.
63
  Refer to the Wordpress Codex for more information about [Multisite Network Administration](https://codex.wordpress.org/Multisite_Network_Administration)
64
  == Changelog ==
 
 
 
 
 
65
  = 2.1.14 =
66
  * Adds support for filter on newsletter field
67
  * fixes inactive log delete button
3
  Tags: ecommerce,email,workflows,mailchimp
4
  Donate link: https://mailchimp.com
5
  Requires at least: 4.3
6
+ Tested up to: 5.1
7
+ Stable tag: 2.1.15
8
  Requires PHP: 7.0
9
  WC tested up to: 3.5.4
10
  License: GPLv2 or later
24
  - Add discount codes created in WooCommerce to your emails and automations with a Promo Code content block
25
  - Create beautiful landing pages that make it easy to highlight your products, promote a sale or giveaway, and grow your list.
26
  ###Important Notes
27
+ This plugin supports our most powerful API 3.0 features, and is intended for users who have not yet integrated their WooCommerce stores with Mailchimp.
28
+ You can run this new integration at the same time as your current WooCommerce integration for Mailchimp. However, data from the older integration will display separately in subscriber profiles, and can’t be used with e-commerce features that require API 3.0.
29
  WordPress.com compatibility is limited to Business tier users only.
30
+ At this time, the synchronization of product categories from WooCommerce to Mailchimp is not supported.
31
+ Attention advanced users, theme makers and developers! We have a Wiki to help with advanced workflows and features of the plugin. You can find it on our GitHub Repository. <https://github.com/mailchimp/mc-woocommerce/wiki>
32
  == Installation ==
33
  ###Before You Start
34
  Here are some things to know before you begin this process.
63
  - Deleting removes the connection between Mailchimp and WooCommerce, and uninstalls the plugin from your site.
64
  Refer to the Wordpress Codex for more information about [Multisite Network Administration](https://codex.wordpress.org/Multisite_Network_Administration)
65
  == Changelog ==
66
+ = 2.1.15 =
67
+ * adds optional feedback survey on deactivate
68
+ * updates syncing engine to use REST API
69
+ * fixes edited orders syncing old and new products into Mailchimp
70
+ * adds support for remove_action
71
  = 2.1.14 =
72
  * Adds support for filter on newsletter field
73
  * fixes inactive log delete button
admin/class-mailchimp-woocommerce-admin.php CHANGED
@@ -25,26 +25,29 @@ class MailChimp_WooCommerce_Admin extends MailChimp_WooCommerce_Options {
25
  protected $swapped_list_id = null;
26
  protected $swapped_store_id = null;
27
 
28
- /**
29
- * @return MailChimp_WooCommerce_Admin
30
- */
31
- public static function connect()
32
- {
33
- $env = mailchimp_environment_variables();
34
 
35
- return new self('mailchimp-woocommerce', $env->version);
36
- }
 
 
 
 
 
 
 
 
 
 
 
37
 
38
  /**
39
- * Initialize the class and set its properties.
40
- *
41
- * @since 1.0.0
42
- * @param string $plugin_name The name of this plugin.
43
- * @param string $version The version of this plugin.
44
  */
45
- public function __construct( $plugin_name, $version ) {
46
- $this->plugin_name = $plugin_name;
47
- $this->version = $version;
48
  }
49
 
50
  /**
@@ -80,6 +83,22 @@ class MailChimp_WooCommerce_Admin extends MailChimp_WooCommerce_Options {
80
  );
81
  }
82
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
83
  /**
84
  * @return string
85
  */
@@ -95,7 +114,7 @@ class MailChimp_WooCommerce_Admin extends MailChimp_WooCommerce_Options {
95
  */
96
  public function add_action_links($links) {
97
  $settings_link = array(
98
- '<a href="' . admin_url( 'options-general.php?page=' . $this->plugin_name ) . '">' . __('Settings', $this->plugin_name) . '</a>',
99
  );
100
  return array_merge($settings_link, $links);
101
  }
@@ -206,8 +225,10 @@ class MailChimp_WooCommerce_Admin extends MailChimp_WooCommerce_Options {
206
  $service = new MailChimp_Service();
207
  $service->removePointers(true, true);
208
 
209
- $this->startSync();
 
210
  $this->showSyncStartedMessage();
 
211
  $this->setData('sync.config.resync', true);
212
  break;
213
 
@@ -222,7 +243,7 @@ class MailChimp_WooCommerce_Admin extends MailChimp_WooCommerce_Options {
222
  );
223
 
224
  if (isset($_POST['mc_action']) && in_array($_POST['mc_action'], array('view_log', 'remove_log'))) {
225
- $path = 'options-general.php?page=mailchimp-woocommerce&tab=logs';
226
  wp_redirect($path);
227
  exit();
228
  }
@@ -499,8 +520,16 @@ class MailChimp_WooCommerce_Admin extends MailChimp_WooCommerce_Options {
499
 
500
  // start the sync automatically if the sync is false
501
  if ((bool) $this->getData('sync.started_at', false) === false) {
502
- $this->startSync();
503
- $this->showSyncStartedMessage();
 
 
 
 
 
 
 
 
504
  }
505
 
506
  $data['active_tab'] = 'sync';
@@ -515,6 +544,8 @@ class MailChimp_WooCommerce_Admin extends MailChimp_WooCommerce_Options {
515
  return $data;
516
  }
517
 
 
 
518
  /**
519
  * @param null|array $data
520
  * @return bool
@@ -679,6 +710,49 @@ class MailChimp_WooCommerce_Admin extends MailChimp_WooCommerce_Options {
679
  return true;
680
  }
681
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
682
  /**
683
  * @param null|array $data
684
  * @return bool|string
@@ -893,19 +967,21 @@ class MailChimp_WooCommerce_Admin extends MailChimp_WooCommerce_Options {
893
  return true;
894
  }
895
 
896
- /**a:4:{s:19:"mailchimp_debugging";b:0;s:25:"mailchimp_account_info_id";N;s:31:"mailchimp_account_info_username";N;s:10:"active_tab";s:7:"api_key";}
897
- * Start the sync
898
- */
899
- private function startSync()
900
  {
901
- mailchimp_flush_sync_pointers();
 
902
 
903
- $coupon_sync = new MailChimp_WooCommerce_Process_Coupons();
904
- mailchimp_handle_or_queue($coupon_sync);
905
 
906
- $job = new MailChimp_WooCommerce_Process_Products();
907
- $job->flagStartSync();
908
- mailchimp_handle_or_queue($job);
 
 
909
  }
910
 
911
  /**
@@ -914,10 +990,10 @@ class MailChimp_WooCommerce_Admin extends MailChimp_WooCommerce_Options {
914
  private function showSyncStartedMessage()
915
  {
916
  $text = 'Starting the sync process…<br/>'.
917
- '<p id="sync-status-message">Please hang tight while we work our mojo. Sometimes the sync can take a while, '.
918
- 'especially on sites with lots of orders and/or products. You may refresh this page at '.
919
- 'anytime to check on the progress.</p>';
920
-
921
  add_settings_error('mailchimp-woocommerce_notice', $this->plugin_name, __($text), 'updated');
922
  }
923
  }
25
  protected $swapped_list_id = null;
26
  protected $swapped_store_id = null;
27
 
28
+ /** @var null|static */
29
+ protected static $_instance = null;
 
 
 
 
30
 
31
+ /**
32
+ * @return MailChimp_WooCommerce_Admin
33
+ */
34
+ public static function instance()
35
+ {
36
+ if (!empty(static::$_instance)) {
37
+ return static::$_instance;
38
+ }
39
+ $env = mailchimp_environment_variables();
40
+ static::$_instance = new MailChimp_WooCommerce_Admin();
41
+ static::$_instance->setVersion($env->version);
42
+ return static::$_instance;
43
+ }
44
 
45
  /**
46
+ * @return MailChimp_WooCommerce_Admin|MailChimp_WooCommerce_Options
 
 
 
 
47
  */
48
+ public static function connect()
49
+ {
50
+ return static::instance();
51
  }
52
 
53
  /**
83
  );
84
  }
85
 
86
+ /**
87
+ * Setup Feedback Survey Form
88
+ *
89
+ * @since 2.1.15
90
+ */
91
+ public function setup_survey_form() {
92
+ if (is_admin()) {
93
+ try {
94
+ new Mailchimp_Woocommerce_Deactivation_Survey($this->plugin_name, 'mailchimp-for-woocommerce');
95
+ } catch (\Throwable $e) {
96
+ mailchimp_error('admin@setup_survey_form', $e->getCode() . ' :: ' . $e->getMessage() . ' on ' . $e->getLine() . ' in ' . $e->getFile());
97
+ return false;
98
+ }
99
+ }
100
+ }
101
+
102
  /**
103
  * @return string
104
  */
114
  */
115
  public function add_action_links($links) {
116
  $settings_link = array(
117
+ '<a href="' . admin_url( 'admin.php?page=' . $this->plugin_name ) . '">' . __('Settings', $this->plugin_name) . '</a>',
118
  );
119
  return array_merge($settings_link, $links);
120
  }
225
  $service = new MailChimp_Service();
226
  $service->removePointers(true, true);
227
 
228
+ static::startSync();
229
+
230
  $this->showSyncStartedMessage();
231
+
232
  $this->setData('sync.config.resync', true);
233
  break;
234
 
243
  );
244
 
245
  if (isset($_POST['mc_action']) && in_array($_POST['mc_action'], array('view_log', 'remove_log'))) {
246
+ $path = 'admin.php?page=mailchimp-woocommerce&tab=logs';
247
  wp_redirect($path);
248
  exit();
249
  }
520
 
521
  // start the sync automatically if the sync is false
522
  if ((bool) $this->getData('sync.started_at', false) === false) {
523
+ // tell the next page view to start the sync with a transient since the data isn't available yet
524
+ set_site_transient('mailchimp_woocommerce_start_sync', microtime(), 30);
525
+
526
+ $this->setData('sync.config.resync', false);
527
+ $this->setData('sync.orders.current_page', 1);
528
+ $this->setData('sync.products.current_page', 1);
529
+ $this->setData('sync.syncing', true);
530
+ $this->setData('sync.started_at', time());
531
+
532
+ $this->showSyncStartedMessage();
533
  }
534
 
535
  $data['active_tab'] = 'sync';
544
  return $data;
545
  }
546
 
547
+
548
+
549
  /**
550
  * @param null|array $data
551
  * @return bool
710
  return true;
711
  }
712
 
713
+ public function inject_sync_ajax_call() { global $wp; ?>
714
+ <script type="text/javascript" >
715
+ jQuery(document).ready(function($) {
716
+ var endpoint = '<?php echo MailChimp_WooCommerce_Rest_Api::url('sync/stats'); ?>';
717
+ var on_sync_tab = '<?php echo (mailchimp_check_if_on_sync_tab() ? 'yes' : 'no')?>';
718
+ var sync_status = '<?php echo ((mailchimp_has_started_syncing() && !mailchimp_is_done_syncing()) ? 'historical' : 'current') ?>';
719
+
720
+ if (on_sync_tab === 'yes') {
721
+ var call_mailchimp_for_stats = function () {
722
+ jQuery.get(endpoint, function(response) {
723
+ if (response.success) {
724
+
725
+ // if the response is now finished - but the original sync status was "historical"
726
+ // perform a page refresh because we need the re-sync buttons to show up again.
727
+ if (response.has_finished === true && sync_status === 'historical') {
728
+ return document.location.reload(true);
729
+ }
730
+
731
+ jQuery('#mailchimp_product_count').html(response.products_in_mailchimp.toLocaleString(undefined, {
732
+ maximumFractionDigits: 0
733
+ }));
734
+
735
+ jQuery('#mailchimp_order_count').html(response.orders_in_mailchimp.toLocaleString(undefined, {
736
+ maximumFractionDigits: 0
737
+ }));
738
+
739
+ jQuery('#mailchimp_last_updated').html(response.date);
740
+
741
+ setTimeout(function() {
742
+ call_mailchimp_for_stats();
743
+ }, 10000);
744
+ }
745
+ });
746
+ };
747
+
748
+ setTimeout(function() {
749
+ call_mailchimp_for_stats();
750
+ }, 10000);
751
+ }
752
+ });
753
+ </script> <?php
754
+ }
755
+
756
  /**
757
  * @param null|array $data
758
  * @return bool|string
967
  return true;
968
  }
969
 
970
+ /**
971
+ * Start the sync
972
+ */
973
+ public static function startSync()
974
  {
975
+ // delete the transient so this only happens one time.
976
+ delete_site_transient('mailchimp_woocommerce_start_sync');
977
 
978
+ $coupon_sync = new MailChimp_WooCommerce_Process_Coupons_Initial_Sync();
 
979
 
980
+ // tell Mailchimp that we're syncing
981
+ $coupon_sync->flagStartSync();
982
+
983
+ // queue up the jobs
984
+ mailchimp_handle_or_queue($coupon_sync, 0, true);
985
  }
986
 
987
  /**
990
  private function showSyncStartedMessage()
991
  {
992
  $text = 'Starting the sync process…<br/>'.
993
+ '<p id="sync-status-message">'.
994
+ 'Please hang tight while we work our mojo. '.
995
+ 'Sometimes the sync can take a while, especially on sites with lots of orders and/or products.'.
996
+ '</p>';
997
  add_settings_error('mailchimp-woocommerce_notice', $this->plugin_name, __($text), 'updated');
998
  }
999
  }
admin/partials/mailchimp-woocommerce-admin-tabs.php CHANGED
@@ -12,10 +12,17 @@ if (!isset($_GET['tab']) && isset($options['active_tab'])) {
12
  }
13
 
14
  $show_sync_tab = isset($_GET['resync']) ? $_GET['resync'] === '1' : false;
 
 
 
 
 
 
 
15
  $show_campaign_defaults = true;
16
  $has_valid_api_key = false;
17
  $allow_new_list = true;
18
- $clicked_sync_button = $is_mailchimp_post&& $active_tab == 'sync';
19
  $has_api_error = isset($options['api_ping_error']) && !empty($options['api_ping_error']) ? $options['api_ping_error'] : null;
20
 
21
  if (isset($options['mailchimp_api_key'])) {
@@ -67,6 +74,8 @@ if (isset($options['mailchimp_api_key'])) {
67
  }
68
  </style>
69
 
 
 
70
  <?php if (!defined('PHP_VERSION_ID') || (PHP_VERSION_ID < 70000)): ?>
71
  <div data-dismissible="notice-php-version" class="error notice notice-error is-dismissible">
72
  <p><?php _e('Mailchimp says: Please upgrade your PHP version to a minimum of 7.0', 'mailchimp-woocommerce'); ?></p>
@@ -79,6 +88,8 @@ if (isset($options['mailchimp_api_key'])) {
79
  </div>
80
  <?php endif; ?>
81
 
 
 
82
  <!-- Create a header in the default WordPress 'wrap' container -->
83
  <div class="wrap">
84
  <div id="icon-themes" class="icon32"></div>
12
  }
13
 
14
  $show_sync_tab = isset($_GET['resync']) ? $_GET['resync'] === '1' : false;
15
+
16
+ // if we have a transient set to start the sync on this page view, initiate it now that the values have been saved.
17
+ if (!$show_sync_tab && (bool) get_site_transient('mailchimp_woocommerce_start_sync', false)) {
18
+ $show_sync_tab = true;
19
+ $active_tab = 'sync';
20
+ }
21
+
22
  $show_campaign_defaults = true;
23
  $has_valid_api_key = false;
24
  $allow_new_list = true;
25
+ $clicked_sync_button = $is_mailchimp_post && $active_tab == 'sync';
26
  $has_api_error = isset($options['api_ping_error']) && !empty($options['api_ping_error']) ? $options['api_ping_error'] : null;
27
 
28
  if (isset($options['mailchimp_api_key'])) {
74
  }
75
  </style>
76
 
77
+
78
+
79
  <?php if (!defined('PHP_VERSION_ID') || (PHP_VERSION_ID < 70000)): ?>
80
  <div data-dismissible="notice-php-version" class="error notice notice-error is-dismissible">
81
  <p><?php _e('Mailchimp says: Please upgrade your PHP version to a minimum of 7.0', 'mailchimp-woocommerce'); ?></p>
88
  </div>
89
  <?php endif; ?>
90
 
91
+ <?php settings_errors(); ?>
92
+
93
  <!-- Create a header in the default WordPress 'wrap' container -->
94
  <div class="wrap">
95
  <div id="icon-themes" class="icon32"></div>
admin/partials/tabs/campaign_defaults.php CHANGED
@@ -4,10 +4,10 @@ $handler = MailChimp_WooCommerce_Admin::connect();
4
 
5
  // if we don't have valid campaign defaults we need to redirect back to the 'campaign_defaults' tab.
6
  if (!$handler->hasValidApiKey()) {
7
- wp_redirect('options-general.php?page=mailchimp-woocommerce&tab=api_key&error_notice=missing_api_key');
8
  }
9
  if (!$handler->hasValidStoreInfo()) {
10
- wp_redirect('options-general.php?page=mailchimp-woocommerce&tab=store_info&error_notice=missing_store');
11
  }
12
  ?>
13
 
4
 
5
  // if we don't have valid campaign defaults we need to redirect back to the 'campaign_defaults' tab.
6
  if (!$handler->hasValidApiKey()) {
7
+ wp_redirect('admin.php?page=mailchimp-woocommerce&tab=api_key&error_notice=missing_api_key');
8
  }
9
  if (!$handler->hasValidStoreInfo()) {
10
+ wp_redirect('admin.php?page=mailchimp-woocommerce&tab=store_info&error_notice=missing_store');
11
  }
12
  ?>
13
 
admin/partials/tabs/logs.php CHANGED
@@ -3,7 +3,7 @@ if (!empty( $_REQUEST['handle'])) {
3
  if (!empty($_REQUEST['_wpnonce']) && wp_verify_nonce($_REQUEST['_wpnonce'], 'remove_log')) {
4
  $log_handler = new WC_Log_Handler_File();
5
  $log_handler->remove($_REQUEST['handle']);
6
- wp_redirect('options-general.php?page=mailchimp-woocommerce&tab=logs');
7
  }
8
  }
9
  $files = defined('WC_LOG_DIR') ? @scandir( WC_LOG_DIR ) : array();
@@ -63,12 +63,12 @@ $handle = !empty($viewed_log) ? substr($viewed_log, 0, strlen($viewed_log) > 37
63
  <h2>
64
  <?php echo esc_html( $viewed_log ); ?>
65
  <?php if ( ! empty( $handle ) ) : ?>
66
- <a class="page-title-action" href="<?php echo esc_url( wp_nonce_url( add_query_arg( array( 'handle' => sanitize_title($viewed_log) ), admin_url( 'options-general.php?page=mailchimp-woocommerce&tab=logs&mc_action=remove_log' ) ), 'remove_log' ) ); ?>" class="button"><?php esc_html_e( 'Delete log', 'woocommerce' );?></a>
67
  <?php endif; ?>
68
  </h2>
69
  </div>
70
  <div class="alignright">
71
- <form action="<?php echo admin_url( 'options-general.php?page=mailchimp-woocommerce&tab=logs&mc_action=view_log' ); ?>" method="post">
72
  <input type="hidden" name="<?php echo $this->plugin_name; ?>[mailchimp_active_tab]" value="logs"/>
73
  <select name="log_file">
74
  <?php foreach ( $logs as $log_key => $log_file ) : ?>
3
  if (!empty($_REQUEST['_wpnonce']) && wp_verify_nonce($_REQUEST['_wpnonce'], 'remove_log')) {
4
  $log_handler = new WC_Log_Handler_File();
5
  $log_handler->remove($_REQUEST['handle']);
6
+ wp_redirect('admin.php?page=mailchimp-woocommerce&tab=logs');
7
  }
8
  }
9
  $files = defined('WC_LOG_DIR') ? @scandir( WC_LOG_DIR ) : array();
63
  <h2>
64
  <?php echo esc_html( $viewed_log ); ?>
65
  <?php if ( ! empty( $handle ) ) : ?>
66
+ <a class="page-title-action" href="<?php echo esc_url( wp_nonce_url( add_query_arg( array( 'handle' => sanitize_title($viewed_log) ), admin_url( 'admin.php?page=mailchimp-woocommerce&tab=logs&mc_action=remove_log' ) ), 'remove_log' ) ); ?>" class="button"><?php esc_html_e( 'Delete log', 'woocommerce' );?></a>
67
  <?php endif; ?>
68
  </h2>
69
  </div>
70
  <div class="alignright">
71
+ <form action="<?php echo admin_url( 'admin.php?page=mailchimp-woocommerce&tab=logs&mc_action=view_log' ); ?>" method="post">
72
  <input type="hidden" name="<?php echo $this->plugin_name; ?>[mailchimp_active_tab]" value="logs"/>
73
  <select name="log_file">
74
  <?php foreach ( $logs as $log_key => $log_file ) : ?>
admin/partials/tabs/newsletter_settings.php CHANGED
@@ -2,22 +2,22 @@
2
 
3
  // if we don't have valid campaign defaults we need to redirect back to the 'campaign_defaults' tab.
4
  if (!$handler->hasValidApiKey()) {
5
- wp_redirect('options-general.php?page=mailchimp-woocommerce&tab=api_key&error_notice=missing_api_key');
6
  }
7
 
8
  // if we don't have valid store information, we need to redirect back to the 'store_info' tab.
9
  if (!$handler->hasValidStoreInfo()) {
10
- wp_redirect('options-general.php?page=mailchimp-woocommerce&tab=store_info&error_notice=missing_store');
11
  }
12
 
13
  // if we don't have a valid api key we need to redirect back to the 'api_key' tab.
14
  if (!isset($mailchimp_lists) && ($mailchimp_lists = $handler->getMailChimpLists()) === false) {
15
- wp_redirect('options-general.php?page=mailchimp-woocommerce&tab=api_key&error_notice=missing_api_key');
16
  }
17
 
18
  // if we don't have valid campaign defaults we need to redirect back to the 'campaign_defaults' tab.
19
  if (empty($mailchimp_lists) && !$handler->hasValidCampaignDefaults()) {
20
- wp_redirect('options-general.php?page=mailchimp-woocommerce&tab=campaign_defaults&error_notice=missing_campaign_defaults');
21
  }
22
 
23
  $list_is_configured = isset($options['mailchimp_list']) && (!empty($options['mailchimp_list'])) && array_key_exists($options['mailchimp_list'], $mailchimp_lists);
2
 
3
  // if we don't have valid campaign defaults we need to redirect back to the 'campaign_defaults' tab.
4
  if (!$handler->hasValidApiKey()) {
5
+ wp_redirect('admin.php?page=mailchimp-woocommerce&tab=api_key&error_notice=missing_api_key');
6
  }
7
 
8
  // if we don't have valid store information, we need to redirect back to the 'store_info' tab.
9
  if (!$handler->hasValidStoreInfo()) {
10
+ wp_redirect('admin.php?page=mailchimp-woocommerce&tab=store_info&error_notice=missing_store');
11
  }
12
 
13
  // if we don't have a valid api key we need to redirect back to the 'api_key' tab.
14
  if (!isset($mailchimp_lists) && ($mailchimp_lists = $handler->getMailChimpLists()) === false) {
15
+ wp_redirect('admin.php?page=mailchimp-woocommerce&tab=api_key&error_notice=missing_api_key');
16
  }
17
 
18
  // if we don't have valid campaign defaults we need to redirect back to the 'campaign_defaults' tab.
19
  if (empty($mailchimp_lists) && !$handler->hasValidCampaignDefaults()) {
20
+ wp_redirect('admin.php?page=mailchimp-woocommerce&tab=campaign_defaults&error_notice=missing_campaign_defaults');
21
  }
22
 
23
  $list_is_configured = isset($options['mailchimp_list']) && (!empty($options['mailchimp_list'])) && array_key_exists($options['mailchimp_list'], $mailchimp_lists);
admin/partials/tabs/store_info.php CHANGED
@@ -4,7 +4,7 @@ $handler = MailChimp_WooCommerce_Admin::connect();
4
 
5
  // if we don't have valid campaign defaults we need to redirect back to the 'campaign_defaults' tab.
6
  if (!$handler->hasValidApiKey()) {
7
- wp_redirect('options-general.php?page=mailchimp-woocommerce&tab=api_key&error_notice=missing_api_key');
8
  }
9
 
10
  ?>
4
 
5
  // if we don't have valid campaign defaults we need to redirect back to the 'campaign_defaults' tab.
6
  if (!$handler->hasValidApiKey()) {
7
+ wp_redirect('admin.php?page=mailchimp-woocommerce&tab=api_key&error_notice=missing_api_key');
8
  }
9
 
10
  ?>
admin/partials/tabs/store_sync.php CHANGED
@@ -24,6 +24,12 @@ $mailchimp_list_name = 'n/a';
24
  if (!empty($last_updated_time)) {
25
  $last_updated_time = mailchimp_date_local($last_updated_time);
26
  }
 
 
 
 
 
 
27
  if (($mailchimp_api = mailchimp_get_api()) && ($store = $mailchimp_api->getStore($store_id))) {
28
  $store_syncing = $store->isSyncing();
29
  if (($account_details = $handler->getAccountDetails())) {
@@ -52,17 +58,17 @@ if (($mailchimp_api = mailchimp_get_api()) && ($store = $mailchimp_api->getStore
52
  <?php endif; ?>
53
 
54
  <?php if ($last_updated_time): ?>
55
- <p><strong>Last Updated:</strong> <i><?php echo $last_updated_time->format('D, M j, Y g:i A'); ?></i></p>
56
  <?php endif; ?>
57
 
58
- <p><strong>Account Connected:</strong> <?php echo $account_name; ?></p>
59
- <p><strong>List Connected:</strong> <?php echo $mailchimp_list_name; ?></p>
60
- <p><strong>Products Synced:</strong> <?php echo $mailchimp_total_products; ?></p>
61
- <p><strong>Orders Synced:</strong> <?php echo $mailchimp_total_orders; ?></p>
62
 
63
  <?php if($mailchimp_api && (!$store_syncing || isset($_GET['resync']) && $_GET['resync'] === '1')): ?>
64
  <h2 style="padding-top: 1em;">Advanced</h2>
65
- <p>
66
  You can resync your list at any time without losing any of your e-commerce data.
67
  </p>
68
  <?php submit_button('Resync', 'primary','submit', TRUE); ?>
24
  if (!empty($last_updated_time)) {
25
  $last_updated_time = mailchimp_date_local($last_updated_time);
26
  }
27
+
28
+ // if we have a transient set to start the sync on this page view, initiate it now that the values have been saved.
29
+ if ((bool) get_site_transient('mailchimp_woocommerce_start_sync', false)) {
30
+ MailChimp_WooCommerce_Admin::startSync();
31
+ }
32
+
33
  if (($mailchimp_api = mailchimp_get_api()) && ($store = $mailchimp_api->getStore($store_id))) {
34
  $store_syncing = $store->isSyncing();
35
  if (($account_details = $handler->getAccountDetails())) {
58
  <?php endif; ?>
59
 
60
  <?php if ($last_updated_time): ?>
61
+ <p><strong>Last Updated:</strong> <i id="mailchimp_last_updated"><?php echo $last_updated_time->format('D, M j, Y g:i A'); ?></i></p>
62
  <?php endif; ?>
63
 
64
+ <p><strong>Account Connected:</strong> <span id="mailchimp_account_connected"><?php echo $account_name; ?></span></p>
65
+ <p><strong>List Connected:</strong> <span id="mailchimp_list_name"><?php echo $mailchimp_list_name; ?></span></p>
66
+ <p><strong>Products Synced:</strong> <span id="mailchimp_product_count"><?php echo $mailchimp_total_products; ?></span></p>
67
+ <p><strong>Orders Synced:</strong> <span id="mailchimp_order_count"><?php echo $mailchimp_total_orders; ?></span></p>
68
 
69
  <?php if($mailchimp_api && (!$store_syncing || isset($_GET['resync']) && $_GET['resync'] === '1')): ?>
70
  <h2 style="padding-top: 1em;">Advanced</h2>
71
+ <p id="resync_data_help_text">
72
  You can resync your list at any time without losing any of your e-commerce data.
73
  </p>
74
  <?php submit_button('Resync', 'primary','submit', TRUE); ?>
bootstrap.php CHANGED
@@ -19,7 +19,10 @@ spl_autoload_register(function($class) {
19
  'MailChimp_WooCommerce_Activator' => 'includes/class-mailchimp-woocommerce-activator.php',
20
  'MailChimp_WooCommerce' => 'includes/class-mailchimp-woocommerce.php',
21
  'MailChimp_WooCommerce_Privacy' => 'includes/class-mailchimp-woocommerce-privacy.php',
22
-
 
 
 
23
  // includes/api/assets
24
  'MailChimp_WooCommerce_Address' => 'includes/api/assets/class-mailchimp-address.php',
25
  'MailChimp_WooCommerce_Cart' => 'includes/api/assets/class-mailchimp-cart.php',
@@ -53,12 +56,14 @@ spl_autoload_register(function($class) {
53
  'MailChimp_WooCommerce_Abstract_Sync' => 'includes/processes/class-mailchimp-woocommerce-abstract-sync.php',
54
  'MailChimp_WooCommerce_Cart_Update' => 'includes/processes/class-mailchimp-woocommerce-cart-update.php',
55
  'MailChimp_WooCommerce_Process_Coupons' => 'includes/processes/class-mailchimp-woocommerce-process-coupons.php',
 
56
  'MailChimp_WooCommerce_Process_Orders' => 'includes/processes/class-mailchimp-woocommerce-process-orders.php',
57
  'MailChimp_WooCommerce_Process_Products' => 'includes/processes/class-mailchimp-woocommerce-process-products.php',
58
  'MailChimp_WooCommerce_SingleCoupon' => 'includes/processes/class-mailchimp-woocommerce-single-coupon.php',
59
  'MailChimp_WooCommerce_Single_Order' => 'includes/processes/class-mailchimp-woocommerce-single-order.php',
60
  'MailChimp_WooCommerce_Single_Product' => 'includes/processes/class-mailchimp-woocommerce-single-product.php',
61
  'MailChimp_WooCommerce_User_Submit' => 'includes/processes/class-mailchimp-woocommerce-user-submit.php',
 
62
 
63
  'MailChimp_WooCommerce_Public' => 'public/class-mailchimp-woocommerce-public.php',
64
  'MailChimp_WooCommerce_Admin' => 'admin/class-mailchimp-woocommerce-admin.php',
@@ -87,12 +92,12 @@ function mailchimp_environment_variables() {
87
 
88
  return (object) array(
89
  'repo' => 'master',
90
- 'environment' => 'production',
91
- 'version' => '2.1.14',
92
  'php_version' => phpversion(),
93
  'wp_version' => (empty($wp_version) ? 'Unknown' : $wp_version),
94
  'wc_version' => function_exists('WC') ? WC()->version : null,
95
- 'logging' => ($o && is_array($o) && isset($o['mailchimp_logging'])) ? $o['mailchimp_logging'] : 'standard',
96
  );
97
  }
98
 
@@ -161,26 +166,29 @@ if (!function_exists( 'wp_queue')) {
161
 
162
  /**
163
  * @param WP_Job $job
164
- * @param $delay
 
165
  */
166
- function mailchimp_handle_or_queue(WP_Job $job, $delay = 0)
167
  {
168
  wp_queue($job, $delay);
169
- if (mailchimp_queue_is_disabled()) {
170
- mailchimp_call_http_worker_manually();
 
 
171
  }
172
  }
173
 
174
  /**
 
175
  * @return bool
176
  */
177
- function mailchimp_should_init_queue() {
178
- return !mailchimp_queue_is_disabled() &&
179
- !mailchimp_running_in_console() &&
180
- !mailchimp_detect_request_contains_http_worker() &&
181
- mailchimp_detect_admin_ajax() &&
182
- mailchimp_is_configured() &&
183
- !mailchimp_http_worker_is_running();
184
  }
185
 
186
  /**
@@ -221,16 +229,6 @@ function mailchimp_reset_http_lock() {
221
  return delete_site_transient( 'http_worker_lock' );
222
  }
223
 
224
- /**
225
- * @return bool
226
- */
227
- function mailchimp_detect_request_contains_http_worker() {
228
- global $wp;
229
- if (empty($wp) || !is_object($wp) || !isset($wp->request)) return false;
230
- $current_url = home_url(add_query_arg(array(), $wp->request));
231
- return mailchimp_string_contains($current_url, 'action=http_worker');
232
- }
233
-
234
  /**
235
  * @param bool $force
236
  * @return bool
@@ -622,7 +620,7 @@ function mailchimp_update_connected_site_script() {
622
  // handle the coupon sync if we don't have a flag that says otherwise.
623
  $job = new MailChimp_WooCommerce_Process_Coupons();
624
  if ($job->getData('sync.coupons.completed_at', false) === false) {
625
- wp_queue($job);
626
  }
627
  return mailchimpi_refresh_connected_site_script($store);
628
  }
@@ -793,45 +791,17 @@ function mailchimp_hash_trim_lower($str) {
793
  }
794
 
795
  /**
796
- * @param bool $block
797
  * @return array|WP_Error
798
  */
799
- function mailchimp_call_http_worker_manually($block = false) {
800
- $action = 'http_worker';
801
- $query_args = apply_filters('http_worker_query_args', array(
802
- 'action' => $action,
803
- 'nonce' => wp_create_nonce($action),
804
- 'test' => $block === true ? '1' : '0',
805
- ));
806
- $query_url = apply_filters('http_worker_query_url', admin_url('admin-ajax.php'));
807
- $post_args = apply_filters('http_worker_post_args', array(
808
- 'timeout' => $block ? 60 : 0.01,
809
- 'blocking' => $block,
810
- 'cookies' => $_COOKIE,
811
- 'sslverify' => apply_filters('https_local_ssl_verify', false),
812
- ));
813
- $url = add_query_arg($query_args, $query_url);
814
- return wp_remote_post(esc_url_raw($url), $post_args);
815
  }
816
 
817
  /**
818
  * @return array|WP_Error
819
  */
820
- function mailchimp_call_admin_ajax_test() {
821
- $action = 'http_worker_test';
822
- $query_args = apply_filters('http_worker_query_args', array(
823
- 'action' => $action,
824
- 'nonce' => wp_create_nonce($action),
825
- ));
826
- $query_url = apply_filters('http_worker_query_url', admin_url('admin-ajax.php'));
827
- $post_args = apply_filters('http_worker_post_args', array(
828
- 'timeout' => 5,
829
- 'blocking' => true,
830
- 'cookies' => $_COOKIE,
831
- 'sslverify' => apply_filters('https_local_ssl_verify', false),
832
- ));
833
- $url = add_query_arg($query_args, $query_url);
834
- return wp_remote_post(esc_url_raw($url), $post_args);
835
  }
836
 
837
  /**
@@ -853,19 +823,23 @@ function mailchimp_woocommerce_check_if_http_worker_fails() {
853
  }
854
 
855
  // apply a blocking call to make sure we get the response back
856
- $response = mailchimp_call_admin_ajax_test();
857
 
858
  if (is_wp_error($response)) {
859
  // nope, we have problems
860
  mailchimp_set_data('test.can.remote_post', false);
861
  mailchimp_set_data('test.can.remote_post.error', $response->get_error_message());
862
  return $response->get_error_message();
863
- } elseif (is_array($response) && isset($response['http_response']) && ($r = $response['http_response'])){
864
  /** @var \WP_HTTP_Requests_Response $r */
865
- if ($r->get_status() >= 400) {
866
- return 'admin-ajax.php seems to be disabled on this wordpress site. Please enable to sync data.';
 
 
 
867
  }
868
  }
 
869
  // yep all good.
870
  mailchimp_set_data('test.can.remote_post', true);
871
  mailchimp_set_data('test.can.remote_post.error', false);
@@ -970,6 +944,22 @@ function mailchimp_get_subscriber_status_options($subscribed) {
970
  );
971
  }
972
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
973
  function mailchimp_flush_queue_tables() {
974
  try {
975
  /** @var \ */
@@ -1009,6 +999,34 @@ function mailchimp_clean_database() {
1009
  delete_option('mailchimp-woocommerce-errors.store_info');
1010
  }
1011
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1012
  function run_mailchimp_woocommerce() {
1013
  $env = mailchimp_environment_variables();
1014
  $plugin = new MailChimp_WooCommerce($env->environment, $env->version);
19
  'MailChimp_WooCommerce_Activator' => 'includes/class-mailchimp-woocommerce-activator.php',
20
  'MailChimp_WooCommerce' => 'includes/class-mailchimp-woocommerce.php',
21
  'MailChimp_WooCommerce_Privacy' => 'includes/class-mailchimp-woocommerce-privacy.php',
22
+ 'Mailchimp_Woocommerce_Deactivation_Survey' => 'includes/class-mailchimp-woocommerce-deactivation-survey.php',
23
+ 'MailChimp_WooCommerce_Queue' => 'includes/class-mailchimp-woocommerce-queue.php',
24
+ 'MailChimp_WooCommerce_Rest_Api' => 'includes/class-mailchimp-woocommerce-rest-api.php',
25
+
26
  // includes/api/assets
27
  'MailChimp_WooCommerce_Address' => 'includes/api/assets/class-mailchimp-address.php',
28
  'MailChimp_WooCommerce_Cart' => 'includes/api/assets/class-mailchimp-cart.php',
56
  'MailChimp_WooCommerce_Abstract_Sync' => 'includes/processes/class-mailchimp-woocommerce-abstract-sync.php',
57
  'MailChimp_WooCommerce_Cart_Update' => 'includes/processes/class-mailchimp-woocommerce-cart-update.php',
58
  'MailChimp_WooCommerce_Process_Coupons' => 'includes/processes/class-mailchimp-woocommerce-process-coupons.php',
59
+ 'MailChimp_WooCommerce_Process_Coupons_Initial_Sync' => 'includes/processes/class-mailchimp-woocommerce-process-coupons-initial-sync.php',
60
  'MailChimp_WooCommerce_Process_Orders' => 'includes/processes/class-mailchimp-woocommerce-process-orders.php',
61
  'MailChimp_WooCommerce_Process_Products' => 'includes/processes/class-mailchimp-woocommerce-process-products.php',
62
  'MailChimp_WooCommerce_SingleCoupon' => 'includes/processes/class-mailchimp-woocommerce-single-coupon.php',
63
  'MailChimp_WooCommerce_Single_Order' => 'includes/processes/class-mailchimp-woocommerce-single-order.php',
64
  'MailChimp_WooCommerce_Single_Product' => 'includes/processes/class-mailchimp-woocommerce-single-product.php',
65
  'MailChimp_WooCommerce_User_Submit' => 'includes/processes/class-mailchimp-woocommerce-user-submit.php',
66
+ 'MailChimp_WooCommerce_Rest_Queue' => 'includes/processes/class-mailchimp-woocommerce-rest-queue.php',
67
 
68
  'MailChimp_WooCommerce_Public' => 'public/class-mailchimp-woocommerce-public.php',
69
  'MailChimp_WooCommerce_Admin' => 'admin/class-mailchimp-woocommerce-admin.php',
92
 
93
  return (object) array(
94
  'repo' => 'master',
95
+ 'environment' => 'production', // staging or production
96
+ 'version' => '2.1.15',
97
  'php_version' => phpversion(),
98
  'wp_version' => (empty($wp_version) ? 'Unknown' : $wp_version),
99
  'wc_version' => function_exists('WC') ? WC()->version : null,
100
+ 'logging' => ($o && is_array($o) && isset($o['mailchimp_logging'])) ? $o['mailchimp_logging'] : 'debug',
101
  );
102
  }
103
 
166
 
167
  /**
168
  * @param WP_Job $job
169
+ * @param int $delay
170
+ * @param bool $force_now
171
  */
172
+ function mailchimp_handle_or_queue(WP_Job $job, $delay = 0, $force_now = false)
173
  {
174
  wp_queue($job, $delay);
175
+
176
+ // force now is used during the sync.
177
+ if ($force_now === true || mailchimp_should_init_rest_queue()) {
178
+ mailchimp_call_rest_api_queue_manually();
179
  }
180
  }
181
 
182
  /**
183
+ * @param bool $job_check
184
  * @return bool
185
  */
186
+ function mailchimp_should_init_rest_queue($job_check = false) {
187
+ if (mailchimp_running_in_console()) return false;
188
+ if (mailchimp_queue_is_disabled()) return false;
189
+ if (!mailchimp_is_configured()) return false;
190
+ if (mailchimp_http_worker_is_running()) return false;
191
+ return !$job_check ? true : MailChimp_WooCommerce_Queue::instance()->available_jobs() > 0;
 
192
  }
193
 
194
  /**
229
  return delete_site_transient( 'http_worker_lock' );
230
  }
231
 
 
 
 
 
 
 
 
 
 
 
232
  /**
233
  * @param bool $force
234
  * @return bool
620
  // handle the coupon sync if we don't have a flag that says otherwise.
621
  $job = new MailChimp_WooCommerce_Process_Coupons();
622
  if ($job->getData('sync.coupons.completed_at', false) === false) {
623
+ mailchimp_handle_or_queue($job);
624
  }
625
  return mailchimpi_refresh_connected_site_script($store);
626
  }
791
  }
792
 
793
  /**
 
794
  * @return array|WP_Error
795
  */
796
+ function mailchimp_call_rest_api_queue_manually() {
797
+ return MailChimp_WooCommerce_Rest_Api::work();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
798
  }
799
 
800
  /**
801
  * @return array|WP_Error
802
  */
803
+ function mailchimp_call_rest_api_test() {
804
+ return MailChimp_WooCommerce_Rest_Api::test();
 
 
 
 
 
 
 
 
 
 
 
 
 
805
  }
806
 
807
  /**
823
  }
824
 
825
  // apply a blocking call to make sure we get the response back
826
+ $response = mailchimp_call_rest_api_test();
827
 
828
  if (is_wp_error($response)) {
829
  // nope, we have problems
830
  mailchimp_set_data('test.can.remote_post', false);
831
  mailchimp_set_data('test.can.remote_post.error', $response->get_error_message());
832
  return $response->get_error_message();
833
+ } elseif (is_array($response) && isset($response['http_response']) && ($r = $response['http_response'])) {
834
  /** @var \WP_HTTP_Requests_Response $r */
835
+ if ((int) $r->get_status() !== 200) {
836
+ $message = 'The REST API seems to be disabled on this wordpress site. Please enable to sync data.';
837
+ mailchimp_set_data('test.can.remote_post', false);
838
+ mailchimp_set_data('test.can.remote_post.error', $message);
839
+ return $message;
840
  }
841
  }
842
+
843
  // yep all good.
844
  mailchimp_set_data('test.can.remote_post', true);
845
  mailchimp_set_data('test.can.remote_post.error', false);
944
  );
945
  }
946
 
947
+ function mailchimp_check_if_on_sync_tab() {
948
+ if ((isset($_GET['page']) && $_GET['page'] === 'mailchimp-woocommerce')) {
949
+ $options = get_option('mailchimp-woocommerce', array());
950
+ if (isset($_GET['tab'])) {
951
+ if ($_GET['tab'] === 'sync') {
952
+ return true;
953
+ }
954
+ return false;
955
+ }
956
+ else if (isset($options['active_tab']) && $options['active_tab'] === 'sync') {
957
+ return true;
958
+ }
959
+ }
960
+ return false;
961
+ }
962
+
963
  function mailchimp_flush_queue_tables() {
964
  try {
965
  /** @var \ */
999
  delete_option('mailchimp-woocommerce-errors.store_info');
1000
  }
1001
 
1002
+ /**
1003
+ * @param array $data
1004
+ * @param int $status
1005
+ * @return WP_REST_Response
1006
+ */
1007
+ function mailchimp_rest_response($data, $status = 200) {
1008
+ if (!is_array($data)) $data = array();
1009
+ $response = new WP_REST_Response($data);
1010
+ $response->set_status($status);
1011
+ return $response;
1012
+ }
1013
+
1014
+ /**
1015
+ * @return bool
1016
+ */
1017
+ function mailchimp_has_started_syncing() {
1018
+ $sync_started_at = get_option('mailchimp-woocommerce-sync.started_at');
1019
+ return !empty($sync_started_at);
1020
+ }
1021
+
1022
+ /**
1023
+ * @return bool
1024
+ */
1025
+ function mailchimp_is_done_syncing() {
1026
+ $sync_completed_at = get_option('mailchimp-woocommerce-sync.completed_at');
1027
+ return !empty($sync_completed_at);
1028
+ }
1029
+
1030
  function run_mailchimp_woocommerce() {
1031
  $env = mailchimp_environment_variables();
1032
  $plugin = new MailChimp_WooCommerce($env->environment, $env->version);
includes/api/assets/class-mailchimp-order.php CHANGED
@@ -426,6 +426,17 @@ class MailChimp_WooCommerce_Order
426
  return $this->updated_at_foreign;
427
  }
428
 
 
 
 
 
 
 
 
 
 
 
 
429
  /**
430
  * @param $bool
431
  * @param $bool
426
  return $this->updated_at_foreign;
427
  }
428
 
429
+ /**
430
+ * @return Array lines_ids
431
+ */
432
+ public function getLinesIds()
433
+ {
434
+ foreach ($this->lines as $line) {
435
+ $lines_ids[] = $line->getId();
436
+ }
437
+ return $lines_ids;
438
+ }
439
+
440
  /**
441
  * @param $bool
442
  * @param $bool
includes/api/class-mailchimp-api.php CHANGED
@@ -877,13 +877,22 @@ class MailChimp_WooCommerce_MailChimpApi
877
  if (!$this->validateStoreSubmission($order)) {
878
  return false;
879
  }
880
- $id = $order->getId();
881
- $data = $this->patch("ecommerce/stores/{$store_id}/orders/{$id}", $order->toArray());
 
 
 
 
 
 
 
 
 
882
 
883
  // if the order is in pending status, we need to submit the order again with a paid status.
884
  if ($order->shouldConfirmAndPay() && $order->getFinancialStatus() !== 'paid') {
885
  $order->setFinancialStatus('paid');
886
- $data = $this->patch("ecommerce/stores/{$store_id}/orders/{$id}", $order->toArray());
887
  }
888
 
889
  $order = new MailChimp_WooCommerce_Order();
@@ -928,6 +937,23 @@ class MailChimp_WooCommerce_MailChimpApi
928
  }
929
  }
930
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
931
  /**
932
  * @param $store_id
933
  * @param $product_id
877
  if (!$this->validateStoreSubmission($order)) {
878
  return false;
879
  }
880
+ $order_id = $order->getId();
881
+ $data = $this->patch("ecommerce/stores/{$store_id}/orders/{$order_id}", $order->toArray());
882
+
883
+ // if products list differs, we should remove the old products and add new ones
884
+ $data_lines = $data['lines'];
885
+ $order_lines = $order->getLinesIds();
886
+ foreach ($data_lines as $line) {
887
+ if (!in_array($line['id'], $order_lines)) {
888
+ $this->deleteStoreOrderLine($store_id, $order_id, $line['id']);
889
+ }
890
+ }
891
 
892
  // if the order is in pending status, we need to submit the order again with a paid status.
893
  if ($order->shouldConfirmAndPay() && $order->getFinancialStatus() !== 'paid') {
894
  $order->setFinancialStatus('paid');
895
+ $data = $this->patch("ecommerce/stores/{$store_id}/orders/{$order_id}", $order->toArray());
896
  }
897
 
898
  $order = new MailChimp_WooCommerce_Order();
937
  }
938
  }
939
 
940
+ /**
941
+ * @param $store_id
942
+ * @param $order_id
943
+ * @param $line_id
944
+ * @return bool
945
+ * @throws Exception
946
+ */
947
+ public function deleteStoreOrderLine($store_id, $order_id, $line_id)
948
+ {
949
+ try {
950
+ $this->delete("ecommerce/stores/{$store_id}/orders/{$order_id}/lines/{$line_id}");
951
+ return true;
952
+ } catch (MailChimp_WooCommerce_Error $e) {
953
+ return false;
954
+ }
955
+ }
956
+
957
  /**
958
  * @param $store_id
959
  * @param $product_id
includes/api/class-mailchimp-woocommerce-transform-orders-wc3.php CHANGED
@@ -111,7 +111,7 @@ class MailChimp_WooCommerce_Transform_Orders
111
  }
112
 
113
  // set the total
114
- $order->setOrderTotal($woo->get_total());
115
 
116
  // set the order URL if it's valid.
117
  if (($view_order_url = $woo->get_view_order_url()) && wc_is_valid_url($view_order_url)) {
111
  }
112
 
113
  // set the total
114
+ $order->setOrderTotal($order_total = $woo->get_total());
115
 
116
  // set the order URL if it's valid.
117
  if (($view_order_url = $woo->get_view_order_url()) && wc_is_valid_url($view_order_url)) {
includes/class-mailchimp-woocommerce-deactivation-survey.php ADDED
@@ -0,0 +1,398 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ if ( ! class_exists( 'Mailchimp_Woocommerce_Deactivation_Survey', false ) ) {
3
+ /**
4
+ * Awesome Motive Deactivation Survey.
5
+ *
6
+ * This prompts the user for more details when they deactivate the plugin.
7
+ *
8
+ * @version 1.2.1
9
+ * @package AwesomeMotive
10
+ * @author Jared Atchison and Chris Christoff (modified by Pedro Germani)
11
+ * @license GPL-2.0+
12
+ * @copyright Copyright (c) 2018
13
+ */
14
+ class Mailchimp_Woocommerce_Deactivation_Survey {
15
+
16
+ /**
17
+ * The API URL we are calling.
18
+ *
19
+ * @since 1.0.0
20
+ * @var string
21
+ */
22
+ public $endpoint;
23
+
24
+ /**
25
+ * Name for this plugin.
26
+ *
27
+ * @since 1.0.0
28
+ * @var string
29
+ */
30
+ public $name;
31
+
32
+ /**
33
+ * Unique slug for this plugin.
34
+ *
35
+ * @since 1.0.0
36
+ * @var string
37
+ */
38
+ public $plugin;
39
+
40
+ /**
41
+ * Primary class constructor.
42
+ *
43
+ * @since 1.0.0
44
+ * @param string $name Plugin name.
45
+ * @param string $plugin Plugin slug.
46
+ */
47
+ public function __construct( $name = '', $plugin = '' ) {
48
+
49
+ $this->name = $name;
50
+ $this->plugin = $plugin;
51
+ $this->endpoint = get_rest_url(null, 'mailchimp-for-woocommerce/v1/survey/disconnect');
52
+
53
+ // Don't run deactivation survey on dev sites.
54
+ if ( $this->is_dev_url() ) {
55
+ return;
56
+ }
57
+
58
+ add_action( 'admin_print_scripts', array( $this, 'js' ), 20 );
59
+ add_action( 'admin_print_scripts', array( $this, 'css' ) );
60
+ add_action( 'admin_footer', array( $this, 'modal' ) );
61
+ }
62
+
63
+ /**
64
+ * Checks if current site is a development one.
65
+ *
66
+ * @since 1.2.0
67
+ * @return bool
68
+ */
69
+ public function is_dev_url() {
70
+ // If it is an AM dev site, return false, so we can see them on our dev sites.
71
+ if ( defined ('AWESOMEMOTIVE_DEV_MODE' ) && AWESOMEMOTIVE_DEV_MODE ) {
72
+ return false;
73
+ }
74
+
75
+ $url = network_site_url( '/' );
76
+ $is_local_url = false;
77
+
78
+ // Trim it up
79
+ $url = strtolower( trim( $url ) );
80
+
81
+ // Need to get the host...so let's add the scheme so we can use parse_url
82
+ if ( false === strpos( $url, 'http://' ) && false === strpos( $url, 'https://' ) ) {
83
+ $url = 'http://' . $url;
84
+ }
85
+ $url_parts = parse_url( $url );
86
+ $host = ! empty( $url_parts['host'] ) ? $url_parts['host'] : false;
87
+ if ( ! empty( $url ) && ! empty( $host ) ) {
88
+ if ( false !== ip2long( $host ) ) {
89
+ if ( ! filter_var( $host, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE ) ) {
90
+ $is_local_url = true;
91
+ }
92
+ } else if ( 'localhost' === $host ) {
93
+ $is_local_url = true;
94
+ }
95
+
96
+ $tlds_to_check = array( '.dev', '.local', ':8888' );
97
+ foreach ( $tlds_to_check as $tld ) {
98
+ if ( false !== strpos( $host, $tld ) ) {
99
+ $is_local_url = true;
100
+ continue;
101
+ }
102
+
103
+ }
104
+ if ( substr_count( $host, '.' ) > 1 ) {
105
+ $subdomains_to_check = array( 'dev.', '*.staging.', 'beta.', 'test.' );
106
+ foreach ( $subdomains_to_check as $subdomain ) {
107
+ $subdomain = str_replace( '.', '(.)', $subdomain );
108
+ $subdomain = str_replace( array( '*', '(.)' ), '(.*)', $subdomain );
109
+ if ( preg_match( '/^(' . $subdomain . ')/', $host ) ) {
110
+ $is_local_url = true;
111
+ continue;
112
+ }
113
+ }
114
+ }
115
+ }
116
+ return $is_local_url;
117
+ }
118
+
119
+ /**
120
+ * Checks if current admin screen is the plugins page.
121
+ *
122
+ * @since 1.0.0
123
+ * @return bool
124
+ */
125
+ public function is_plugin_page() {
126
+ $screen = function_exists( 'get_current_screen' ) ? get_current_screen() : false;
127
+ if ( empty( $screen ) ) {
128
+ return false;
129
+ }
130
+ return ( ! empty( $screen->id ) && in_array( $screen->id, array( 'plugins', 'plugins-network' ), true ) );
131
+ }
132
+
133
+ /**
134
+ * Survey javascript.
135
+ *
136
+ * @since 1.0.0
137
+ */
138
+ public function js() {
139
+
140
+ if ( ! $this->is_plugin_page() ) {
141
+ return;
142
+ }
143
+ ?>
144
+ <script type="text/javascript">
145
+ jQuery(function($){
146
+ var $deactivateLink = $('#the-list').find('[data-slug="<?php echo $this->plugin; ?>"] span.deactivate a'),
147
+ $overlay = $('#mailchimp-woocommerce-deactivate-survey-<?php echo $this->plugin; ?>'),
148
+ $form = $overlay.find('form'),
149
+ formOpen = false;
150
+ // Plugin listing table deactivate link.
151
+ $deactivateLink.on('click', function(event) {
152
+ event.preventDefault();
153
+ $overlay.css('display', 'table');
154
+ formOpen = true;
155
+ $form.find('.mailchimp-woocommerce-deactivate-survey-option:first-of-type input[type=radio]').focus();
156
+ });
157
+ // Survey radio option selected.
158
+ $form.on('change', 'input[type=radio]', function(event) {
159
+ event.preventDefault();
160
+ $form.find('input[type=text], .error').hide();
161
+ $form.find('.mailchimp-woocommerce-deactivate-survey-option').removeClass('selected');
162
+ $(this).closest('.mailchimp-woocommerce-deactivate-survey-option').addClass('selected').find('input[type=text]').show();
163
+ });
164
+ // Survey Skip & Deactivate.
165
+ $form.on('click', '.mailchimp-woocommerce-deactivate-survey-deactivate', function(event) {
166
+ event.preventDefault();
167
+ location.href = $deactivateLink.attr('href');
168
+ });
169
+ // close button
170
+ $form.on('click', '.mailchimp-woocommerce-deactivate-survey-close', function(event) {
171
+ event.preventDefault();
172
+ $overlay.css('display', 'none');
173
+ formOpen = false;
174
+ });
175
+ // Survey submit.
176
+ $form.submit(function(event) {
177
+ event.preventDefault();
178
+ if (! $form.find('input[type=radio]:checked').val()) {
179
+ $form.find('.mailchimp-woocommerce-deactivate-survey-footer').prepend('<span class="error"><?php echo esc_js( __( 'Please select an option', 'mailchimp-woocommerce' ) ); ?></span>');
180
+ return;
181
+ }
182
+
183
+ $form.find('.mailchimp-woocommerce-deactivate-survey-submit').html("Sending feedback...").attr("disabled", true).removeClass('button-primary');
184
+
185
+ var submitSurvey = $.ajax(
186
+ {
187
+ url: "<?php echo $this->endpoint; ?>",
188
+ type: "POST",
189
+ data: {
190
+ id: '<?php echo mailchimp_get_store_id()?>',
191
+ url: '<?php echo esc_url( home_url() ); ?>',
192
+ data: {
193
+ code: $form.find('.selected input[type=radio]').val(),
194
+ reason: $form.find('.selected .mailchimp-woocommerce-deactivate-survey-option-reason').text(),
195
+ details: $form.find('.selected input[type=text]').val(),
196
+ plugin: '<?php echo sanitize_key( $this->name ); ?>'
197
+ }
198
+ },
199
+ dataType: 'json',
200
+ async: false,
201
+ success: function(msg) {
202
+ location.href = $deactivateLink.attr('href');
203
+ }
204
+ }
205
+ )
206
+ });
207
+ // Exit key closes survey when open.
208
+ $(document).keyup(function(event) {
209
+ if (27 === event.keyCode && formOpen) {
210
+ $overlay.hide();
211
+ formOpen = false;
212
+ $deactivateLink.focus();
213
+ }
214
+ });
215
+ });
216
+ </script>
217
+ <?php
218
+ }
219
+
220
+ /**
221
+ * Survey CSS.
222
+ *
223
+ * @since 1.0.0
224
+ */
225
+ public function css() {
226
+
227
+ if ( ! $this->is_plugin_page() ) {
228
+ return;
229
+ }
230
+ ?>
231
+ <style type="text/css">
232
+ .mailchimp-woocommerce-deactivate-survey-modal {
233
+ display: none;
234
+ table-layout: fixed;
235
+ position: fixed;
236
+ z-index: 9999;
237
+ width: 100%;
238
+ height: 100%;
239
+ text-align: center;
240
+ font-size: 14px;
241
+ top: 0;
242
+ left: 0;
243
+ background: rgba(0,0,0,0.8);
244
+ }
245
+ .mailchimp-woocommerce-deactivate-survey-wrap {
246
+ display: table-cell;
247
+ vertical-align: middle;
248
+ }
249
+ .mailchimp-woocommerce-deactivate-survey {
250
+ background-color: #fff;
251
+ max-width: 550px;
252
+ margin: 0 auto;
253
+ padding: 30px;
254
+ text-align: left;
255
+ }
256
+ .mailchimp-woocommerce-deactivate-survey .error {
257
+ display: block;
258
+ color: red;
259
+ margin: 0 0 10px 0;
260
+ }
261
+ .mailchimp-woocommerce-deactivate-survey-header {
262
+ display: block;
263
+ font-size: 18px;
264
+ font-weight: 700;
265
+ text-transform: uppercase;
266
+ border-bottom: 1px solid #ddd;
267
+ padding: 0 0 18px 0;
268
+ margin: 0 0 18px 0;
269
+ position: relative;
270
+ }
271
+ .mailchimp-woocommerce-deactivate-survey-title {
272
+ text-align: left;
273
+ }
274
+ .mailchimp-woocommerce-deactivate-survey-close {
275
+ text-align: right;
276
+ position: absolute;
277
+ right: 0px;
278
+ font-size: 24px;
279
+ cursor: pointer;
280
+ }
281
+ .mailchimp-woocommerce-deactivate-survey-title span {
282
+ color: #999;
283
+ margin-right: 10px;
284
+ }
285
+ .mailchimp-woocommerce-deactivate-survey-desc {
286
+ display: block;
287
+ font-weight: 600;
288
+ margin: 0 0 18px 0;
289
+ }
290
+ .mailchimp-woocommerce-deactivate-survey-option {
291
+ margin: 0 0 10px 0;
292
+ }
293
+ .mailchimp-woocommerce-deactivate-survey-option-input {
294
+ margin-right: 10px !important;
295
+ }
296
+ .mailchimp-woocommerce-deactivate-survey-option-details {
297
+ display: none;
298
+ width: 90%;
299
+ margin: 10px 0 0 30px;
300
+ }
301
+ .mailchimp-woocommerce-deactivate-survey-footer {
302
+ margin-top: 18px;
303
+ }
304
+ .mailchimp-woocommerce-deactivate-survey-deactivate {
305
+ float: right;
306
+ font-size: 13px;
307
+ color: #ccc;
308
+ text-decoration: none;
309
+ padding-top: 7px;
310
+ }
311
+ </style>
312
+ <?php
313
+ }
314
+
315
+ /**
316
+ * Survey modal.
317
+ *
318
+ * @since 1.0.0
319
+ */
320
+ public function modal() {
321
+
322
+ if ( ! $this->is_plugin_page() ) {
323
+ return;
324
+ }
325
+
326
+ $options = array(
327
+ 1 => array(
328
+ 'title' => esc_html__( 'I want to change the list associated with this integration.', 'mailchimp-woocommerce' ),
329
+ ),
330
+ 2 => array(
331
+ 'title' => esc_html__( 'I want to change the site or store connected through this integration.', 'mailchimp-woocommerce' ),
332
+ ),
333
+ 3 => array(
334
+ 'title' => esc_html__( 'The order data isn\'t syncing.', 'mailchimp-woocommerce' ),
335
+ ),
336
+ 4 => array(
337
+ 'title' => esc_html__( 'The promo codes aren\'t showing up.', 'mailchimp-woocommerce' ),
338
+ ),
339
+ 5 => array(
340
+ 'title' => esc_html__( 'I\'m trying to troubleshoot the integration.', 'mailchimp-woocommerce' ),
341
+ ),
342
+ 6 => array(
343
+ 'title' => esc_html__( 'I was instructed to disconnect by Mailchimp Support.', 'mailchimp-woocommerce' ),
344
+ ),
345
+ 7 => array(
346
+ 'title' => esc_html__( 'I no longer use this integration.', 'mailchimp-woocommerce' ),
347
+ ),
348
+ 8 => array(
349
+ 'title' => esc_html__( 'It\'s a temporary deactivation.', 'mailchimp-woocommerce' ),
350
+ ),
351
+ 9 => array(
352
+ 'title' => esc_html__( 'Other', 'mailchimp-woocommerce' ),
353
+ 'details' => esc_html__( 'Please share the reason', 'mailchimp-woocommerce' ),
354
+ ),
355
+ );
356
+ ?>
357
+ <div class="mailchimp-woocommerce-deactivate-survey-modal" id="mailchimp-woocommerce-deactivate-survey-<?php echo $this->plugin; ?>">
358
+ <div class="mailchimp-woocommerce-deactivate-survey-wrap">
359
+ <form class="mailchimp-woocommerce-deactivate-survey" method="post">
360
+ <span class="mailchimp-woocommerce-deactivate-survey-header">
361
+ <span class="dashicons dashicons-testimonial"></span>
362
+ <?php echo ' ' . esc_html__( 'Quick Feedback', 'mailchimp-woocommerce' ); ?>
363
+ <span title="<?php _e( 'Close', 'mailchimp-woocommerce' );?> " class="mailchimp-woocommerce-deactivate-survey-close">✕</span>
364
+ </span>
365
+
366
+ <span class="mailchimp-woocommerce-deactivate-survey-desc">
367
+ <?php
368
+ printf(
369
+ /* translators: %s - plugin name. */
370
+ esc_html__( 'If you have a moment, please share why you are deactivating %s:', 'mailchimp-woocommerce' ),
371
+ 'Mailchimp for Woocommerce'
372
+ );
373
+ ?>
374
+ </span>
375
+ <div class="mailchimp-woocommerce-deactivate-survey-options">
376
+ <?php foreach ( $options as $id => $option ) : ?>
377
+ <div class="mailchimp-woocommerce-deactivate-survey-option">
378
+ <label for="mailchimp-woocommerce-deactivate-survey-option-<?php echo $this->plugin; ?>-<?php echo $id; ?>" class="mailchimp-woocommerce-deactivate-survey-option-label">
379
+ <input id="mailchimp-woocommerce-deactivate-survey-option-<?php echo $this->plugin; ?>-<?php echo $id; ?>" class="mailchimp-woocommerce-deactivate-survey-option-input" type="radio" name="code" value="<?php echo $id; ?>" />
380
+ <span class="mailchimp-woocommerce-deactivate-survey-option-reason"><?php echo $option['title']; ?></span>
381
+ </label>
382
+ <?php if ( ! empty( $option['details'] ) ) : ?>
383
+ <input class="mailchimp-woocommerce-deactivate-survey-option-details" type="text" placeholder="<?php echo $option['details']; ?>" />
384
+ <?php endif; ?>
385
+ </div>
386
+ <?php endforeach; ?>
387
+ </div>
388
+ <div class="mailchimp-woocommerce-deactivate-survey-footer">
389
+ <button type="submit" class="mailchimp-woocommerce-deactivate-survey-submit button button-primary button-large"><?php echo esc_html__( 'Submit & Deactivate', 'mailchimp-woocommerce' ); ?></button>
390
+ <a href="#" class="mailchimp-woocommerce-deactivate-survey-deactivate"><?php echo esc_html__( 'Skip & Deactivate', 'mailchimp-woocommerce' ); ?></a>
391
+ </div>
392
+ </form>
393
+ </div>
394
+ </div>
395
+ <?php
396
+ }
397
+ }
398
+ } // End if().
includes/class-mailchimp-woocommerce-newsletter.php CHANGED
@@ -10,6 +10,23 @@
10
  */
11
  class MailChimp_Newsletter extends MailChimp_WooCommerce_Options
12
  {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
13
  /**
14
  * @param WC_Checkout $checkout
15
  */
10
  */
11
  class MailChimp_Newsletter extends MailChimp_WooCommerce_Options
12
  {
13
+ /** @var null|static */
14
+ protected static $_instance = null;
15
+
16
+ /**
17
+ * @return MailChimp_Newsletter
18
+ */
19
+ public static function instance()
20
+ {
21
+ if (!empty(static::$_instance)) {
22
+ return static::$_instance;
23
+ }
24
+ $env = mailchimp_environment_variables();
25
+ static::$_instance = new MailChimp_Newsletter();
26
+ static::$_instance->setVersion($env->version);
27
+ return static::$_instance;
28
+ }
29
+
30
  /**
31
  * @param WC_Checkout $checkout
32
  */
includes/class-mailchimp-woocommerce-options.php CHANGED
@@ -35,7 +35,7 @@ abstract class MailChimp_WooCommerce_Options
35
  }
36
 
37
  if (!isset($_GET['activate-multi'])) {
38
- wp_redirect("options-general.php?page=mailchimp-woocommerce");
39
  }
40
  }
41
  }
@@ -50,10 +50,13 @@ abstract class MailChimp_WooCommerce_Options
50
 
51
  /**
52
  * @param $version
 
53
  */
54
  public function setVersion($version)
55
  {
56
  $this->version = $version;
 
 
57
  }
58
 
59
  /**
@@ -295,10 +298,7 @@ abstract class MailChimp_WooCommerce_Options
295
 
296
  public function removeSyncPointers()
297
  {
298
- delete_option('mailchimp-woocommerce-sync.orders.prevent');
299
- delete_option('mailchimp-woocommerce-sync.syncing');
300
- delete_option('mailchimp-woocommerce-sync.started_at');
301
- delete_option('mailchimp-woocommerce-sync.completed_at');
302
  }
303
 
304
  public function removeMiscPointers()
35
  }
36
 
37
  if (!isset($_GET['activate-multi'])) {
38
+ wp_redirect("admin.php?page=mailchimp-woocommerce");
39
  }
40
  }
41
  }
50
 
51
  /**
52
  * @param $version
53
+ * @return $this
54
  */
55
  public function setVersion($version)
56
  {
57
  $this->version = $version;
58
+
59
+ return $this;
60
  }
61
 
62
  /**
298
 
299
  public function removeSyncPointers()
300
  {
301
+ mailchimp_flush_sync_pointers();
 
 
 
302
  }
303
 
304
  public function removeMiscPointers()
includes/class-mailchimp-woocommerce-queue.php ADDED
@@ -0,0 +1,226 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class MailChimp_WooCommerce_Queue
4
+ {
5
+ /**
6
+ * @var string
7
+ */
8
+ public $table;
9
+
10
+ /**
11
+ * @var string
12
+ */
13
+ public $failed_table;
14
+
15
+ /**
16
+ * @var int
17
+ */
18
+ public $release_time = 60;
19
+
20
+ public $max_tries = 3;
21
+
22
+ protected static $_instance = null;
23
+
24
+ /**
25
+ * @return MailChimp_WooCommerce_Queue
26
+ */
27
+ public static function instance()
28
+ {
29
+ if (!empty(static::$_instance)) return static::$_instance;
30
+ return static::$_instance = new MailChimp_WooCommerce_Queue();
31
+ }
32
+
33
+ /**
34
+ * WP_Queue constructor
35
+ */
36
+ public function __construct() {
37
+ global $wpdb;
38
+ $this->table = $wpdb->prefix . 'queue';
39
+ $this->failed_table = $wpdb->prefix . 'failed_jobs';
40
+ }
41
+
42
+ /**
43
+ * Push a job onto the queue.
44
+ *
45
+ * @param WP_Job $job
46
+ * @param int $delay
47
+ *
48
+ * @return $this
49
+ */
50
+ public function push(WP_Job $job, $delay = 0)
51
+ {
52
+ global $wpdb;
53
+
54
+ $data = array(
55
+ 'job' => maybe_serialize($job),
56
+ 'available_at' => $this->datetime($delay),
57
+ 'created_at' => $this->datetime(),
58
+ );
59
+
60
+ if (!$wpdb->insert($this->table, $data) && $this->create_tables_if_required()) {
61
+ if (!$wpdb->insert($this->table, $data)) {
62
+ mailchimp_debug('Queue Job '.get_class($job), $wpdb->last_error);
63
+ }
64
+ }
65
+
66
+ return $this;
67
+ }
68
+
69
+ /**
70
+ * Release.
71
+ *
72
+ * @param object $job
73
+ * @param int $delay
74
+ */
75
+ public function release( $job, $delay = 0 )
76
+ {
77
+ if ($job->attempts >= $this->max_tries) {
78
+ return $this->failed($job);
79
+ }
80
+
81
+ global $wpdb;
82
+
83
+ $wpdb->update($this->table, array(
84
+ 'attempts' => $job->attempts + 1,
85
+ 'locked' => 0,
86
+ 'locked_at' => null,
87
+ 'available_at' => $this->datetime( $delay ),
88
+ ), array('id' => $job->id));
89
+ }
90
+
91
+ /**
92
+ * Failed
93
+ *
94
+ * @param stdClass $job
95
+ */
96
+ protected function failed($job)
97
+ {
98
+ global $wpdb;
99
+
100
+ $wpdb->insert($this->failed_table, array(
101
+ 'job' => $job->job,
102
+ 'failed_at' => $this->datetime(),
103
+ ));
104
+
105
+ $payload = unserialize($job->job);
106
+
107
+ if (method_exists($payload, 'failed')) {
108
+ $payload->failed();
109
+ }
110
+
111
+ $this->delete($job);
112
+ }
113
+
114
+ /**
115
+ * Delete.
116
+ *
117
+ * @param object $job
118
+ */
119
+ public function delete( $job )
120
+ {
121
+ global $wpdb;
122
+ $wpdb->delete($this->table, array('id' => $job->id));
123
+ }
124
+
125
+ /**
126
+ * Get MySQL datetime.
127
+ *
128
+ * @param int $offset Seconds, can pass negative int.
129
+ *
130
+ * @return string
131
+ */
132
+ protected function datetime($offset = 0)
133
+ {
134
+ return gmdate( 'Y-m-d H:i:s', time() + $offset);
135
+ }
136
+
137
+ /**
138
+ * Available jobs.
139
+ */
140
+ public function available_jobs()
141
+ {
142
+ global $wpdb;
143
+ $now = $this->datetime();
144
+ $sql = $wpdb->prepare("SELECT COUNT(*) FROM {$this->table} WHERE available_at <= %s", $now);
145
+ return $wpdb->get_var($sql);
146
+ }
147
+
148
+ /**
149
+ * Available jobs.
150
+ */
151
+ public function failed_jobs()
152
+ {
153
+ global $wpdb;
154
+ return $wpdb->get_var("SELECT COUNT(*) FROM {$this->failed_table}");
155
+ }
156
+
157
+ /**
158
+ * Restart failed jobs.
159
+ */
160
+ public function restart_failed_jobs()
161
+ {
162
+ global $wpdb;
163
+ $count = 0;
164
+ $jobs = $wpdb->get_results("SELECT * FROM {$this->failed_table}");
165
+
166
+ foreach ($jobs as $job) {
167
+ $this->push(maybe_unserialize($job->job));
168
+ $wpdb->delete($this->failed_table, array('id' => $job->id));
169
+ $count++;
170
+ }
171
+
172
+ return $count;
173
+ }
174
+
175
+ /**
176
+ * Get next job.
177
+ */
178
+ public function get_next_job()
179
+ {
180
+ global $wpdb;
181
+ $this->maybe_release_locked_jobs();
182
+ $now = $this->datetime();
183
+ $sql = $wpdb->prepare("SELECT * FROM {$this->table} WHERE locked = 0 AND available_at <= %s", $now);
184
+ return $wpdb->get_row($sql);
185
+ }
186
+
187
+ /**
188
+ * Maybe release locked jobs.
189
+ */
190
+ protected function maybe_release_locked_jobs()
191
+ {
192
+ global $wpdb;
193
+ $expired = $this->datetime(-$this->release_time);
194
+ $sql = $wpdb->prepare("UPDATE {$this->table} SET attempts = attempts + 1, locked = 0, locked_at = NULL WHERE locked = 1 AND locked_at <= %s", $expired);
195
+ $wpdb->query($sql);
196
+ }
197
+
198
+ /**
199
+ * Lock job.
200
+ *
201
+ * @param object $job
202
+ */
203
+ public function lock_job( $job )
204
+ {
205
+ global $wpdb;
206
+ $wpdb->update( $this->table, array('locked' => 1, 'locked_at' => $this->datetime()), array('id' => $job->id));
207
+ }
208
+
209
+ /**
210
+ * @return bool
211
+ */
212
+ public function create_tables_if_required()
213
+ {
214
+ global $wpdb;
215
+ try {
216
+ if (mailchimp_string_contains($wpdb->last_error, 'Table')) {
217
+ mailchimp_debug('Queue Table Was Not Found!', 'Creating Tables');
218
+ MailChimp_WooCommerce_Activator::create_queue_tables();
219
+ return true;
220
+ }
221
+ } catch (\Exception $e) {
222
+ mailchimp_error_trace($e, 'trying to create queue tables');
223
+ }
224
+ return false;
225
+ }
226
+ }
includes/class-mailchimp-woocommerce-rest-api.php ADDED
@@ -0,0 +1,296 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class MailChimp_WooCommerce_Rest_Api
4
+ {
5
+ protected static $namespace = 'mailchimp-for-woocommerce/v1';
6
+ protected $http_worker_listen = false;
7
+
8
+ /**
9
+ * @param $path
10
+ * @return string
11
+ */
12
+ public static function url($path)
13
+ {
14
+ return esc_url_raw(rest_url(static::$namespace.'/'.ltrim($path, '/')));
15
+ }
16
+
17
+ /**
18
+ * @return mixed
19
+ */
20
+ public static function test()
21
+ {
22
+ return wp_remote_get(static::url('ping'), array(
23
+ 'timeout' => 5,
24
+ 'blocking' => true,
25
+ 'cookies' => $_COOKIE,
26
+ 'sslverify' => apply_filters('https_local_ssl_verify', false)
27
+ ));
28
+ }
29
+
30
+ /**
31
+ * Call the "work" command manually to initiate the queue.
32
+ *
33
+ * @param bool $force
34
+ * @return mixed
35
+ */
36
+ public static function work($force = false)
37
+ {
38
+ $path = $force ? 'queue/work/force' : 'queue/work';
39
+ // this is the new rest API version
40
+ return wp_remote_get(static::url($path), array(
41
+ 'timeout' => 0.01,
42
+ 'blocking' => false,
43
+ 'cookies' => $_COOKIE,
44
+ 'sslverify' => apply_filters('https_local_ssl_verify', false)
45
+ ));
46
+ }
47
+
48
+ /**
49
+ * Register all Mailchimp API routes.
50
+ */
51
+ public function register_routes()
52
+ {
53
+ $this->register_ping();
54
+ $this->register_routes_for_queue();
55
+ $this->register_survey_routes();
56
+ $this->register_sync_stats();
57
+ }
58
+
59
+ /**
60
+ * Ping
61
+ */
62
+ protected function register_ping()
63
+ {
64
+ register_rest_route(static::$namespace, '/ping', array(
65
+ 'methods' => 'GET',
66
+ 'callback' => array($this, 'ping'),
67
+ ));
68
+ }
69
+
70
+ /**
71
+ * Right now we only have a survey disconnect endpoint.
72
+ */
73
+ protected function register_survey_routes()
74
+ {
75
+ register_rest_route(static::$namespace, "/survey/disconnect", array(
76
+ 'methods' => 'POST',
77
+ 'callback' => array($this, 'post_disconnect_survey'),
78
+ ));
79
+ }
80
+
81
+ /**
82
+ * These are the routes for the queue and testing the functionality of the REST API during setup.
83
+ */
84
+ protected function register_routes_for_queue()
85
+ {
86
+ register_rest_route(static::$namespace, "/queue/work", array(
87
+ 'methods' => 'GET',
88
+ 'callback' => array($this, 'queue_work'),
89
+ ));
90
+
91
+ register_rest_route(static::$namespace, "/queue/work/force", array(
92
+ 'methods' => 'GET',
93
+ 'callback' => array($this, 'queue_work_force'),
94
+ ));
95
+
96
+ register_rest_route(static::$namespace, "/queue/stats", array(
97
+ 'methods' => 'GET',
98
+ 'callback' => array($this, 'queue_stats'),
99
+ ));
100
+
101
+ // if we have available jobs, it will handle async
102
+ if ($this->maybe_fire_manually()) {
103
+ static::work();
104
+ }
105
+ }
106
+
107
+ /**
108
+ * @param WP_REST_Request $request
109
+ * @return WP_Error|WP_REST_Response
110
+ */
111
+ public function ping(WP_REST_Request $request)
112
+ {
113
+ return mailchimp_rest_response(array('success' => true));
114
+ }
115
+
116
+ /**
117
+ * Ping
118
+ */
119
+ protected function register_sync_stats()
120
+ {
121
+ if (current_user_can('editor') || current_user_can('administrator')) {
122
+ register_rest_route(static::$namespace, '/sync/stats', array(
123
+ 'methods' => 'GET',
124
+ 'callback' => array($this, 'get_sync_stats'),
125
+ ));
126
+ }
127
+ }
128
+
129
+ /**
130
+ * @return WP_REST_Response
131
+ */
132
+ public function queue_stats()
133
+ {
134
+ return mailchimp_rest_response(array(
135
+ 'mailchimp_is_configured' => mailchimp_is_configured(),
136
+ 'queue_type' => mailchimp_running_in_console() ? 'console' : 'rest',
137
+ 'one_at_at_time' => mailchimp_queue_is_disabled(),
138
+ 'queue_is_running' => mailchimp_http_worker_is_running(),
139
+ 'should_init_queue' => mailchimp_should_init_rest_queue(),
140
+ 'jobs_in_queue' => number_format(MailChimp_WooCommerce_Queue::instance()->available_jobs()),
141
+ ));
142
+ }
143
+
144
+ /**
145
+ * This is the new HTTP queue handler - which should only fire when the rest API route has been called.
146
+ * Replacing admin-ajax.php
147
+ *
148
+ * @param WP_REST_Request $request
149
+ * @return WP_Error|WP_REST_Response
150
+ */
151
+ public function queue_work(WP_REST_Request $request)
152
+ {
153
+ // if we're going to dispatch the manual request on this process, just return a "spawning" reason.
154
+ if ($this->http_worker_listen === true) {
155
+ return mailchimp_rest_response(array('success' => false, 'reason' => 'spawning'));
156
+ }
157
+
158
+ // if the queue is running in the console - we need to say tell the response why it's not going to fire this way.
159
+ if (mailchimp_running_in_console()) {
160
+ return mailchimp_rest_response(array('success' => false, 'reason' => 'cli enabled'));
161
+ }
162
+
163
+ // if the worker is already running - just respond with a reason of "running"
164
+ if (mailchimp_http_worker_is_running()) {
165
+ return mailchimp_rest_response(array('success' => false, 'reason' => 'running'));
166
+ }
167
+
168
+ // using the singleton - handle the jobs if we have things to do - will return a count
169
+ $jobs_processed = MailChimp_WooCommerce_Rest_Queue::instance()->handle();
170
+
171
+ // chances are this will never be returned to JS at all just because we're using a 0.01 second timeout
172
+ // but we need to do it just in case.
173
+ return mailchimp_rest_response(array('success' => true, 'processed' => $jobs_processed));
174
+ }
175
+
176
+ /**
177
+ * @param WP_REST_Request $request
178
+ * @return WP_REST_Response
179
+ */
180
+ public function queue_work_force(WP_REST_Request $request)
181
+ {
182
+ // if we're going to dispatch the manual request on this process, just return a "spawning" reason.
183
+ if ($this->http_worker_listen === true) {
184
+ return mailchimp_rest_response(array('success' => false, 'reason' => 'spawning'));
185
+ }
186
+
187
+ // if the queue is running in the console - we need to say tell the response why it's not going to fire this way.
188
+ if (mailchimp_running_in_console()) {
189
+ return mailchimp_rest_response(array('success' => false, 'reason' => 'cli enabled'));
190
+ }
191
+
192
+ // reset the lock
193
+ mailchimp_reset_http_lock();
194
+
195
+ // using the singleton - handle the jobs if we have things to do - will return a count
196
+ $jobs_processed = MailChimp_WooCommerce_Rest_Queue::instance()->handle();
197
+
198
+ // chances are this will never be returned to JS at all just because we're using a 0.01 second timeout
199
+ // but we need to do it just in case.
200
+ return mailchimp_rest_response(array('success' => true, 'processed' => $jobs_processed));
201
+ }
202
+
203
+ /**
204
+ * @param WP_REST_Request $request
205
+ * @return WP_REST_Response
206
+ */
207
+ public function post_disconnect_survey(WP_REST_Request $request)
208
+ {
209
+ // need to send a post request to
210
+ $host = mailchimp_environment_variables()->environment === 'staging' ?
211
+ 'https://staging.conduit.vextras.com' : 'https://conduit.mailchimpapp.com';
212
+
213
+ $route = "{$host}/survey/woocommerce";
214
+
215
+ $result = wp_remote_post(esc_url_raw($route), array(
216
+ 'timeout' => 12,
217
+ 'blocking' => true,
218
+ 'sslverify' => apply_filters('https_local_ssl_verify', false),
219
+ 'method' => 'POST',
220
+ 'data_format' => 'body',
221
+ 'headers' => array('Content-Type' => 'application/json; charset=utf-8'),
222
+ 'body' => json_encode($request->get_params()),
223
+ ));
224
+
225
+ return mailchimp_rest_response($result);
226
+ }
227
+
228
+ /**
229
+ * @param WP_REST_Request $request
230
+ * @return WP_REST_Response
231
+ */
232
+ public function get_sync_stats(WP_REST_Request $request)
233
+ {
234
+ // if the queue is running in the console - we need to say tell the response why it's not going to fire this way.
235
+ if (!mailchimp_is_configured() || !($api = mailchimp_get_api())) {
236
+ return mailchimp_rest_response(array('success' => false, 'reason' => 'not configured'));
237
+ }
238
+
239
+ $store_id = mailchimp_get_store_id();
240
+ $product_count = mailchimp_get_product_count();
241
+ $order_count = mailchimp_get_order_count();
242
+
243
+ try {
244
+ $products = $api->products($store_id, 1, 1);
245
+ $mailchimp_total_products = $products['total_items'];
246
+ if ($mailchimp_total_products > $product_count) $mailchimp_total_products = $product_count;
247
+ } catch (\Exception $e) { $mailchimp_total_products = 0; }
248
+ try {
249
+ $orders = $api->orders($store_id, 1, 1);
250
+ $mailchimp_total_orders = $orders['total_items'];
251
+ if ($mailchimp_total_orders > $order_count) $mailchimp_total_orders = $order_count;
252
+ } catch (\Exception $e) { $mailchimp_total_orders = 0; }
253
+
254
+ $date = mailchimp_date_local('now');
255
+
256
+ // but we need to do it just in case.
257
+ return mailchimp_rest_response(array(
258
+ 'success' => true,
259
+ 'products_in_store' => $product_count,
260
+ 'products_in_mailchimp' => $mailchimp_total_products,
261
+ 'orders_in_store' => $order_count,
262
+ 'orders_in_mailchimp' => $mailchimp_total_orders,
263
+ 'date' => $date->format('D, M j, Y g:i A'),
264
+ 'has_started' => mailchimp_has_started_syncing(),
265
+ 'has_finished' => mailchimp_is_done_syncing(),
266
+ ));
267
+ }
268
+
269
+ /**
270
+ * @return bool
271
+ */
272
+ protected function maybe_fire_manually()
273
+ {
274
+ $transient = 'http_worker_queue_listen';
275
+ $transient_expiration = 30;
276
+
277
+ // if we're not running in the console, and the http_worker is not running
278
+ if (mailchimp_should_init_rest_queue(false)) {
279
+ try {
280
+ // if we do not have a site transient for the queue listener
281
+ if (!get_site_transient($transient)) {
282
+ // set the site transient to expire in X seconds so this will not happen too many times
283
+ // but still work for cron scripts on the minute mark.
284
+ set_site_transient($transient, microtime(), $transient_expiration);
285
+
286
+ // tell the site we're firing off a worker process now.
287
+ return $this->http_worker_listen = true;
288
+ }
289
+ } catch (\Exception $e) {
290
+ mailchimp_error('maybe_fire_manually', mailchimp_error_trace($e, "maybe_fire_manually"));
291
+ }
292
+ }
293
+
294
+ return false;
295
+ }
296
+ }
includes/class-mailchimp-woocommerce-service.php CHANGED
@@ -16,6 +16,22 @@ class MailChimp_Service extends MailChimp_WooCommerce_Options
16
  protected $cart_was_submitted = false;
17
  protected $cart = array();
18
  protected $validated_cart_db = false;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
19
 
20
  /**
21
  * hook fired when we know everything is booted
@@ -109,6 +125,17 @@ class MailChimp_Service extends MailChimp_WooCommerce_Options
109
  mailchimp_handle_or_queue($handler, 90);
110
  }
111
 
 
 
 
 
 
 
 
 
 
 
 
112
  /**
113
  * @param $order_id
114
  */
16
  protected $cart_was_submitted = false;
17
  protected $cart = array();
18
  protected $validated_cart_db = false;
19
+ /** @var null|static */
20
+ protected static $_instance = null;
21
+
22
+ /**
23
+ * @return MailChimp_Service
24
+ */
25
+ public static function instance()
26
+ {
27
+ if (!empty(static::$_instance)) {
28
+ return static::$_instance;
29
+ }
30
+ $env = mailchimp_environment_variables();
31
+ static::$_instance = new MailChimp_Service();
32
+ static::$_instance->setVersion($env->version);
33
+ return static::$_instance;
34
+ }
35
 
36
  /**
37
  * hook fired when we know everything is booted
125
  mailchimp_handle_or_queue($handler, 90);
126
  }
127
 
128
+ /**
129
+ * @param $order_id
130
+ */
131
+ public function onOrderRefunded($order_id)
132
+ {
133
+ if (!mailchimp_is_configured()) return;
134
+
135
+ $handler = new MailChimp_WooCommerce_Single_Order($order_id, null, null, null);
136
+ mailchimp_handle_or_queue($handler);
137
+ }
138
+
139
  /**
140
  * @param $order_id
141
  */
includes/class-mailchimp-woocommerce.php CHANGED
@@ -118,7 +118,6 @@ class MailChimp_WooCommerce
118
  */
119
  public function __construct($environment = 'production', $version = '1.0.0')
120
  {
121
-
122
  $this->plugin_name = 'mailchimp-woocommerce';
123
  $this->version = $version;
124
  $this->environment = $environment;
@@ -176,6 +175,7 @@ class MailChimp_WooCommerce
176
  private function load_dependencies()
177
  {
178
  global $wp_queue;
 
179
  if (empty($wp_queue)) {
180
  $wp_queue = new WP_Queue();
181
  }
@@ -183,29 +183,9 @@ class MailChimp_WooCommerce
183
  // fire up the loader
184
  $this->loader = new MailChimp_WooCommerce_Loader();
185
 
186
- // only fire this up if they have configured mailchimp - and not running in the console.
187
- if ((!mailchimp_running_in_console() && mailchimp_is_configured())) {
188
- // fire up the http worker container
189
- new WP_Http_Worker($wp_queue);
190
- }
191
-
192
- // if we're not running in the console, and the http_worker is not running
193
- if (mailchimp_should_init_queue()) {
194
- try {
195
- // if we do not have a site transient for the queue listener
196
- if (!get_site_transient('http_worker_queue_listen')) {
197
- // set the site transient to expire in 50 seconds so this will not happen too many times
198
- // but still work for cron scripts on the minute mark.
199
- set_site_transient('http_worker_queue_listen', microtime(), 50);
200
- // if we have available jobs, call the http worker manually
201
- if ($wp_queue->available_jobs()) {
202
- mailchimp_call_http_worker_manually();
203
- }
204
- }
205
- } catch (\Exception $e) {
206
- mailchimp_error_trace($e, "loading dependencies");
207
- }
208
- }
209
  }
210
 
211
  /**
@@ -244,7 +224,7 @@ class MailChimp_WooCommerce
244
  */
245
  private function define_admin_hooks() {
246
 
247
- $plugin_admin = new MailChimp_WooCommerce_Admin( $this->get_plugin_name(), $this->get_version() );
248
 
249
  $this->loader->add_action('admin_enqueue_scripts', $plugin_admin, 'enqueue_styles');
250
  $this->loader->add_action('admin_enqueue_scripts', $plugin_admin, 'enqueue_scripts');
@@ -262,8 +242,10 @@ class MailChimp_WooCommerce
262
  // put the menu on the admin top bar.
263
  //$this->loader->add_action('admin_bar_menu', $plugin_admin, 'admin_bar', 100);
264
 
265
- $this->loader->add_action('plugins_loaded', $plugin_admin, 'update_db_check');
266
- }
 
 
267
 
268
  /**
269
  * Register all of the hooks related to the public-facing functionality
@@ -285,7 +267,7 @@ class MailChimp_WooCommerce
285
  */
286
  private function activateMailChimpNewsletter()
287
  {
288
- $service = new MailChimp_Newsletter();
289
 
290
  if ($this->is_configured && $service->isConfigured()) {
291
 
@@ -311,7 +293,7 @@ class MailChimp_WooCommerce
311
  */
312
  private function activateMailChimpService()
313
  {
314
- $service = new MailChimp_Service();
315
 
316
  if ($service->isConfigured()) {
317
 
118
  */
119
  public function __construct($environment = 'production', $version = '1.0.0')
120
  {
 
121
  $this->plugin_name = 'mailchimp-woocommerce';
122
  $this->version = $version;
123
  $this->environment = $environment;
175
  private function load_dependencies()
176
  {
177
  global $wp_queue;
178
+
179
  if (empty($wp_queue)) {
180
  $wp_queue = new WP_Queue();
181
  }
183
  // fire up the loader
184
  $this->loader = new MailChimp_WooCommerce_Loader();
185
 
186
+ // change up the queue to use the new rest api version
187
+ $service = new MailChimp_WooCommerce_Rest_Api();
188
+ $this->loader->add_action( 'rest_api_init', $service, 'register_routes');
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
189
  }
190
 
191
  /**
224
  */
225
  private function define_admin_hooks() {
226
 
227
+ $plugin_admin = MailChimp_WooCommerce_Admin::instance();
228
 
229
  $this->loader->add_action('admin_enqueue_scripts', $plugin_admin, 'enqueue_styles');
230
  $this->loader->add_action('admin_enqueue_scripts', $plugin_admin, 'enqueue_scripts');
242
  // put the menu on the admin top bar.
243
  //$this->loader->add_action('admin_bar_menu', $plugin_admin, 'admin_bar', 100);
244
 
245
+ $this->loader->add_action('plugins_loaded', $plugin_admin, 'update_db_check');
246
+ $this->loader->add_action('admin_init', $plugin_admin, 'setup_survey_form');
247
+ $this->loader->add_action('admin_footer', $plugin_admin, 'inject_sync_ajax_call');
248
+ }
249
 
250
  /**
251
  * Register all of the hooks related to the public-facing functionality
267
  */
268
  private function activateMailChimpNewsletter()
269
  {
270
+ $service = MailChimp_Newsletter::instance();
271
 
272
  if ($this->is_configured && $service->isConfigured()) {
273
 
293
  */
294
  private function activateMailChimpService()
295
  {
296
+ $service = MailChimp_Service::instance();
297
 
298
  if ($service->isConfigured()) {
299
 
includes/processes/class-mailchimp-woocommerce-abstract-sync.php CHANGED
@@ -471,7 +471,7 @@ abstract class MailChimp_WooCommerce_Abstract_Sync extends WP_Job
471
  $wpdb->query("DELETE FROM {$wpdb->prefix}queue WHERE job LIKE '%{$class_name}%'");
472
 
473
  // this will paginate through all records for the resource type until they return no records.
474
- mailchimp_handle_or_queue(new static());
475
  mailchimp_debug(get_called_class().'@handle', 'queuing up the next job');
476
  }
477
  }
471
  $wpdb->query("DELETE FROM {$wpdb->prefix}queue WHERE job LIKE '%{$class_name}%'");
472
 
473
  // this will paginate through all records for the resource type until they return no records.
474
+ mailchimp_handle_or_queue(new static(), 0, true);
475
  mailchimp_debug(get_called_class().'@handle', 'queuing up the next job');
476
  }
477
  }
includes/processes/class-mailchimp-woocommerce-process-coupons-initial-sync.php ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Class MailChimp_WooCommerce_Process_Coupons_Then_Products
5
+ */
6
+ class MailChimp_WooCommerce_Process_Coupons_Initial_Sync extends MailChimp_WooCommerce_Process_Coupons
7
+ {
8
+ /**
9
+ * After the resources have been loaded and pushed
10
+ */
11
+ protected function complete()
12
+ {
13
+ mailchimp_log('coupon_sync.completed', 'Done with the coupon sync, queuing up products.');
14
+
15
+ // add a timestamp for the orders sync completion
16
+ $this->setResourceCompleteTime();
17
+
18
+ $product_sync = new MailChimp_WooCommerce_Process_Products();
19
+ mailchimp_handle_or_queue($product_sync, 0, true);
20
+ }
21
+ }
includes/processes/class-mailchimp-woocommerce-process-products.php CHANGED
@@ -20,7 +20,7 @@ class MailChimp_WooCommerce_Process_Products extends MailChimp_WooCommerce_Abstr
20
  {
21
  $job = new MailChimp_WooCommerce_Process_Products();
22
  $job->flagStartSync();
23
- mailchimp_handle_or_queue($job);
24
  }
25
 
26
 
20
  {
21
  $job = new MailChimp_WooCommerce_Process_Products();
22
  $job->flagStartSync();
23
+ mailchimp_handle_or_queue($job, 0, true);
24
  }
25
 
26
 
includes/processes/class-mailchimp-woocommerce-rest-queue.php ADDED
@@ -0,0 +1,244 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Class MailChimp_WooCommerce_Rest_Queue
5
+ */
6
+ class MailChimp_WooCommerce_Rest_Queue
7
+ {
8
+ /**
9
+ * @var WP_Queue
10
+ */
11
+ protected $queue;
12
+
13
+ /**
14
+ * @var WP_Job
15
+ */
16
+ protected $payload;
17
+
18
+ /**
19
+ * Has the worker been dispatched in this request?
20
+ *
21
+ * @var bool
22
+ */
23
+ protected $dispatched = false;
24
+
25
+ /**
26
+ * Timestamp of when this worker started processing the queue.
27
+ *
28
+ * @var int
29
+ */
30
+ protected $start_time;
31
+
32
+ protected static $_instance = null;
33
+
34
+ /**
35
+ * @return MailChimp_WooCommerce_Rest_Queue
36
+ */
37
+ public static function instance()
38
+ {
39
+ if (!empty(static::$_instance)) return static::$_instance;
40
+ return static::$_instance = new MailChimp_WooCommerce_Rest_Queue();
41
+ }
42
+
43
+ /**
44
+ * MailChimp_WooCommerce_Rest_Queue constructor.
45
+ */
46
+ public function __construct()
47
+ {
48
+ $this->queue = MailChimp_WooCommerce_Queue::instance();
49
+ }
50
+
51
+ /**
52
+ * @return bool|int
53
+ */
54
+ public function handle()
55
+ {
56
+ // if we have the queue runner disabled, process 1 and exit.
57
+ if (mailchimp_queue_is_disabled()) {
58
+ return $this->process_next_job();
59
+ }
60
+
61
+ // Worker already running, die
62
+ if ($this->is_worker_running()) {
63
+ mailchimp_debug('rest_queue', 'blocked process because it was already running');
64
+ return 'worker is running';
65
+ }
66
+
67
+ // Lock worker to prevent multiple instances spawning
68
+ $this->lock_worker();
69
+
70
+ // counter.
71
+ $jobs_processed = 0;
72
+ // Loop over jobs while within server limits
73
+ while (!$this->time_exceeded() && !$this->memory_exceeded()) {
74
+ if ($this->queue->available_jobs() > 0) {
75
+ if ($this->process_next_job()) {
76
+ $jobs_processed++;
77
+ }
78
+ continue;
79
+ }
80
+ break;
81
+ }
82
+
83
+ // Unlock worker to allow another instance to be spawned
84
+ $this->unlock_worker();
85
+
86
+ // if the queue still has jobs, rinse and repeat.
87
+ if ($this->queue->available_jobs() > 0) {
88
+ $this->again();
89
+ }
90
+
91
+ return $jobs_processed;
92
+ }
93
+
94
+ /**
95
+ * Process next job.
96
+ *
97
+ * @return bool
98
+ */
99
+ public function process_next_job()
100
+ {
101
+ $job = $this->queue->get_next_job();
102
+
103
+ if (empty($job)) {
104
+ return false;
105
+ }
106
+
107
+ $this->payload = unserialize($job->job);
108
+ $this->queue->lock_job($job);
109
+ $this->payload->set_job($job);
110
+
111
+ try {
112
+ $this->payload->handle();
113
+
114
+ if ($this->payload->is_deleted()) {
115
+ $this->queue->delete($job);
116
+ return true;
117
+ }
118
+
119
+ if ($this->payload->is_released()) {
120
+ $this->queue->release($job, $this->payload->get_delay());
121
+ }
122
+
123
+ if (!$this->payload->is_deleted_or_released()) {
124
+ $this->queue->delete($job);
125
+ }
126
+
127
+ } catch ( Exception $e ) {
128
+ mailchimp_log('queue.error', "{$e->getMessage()} on {$e->getLine()} in {$e->getFile()}", array('job' => get_class($this->payload)));
129
+ $this->queue->release($job);
130
+ return false;
131
+ }
132
+
133
+ if (defined('WP_CLI') && WP_CLI && property_exists($this->payload, 'should_kill_queue_listener') && $this->payload->should_kill_queue_listener === true) {
134
+ wp_die('killing queue listener');
135
+ }
136
+
137
+ return true;
138
+ }
139
+
140
+ /**
141
+ * Memory exceeded
142
+ *
143
+ * Ensures the worker process never exceeds 80%
144
+ * of the maximum allowed PHP memory.
145
+ *
146
+ * @return bool
147
+ */
148
+ public function memory_exceeded()
149
+ {
150
+ $memory_limit = $this->get_memory_limit() * 0.8; // 80% of max memory
151
+ return apply_filters( 'http_worker_memory_exceeded', memory_get_usage( true) >= $memory_limit);
152
+ }
153
+
154
+ /**
155
+ * Get memory limit
156
+ *
157
+ * @return int
158
+ */
159
+ protected function get_memory_limit()
160
+ {
161
+ $memory_limit = function_exists( 'ini_get' ) ? ini_get( 'memory_limit' ) : '128M';
162
+ if (!$memory_limit || -1 == $memory_limit) {
163
+ // Unlimited, set to 32GB
164
+ $memory_limit = '32000M';
165
+ }
166
+
167
+ return (int) preg_replace_callback('/(\-?\d+)(.?)/', function ($m) {
168
+ return $m[1] * pow(1024, strpos('BKMG', $m[2]));
169
+ }, strtoupper($memory_limit));
170
+ }
171
+
172
+ /**
173
+ * Time exceeded
174
+ *
175
+ * Ensures the worker never exceeds a sensible time limit (20s by default).
176
+ * A timeout limit of 30s is common on shared hosting.
177
+ *
178
+ * @return bool
179
+ */
180
+ protected function time_exceeded()
181
+ {
182
+ $time_limit = apply_filters('http_worker_default_time_limit', 20);
183
+ $finish = $this->start_time + $time_limit; // 20 seconds
184
+ return apply_filters( 'http_worker_time_exceeded', ((time() + 2) >= $finish));
185
+ }
186
+
187
+ /**
188
+ * Is HTTP worker disabled
189
+ *
190
+ * @return bool
191
+ */
192
+ public function is_http_worker_disabled()
193
+ {
194
+ return defined( 'DISABLE_WP_HTTP_WORKER' ) && DISABLE_WP_HTTP_WORKER === true;
195
+ }
196
+
197
+ /**
198
+ * Is worker running
199
+ *
200
+ * Check if another instance of the HTTP worker is running.
201
+ *
202
+ * @return bool
203
+ */
204
+ public function is_worker_running()
205
+ {
206
+ return (bool) get_site_transient('http_worker_lock');
207
+ }
208
+
209
+ /**
210
+ * Lock worker
211
+ *
212
+ * Lock the HTTP worker to prevent multiple instances running.
213
+ */
214
+ public function lock_worker()
215
+ {
216
+ $this->start_time = time(); // Set start time of current worker
217
+ set_site_transient('http_worker_lock', microtime(), 60);
218
+ }
219
+
220
+ /**
221
+ * Unlock worker
222
+ *
223
+ * Unlock the HTTP worker to allow other instances to be spawned.
224
+ */
225
+ public function unlock_worker()
226
+ {
227
+ if (!delete_site_transient('http_worker_lock')) {
228
+ mailchimp_log('rest-queue', 'http_worker_lock did not delete properly - will respawn in 60 seconds.');
229
+ }
230
+ }
231
+
232
+ /**
233
+ *
234
+ */
235
+ protected function again()
236
+ {
237
+ wp_remote_get(esc_url_raw(rest_url('mailchimp-for-woocommerce/v1/queue/work')), array(
238
+ 'timeout' => 0.01,
239
+ 'blocking' => false,
240
+ 'cookies' => $_COOKIE,
241
+ 'sslverify' => apply_filters('https_local_ssl_verify', false)
242
+ ));
243
+ }
244
+ }
includes/vendor/queue/classes/worker/wp-http-worker.php CHANGED
@@ -277,7 +277,7 @@ if ( ! class_exists( 'WP_Http_Worker' ) ) {
277
  $query_args = apply_filters( 'http_worker_query_args', array(
278
  'action' => $action,
279
  'nonce' => wp_create_nonce( $action ),
280
- ) );
281
 
282
  $query_url = apply_filters( 'http_worker_query_url', admin_url( 'admin-ajax.php' ) );
283
 
277
  $query_args = apply_filters( 'http_worker_query_args', array(
278
  'action' => $action,
279
  'nonce' => wp_create_nonce( $action ),
280
+ ));
281
 
282
  $query_url = apply_filters( 'http_worker_query_url', admin_url( 'admin-ajax.php' ) );
283
 
includes/vendor/queue/classes/worker/wp-worker.php CHANGED
@@ -29,7 +29,7 @@ if ( ! class_exists( 'WP_Worker' ) ) {
29
  */
30
  public function should_run() {
31
 
32
- if ( $this->queue->available_jobs() ) {
33
  return true;
34
  }
35
 
29
  */
30
  public function should_run() {
31
 
32
+ if ($this->queue->available_jobs()) {
33
  return true;
34
  }
35
 
mailchimp-woocommerce.php CHANGED
@@ -16,7 +16,7 @@
16
  * Plugin Name: Mailchimp for WooCommerce
17
  * Plugin URI: https://mailchimp.com/connect-your-store/
18
  * Description: Mailchimp - WooCommerce plugin
19
- * Version: 2.1.14
20
  * Author: Mailchimp
21
  * Author URI: https://mailchimp.com
22
  * License: GPL-2.0+
@@ -24,7 +24,7 @@
24
  * Text Domain: mailchimp-woocommerce
25
  * Domain Path: /languages
26
  * Requires at least: 4.4
27
- * Tested up to: 5.0.3
28
  */
29
 
30
  // If this file is called directly, abort.
16
  * Plugin Name: Mailchimp for WooCommerce
17
  * Plugin URI: https://mailchimp.com/connect-your-store/
18
  * Description: Mailchimp - WooCommerce plugin
19
+ * Version: 2.1.15
20
  * Author: Mailchimp
21
  * Author URI: https://mailchimp.com
22
  * License: GPL-2.0+
24
  * Text Domain: mailchimp-woocommerce
25
  * Domain Path: /languages
26
  * Requires at least: 4.4
27
+ * Tested up to: 5.1
28
  */
29
 
30
  // If this file is called directly, abort.
public/class-mailchimp-woocommerce-public.php CHANGED
@@ -72,9 +72,13 @@ class MailChimp_WooCommerce_Public {
72
  wp_localize_script($this->plugin_name, 'mailchimp_public_data', array(
73
  'site_url' => site_url(),
74
  'ajax_url' => admin_url('admin-ajax.php'),
 
 
75
  ));
76
- // Enqueued script with localized data.
77
- wp_enqueue_script($this->plugin_name, '', array(), $this->version, true);
 
 
78
  //if we have the connected_site script url saved, we need to inject it
79
  if (($site = mailchimp_get_connected_site_script_url()) && !empty($site)) {
80
  wp_enqueue_script($this->plugin_name.'_connected_site', $site, array(), $this->version, true);
72
  wp_localize_script($this->plugin_name, 'mailchimp_public_data', array(
73
  'site_url' => site_url(),
74
  'ajax_url' => admin_url('admin-ajax.php'),
75
+ 'queue_url' => MailChimp_WooCommerce_Rest_Api::url('queue/work'),
76
+ 'queue_should_fire' => mailchimp_should_init_rest_queue(),
77
  ));
78
+
79
+ // Enqueued script with localized data.
80
+ wp_enqueue_script($this->plugin_name, '', array(), $this->version, true);
81
+
82
  //if we have the connected_site script url saved, we need to inject it
83
  if (($site = mailchimp_get_connected_site_script_url()) && !empty($site)) {
84
  wp_enqueue_script($this->plugin_name.'_connected_site', $site, array(), $this->version, true);
public/js/mailchimp-woocommerce-public.js CHANGED
@@ -6,6 +6,19 @@ var mailchimp,
6
  mailchimp_submitted_email = false,
7
  mailchimpReady = function (a) { /in/.test(document.readyState) ? setTimeout("mailchimpReady(" + a + ")", 9) : a(); };
8
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9
  function mailchimpGetCurrentUserByHash(a) {
10
  try {
11
  var b = mailchimp_public_data.ajax_url + "?action=mailchimp_get_user_by_hash&hash=" + a, c = new XMLHttpRequest;
@@ -199,6 +212,10 @@ mailchimpReady(function () {
199
  mailchimp_registration_email.onblur = function () { mailchimpHandleBillingEmail('#reg_email'); };
200
  mailchimp_registration_email.onfocus = function () { mailchimpHandleBillingEmail('#reg_email'); }
201
  }
 
 
 
 
202
  } catch (e) {
203
  console.log('mailchimp ready error', e);
204
  }
6
  mailchimp_submitted_email = false,
7
  mailchimpReady = function (a) { /in/.test(document.readyState) ? setTimeout("mailchimpReady(" + a + ")", 9) : a(); };
8
 
9
+ function mailchimpPollQueue() {
10
+ try {
11
+ var queue = new XMLHttpRequest;
12
+ queue.open("GET", mailchimp_public_data.queue_url, true);
13
+ queue.setRequestHeader("Accept", "application/json");
14
+ queue.timeout = 4000; // Set timeout to 4 seconds (4000 milliseconds)
15
+ queue.ontimeout = function () { console.log('queue success'); };
16
+ queue.send();
17
+ } catch (a) {
18
+ console.log("mailchimp.init_queue.error", a)
19
+ }
20
+ }
21
+
22
  function mailchimpGetCurrentUserByHash(a) {
23
  try {
24
  var b = mailchimp_public_data.ajax_url + "?action=mailchimp_get_user_by_hash&hash=" + a, c = new XMLHttpRequest;
212
  mailchimp_registration_email.onblur = function () { mailchimpHandleBillingEmail('#reg_email'); };
213
  mailchimp_registration_email.onfocus = function () { mailchimpHandleBillingEmail('#reg_email'); }
214
  }
215
+
216
+ if (mailchimp_public_data.queue_should_fire) {
217
+ mailchimpPollQueue();
218
+ }
219
  } catch (e) {
220
  console.log('mailchimp ready error', e);
221
  }
public/js/mailchimp-woocommerce-public.min.js CHANGED
@@ -1 +1 @@
1
- var mailchimp,mailchimp_cart,mailchimp_billing_email,mailchimp_username_email,mailchimp_registration_email,mailchimp_submitted_email=!1,mailchimpReady=function(e){/in/.test(document.readyState)?setTimeout("mailchimpReady("+e+")",9):e()};function mailchimpGetCurrentUserByHash(e){try{var i=mailchimp_public_data.ajax_url+"?action=mailchimp_get_user_by_hash&hash="+e,a=new XMLHttpRequest;a.open("POST",i,!0),a.onload=function(){if(a.status>=200&&a.status<400){var e=JSON.parse(a.responseText);if(!e)return;mailchimp_cart.valueEmail(e.email)&&mailchimp_cart.setEmail(e.email)}},a.onerror=function(){console.log("mailchimp.get_email_by_hash.request.error",a.responseText)},a.setRequestHeader("Content-Type","application/json"),a.setRequestHeader("Accept","application/json"),a.send()}catch(e){console.log("mailchimp.get_email_by_hash.error",e)}}function mailchimpHandleBillingEmail(e){try{e||(e="#billing_email");var i=document.querySelector(e),a=void 0!==i?i.value:"";if(!mailchimp_cart.valueEmail(a)||mailchimp_submitted_email===a)return!1;mailchimp_cart.setEmail(a);var t=mailchimp_public_data.ajax_url+"?action=mailchimp_set_user_by_email&email="+a,n=new XMLHttpRequest;return n.open("POST",t,!0),n.onload=function(){var e=n.status>=200&&n.status<400,i=e?"mailchimp.handle_billing_email.request.success":"mailchimp.handle_billing_email.request.error";e&&(mailchimp_submitted_email=a),console.log(i,n.responseText)},n.onerror=function(){console.log("mailchimp.handle_billing_email.request.error",n.responseText)},n.setRequestHeader("Content-Type","application/json"),n.setRequestHeader("Accept","application/json"),n.send(),!0}catch(i){console.log("mailchimp.handle_billing_email.error",i),mailchimp_submitted_email=!1}}!function(){"use strict";var e,i,a,t,n={extend:function(e,i){for(var a in i||{})i.hasOwnProperty(a)&&(e[a]=i[a]);return e},getQueryStringVars:function(){var e=window.location.search||"",i=[],a={};if((e=e.substr(1)).length){i=e.split("&");for(var t in i){var n=i[t];if("string"==typeof n){var l=n.split("="),r=l[0],m=l[1];r.length&&(void 0===a[r]&&(a[r]=[]),a[r].push(m))}}}return a},unEscape:function(e){return decodeURIComponent(e)},escape:function(e){return encodeURIComponent(e)},createDate:function(e,i){e||(e=0);var a=new Date,t=i?a.getDate()-e:a.getDate()+e;return a.setDate(t),a},arrayUnique:function(e){for(var i=e.concat(),a=0;a<i.length;++a)for(var t=a+1;t<i.length;++t)i[a]===i[t]&&i.splice(t,1);return i},objectCombineUnique:function(e){for(var i=e[0],a=1;a<e.length;a++){var t=e[a];for(var n in t)i[n]=t[n]}return i}},l=(e=document,(t=function(e,i,a){return 1===arguments.length?t.get(e):t.set(e,i,a)}).get=function(i,a){return e.cookie!==t._cacheString&&t._populateCache(),void 0==t._cache[i]?a:t._cache[i]},t.defaults={path:"/"},t.set=function(a,n,l){switch(l={path:l&&l.path||t.defaults.path,domain:l&&l.domain||t.defaults.domain,expires:l&&l.expires||t.defaults.expires,secure:l&&l.secure!==i?l.secure:t.defaults.secure},n===i&&(l.expires=-1),typeof l.expires){case"number":l.expires=new Date((new Date).getTime()+1e3*l.expires);break;case"string":l.expires=new Date(l.expires)}return a=encodeURIComponent(a)+"="+(n+"").replace(/[^!#-+\--:<-\[\]-~]/g,encodeURIComponent),a+=l.path?";path="+l.path:"",a+=l.domain?";domain="+l.domain:"",a+=l.expires?";expires="+l.expires.toGMTString():"",a+=l.secure?";secure":"",e.cookie=a,t},t.expire=function(e,a){return t.set(e,i,a)},t._populateCache=function(){t._cache={};try{t._cacheString=e.cookie;for(var a=t._cacheString.split("; "),n=0;n<a.length;n++){var l=a[n].indexOf("="),r=decodeURIComponent(a[n].substr(0,l));l=decodeURIComponent(a[n].substr(l+1)),t._cache[r]===i&&(t._cache[r]=l)}}catch(e){console.log(e)}},t.enabled=(a="1"===t.set("cookies.js","1").get("cookies.js"),t.expire("cookies.js"),a),t);mailchimp={storage:l,utils:n},mailchimp_cart=new function(){return this.email_types="input[type=email]",this.regex_email=/^([A-Za-z0-9_+\-\.])+\@([A-Za-z0-9_\-\.])+\.([A-Za-z]{2,4})$/,this.current_email=null,this.previous_email=null,this.expireUser=function(){this.current_email=null,mailchimp.storage.expire("mailchimp.cart.current_email")},this.expireSaved=function(){mailchimp.storage.expire("mailchimp.cart.items")},this.setEmail=function(e){if(!this.valueEmail(e))return!1;this.setPreviousEmail(this.getEmail()),mailchimp.storage.set("mailchimp.cart.current_email",this.current_email=e)},this.getEmail=function(){if(this.current_email)return this.current_email;var e=mailchimp.storage.get("mailchimp.cart.current_email",!1);return!(!e||!this.valueEmail(e))&&(this.current_email=e)},this.setPreviousEmail=function(e){if(!this.valueEmail(e))return!1;mailchimp.storage.set("mailchimp.cart.previous_email",this.previous_email=e)},this.valueEmail=function(e){return this.regex_email.test(e)},this}}(),mailchimpReady(function(){if(void 0===e)var e={site_url:document.location.origin,defaulted:!0,ajax_url:document.location.origin+"/wp-admin?admin-ajax.php"};try{var i=mailchimp.utils.getQueryStringVars();void 0!==i.mc_cart_id&&mailchimpGetCurrentUserByHash(i.mc_cart_id),mailchimp_username_email=document.querySelector("#username"),mailchimp_billing_email=document.querySelector("#billing_email"),mailchimp_registration_email=document.querySelector("#reg_email"),mailchimp_billing_email&&(mailchimp_billing_email.onblur=function(){mailchimpHandleBillingEmail("#billing_email")},mailchimp_billing_email.onfocus=function(){mailchimpHandleBillingEmail("#billing_email")}),mailchimp_username_email&&(mailchimp_username_email.onblur=function(){mailchimpHandleBillingEmail("#username")},mailchimp_username_email.onfocus=function(){mailchimpHandleBillingEmail("#username")}),mailchimp_registration_email&&(mailchimp_registration_email.onblur=function(){mailchimpHandleBillingEmail("#reg_email")},mailchimp_registration_email.onfocus=function(){mailchimpHandleBillingEmail("#reg_email")})}catch(e){console.log("mailchimp ready error",e)}});
1
+ var mailchimp,mailchimp_cart,mailchimp_billing_email,mailchimp_username_email,mailchimp_registration_email,mailchimp_submitted_email=!1,mailchimpReady=function(e){/in/.test(document.readyState)?setTimeout("mailchimpReady("+e+")",9):e()};function mailchimpPollQueue(){try{var e=new XMLHttpRequest;e.open("GET",mailchimp_public_data.queue_url,!0),e.setRequestHeader("Accept","application/json"),e.timeout=4e3,e.ontimeout=function(){console.log("queue success")},e.send()}catch(e){console.log("mailchimp.init_queue.error",e)}}function mailchimpGetCurrentUserByHash(e){try{var i=mailchimp_public_data.ajax_url+"?action=mailchimp_get_user_by_hash&hash="+e,a=new XMLHttpRequest;a.open("POST",i,!0),a.onload=function(){if(a.status>=200&&a.status<400){var e=JSON.parse(a.responseText);if(!e)return;mailchimp_cart.valueEmail(e.email)&&mailchimp_cart.setEmail(e.email)}},a.onerror=function(){console.log("mailchimp.get_email_by_hash.request.error",a.responseText)},a.setRequestHeader("Content-Type","application/json"),a.setRequestHeader("Accept","application/json"),a.send()}catch(e){console.log("mailchimp.get_email_by_hash.error",e)}}function mailchimpHandleBillingEmail(e){try{e||(e="#billing_email");var i=document.querySelector(e),a=void 0!==i?i.value:"";if(!mailchimp_cart.valueEmail(a)||mailchimp_submitted_email===a)return!1;mailchimp_cart.setEmail(a);var t=mailchimp_public_data.ajax_url+"?action=mailchimp_set_user_by_email&email="+a,l=new XMLHttpRequest;return l.open("POST",t,!0),l.onload=function(){var e=l.status>=200&&l.status<400,i=e?"mailchimp.handle_billing_email.request.success":"mailchimp.handle_billing_email.request.error";e&&(mailchimp_submitted_email=a),console.log(i,l.responseText)},l.onerror=function(){console.log("mailchimp.handle_billing_email.request.error",l.responseText)},l.setRequestHeader("Content-Type","application/json"),l.setRequestHeader("Accept","application/json"),l.send(),!0}catch(i){console.log("mailchimp.handle_billing_email.error",i),mailchimp_submitted_email=!1}}!function(){"use strict";var e,i,a,t={extend:function(e,i){for(var a in i||{})i.hasOwnProperty(a)&&(e[a]=i[a]);return e},getQueryStringVars:function(){var e=window.location.search||"",i=[],a={};if((e=e.substr(1)).length)for(var t in i=e.split("&")){var l=i[t];if("string"==typeof l){var n=l.split("="),r=n[0],m=n[1];r.length&&(void 0===a[r]&&(a[r]=[]),a[r].push(m))}}return a},unEscape:function(e){return decodeURIComponent(e)},escape:function(e){return encodeURIComponent(e)},createDate:function(e,i){e||(e=0);var a=new Date,t=i?a.getDate()-e:a.getDate()+e;return a.setDate(t),a},arrayUnique:function(e){for(var i=e.concat(),a=0;a<i.length;++a)for(var t=a+1;t<i.length;++t)i[a]===i[t]&&i.splice(t,1);return i},objectCombineUnique:function(e){for(var i=e[0],a=1;a<e.length;a++){var t=e[a];for(var l in t)i[l]=t[l]}return i}},l=(e=document,(a=function(e,i,t){return 1===arguments.length?a.get(e):a.set(e,i,t)}).get=function(i,t){return e.cookie!==a._cacheString&&a._populateCache(),null==a._cache[i]?t:a._cache[i]},a.defaults={path:"/"},a.set=function(t,l,n){switch(n={path:n&&n.path||a.defaults.path,domain:n&&n.domain||a.defaults.domain,expires:n&&n.expires||a.defaults.expires,secure:n&&n.secure!==i?n.secure:a.defaults.secure},l===i&&(n.expires=-1),typeof n.expires){case"number":n.expires=new Date((new Date).getTime()+1e3*n.expires);break;case"string":n.expires=new Date(n.expires)}return t=encodeURIComponent(t)+"="+(l+"").replace(/[^!#-+\--:<-\[\]-~]/g,encodeURIComponent),t+=n.path?";path="+n.path:"",t+=n.domain?";domain="+n.domain:"",t+=n.expires?";expires="+n.expires.toGMTString():"",t+=n.secure?";secure":"",e.cookie=t,a},a.expire=function(e,t){return a.set(e,i,t)},a._populateCache=function(){a._cache={};try{a._cacheString=e.cookie;for(var t=a._cacheString.split("; "),l=0;l<t.length;l++){var n=t[l].indexOf("="),r=decodeURIComponent(t[l].substr(0,n));n=decodeURIComponent(t[l].substr(n+1)),a._cache[r]===i&&(a._cache[r]=n)}}catch(e){console.log(e)}},a.enabled=function(){var e="1"===a.set("cookies.js","1").get("cookies.js");return a.expire("cookies.js"),e}(),a);mailchimp={storage:l,utils:t},mailchimp_cart=new function(){return this.email_types="input[type=email]",this.regex_email=/^([A-Za-z0-9_+\-\.])+\@([A-Za-z0-9_\-\.])+\.([A-Za-z]{2,4})$/,this.current_email=null,this.previous_email=null,this.expireUser=function(){this.current_email=null,mailchimp.storage.expire("mailchimp.cart.current_email")},this.expireSaved=function(){mailchimp.storage.expire("mailchimp.cart.items")},this.setEmail=function(e){if(!this.valueEmail(e))return!1;this.setPreviousEmail(this.getEmail()),mailchimp.storage.set("mailchimp.cart.current_email",this.current_email=e)},this.getEmail=function(){if(this.current_email)return this.current_email;var e=mailchimp.storage.get("mailchimp.cart.current_email",!1);return!(!e||!this.valueEmail(e))&&(this.current_email=e)},this.setPreviousEmail=function(e){if(!this.valueEmail(e))return!1;mailchimp.storage.set("mailchimp.cart.previous_email",this.previous_email=e)},this.valueEmail=function(e){return this.regex_email.test(e)},this}}(),mailchimpReady(function(){if(void 0===e)var e={site_url:document.location.origin,defaulted:!0,ajax_url:document.location.origin+"/wp-admin?admin-ajax.php"};try{var i=mailchimp.utils.getQueryStringVars();void 0!==i.mc_cart_id&&mailchimpGetCurrentUserByHash(i.mc_cart_id),mailchimp_username_email=document.querySelector("#username"),mailchimp_billing_email=document.querySelector("#billing_email"),mailchimp_registration_email=document.querySelector("#reg_email"),mailchimp_billing_email&&(mailchimp_billing_email.onblur=function(){mailchimpHandleBillingEmail("#billing_email")},mailchimp_billing_email.onfocus=function(){mailchimpHandleBillingEmail("#billing_email")}),mailchimp_username_email&&(mailchimp_username_email.onblur=function(){mailchimpHandleBillingEmail("#username")},mailchimp_username_email.onfocus=function(){mailchimpHandleBillingEmail("#username")}),mailchimp_registration_email&&(mailchimp_registration_email.onblur=function(){mailchimpHandleBillingEmail("#reg_email")},mailchimp_registration_email.onfocus=function(){mailchimpHandleBillingEmail("#reg_email")}),mailchimp_public_data.queue_should_fire&&mailchimpPollQueue()}catch(e){console.log("mailchimp ready error",e)}});