MailChimp for WooCommerce - Version 2.3.2

Version Description

  • update to action scheduler v3.0.1
  • adds low-bandwidth setting on sync
  • fixes audience defaults settings to Mailchimp not passed
  • tweaks to review banner behavior
  • required fields API update
  • fix for orders with deleted products
  • support for orders with 0 line items
Download this release

Release Info

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

Code changes from version 2.3.1 to 2.3.2

Files changed (132) hide show
  1. README.txt +11 -3
  2. admin/class-mailchimp-woocommerce-admin.php +35 -23
  3. admin/js/mailchimp-woocommerce-admin.js +5 -3
  4. admin/partials/tabs/store_sync.php +2 -7
  5. bootstrap.php +8 -7
  6. includes/api/assets/class-mailchimp-line-item.php +38 -0
  7. includes/api/class-mailchimp-api.php +57 -7
  8. includes/api/class-mailchimp-woocommerce-transform-orders-wc3.php +23 -5
  9. includes/api/class-mailchimp-woocommerce-transform-products.php +86 -14
  10. includes/class-mailchimp-woocommerce-rest-api.php +26 -31
  11. includes/class-mailchimp-woocommerce.php +3 -5
  12. includes/processes/class-mailchimp-woocommerce-process-orders.php +24 -1
  13. includes/processes/class-mailchimp-woocommerce-single-product.php +41 -2
  14. includes/vendor/action-scheduler/.editorconfig +24 -0
  15. includes/vendor/action-scheduler/.gitattributes +6 -2
  16. includes/vendor/action-scheduler/.gitignore +1 -0
  17. includes/vendor/action-scheduler/Gruntfile.js +57 -0
  18. includes/vendor/action-scheduler/README.md +3 -9
  19. includes/vendor/action-scheduler/action-scheduler.php +17 -11
  20. includes/vendor/action-scheduler/classes/ActionScheduler.php +0 -133
  21. includes/vendor/action-scheduler/classes/ActionScheduler_ActionFactory.php +73 -5
  22. includes/vendor/action-scheduler/classes/ActionScheduler_AdminView.php +56 -2
  23. includes/vendor/action-scheduler/classes/ActionScheduler_AsyncRequest_QueueRunner.php +96 -0
  24. includes/vendor/action-scheduler/classes/ActionScheduler_CronSchedule.php +0 -57
  25. includes/vendor/action-scheduler/classes/ActionScheduler_DataController.php +177 -0
  26. includes/vendor/action-scheduler/classes/ActionScheduler_Exception.php +1 -1
  27. includes/vendor/action-scheduler/classes/ActionScheduler_IntervalSchedule.php +0 -60
  28. includes/vendor/action-scheduler/classes/ActionScheduler_InvalidActionException.php +23 -4
  29. includes/vendor/action-scheduler/classes/ActionScheduler_ListTable.php +51 -25
  30. includes/vendor/action-scheduler/classes/ActionScheduler_Logger.php +0 -102
  31. includes/vendor/action-scheduler/classes/ActionScheduler_NullSchedule.php +0 -19
  32. includes/vendor/action-scheduler/classes/ActionScheduler_OptionLock.php +49 -0
  33. includes/vendor/action-scheduler/classes/ActionScheduler_QueueRunner.php +79 -9
  34. includes/vendor/action-scheduler/classes/ActionScheduler_SimpleSchedule.php +0 -44
  35. includes/vendor/action-scheduler/classes/ActionScheduler_Store.php +0 -212
  36. includes/vendor/action-scheduler/classes/ActionScheduler_WPCommentCleaner.php +108 -0
  37. includes/vendor/action-scheduler/classes/ActionScheduler_wcSystemStatus.php +2 -2
  38. includes/vendor/action-scheduler/classes/{ActionScheduler_WPCLI_QueueRunner.php → WP_CLI/ActionScheduler_WPCLI_QueueRunner.php} +16 -36
  39. includes/vendor/action-scheduler/classes/{ActionScheduler_WPCLI_Scheduler_command.php → WP_CLI/ActionScheduler_WPCLI_Scheduler_command.php} +15 -2
  40. includes/vendor/action-scheduler/classes/WP_CLI/Migration_Command.php +148 -0
  41. includes/vendor/action-scheduler/classes/WP_CLI/ProgressBar.php +119 -0
  42. includes/vendor/action-scheduler/classes/abstracts/ActionScheduler.php +269 -0
  43. includes/vendor/action-scheduler/classes/{ActionScheduler_Abstract_ListTable.php → abstracts/ActionScheduler_Abstract_ListTable.php} +28 -10
  44. includes/vendor/action-scheduler/classes/{ActionScheduler_Abstract_QueueRunner.php → abstracts/ActionScheduler_Abstract_QueueRunner.php} +28 -15
  45. includes/vendor/action-scheduler/classes/abstracts/ActionScheduler_Abstract_RecurringSchedule.php +102 -0
  46. includes/vendor/action-scheduler/classes/abstracts/ActionScheduler_Abstract_Schedule.php +83 -0
  47. includes/vendor/action-scheduler/classes/abstracts/ActionScheduler_Abstract_Schema.php +133 -0
  48. includes/vendor/action-scheduler/classes/abstracts/ActionScheduler_Lock.php +62 -0
  49. includes/vendor/action-scheduler/classes/abstracts/ActionScheduler_Logger.php +176 -0
  50. includes/vendor/action-scheduler/classes/abstracts/ActionScheduler_Store.php +345 -0
  51. includes/vendor/action-scheduler/classes/{ActionScheduler_TimezoneHelper.php → abstracts/ActionScheduler_TimezoneHelper.php} +0 -0
  52. includes/vendor/action-scheduler/classes/{ActionScheduler_Action.php → actions/ActionScheduler_Action.php} +0 -0
  53. includes/vendor/action-scheduler/classes/{ActionScheduler_CanceledAction.php → actions/ActionScheduler_CanceledAction.php} +3 -1
  54. includes/vendor/action-scheduler/classes/{ActionScheduler_FinishedAction.php → actions/ActionScheduler_FinishedAction.php} +0 -0
  55. includes/vendor/action-scheduler/classes/{ActionScheduler_NullAction.php → actions/ActionScheduler_NullAction.php} +0 -0
  56. includes/vendor/action-scheduler/classes/data-stores/ActionScheduler_DBLogger.php +146 -0
  57. includes/vendor/action-scheduler/classes/data-stores/ActionScheduler_DBStore.php +803 -0
  58. includes/vendor/action-scheduler/classes/data-stores/ActionScheduler_HybridStore.php +380 -0
  59. includes/vendor/action-scheduler/classes/{ActionScheduler_wpCommentLogger.php → data-stores/ActionScheduler_wpCommentLogger.php} +0 -0
  60. includes/vendor/action-scheduler/classes/{ActionScheduler_wpPostStore.php → data-stores/ActionScheduler_wpPostStore.php} +91 -54
  61. includes/vendor/action-scheduler/classes/{ActionScheduler_wpPostStore_PostStatusRegistrar.php → data-stores/ActionScheduler_wpPostStore_PostStatusRegistrar.php} +6 -5
  62. includes/vendor/action-scheduler/classes/{ActionScheduler_wpPostStore_PostTypeRegistrar.php → data-stores/ActionScheduler_wpPostStore_PostTypeRegistrar.php} +0 -0
  63. includes/vendor/action-scheduler/classes/{ActionScheduler_wpPostStore_TaxonomyRegistrar.php → data-stores/ActionScheduler_wpPostStore_TaxonomyRegistrar.php} +0 -0
  64. includes/vendor/action-scheduler/classes/migration/ActionMigrator.php +109 -0
  65. includes/vendor/action-scheduler/classes/migration/ActionScheduler_DBStoreMigrator.php +47 -0
  66. includes/vendor/action-scheduler/classes/migration/BatchFetcher.php +86 -0
  67. includes/vendor/action-scheduler/classes/migration/Config.php +168 -0
  68. includes/vendor/action-scheduler/classes/migration/Controller.php +206 -0
  69. includes/vendor/action-scheduler/classes/migration/DryRun_ActionMigrator.php +28 -0
  70. includes/vendor/action-scheduler/classes/migration/DryRun_LogMigrator.php +23 -0
  71. includes/vendor/action-scheduler/classes/migration/LogMigrator.php +49 -0
  72. includes/vendor/action-scheduler/classes/migration/Runner.php +136 -0
  73. includes/vendor/action-scheduler/classes/migration/Scheduler.php +128 -0
  74. includes/vendor/action-scheduler/classes/schedules/ActionScheduler_CanceledSchedule.php +57 -0
  75. includes/vendor/action-scheduler/classes/schedules/ActionScheduler_CronSchedule.php +102 -0
  76. includes/vendor/action-scheduler/classes/schedules/ActionScheduler_IntervalSchedule.php +81 -0
  77. includes/vendor/action-scheduler/classes/schedules/ActionScheduler_NullSchedule.php +28 -0
  78. includes/vendor/action-scheduler/classes/{ActionScheduler_Schedule.php → schedules/ActionScheduler_Schedule.php} +0 -0
  79. includes/vendor/action-scheduler/classes/schedules/ActionScheduler_SimpleSchedule.php +71 -0
  80. includes/vendor/action-scheduler/classes/schema/ActionScheduler_LoggerSchema.php +48 -0
  81. includes/vendor/action-scheduler/classes/schema/ActionScheduler_StoreSchema.php +82 -0
  82. includes/vendor/action-scheduler/composer.json +28 -3
  83. includes/vendor/action-scheduler/composer.lock +2400 -429
  84. includes/vendor/action-scheduler/deprecated/ActionScheduler_Schedule_Deprecated.php +29 -0
  85. includes/vendor/action-scheduler/deprecated/ActionScheduler_Store_Deprecated.php +49 -0
  86. includes/vendor/action-scheduler/docs/_layouts/default.html +1 -4
  87. includes/vendor/action-scheduler/docs/android-chrome-192x192.png +0 -0
  88. includes/vendor/action-scheduler/docs/android-chrome-256x256.png +0 -0
  89. includes/vendor/action-scheduler/docs/api.md +52 -7
  90. includes/vendor/action-scheduler/docs/apple-touch-icon.png +0 -0
  91. includes/vendor/action-scheduler/docs/assets/css/style.scss +2 -2
  92. includes/vendor/action-scheduler/docs/faq.md +22 -16
  93. includes/vendor/action-scheduler/docs/favicon-16x16.png +0 -0
  94. includes/vendor/action-scheduler/docs/favicon-32x32.png +0 -0
  95. includes/vendor/action-scheduler/docs/favicon.ico +0 -0
  96. includes/vendor/action-scheduler/docs/index.md +13 -13
  97. includes/vendor/action-scheduler/docs/perf.md +21 -16
  98. includes/vendor/action-scheduler/docs/usage.md +7 -3
  99. includes/vendor/action-scheduler/docs/wp-cli.md +1 -1
  100. includes/vendor/action-scheduler/functions.php +47 -5
  101. includes/vendor/action-scheduler/lib/WP_Async_Request.php +170 -0
  102. includes/vendor/action-scheduler/package-lock.json +2138 -0
  103. includes/vendor/action-scheduler/package.json +39 -0
  104. includes/vendor/action-scheduler/phpcs.xml +39 -0
  105. includes/vendor/action-scheduler/tests/bootstrap.php +3 -0
  106. includes/vendor/action-scheduler/tests/phpunit.xml.dist +17 -1
  107. includes/vendor/action-scheduler/tests/phpunit/ActionScheduler_Mock_Async_Request_QueueRunner.php +19 -0
  108. includes/vendor/action-scheduler/tests/phpunit/ActionScheduler_Mocker.php +35 -0
  109. includes/vendor/action-scheduler/tests/phpunit/jobs/ActionScheduler_NullAction_Test.php +1 -1
  110. includes/vendor/action-scheduler/tests/phpunit/jobstore/ActionScheduler_DBStoreMigrator_Test.php +26 -0
  111. includes/vendor/action-scheduler/tests/phpunit/jobstore/ActionScheduler_DBStore_Test.php +396 -0
  112. includes/vendor/action-scheduler/tests/phpunit/jobstore/ActionScheduler_HybridStore_Test.php +272 -0
  113. includes/vendor/action-scheduler/tests/phpunit/jobstore/ActionScheduler_wpPostStore_Test.php +43 -4
  114. includes/vendor/action-scheduler/tests/phpunit/lock/ActionScheduler_OptionLock_Test.php +45 -0
  115. includes/vendor/action-scheduler/tests/phpunit/logging/ActionScheduler_DBLogger_Test.php +139 -0
  116. includes/vendor/action-scheduler/tests/phpunit/logging/ActionScheduler_wpCommentLogger_Test.php +43 -10
  117. includes/vendor/action-scheduler/tests/phpunit/migration/ActionMigrator_Test.php +145 -0
  118. includes/vendor/action-scheduler/tests/phpunit/migration/BatchFetcher_Test.php +76 -0
  119. includes/vendor/action-scheduler/tests/phpunit/migration/Config_Test.php +33 -0
  120. includes/vendor/action-scheduler/tests/phpunit/migration/LogMigrator_Test.php +44 -0
  121. includes/vendor/action-scheduler/tests/phpunit/migration/Runner_Test.php +92 -0
  122. includes/vendor/action-scheduler/tests/phpunit/migration/Scheduler_Test.php +122 -0
  123. includes/vendor/action-scheduler/tests/phpunit/procedural_api/procedural_api_Test.php +46 -9
  124. includes/vendor/action-scheduler/tests/phpunit/runner/ActionScheduler_QueueCleaner_Test.php +2 -2
  125. includes/vendor/action-scheduler/tests/phpunit/runner/ActionScheduler_QueueRunner_Test.php +102 -34
  126. includes/vendor/action-scheduler/tests/phpunit/schedules/ActionScheduler_CronSchedule_Test.php +40 -9
  127. includes/vendor/action-scheduler/tests/phpunit/schedules/ActionScheduler_IntervalSchedule_Test.php +13 -4
  128. includes/vendor/action-scheduler/tests/phpunit/schedules/ActionScheduler_NullSchedule_Test.php +1 -1
  129. includes/vendor/action-scheduler/tests/phpunit/schedules/ActionScheduler_SimpleSchedule_Test.php +4 -4
  130. languages/mc-woocommerce.pot +206 -63
  131. mailchimp-woocommerce.php +3 -3
  132. public/class-mailchimp-woocommerce-public.php +11 -4
README.txt CHANGED
@@ -3,11 +3,11 @@ Contributors: ryanhungate, Mailchimp
3
  Tags: ecommerce,email,workflows,mailchimp
4
  Donate link: https://mailchimp.com
5
  Requires at least: 4.9
6
- Tested up to: 5.3
7
- Stable tag: 2.3.1
8
  Requires PHP: 7.0
9
  WC requires at least: 3.5
10
- WC tested up to: 3.8
11
  License: GPLv2 or later
12
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
13
  Connect your store to your Mailchimp audience to track sales, create targeted emails, send abandoned cart emails, and more.
@@ -63,6 +63,14 @@ The Mailchimp for WooCommerce supports Wordpress Multi Sites and below are a few
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.3.1 =
67
  * adds fallback for mb_strpos if extension is not installed
68
  * implements communications box on sync page
3
  Tags: ecommerce,email,workflows,mailchimp
4
  Donate link: https://mailchimp.com
5
  Requires at least: 4.9
6
+ Tested up to: 5.3.2
7
+ Stable tag: 2.3.2
8
  Requires PHP: 7.0
9
  WC requires at least: 3.5
10
+ WC tested up to: 3.9
11
  License: GPLv2 or later
12
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
13
  Connect your store to your Mailchimp audience to track sales, create targeted emails, send abandoned cart emails, and more.
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.3.2 =
67
+ * update to action scheduler v3.0.1
68
+ * adds low-bandwidth setting on sync
69
+ * fixes audience defaults settings to Mailchimp not passed
70
+ * tweaks to review banner behavior
71
+ * required fields API update
72
+ * fix for orders with deleted products
73
+ * support for orders with 0 line items
74
  = 2.3.1 =
75
  * adds fallback for mb_strpos if extension is not installed
76
  * implements communications box on sync page
admin/class-mailchimp-woocommerce-admin.php CHANGED
@@ -66,6 +66,7 @@ class MailChimp_WooCommerce_Admin extends MailChimp_WooCommerce_Options {
66
  update_option('mailchimp-woocommerce-sync.started_at', false);
67
  update_option('mailchimp-woocommerce-sync.completed_at', false);
68
  update_option('mailchimp-woocommerce-resource-last-updated', false);
 
69
 
70
  if (($store_id = mailchimp_get_store_id()) && ($mc = mailchimp_get_api())) {
71
  if ($mc->deleteStore($store_id)) {
@@ -112,7 +113,9 @@ class MailChimp_WooCommerce_Admin extends MailChimp_WooCommerce_Options {
112
  */
113
  public function enqueue_scripts($hook) {
114
  if ( $hook === 'toplevel_page_mailchimp-woocommerce' ) {
115
- wp_enqueue_script( $this->plugin_name, plugin_dir_url( __FILE__ ) . 'js/mailchimp-woocommerce-admin.js', array( 'jquery', 'swal' ), $this->version, false );
 
 
116
  wp_enqueue_script('swal', "//cdn.jsdelivr.net/npm/sweetalert2@8", '', $this->version, false);
117
  }
118
  }
@@ -188,6 +191,7 @@ class MailChimp_WooCommerce_Admin extends MailChimp_WooCommerce_Options {
188
  *
189
  */
190
  public function options_update() {
 
191
 
192
  $this->handle_abandoned_cart_table();
193
 
@@ -195,8 +199,10 @@ class MailChimp_WooCommerce_Admin extends MailChimp_WooCommerce_Options {
195
 
196
  register_setting($this->plugin_name, $this->plugin_name, array($this, 'validate'));
197
 
198
- if (get_option('mailchimp-woocommerce-sync.initial_sync') == 1 && get_option('mailchimp-woocommerce-sync.completed_at') > 0 ) {
199
- $this->mailchimp_show_initial_sync_message();
 
 
200
  }
201
  }
202
 
@@ -828,6 +834,12 @@ class MailChimp_WooCommerce_Admin extends MailChimp_WooCommerce_Options {
828
 
829
  $data['active_tab'] = 'newsletter_settings';
830
 
 
 
 
 
 
 
831
  return $data;
832
  }
833
 
@@ -869,10 +881,6 @@ class MailChimp_WooCommerce_Admin extends MailChimp_WooCommerce_Options {
869
  'mailchimp_product_image_key' => isset($input['mailchimp_product_image_key']) ? $input['mailchimp_product_image_key'] : 'medium',
870
  );
871
 
872
- if ($data['mailchimp_list'] === 'create_new') {
873
- $data['mailchimp_list'] = $this->createMailChimpList(array_merge($this->getOptions(), $data));
874
- }
875
-
876
  // as long as we have a list set, and it's currently in MC as a valid list, let's sync the store.
877
  if (!empty($data['mailchimp_list']) && $this->api()->hasList($data['mailchimp_list'])) {
878
 
@@ -1199,7 +1207,7 @@ class MailChimp_WooCommerce_Admin extends MailChimp_WooCommerce_Options {
1199
  * @param null|array $data
1200
  * @return bool|string
1201
  */
1202
- private function createMailChimpList($data = null)
1203
  {
1204
  if (empty($data)) {
1205
  $data = $this->getOptions();
@@ -1213,6 +1221,7 @@ class MailChimp_WooCommerce_Admin extends MailChimp_WooCommerce_Options {
1213
 
1214
  foreach ($required as $requirement) {
1215
  if (!isset($data[$requirement]) || empty($data[$requirement])) {
 
1216
  return false;
1217
  }
1218
  }
@@ -1222,8 +1231,10 @@ class MailChimp_WooCommerce_Admin extends MailChimp_WooCommerce_Options {
1222
  // allow the subscribers to choose preferred email type (html or text).
1223
  $submission->setEmailTypeOption(true);
1224
 
1225
- // set the store name
1226
- $submission->setName($data['store_name']);
 
 
1227
 
1228
  // set the campaign defaults
1229
  $submission->setCampaignDefaults(
@@ -1243,16 +1254,24 @@ class MailChimp_WooCommerce_Admin extends MailChimp_WooCommerce_Options {
1243
 
1244
  $submission->setContact($this->address($data));
1245
 
 
 
 
1246
  try {
1247
- $response = $this->api()->createList($submission);
 
 
1248
 
1249
- $list_id = array_key_exists('id', $response) ? $response['id'] : false;
 
 
1250
 
1251
  $this->setData('errors.mailchimp_list', false);
1252
 
1253
  return $list_id;
1254
 
1255
  } catch (MailChimp_WooCommerce_Error $e) {
 
1256
  $this->setData('errors.mailchimp_list', $e->getMessage());
1257
  return false;
1258
  }
@@ -1315,9 +1334,10 @@ class MailChimp_WooCommerce_Admin extends MailChimp_WooCommerce_Options {
1315
  $this->setData($time_key, time());
1316
 
1317
  // on a new store push, we need to make sure we save the site script into a local variable.
1318
- if ($new) {
1319
- mailchimp_update_connected_site_script();
1320
- }
 
1321
 
1322
  return true;
1323
 
@@ -1473,14 +1493,6 @@ class MailChimp_WooCommerce_Admin extends MailChimp_WooCommerce_Options {
1473
  add_settings_error('mailchimp-woocommerce_notice', $this->plugin_name.'-initial-sync-end', $text, 'updated');
1474
  }
1475
 
1476
- /**
1477
- * Remove review banner.
1478
- */
1479
- public function mailchimp_woocommerce_remove_review_banner() {
1480
- $this->removeData('sync.initial_sync');
1481
- wp_die();
1482
- }
1483
-
1484
  /**
1485
  * set Communications status via sync page.
1486
  */
66
  update_option('mailchimp-woocommerce-sync.started_at', false);
67
  update_option('mailchimp-woocommerce-sync.completed_at', false);
68
  update_option('mailchimp-woocommerce-resource-last-updated', false);
69
+ update_option('mailchimp-woocommerce-empty_line_item_placeholder', false);
70
 
71
  if (($store_id = mailchimp_get_store_id()) && ($mc = mailchimp_get_api())) {
72
  if ($mc->deleteStore($store_id)) {
113
  */
114
  public function enqueue_scripts($hook) {
115
  if ( $hook === 'toplevel_page_mailchimp-woocommerce' ) {
116
+ wp_register_script( $this->plugin_name, plugin_dir_url( __FILE__ ) . 'js/mailchimp-woocommerce-admin.js', array( 'jquery', 'swal' ), $this->version, false );
117
+ wp_localize_script( $this->plugin_name, 'phpVars', array( 'removeReviewBannerRestUrl' => MailChimp_WooCommerce_Rest_Api::url('review-banner')) );
118
+ wp_enqueue_script( $this->plugin_name);
119
  wp_enqueue_script('swal', "//cdn.jsdelivr.net/npm/sweetalert2@8", '', $this->version, false);
120
  }
121
  }
191
  *
192
  */
193
  public function options_update() {
194
+ global $pagenow;
195
 
196
  $this->handle_abandoned_cart_table();
197
 
199
 
200
  register_setting($this->plugin_name, $this->plugin_name, array($this, 'validate'));
201
 
202
+ if ($pagenow == 'admin.php' && 'mailchimp-woocommerce' === $_GET['page']) {
203
+ if (get_option('mailchimp-woocommerce-sync.initial_sync') == 1 && get_option('mailchimp-woocommerce-sync.completed_at') > 0 ) {
204
+ $this->mailchimp_show_initial_sync_message();
205
+ }
206
  }
207
  }
208
 
834
 
835
  $data['active_tab'] = 'newsletter_settings';
836
 
837
+ $list_id = mailchimp_get_list_id();
838
+
839
+ if (!empty($list_id)) {
840
+ $this->updateMailChimpList(array_merge($this->getOptions(), $data), $list_id);
841
+ }
842
+
843
  return $data;
844
  }
845
 
881
  'mailchimp_product_image_key' => isset($input['mailchimp_product_image_key']) ? $input['mailchimp_product_image_key'] : 'medium',
882
  );
883
 
 
 
 
 
884
  // as long as we have a list set, and it's currently in MC as a valid list, let's sync the store.
885
  if (!empty($data['mailchimp_list']) && $this->api()->hasList($data['mailchimp_list'])) {
886
 
1207
  * @param null|array $data
1208
  * @return bool|string
1209
  */
1210
+ private function updateMailChimpList($data = null, $list_id = null)
1211
  {
1212
  if (empty($data)) {
1213
  $data = $this->getOptions();
1221
 
1222
  foreach ($required as $requirement) {
1223
  if (!isset($data[$requirement]) || empty($data[$requirement])) {
1224
+ mailchimp_log('admin', 'does not have enough data to update the mailchimp list.');
1225
  return false;
1226
  }
1227
  }
1231
  // allow the subscribers to choose preferred email type (html or text).
1232
  $submission->setEmailTypeOption(true);
1233
 
1234
+ // set the store name if the list id is not set.
1235
+ if (empty($list_id)) {
1236
+ $submission->setName($data['store_name']);
1237
+ }
1238
 
1239
  // set the campaign defaults
1240
  $submission->setCampaignDefaults(
1254
 
1255
  $submission->setContact($this->address($data));
1256
 
1257
+ // let's turn this on for debugging purposes.
1258
+ mailchimp_debug('admin', 'list info submission', array('submission' => print_r($submission->getSubmission(), true)));
1259
+
1260
  try {
1261
+ $response = !empty($list_id) ?
1262
+ $this->api()->updateList($list_id, $submission) :
1263
+ $this->api()->createList($submission);
1264
 
1265
+ if (empty($list_id)) {
1266
+ $list_id = array_key_exists('id', $response) ? $response['id'] : false;
1267
+ }
1268
 
1269
  $this->setData('errors.mailchimp_list', false);
1270
 
1271
  return $list_id;
1272
 
1273
  } catch (MailChimp_WooCommerce_Error $e) {
1274
+ mailchimp_error('admin', $e->getMessage());
1275
  $this->setData('errors.mailchimp_list', $e->getMessage());
1276
  return false;
1277
  }
1334
  $this->setData($time_key, time());
1335
 
1336
  // on a new store push, we need to make sure we save the site script into a local variable.
1337
+ mailchimp_update_connected_site_script();
1338
+
1339
+ // we need to update the list again with the campaign defaults
1340
+ $this->updateMailChimpList(null, $list_id);
1341
 
1342
  return true;
1343
 
1493
  add_settings_error('mailchimp-woocommerce_notice', $this->plugin_name.'-initial-sync-end', $text, 'updated');
1494
  }
1495
 
 
 
 
 
 
 
 
 
1496
  /**
1497
  * set Communications status via sync page.
1498
  */
admin/js/mailchimp-woocommerce-admin.js CHANGED
@@ -233,11 +233,13 @@
233
  // While the popup is open, wait. when closed, try to get status=accepted
234
  }
235
 
236
- // Mailchimp OAuth connection (tab "connect")
237
  $('#setting-error-mailchimp-woocommerce-initial-sync-end .notice-dismiss').click(function(e){
238
- var data = {action:'mailchimp_woocommerce_remove_review_banner'};
239
- $.get(ajaxurl, data);
 
240
  });
 
241
  $('#comm_box_switch').change(function (e){
242
  var switch_button = this;
243
  var opt = this.checked ? 1 : 0;
233
  // While the popup is open, wait. when closed, try to get status=accepted
234
  }
235
 
236
+ // Remove Initial Sync Banner oon dismiss
237
  $('#setting-error-mailchimp-woocommerce-initial-sync-end .notice-dismiss').click(function(e){
238
+ $.get(phpVars.removeReviewBannerRestUrl, [], function(response){
239
+ console.log(response);
240
+ });
241
  });
242
+
243
  $('#comm_box_switch').change(function (e){
244
  var switch_button = this;
245
  var opt = this.checked ? 1 : 0;
admin/partials/tabs/store_sync.php CHANGED
@@ -5,11 +5,6 @@ $store_id = mailchimp_get_store_id();
5
  $product_count = mailchimp_get_product_count();
6
  $order_count = mailchimp_get_order_count();
7
  $promo_rules_count = mailchimp_count_posts('shop_coupon');
8
- $subscribers_args = array(
9
- 'meta_key' => 'mailchimp_woocommerce_is_subscribed',
10
- 'meta_value' => true
11
- );
12
- $subscribers_count = get_users($subscribers_args);
13
 
14
  $mailchimp_total_products = $mailchimp_total_orders = $mailchimp_total_promo_rules = 0;
15
  $mailchimp_total_subscribers = $mailchimp_total_unsubscribed = $mailchimp_total_transactional = 0;
@@ -220,8 +215,8 @@ $comm_enabled = $opt != null ? $opt : '0';
220
  <h2 style="padding-top: 1em;"><?php esc_html_e('More Information', 'mailchimp-for-woocommerce'); ?></h2>
221
  <ul>
222
  <li><?= sprintf(/* translators: %s - Plugin review URL. */wp_kses( __( 'Is this plugin helping your e-commerce business? <a href=%s target=_blank>Please leave us a ★★★★★ review!</a>.', 'mailchimp-for-woocommerce' ), array( 'a' => array( 'href' => array(), 'target'=> '_blank' ) ) ), esc_url( 'https://wordpress.org/support/plugin/mailchimp-for-woocommerce/reviews/' ) );?></li>
223
- <li><?= sprintf(/* translators: %s - WP-CLI URL. */wp_kses( __( 'Have a larger store or having issues syncing? Consider using <a href=%s target=_blank>WP-CLI</a>.', 'mailchimp-for-woocommerce' ), array( 'a' => array( 'href' => array(), 'target'=> '_blank' ) ) ), esc_url( 'https://github.com/mailchimp/mc-woocommerce/issues/158' ) );?></li>
224
  <li><?= esc_html__('Order and customer information will not sync if they contain an Amazon or generic email address.', 'mailchimp-for-woocommerce');?></li>
225
- <li><?= sprintf(/* translators: %s - Mailchimp Support URL. */wp_kses( __( 'Need help to connect your store? Visit the Mailchimp <a href=%s target=_blank>Knowledge Base</a>.', 'mailchimp-for-woocommerce' ), array( 'a' => array( 'href' => array(), 'target'=> '_blank' ) ) ), esc_url( 'https://mailchimp.com/help/connect-or-disconnect-mailchimp-for-woocommerce/' ) );?></li>
226
  <li><?= sprintf(/* translators: %s - Mailchimp Privacy Policy URL. */wp_kses( __( 'By using this plugin, Mailchimp will process customer information in accordance with their <a href=%s target=_blank>Privacy Policy</a>.', 'mailchimp-for-woocommerce' ), array( 'a' => array( 'href' => array(), 'target'=> '_blank' ) ) ), esc_url( 'https://mailchimp.com/legal/privacy/' ) );?></li>
227
  </ul>
5
  $product_count = mailchimp_get_product_count();
6
  $order_count = mailchimp_get_order_count();
7
  $promo_rules_count = mailchimp_count_posts('shop_coupon');
 
 
 
 
 
8
 
9
  $mailchimp_total_products = $mailchimp_total_orders = $mailchimp_total_promo_rules = 0;
10
  $mailchimp_total_subscribers = $mailchimp_total_unsubscribed = $mailchimp_total_transactional = 0;
215
  <h2 style="padding-top: 1em;"><?php esc_html_e('More Information', 'mailchimp-for-woocommerce'); ?></h2>
216
  <ul>
217
  <li><?= sprintf(/* translators: %s - Plugin review URL. */wp_kses( __( 'Is this plugin helping your e-commerce business? <a href=%s target=_blank>Please leave us a ★★★★★ review!</a>.', 'mailchimp-for-woocommerce' ), array( 'a' => array( 'href' => array(), 'target'=> '_blank' ) ) ), esc_url( 'https://wordpress.org/support/plugin/mailchimp-for-woocommerce/reviews/' ) );?></li>
218
+ <li><?= sprintf(/* translators: %s - WP-CLI URL. */wp_kses( __( 'Have a larger store or having issues syncing? Consider using <a href=%s target=_blank>WP-CLI</a>.', 'mailchimp-for-woocommerce' ), array( 'a' => array( 'href' => array(), 'target'=> '_blank' ) ) ), esc_url( 'https://github.com/mailchimp/mc-woocommerce/wiki/Advanced-Queue-Setup-In-CLI-mode' ) );?></li>
219
  <li><?= esc_html__('Order and customer information will not sync if they contain an Amazon or generic email address.', 'mailchimp-for-woocommerce');?></li>
220
+ <li><?= sprintf(/* translators: %s - Mailchimp Support URL. */wp_kses( __( 'Need help? Visit Mailchimp <a href=%s target=_blank>support</a>.', 'mailchimp-for-woocommerce' ), array( 'a' => array( 'href' => array(), 'target'=> '_blank' ) ) ), esc_url( 'https://us1.admin.mailchimp.com/support?support_key=woo_forum' ) );?></li>
221
  <li><?= sprintf(/* translators: %s - Mailchimp Privacy Policy URL. */wp_kses( __( 'By using this plugin, Mailchimp will process customer information in accordance with their <a href=%s target=_blank>Privacy Policy</a>.', 'mailchimp-for-woocommerce' ), array( 'a' => array( 'href' => array(), 'target'=> '_blank' ) ) ), esc_url( 'https://mailchimp.com/legal/privacy/' ) );?></li>
222
  </ul>
bootstrap.php CHANGED
@@ -67,9 +67,6 @@ spl_autoload_register(function($class) {
67
 
68
  'MailChimp_WooCommerce_Public' => 'public/class-mailchimp-woocommerce-public.php',
69
  'MailChimp_WooCommerce_Admin' => 'admin/class-mailchimp-woocommerce-admin.php',
70
-
71
- // Queue system Action Scheduler
72
- 'ActionScheduler' => 'includes/vendor/action-scheduler/action-scheduler.php',
73
  );
74
 
75
  // if the file exists, require it
@@ -77,6 +74,9 @@ spl_autoload_register(function($class) {
77
  if (array_key_exists($class, $classes) && file_exists($path.$classes[$class])) {
78
  require $path.$classes[$class];
79
  }
 
 
 
80
  });
81
 
82
  /**
@@ -90,7 +90,7 @@ function mailchimp_environment_variables() {
90
  return (object) array(
91
  'repo' => 'master',
92
  'environment' => 'production', // staging or production
93
- 'version' => '2.3.1',
94
  'php_version' => phpversion(),
95
  'wp_version' => (empty($wp_version) ? 'Unknown' : $wp_version),
96
  'wc_version' => function_exists('WC') ? WC()->version : null,
@@ -596,11 +596,11 @@ function mailchimp_get_order_count() {
596
  function mailchimp_count_posts($type) {
597
  global $wpdb;
598
  if ($type === 'shop_order') {
599
- $query = "SELECT post_status, COUNT( * ) AS num_posts FROM {$wpdb->posts} WHERE post_type = %s AND post_status = %s GROUP BY post_status";
600
  $posts = $wpdb->get_results( $wpdb->prepare($query, $type, 'wc-completed'));
601
  } else {
602
- $query = "SELECT post_status, COUNT( * ) AS num_posts FROM {$wpdb->posts} WHERE post_type = %s GROUP BY post_status";
603
- $posts = $wpdb->get_results( $wpdb->prepare($query, $type));
604
  }
605
 
606
  $response = array();
@@ -924,6 +924,7 @@ function mailchimp_clean_database() {
924
  delete_option('mailchimp-woocommerce-cached-api-lists');
925
  delete_option('mailchimp-woocommerce-cached-api-ping-check');
926
  delete_option('mailchimp-woocommerce-errors.store_info');
 
927
  }
928
 
929
  /**
67
 
68
  'MailChimp_WooCommerce_Public' => 'public/class-mailchimp-woocommerce-public.php',
69
  'MailChimp_WooCommerce_Admin' => 'admin/class-mailchimp-woocommerce-admin.php',
 
 
 
70
  );
71
 
72
  // if the file exists, require it
74
  if (array_key_exists($class, $classes) && file_exists($path.$classes[$class])) {
75
  require $path.$classes[$class];
76
  }
77
+
78
+ // require Action Scheduler
79
+ include_once "includes/vendor/action-scheduler/action-scheduler.php";
80
  });
81
 
82
  /**
90
  return (object) array(
91
  'repo' => 'master',
92
  'environment' => 'production', // staging or production
93
+ 'version' => '2.3.2',
94
  'php_version' => phpversion(),
95
  'wp_version' => (empty($wp_version) ? 'Unknown' : $wp_version),
96
  'wc_version' => function_exists('WC') ? WC()->version : null,
596
  function mailchimp_count_posts($type) {
597
  global $wpdb;
598
  if ($type === 'shop_order') {
599
+ $query = "SELECT post_status, COUNT( * ) AS num_posts FROM {$wpdb->posts} WHERE post_type = %s AND post_status = %s";
600
  $posts = $wpdb->get_results( $wpdb->prepare($query, $type, 'wc-completed'));
601
  } else {
602
+ $query = "SELECT post_status, COUNT( * ) AS num_posts FROM {$wpdb->posts} WHERE post_type = %s AND post_status = %s";
603
+ $posts = $wpdb->get_results( $wpdb->prepare($query, $type, 'publish'));
604
  }
605
 
606
  $response = array();
924
  delete_option('mailchimp-woocommerce-cached-api-lists');
925
  delete_option('mailchimp-woocommerce-cached-api-ping-check');
926
  delete_option('mailchimp-woocommerce-errors.store_info');
927
+ delete_option('mailchimp-woocommerce-empty_line_item_placeholder');
928
  }
929
 
930
  /**
includes/api/assets/class-mailchimp-line-item.php CHANGED
@@ -15,6 +15,8 @@ class MailChimp_WooCommerce_LineItem
15
  protected $product_variant_id;
16
  protected $quantity;
17
  protected $price;
 
 
18
 
19
  /**
20
  * @return array
@@ -145,6 +147,42 @@ class MailChimp_WooCommerce_LineItem
145
  return $this;
146
  }
147
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
148
  /**
149
  * @return array
150
  */
15
  protected $product_variant_id;
16
  protected $quantity;
17
  protected $price;
18
+ protected $fallback_title = null;
19
+ protected $fallback_sku = null;
20
 
21
  /**
22
  * @return array
147
  return $this;
148
  }
149
 
150
+ /**
151
+ * @param $fallback
152
+ * @return $this
153
+ */
154
+ public function setFallbackTitle($fallback)
155
+ {
156
+ $this->fallback_title = $fallback;
157
+ return $this;
158
+ }
159
+
160
+ /**
161
+ * @return null
162
+ */
163
+ public function getFallbackTitle()
164
+ {
165
+ return $this->fallback_title;
166
+ }
167
+
168
+ /**
169
+ * @param $fallback
170
+ * @return $this
171
+ */
172
+ public function setFallbackSku($fallback)
173
+ {
174
+ $this->fallback_sku = $fallback;
175
+ return $this;
176
+ }
177
+
178
+ /**
179
+ * @return null
180
+ */
181
+ public function getFallbackSku()
182
+ {
183
+ return $this->fallback_sku;
184
+ }
185
+
186
  /**
187
  * @return array
188
  */
includes/api/class-mailchimp-api.php CHANGED
@@ -221,7 +221,7 @@ class MailChimp_WooCommerce_MailChimpApi
221
 
222
  mailchimp_debug('api.subscribe', "Subscribing {$email}", $data);
223
 
224
- return $this->post("lists/$list_id/members", $data);
225
  }
226
 
227
  /**
@@ -270,7 +270,7 @@ class MailChimp_WooCommerce_MailChimpApi
270
 
271
  mailchimp_debug('api.update_member', "Updating {$email}", $data);
272
 
273
- return $this->patch("lists/$list_id/members/$hash", $data);
274
  }
275
 
276
  /**
@@ -324,9 +324,9 @@ class MailChimp_WooCommerce_MailChimpApi
324
  {
325
  $hash = md5(strtolower(trim($email)));
326
  $tags = mailchimp_get_user_tags_to_update();
327
-
328
  if (empty($tags)) return false;
329
-
330
  $data = array(
331
  'tags' => $tags
332
  );
@@ -409,6 +409,19 @@ class MailChimp_WooCommerce_MailChimpApi
409
  return $this->post('lists', $submission->getSubmission());
410
  }
411
 
 
 
 
 
 
 
 
 
 
 
 
 
 
412
  /**
413
  * @param bool $as_list
414
  * @param int $count
@@ -1038,7 +1051,7 @@ class MailChimp_WooCommerce_MailChimpApi
1038
  }
1039
  $order_id = $order->getId();
1040
  $data = $this->patch("ecommerce/stores/{$store_id}/orders/{$order_id}", $order->toArray());
1041
-
1042
  //update user tags
1043
  $email_address = $order->getCustomer()->getEmailAddress();
1044
 
@@ -1221,14 +1234,50 @@ class MailChimp_WooCommerce_MailChimpApi
1221
  $missing_products = array();
1222
  foreach ($order->items() as $order_item) {
1223
  /** @var \MailChimp_WooCommerce_LineItem $order_item */
1224
- $job = new MailChimp_WooCommerce_Single_Product($order_item->getId());
1225
- if ($missing_products[$order_item->getId()] = $job->createModeOnly()->handle()) {
 
1226
  mailchimp_debug("missing_products.fallback", "Product {$order_item->getId()} had to be re-pushed into Mailchimp");
1227
  }
1228
  }
1229
  return $missing_products;
1230
  }
1231
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1232
  /**
1233
  * @param $store_id
1234
  * @param $product_id
@@ -1736,6 +1785,7 @@ class MailChimp_WooCommerce_MailChimpApi
1736
  if ($http_code == 403) {
1737
  throw new MailChimp_WooCommerce_RateLimitError();
1738
  }
 
1739
  throw new MailChimp_WooCommerce_Error($data['title'] .' :: '.$data['detail'], $data['status']);
1740
  }
1741
 
221
 
222
  mailchimp_debug('api.subscribe', "Subscribing {$email}", $data);
223
 
224
+ return $this->post("lists/$list_id/members?skip_merge_validation=true", $data);
225
  }
226
 
227
  /**
270
 
271
  mailchimp_debug('api.update_member', "Updating {$email}", $data);
272
 
273
+ return $this->patch("lists/$list_id/members/$hash?skip_merge_validation=true", $data);
274
  }
275
 
276
  /**
324
  {
325
  $hash = md5(strtolower(trim($email)));
326
  $tags = mailchimp_get_user_tags_to_update();
327
+
328
  if (empty($tags)) return false;
329
+
330
  $data = array(
331
  'tags' => $tags
332
  );
409
  return $this->post('lists', $submission->getSubmission());
410
  }
411
 
412
+ /**
413
+ * @param string $list_id
414
+ * @param MailChimp_WooCommerce_CreateListSubmission $submission
415
+ * @return array|mixed|null|object
416
+ * @throws Exception
417
+ * @throws MailChimp_WooCommerce_Error
418
+ * @throws MailChimp_WooCommerce_ServerError
419
+ */
420
+ public function updateList($list_id, MailChimp_WooCommerce_CreateListSubmission $submission)
421
+ {
422
+ return $this->patch("lists/{$list_id}", $submission->getSubmission());
423
+ }
424
+
425
  /**
426
  * @param bool $as_list
427
  * @param int $count
1051
  }
1052
  $order_id = $order->getId();
1053
  $data = $this->patch("ecommerce/stores/{$store_id}/orders/{$order_id}", $order->toArray());
1054
+
1055
  //update user tags
1056
  $email_address = $order->getCustomer()->getEmailAddress();
1057
 
1234
  $missing_products = array();
1235
  foreach ($order->items() as $order_item) {
1236
  /** @var \MailChimp_WooCommerce_LineItem $order_item */
1237
+ // get the line item name from the order detail just in case we need that title for the product.
1238
+ $job = new MailChimp_WooCommerce_Single_Product($order_item->getProductId(), $order_item->getFallbackTitle());
1239
+ if ($missing_products[$order_item->getId()] = $job->createModeOnly()->fromOrderItem($order_item)->handle()) {
1240
  mailchimp_debug("missing_products.fallback", "Product {$order_item->getId()} had to be re-pushed into Mailchimp");
1241
  }
1242
  }
1243
  return $missing_products;
1244
  }
1245
 
1246
+ /**
1247
+ * @return MailChimp_WooCommerce_Product
1248
+ */
1249
+ public function createEmptyLineItemProductPlaceholder()
1250
+ {
1251
+ $product = new MailChimp_WooCommerce_Product();
1252
+ $product->setId('empty_line_item_placeholder');
1253
+ $product->setTitle('Empty Line Item Placeholder');
1254
+ $product->setVendor('deleted');
1255
+
1256
+ $variation = new MailChimp_WooCommerce_ProductVariation();
1257
+ $variation->setId($product->getId());
1258
+ $variation->setTitle($product->getTitle());
1259
+ $variation->setInventoryQuantity(0);
1260
+ $variation->setVisibility('hidden');
1261
+ $variation->setPrice(1);
1262
+
1263
+ $product->addVariant($variation);
1264
+
1265
+ if ((bool) mailchimp_get_data('empty_line_item_placeholder', false)) {
1266
+ return $product;
1267
+ }
1268
+
1269
+ $store_id = mailchimp_get_store_id();
1270
+ $api = mailchimp_get_api();
1271
+
1272
+ try {
1273
+ $response = $api->addStoreProduct($store_id, $product);
1274
+ mailchimp_set_data('empty_line_item_placeholder', true, 'yes');
1275
+ return $response;
1276
+ } catch (\Exception $e) {
1277
+ return $product;
1278
+ }
1279
+ }
1280
+
1281
  /**
1282
  * @param $store_id
1283
  * @param $product_id
1785
  if ($http_code == 403) {
1786
  throw new MailChimp_WooCommerce_RateLimitError();
1787
  }
1788
+
1789
  throw new MailChimp_WooCommerce_Error($data['title'] .' :: '.$data['detail'], $data['status']);
1790
  }
1791
 
includes/api/class-mailchimp-woocommerce-transform-orders-wc3.php CHANGED
@@ -185,13 +185,27 @@ class MailChimp_WooCommerce_Transform_Orders
185
  // add it into the order item container.
186
  $item = $this->transformLineItem($key, $order_detail);
187
 
 
 
 
 
 
 
 
 
 
 
 
 
 
188
  // if we don't have a product post with this id, we need to add a deleted product to the MC side
189
- if (!($product = $order_detail->get_product()) || 'trash' === $product->get_status()) {
190
 
191
  $pid = $order_detail->get_product_id();
192
-
 
193
  try {
194
- $deleted_product = MailChimp_WooCommerce_Transform_Products::deleted($pid);
195
  } catch (\Exception $e) {
196
  mailchimp_log('order.items.error', "Order #{$woo->get_id()} :: Product {$pid} does not exist!");
197
  continue;
@@ -202,7 +216,7 @@ class MailChimp_WooCommerce_Transform_Orders
202
  // swap out the old item id and product variant id with the deleted version.
203
  $item->setProductId("deleted_{$pid}");
204
  $item->setProductVariantId("deleted_{$pid}");
205
-
206
  // add the item and continue on the loop.
207
  $order->addItem($item);
208
  continue;
@@ -297,6 +311,10 @@ class MailChimp_WooCommerce_Transform_Orders
297
  $item = new MailChimp_WooCommerce_LineItem();
298
  $item->setId($key);
299
 
 
 
 
 
300
  $item->setPrice($order_detail->get_total());
301
  $item->setProductId($order_detail->get_product_id());
302
  $variation_id = $order_detail->get_variation_id();
@@ -420,7 +438,7 @@ class MailChimp_WooCommerce_Transform_Orders
420
  foreach ($orders as $order) {
421
  $order = wc_get_order($order);
422
 
423
- if ($order->get_status() !== 'cancelled' && $order->is_paid()) {
424
  $stats->total += $order->get_total();
425
  $stats->count ++;
426
  }
185
  // add it into the order item container.
186
  $item = $this->transformLineItem($key, $order_detail);
187
 
188
+ $product = $order_detail->get_product();
189
+
190
+ // if we can't find the product, we need to populate this
191
+ if (empty($product)) {
192
+ if (($empty_order_item = MailChimp_WooCommerce_Transform_Products::missing_order_item($order_detail))) {
193
+ $item->setFallbackTitle($empty_order_item->getTitle());
194
+ $item->setProductId($empty_order_item->getId());
195
+ $item->setProductVariantId($empty_order_item->getId());
196
+ $order->addItem($item);
197
+ continue;
198
+ }
199
+ }
200
+
201
  // if we don't have a product post with this id, we need to add a deleted product to the MC side
202
+ if (!$product || ($trashed = 'trash' === $product->get_status())) {
203
 
204
  $pid = $order_detail->get_product_id();
205
+ $title = $order_detail->get_name();
206
+
207
  try {
208
+ $deleted_product = MailChimp_WooCommerce_Transform_Products::deleted($pid, $title);
209
  } catch (\Exception $e) {
210
  mailchimp_log('order.items.error', "Order #{$woo->get_id()} :: Product {$pid} does not exist!");
211
  continue;
216
  // swap out the old item id and product variant id with the deleted version.
217
  $item->setProductId("deleted_{$pid}");
218
  $item->setProductVariantId("deleted_{$pid}");
219
+
220
  // add the item and continue on the loop.
221
  $order->addItem($item);
222
  continue;
311
  $item = new MailChimp_WooCommerce_LineItem();
312
  $item->setId($key);
313
 
314
+ // set the fallback title for the order detail name just in case we need to create a product
315
+ // from this order item.
316
+ $item->setFallbackTitle($order_detail->get_name());
317
+
318
  $item->setPrice($order_detail->get_total());
319
  $item->setProductId($order_detail->get_product_id());
320
  $variation_id = $order_detail->get_variation_id();
438
  foreach ($orders as $order) {
439
  $order = wc_get_order($order);
440
 
441
+ if ($order->get_status() !== 'cancelled' && (method_exists($order, 'is_paid') && $order->is_paid())) {
442
  $stats->total += $order->get_total();
443
  $stats->count ++;
444
  }
includes/api/class-mailchimp-woocommerce-transform-products.php CHANGED
@@ -38,14 +38,40 @@ class MailChimp_WooCommerce_Transform_Products
38
  return $response;
39
  }
40
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
41
  /**
42
  * @param WP_Post $post
43
  * @return MailChimp_WooCommerce_Product
44
  */
45
- public function transform(WP_Post $post)
46
  {
47
  if (!($woo = wc_get_product($post))) {
48
- return $this->wooProductNotLoadedCorrectly($post);
49
  }
50
 
51
  $variant_posts = $this->getProductVariantPosts($post->ID);
@@ -132,6 +158,14 @@ class MailChimp_WooCommerce_Transform_Products
132
  $variant->setSku($woo->get_sku());
133
  $variant->setBackorders($woo->backorders_allowed());
134
 
 
 
 
 
 
 
 
 
135
  // only set these properties if the product is currently visible or purchasable.
136
  if ($woo->is_purchasable() && $woo->is_visible()) {
137
  if ($woo->is_in_stock()) {
@@ -183,7 +217,7 @@ class MailChimp_WooCommerce_Transform_Products
183
  $params = array(
184
  'post_type' => array_merge(array_keys(wc_get_product_types()), array('product')),
185
  'posts_per_page' => $posts,
186
- 'post_status' => 'publish',
187
  'offset' => $offset,
188
  'orderby' => 'ID',
189
  'order' => 'ASC',
@@ -209,12 +243,10 @@ class MailChimp_WooCommerce_Transform_Products
209
  public function getProductVariantPosts($id)
210
  {
211
  $variants = get_posts(array(
212
- 'numberposts' => 99999,
213
- 'order' => 'ASC',
214
- 'orderby' => 'ID',
215
  'post_type' => 'product_variation',
216
- 'post_parent' => $id,
217
- 'post_status' => 'publish',
 
218
  ));
219
 
220
  if (empty($variants)) {
@@ -255,20 +287,59 @@ class MailChimp_WooCommerce_Transform_Products
255
  * @return bool|MailChimp_WooCommerce_Product
256
  * @throws Exception
257
  */
258
- public static function deleted($id)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
259
  {
 
 
 
260
  $store_id = mailchimp_get_store_id();
261
  $api = mailchimp_get_api();
262
 
 
 
 
 
263
  if (!($product = $api->getStoreProduct($store_id, "deleted_{$id}"))) {
264
  $product = new MailChimp_WooCommerce_Product();
265
 
266
  $product->setId("deleted_{$id}");
267
- $product->setTitle("deleted_{$id}");
268
 
269
  $variant = new MailChimp_WooCommerce_ProductVariation();
270
- $variant->setId("deleted_{$id}");
271
- $variant->setTitle("deleted_{$id}");
 
 
272
 
273
  $product->addVariant($variant);
274
 
@@ -280,9 +351,10 @@ class MailChimp_WooCommerce_Transform_Products
280
 
281
  /**
282
  * @param \WP_Post $post
 
283
  * @return MailChimp_WooCommerce_Product
284
  */
285
- protected function wooProductNotLoadedCorrectly($post)
286
  {
287
  $product = new MailChimp_WooCommerce_Product();
288
  $product->setId($post->ID);
@@ -290,7 +362,7 @@ class MailChimp_WooCommerce_Transform_Products
290
  $product->setDescription($post->post_content);
291
  $product->setImageUrl($this->getProductImage($post));
292
 
293
- $variant = $this->variant($post, $post->post_name);
294
 
295
  if (!$variant->getImageUrl()) {
296
  $variant->setImageUrl($product->getImageUrl());
38
  return $response;
39
  }
40
 
41
+ /**
42
+ * @param MailChimp_WooCommerce_LineItem $item
43
+ * @return MailChimp_WooCommerce_Product
44
+ */
45
+ public function fromOrderItem(MailChimp_WooCommerce_LineItem $item)
46
+ {
47
+ $product = new MailChimp_WooCommerce_Product();
48
+
49
+ $fallback_title = $item->getFallbackTitle();
50
+ if (empty($fallback_title)) $fallback_title = "deleted_{$item->getProductId()}";
51
+
52
+ $product->setId($item->getProductId());
53
+ $product->setTitle($fallback_title);
54
+
55
+ $variant = new MailChimp_WooCommerce_ProductVariation();
56
+ $variant->setId($item->getProductId());
57
+ $variant->setTitle($fallback_title);
58
+ $variant->setInventoryQuantity(0);
59
+ $variant->setVisibility('hidden');
60
+ $variant->setSku($item->getFallbackSku());
61
+
62
+ $product->addVariant($variant);
63
+
64
+ return $product;
65
+ }
66
+
67
  /**
68
  * @param WP_Post $post
69
  * @return MailChimp_WooCommerce_Product
70
  */
71
+ public function transform(WP_Post $post, $fallback_title = null)
72
  {
73
  if (!($woo = wc_get_product($post))) {
74
+ return $this->wooProductNotLoadedCorrectly($post, $fallback_title);
75
  }
76
 
77
  $variant_posts = $this->getProductVariantPosts($post->ID);
158
  $variant->setSku($woo->get_sku());
159
  $variant->setBackorders($woo->backorders_allowed());
160
 
161
+ if (empty($variant->getTitle())) {
162
+ if (!empty($fallback_title)) {
163
+ $variant->setTitle($fallback_title);
164
+ } elseif (!empty($variant->getSku())) {
165
+ $variant->setTitle($variant->getSku());
166
+ }
167
+ }
168
+
169
  // only set these properties if the product is currently visible or purchasable.
170
  if ($woo->is_purchasable() && $woo->is_visible()) {
171
  if ($woo->is_in_stock()) {
217
  $params = array(
218
  'post_type' => array_merge(array_keys(wc_get_product_types()), array('product')),
219
  'posts_per_page' => $posts,
220
+ 'post_status' => array('private', 'publish', 'draft'),
221
  'offset' => $offset,
222
  'orderby' => 'ID',
223
  'order' => 'ASC',
243
  public function getProductVariantPosts($id)
244
  {
245
  $variants = get_posts(array(
 
 
 
246
  'post_type' => 'product_variation',
247
+ 'post_status' => array('private', 'publish', 'draft'),
248
+ 'numberposts' => -1,
249
+ 'post_parent' => $id
250
  ));
251
 
252
  if (empty($variants)) {
287
  * @return bool|MailChimp_WooCommerce_Product
288
  * @throws Exception
289
  */
290
+ public static function deleted($id, $title)
291
+ {
292
+ $store_id = mailchimp_get_store_id();
293
+ $api = mailchimp_get_api();
294
+
295
+ if (!($product = $api->getStoreProduct($store_id, "deleted_{$id}"))) {
296
+ $product = new MailChimp_WooCommerce_Product();
297
+
298
+ $product->setId("deleted_{$id}");
299
+ $product->setTitle($title);
300
+
301
+ $variant = new MailChimp_WooCommerce_ProductVariation();
302
+ $variant->setId($product->getId());
303
+ $variant->setTitle($title);
304
+ $variant->setInventoryQuantity(0);
305
+ $variant->setVisibility('hidden');
306
+
307
+ $product->addVariant($variant);
308
+
309
+ return $api->addStoreProduct($store_id, $product);
310
+ }
311
+
312
+ return $product;
313
+ }
314
+
315
+ /**
316
+ * @param $id
317
+ * @return bool|MailChimp_WooCommerce_Product
318
+ * @throws Exception
319
+ */
320
+ public static function missing_order_item($item)
321
  {
322
+ // we can only do this with an order item
323
+ if (!$item instanceof WC_Order_Item_Product) return false;
324
+
325
  $store_id = mailchimp_get_store_id();
326
  $api = mailchimp_get_api();
327
 
328
+ $id = $item->get_product_id();
329
+ $title = $item->get_name();
330
+
331
+ // only do this if we haven't pushed this product ID up yet to Mailchimp
332
  if (!($product = $api->getStoreProduct($store_id, "deleted_{$id}"))) {
333
  $product = new MailChimp_WooCommerce_Product();
334
 
335
  $product->setId("deleted_{$id}");
336
+ $product->setTitle($title);
337
 
338
  $variant = new MailChimp_WooCommerce_ProductVariation();
339
+ $variant->setId($product->getId());
340
+ $variant->setTitle($title);
341
+ $variant->setInventoryQuantity(0);
342
+ $variant->setVisibility('hidden');
343
 
344
  $product->addVariant($variant);
345
 
351
 
352
  /**
353
  * @param \WP_Post $post
354
+ * @param string|null $fallback_title
355
  * @return MailChimp_WooCommerce_Product
356
  */
357
+ protected function wooProductNotLoadedCorrectly($post, $fallback_title = null)
358
  {
359
  $product = new MailChimp_WooCommerce_Product();
360
  $product->setId($post->ID);
362
  $product->setDescription($post->post_content);
363
  $product->setImageUrl($this->getProductImage($post));
364
 
365
+ $variant = $this->variant($post, ($post->post_name ? $post->post_name : $fallback_title));
366
 
367
  if (!$variant->getImageUrl()) {
368
  $variant->setImageUrl($product->getImageUrl());
includes/class-mailchimp-woocommerce-rest-api.php CHANGED
@@ -17,33 +17,32 @@ class MailChimp_WooCommerce_Rest_Api
17
  */
18
  public function register_routes()
19
  {
20
- $this->register_ping();
21
- $this->register_survey_routes();
22
- $this->register_sync_stats();
23
- }
24
-
25
- /**
26
- * Ping
27
- */
28
- protected function register_ping()
29
- {
30
  register_rest_route(static::$namespace, '/ping', array(
31
  'methods' => 'GET',
32
  'callback' => array($this, 'ping'),
33
  ));
34
- }
35
 
36
- /**
37
- * Right now we only have a survey disconnect endpoint.
38
- */
39
- protected function register_survey_routes()
40
- {
41
  register_rest_route(static::$namespace, "/survey/disconnect", array(
42
  'methods' => 'POST',
43
  'callback' => array($this, 'post_disconnect_survey'),
44
  ));
45
- }
46
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
47
 
48
  /**
49
  * @param WP_REST_Request $request
@@ -54,20 +53,6 @@ class MailChimp_WooCommerce_Rest_Api
54
  return $this->mailchimp_rest_response(array('success' => true));
55
  }
56
 
57
- /**
58
- * Ping
59
- */
60
- protected function register_sync_stats()
61
- {
62
- if (mailchimp_get_allowed_capability()) {
63
- register_rest_route(static::$namespace, '/sync/stats', array(
64
- 'methods' => 'GET',
65
- 'callback' => array($this, 'get_sync_stats'),
66
- ));
67
- }
68
- }
69
-
70
-
71
  /**
72
  * @param WP_REST_Request $request
73
  * @return WP_REST_Response
@@ -143,6 +128,16 @@ class MailChimp_WooCommerce_Rest_Api
143
  'has_finished' => mailchimp_is_done_syncing(),
144
  ));
145
  }
 
 
 
 
 
 
 
 
 
 
146
 
147
  /**
148
  * @param array $data
17
  */
18
  public function register_routes()
19
  {
20
+ // ping
 
 
 
 
 
 
 
 
 
21
  register_rest_route(static::$namespace, '/ping', array(
22
  'methods' => 'GET',
23
  'callback' => array($this, 'ping'),
24
  ));
 
25
 
26
+ // Right now we only have a survey disconnect endpoint.
 
 
 
 
27
  register_rest_route(static::$namespace, "/survey/disconnect", array(
28
  'methods' => 'POST',
29
  'callback' => array($this, 'post_disconnect_survey'),
30
  ));
 
31
 
32
+ // Sync Stats
33
+ if (mailchimp_get_allowed_capability()) {
34
+ register_rest_route(static::$namespace, '/sync/stats', array(
35
+ 'methods' => 'GET',
36
+ 'callback' => array($this, 'get_sync_stats'),
37
+ ));
38
+ }
39
+
40
+ // remove review banner
41
+ register_rest_route(static::$namespace, "/review-banner", array(
42
+ 'methods' => 'GET',
43
+ 'callback' => array($this, 'dismiss_review_banner'),
44
+ ));
45
+ }
46
 
47
  /**
48
  * @param WP_REST_Request $request
53
  return $this->mailchimp_rest_response(array('success' => true));
54
  }
55
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
56
  /**
57
  * @param WP_REST_Request $request
58
  * @return WP_REST_Response
128
  'has_finished' => mailchimp_is_done_syncing(),
129
  ));
130
  }
131
+
132
+ /**
133
+ * @param WP_REST_Request $request
134
+ * @return WP_Error|WP_REST_Response
135
+ */
136
+ public function dismiss_review_banner(WP_REST_Request $request)
137
+ {
138
+ return $this->mailchimp_rest_response(array('success' => delete_option('mailchimp-woocommerce-sync.initial_sync')));
139
+ }
140
+
141
 
142
  /**
143
  * @param array $data
includes/class-mailchimp-woocommerce.php CHANGED
@@ -259,11 +259,8 @@ class MailChimp_WooCommerce
259
  // add Shop Manager capability to save options
260
  $this->loader->add_action('option_page_capability_mailchimp-woocommerce', $plugin_admin, 'mailchimp_woocommerce_option_page_capability');
261
 
262
- // remove initial sync "leave a review" banner on notice dismiss
263
- $this->loader->add_action( 'wp_ajax_mailchimp_woocommerce_remove_review_banner', $plugin_admin, 'mailchimp_woocommerce_remove_review_banner' );
264
-
265
- // set communications box status
266
- $this->loader->add_action( 'wp_ajax_mailchimp_woocommerce_communication_status', $plugin_admin, 'mailchimp_woocommerce_communication_status' );
267
  }
268
 
269
  /**
@@ -277,6 +274,7 @@ class MailChimp_WooCommerce
277
 
278
  $plugin_public = new MailChimp_WooCommerce_Public( $this->get_plugin_name(), $this->get_version() );
279
  $this->loader->add_action('wp_enqueue_scripts', $plugin_public, 'enqueue_scripts');
 
280
  }
281
 
282
  /**
259
  // add Shop Manager capability to save options
260
  $this->loader->add_action('option_page_capability_mailchimp-woocommerce', $plugin_admin, 'mailchimp_woocommerce_option_page_capability');
261
 
262
+ // set communications box status
263
+ $this->loader->add_action( 'wp_ajax_mailchimp_woocommerce_communication_status', $plugin_admin, 'mailchimp_woocommerce_communication_status' );
 
 
 
264
  }
265
 
266
  /**
274
 
275
  $plugin_public = new MailChimp_WooCommerce_Public( $this->get_plugin_name(), $this->get_version() );
276
  $this->loader->add_action('wp_enqueue_scripts', $plugin_public, 'enqueue_scripts');
277
+ $this->loader->add_action('wp_footer', $plugin_public, 'add_inline_footer_script');
278
  }
279
 
280
  /**
includes/processes/class-mailchimp-woocommerce-process-orders.php CHANGED
@@ -55,7 +55,8 @@ class MailChimp_WooCommerce_Process_Orders extends MailChimp_WooCommerce_Abstrac
55
  mailchimp_error('order_sync.error', mailchimp_error_trace($e, "GET subscriber :: {$item->getId()}"));
56
  throw $e;
57
  }
58
- $status = $should_auto_subscribe;
 
59
  }
60
  $item->getCustomer()->setOptInStatus($status);
61
  }
@@ -80,6 +81,28 @@ class MailChimp_WooCommerce_Process_Orders extends MailChimp_WooCommerce_Abstrac
80
  return false;
81
  }
82
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
83
  mailchimp_debug('order_sync', "#{$item->getId()}", $item->toArray());
84
 
85
  try {
55
  mailchimp_error('order_sync.error', mailchimp_error_trace($e, "GET subscriber :: {$item->getId()}"));
56
  throw $e;
57
  }
58
+ // if they are using double opt in, we need to pass this in as false here so it doesn't auto subscribe.
59
+ $status = mailchimp_list_has_double_optin() ? false : $should_auto_subscribe;
60
  }
61
  $item->getCustomer()->setOptInStatus($status);
62
  }
81
  return false;
82
  }
83
 
84
+ $line_items = $item->items();
85
+
86
+ // if we don't have any line items, we need to create the mailchimp product
87
+ // with a price of 1.00 and we'll use the inventory quantity to adjust correctly.
88
+ if (empty($line_items) || !count($line_items)) {
89
+
90
+ // this will create an empty product placeholder, or return the pre populated version if already
91
+ // sent to Mailchimp.
92
+ $product = $this->mailchimp()->createEmptyLineItemProductPlaceholder();
93
+
94
+ $line_item = new MailChimp_WooCommerce_LineItem();
95
+ $line_item->setId($product->getId());
96
+ $line_item->setPrice(1);
97
+ $line_item->setProductId($product->getId());
98
+ $line_item->setProductVariantId($product->getId());
99
+ $line_item->setQuantity((int) $item->getOrderTotal());
100
+
101
+ $item->addItem($line_item);
102
+
103
+ mailchimp_log('order_sync.error', "order {$item->getId()} does not have any line items, so we are using 'empty_line_item_placeholder' instead.");
104
+ }
105
+
106
  mailchimp_debug('order_sync', "#{$item->getId()}", $item->toArray());
107
 
108
  try {
includes/processes/class-mailchimp-woocommerce-single-product.php CHANGED
@@ -11,18 +11,21 @@
11
  class MailChimp_WooCommerce_Single_Product extends Mailchimp_Woocommerce_Job
12
  {
13
  public $id;
 
14
  protected $store_id;
15
  protected $api;
16
  protected $service;
17
  protected $mode = 'update_or_create';
 
18
 
19
  /**
20
  * MailChimp_WooCommerce_Single_product constructor.
21
  * @param null|int $id
22
  */
23
- public function __construct($id = null)
24
  {
25
  $this->setId($id);
 
26
  }
27
 
28
  /**
@@ -36,6 +39,17 @@ class MailChimp_WooCommerce_Single_Product extends Mailchimp_Woocommerce_Job
36
  }
37
  }
38
 
 
 
 
 
 
 
 
 
 
 
 
39
  /**
40
  * @return $this
41
  */
@@ -65,6 +79,16 @@ class MailChimp_WooCommerce_Single_Product extends Mailchimp_Woocommerce_Job
65
  return $this;
66
  }
67
 
 
 
 
 
 
 
 
 
 
 
68
  /**
69
  * @return bool
70
  */
@@ -120,10 +144,25 @@ class MailChimp_WooCommerce_Single_Product extends Mailchimp_Woocommerce_Job
120
  return false;
121
  }
122
 
123
- $product = $this->transformer()->transform($product_post);
 
 
 
 
 
 
 
 
 
 
124
 
125
  mailchimp_debug('product_submit.debug', "#{$this->id}", $product->toArray());
126
 
 
 
 
 
 
127
  // either updating or creating the product
128
  $this->api()->{$method}($this->store_id, $product, false);
129
 
11
  class MailChimp_WooCommerce_Single_Product extends Mailchimp_Woocommerce_Job
12
  {
13
  public $id;
14
+ public $fallback_title;
15
  protected $store_id;
16
  protected $api;
17
  protected $service;
18
  protected $mode = 'update_or_create';
19
+ protected $order_item = null;
20
 
21
  /**
22
  * MailChimp_WooCommerce_Single_product constructor.
23
  * @param null|int $id
24
  */
25
+ public function __construct($id = null, $fallback_title = null)
26
  {
27
  $this->setId($id);
28
+ $this->setFallbackTitle($fallback_title);
29
  }
30
 
31
  /**
39
  }
40
  }
41
 
42
+ /**
43
+ * @param $title
44
+ * @return $this
45
+ */
46
+ public function setFallbackTitle($title)
47
+ {
48
+ $this->fallback_title = $title;
49
+
50
+ return $this;
51
+ }
52
+
53
  /**
54
  * @return $this
55
  */
79
  return $this;
80
  }
81
 
82
+ /**
83
+ * @param MailChimp_WooCommerce_LineItem $item
84
+ * @return $this
85
+ */
86
+ public function fromOrderItem(MailChimp_WooCommerce_LineItem $item)
87
+ {
88
+ $this->order_item = $item;
89
+ return $this;
90
+ }
91
+
92
  /**
93
  * @return bool
94
  */
144
  return false;
145
  }
146
 
147
+ // if qe instructed this job to build from the order item, let's do that instead of the product post.
148
+ if ($this->order_item) {
149
+ mailchimp_debug('product_submit.debug', 'using order item', array('item' => $this->order_item));
150
+ $product = $this->transformer()->fromOrderItem($this->order_item);
151
+ } else {
152
+ $product = $this->transformer()->transform($product_post, $this->fallback_title);
153
+ }
154
+
155
+ if (empty($product->getTitle()) && !empty($this->fallback_title)) {
156
+ $product->setTitle($this->fallback_title);
157
+ }
158
 
159
  mailchimp_debug('product_submit.debug', "#{$this->id}", $product->toArray());
160
 
161
+ if (!$product->getId() || !$product->getTitle()) {
162
+ mailchimp_log('product_submit.warning', "{$method} :: post #{$this->id} was invalid.");
163
+ return false;
164
+ }
165
+
166
  // either updating or creating the product
167
  $this->api()->{$method}($this->store_id, $product, false);
168
 
includes/vendor/action-scheduler/.editorconfig ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # This file is for unifying the coding style for different editors and IDEs
2
+ # editorconfig.org
3
+
4
+ # WordPress Coding Standards
5
+ # https://make.wordpress.org/core/handbook/coding-standards/
6
+
7
+ root = true
8
+
9
+ [*]
10
+ charset = utf-8
11
+ end_of_line = lf
12
+ indent_size = 4
13
+ tab_width = 4
14
+ indent_style = tab
15
+ insert_final_newline = true
16
+ trim_trailing_whitespace = true
17
+
18
+ [*.txt]
19
+ trim_trailing_whitespace = false
20
+
21
+ [*.{md,json,yml}]
22
+ trim_trailing_whitespace = false
23
+ indent_style = space
24
+ indent_size = 2
includes/vendor/action-scheduler/.gitattributes CHANGED
@@ -5,5 +5,9 @@ codecov.yml export-ignore
5
  .travis.yml export-ignore
6
  .gitattributes export-ignore
7
  .gitignore export-ignore
8
- phpunit.xml.dist export-ignore
9
-
 
 
 
 
5
  .travis.yml export-ignore
6
  .gitattributes export-ignore
7
  .gitignore export-ignore
8
+ composer.* export-ignore
9
+ Gruntfile.js export-ignore
10
+ package.json export-ignore
11
+ package-lock.json export-ignore
12
+ phpcs.xml export-ignore
13
+ phpunit.* export-ignore
includes/vendor/action-scheduler/.gitignore CHANGED
@@ -1,3 +1,4 @@
1
  phpunit.xml
2
  vendor
3
  .idea
 
1
  phpunit.xml
2
  vendor
3
  .idea
4
+ node_modules
includes/vendor/action-scheduler/Gruntfile.js ADDED
@@ -0,0 +1,57 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ module.exports = function( grunt ) {
2
+ 'use strict';
3
+
4
+ grunt.initConfig({
5
+ // Check textdomain errors.
6
+ checktextdomain: {
7
+ options:{
8
+ text_domain: 'action-scheduler',
9
+ keywords: [
10
+ '__:1,2d',
11
+ '_e:1,2d',
12
+ '_x:1,2c,3d',
13
+ 'esc_html__:1,2d',
14
+ 'esc_html_e:1,2d',
15
+ 'esc_html_x:1,2c,3d',
16
+ 'esc_attr__:1,2d',
17
+ 'esc_attr_e:1,2d',
18
+ 'esc_attr_x:1,2c,3d',
19
+ '_ex:1,2c,3d',
20
+ '_n:1,2,4d',
21
+ '_nx:1,2,4c,5d',
22
+ '_n_noop:1,2,3d',
23
+ '_nx_noop:1,2,3c,4d'
24
+ ]
25
+ },
26
+ files: {
27
+ src: [
28
+ '**/*.php',
29
+ '!node_modules/**',
30
+ '!tests/**',
31
+ '!vendor/**',
32
+ '!tmp/**'
33
+ ],
34
+ expand: true
35
+ }
36
+ },
37
+
38
+ // PHP Code Sniffer.
39
+ phpcs: {
40
+ options: {
41
+ bin: 'vendor/bin/phpcs'
42
+ },
43
+ dist: {
44
+ src: [
45
+ '**/*.php', // Include all php files.
46
+ '!deprecated/**',
47
+ '!node_modules/**',
48
+ '!vendor/**'
49
+ ]
50
+ }
51
+ }
52
+ });
53
+
54
+ // Load NPM tasks to be used here.
55
+ grunt.loadNpmTasks( 'grunt-phpcs' );
56
+ grunt.loadNpmTasks( 'grunt-checktextdomain' );
57
+ };
includes/vendor/action-scheduler/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # Action Scheduler - Job Queue for WordPress [![Build Status](https://travis-ci.org/Prospress/action-scheduler.png?branch=master)](https://travis-ci.org/Prospress/action-scheduler) [![codecov](https://codecov.io/gh/Prospress/action-scheduler/branch/master/graph/badge.svg)](https://codecov.io/gh/Prospress/action-scheduler)
2
 
3
  Action Scheduler is a scalable, traceable job queue for background processing large sets of actions in WordPress. It's specially designed to be distributed in WordPress plugins.
4
 
@@ -30,12 +30,6 @@ There you will find:
30
 
31
  ## Credits
32
 
33
- Action Scheduler is developed and maintained by [Prospress](http://prospress.com/) in collaboration with [Flightless](https://flightless.us/).
34
 
35
- Collaboration is cool. We'd love to work with you to improve Action Scheduler. [Pull Requests](https://github.com/prospress/action-scheduler/pulls) welcome.
36
-
37
- ---
38
-
39
- <p align="center">
40
- <img src="https://cloud.githubusercontent.com/assets/235523/11986380/bb6a0958-a983-11e5-8e9b-b9781d37c64a.png" width="160">
41
- </p>
1
+ # Action Scheduler - Job Queue for WordPress [![Build Status](https://travis-ci.org/woocommerce/action-scheduler.png?branch=master)](https://travis-ci.org/woocommerce/action-scheduler) [![codecov](https://codecov.io/gh/woocommerce/action-scheduler/branch/master/graph/badge.svg)](https://codecov.io/gh/woocommerce/action-scheduler)
2
 
3
  Action Scheduler is a scalable, traceable job queue for background processing large sets of actions in WordPress. It's specially designed to be distributed in WordPress plugins.
4
 
30
 
31
  ## Credits
32
 
33
+ Action Scheduler is developed and maintained by [Automattic](http://automattic.com/) with significant early development completed by [Flightless](https://flightless.us/).
34
 
35
+ Collaboration is cool. We'd love to work with you to improve Action Scheduler. [Pull Requests](https://github.com/woocommerce/action-scheduler/pulls) welcome.
 
 
 
 
 
 
includes/vendor/action-scheduler/action-scheduler.php CHANGED
@@ -3,12 +3,12 @@
3
  * Plugin Name: Action Scheduler
4
  * Plugin URI: https://actionscheduler.org
5
  * Description: A robust scheduling library for use in WordPress plugins.
6
- * Author: Prospress
7
- * Author URI: https://prospress.com/
8
- * Version: 2.2.5
9
  * License: GPLv3
10
  *
11
- * Copyright 2019 Prospress, Inc. (email : freedoms@prospress.com)
12
  *
13
  * This program is free software: you can redistribute it and/or modify
14
  * it under the terms of the GNU General Public License as published by
@@ -21,27 +21,33 @@
21
  * GNU General Public License for more details.
22
  *
23
  * You should have received a copy of the GNU General Public License
24
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
25
  *
26
  */
27
 
28
- if ( ! function_exists( 'action_scheduler_register_2_dot_2_dot_5' ) ) {
29
 
30
  if ( ! class_exists( 'ActionScheduler_Versions' ) ) {
31
  require_once( 'classes/ActionScheduler_Versions.php' );
32
  add_action( 'plugins_loaded', array( 'ActionScheduler_Versions', 'initialize_latest_version' ), 1, 0 );
33
  }
34
 
35
- add_action( 'plugins_loaded', 'action_scheduler_register_2_dot_2_dot_5', 0, 0 );
36
 
37
- function action_scheduler_register_2_dot_2_dot_5() {
38
  $versions = ActionScheduler_Versions::instance();
39
- $versions->register( '2.2.5', 'action_scheduler_initialize_2_dot_2_dot_5' );
40
  }
41
 
42
- function action_scheduler_initialize_2_dot_2_dot_5() {
43
- require_once( 'classes/ActionScheduler.php' );
44
  ActionScheduler::init( __FILE__ );
45
  }
46
 
 
 
 
 
 
 
47
  }
3
  * Plugin Name: Action Scheduler
4
  * Plugin URI: https://actionscheduler.org
5
  * Description: A robust scheduling library for use in WordPress plugins.
6
+ * Author: Automattic
7
+ * Author URI: https://automattic.com/
8
+ * Version: 3.0.1
9
  * License: GPLv3
10
  *
11
+ * Copyright 2019 Automattic, Inc. (https://automattic.com/contact/)
12
  *
13
  * This program is free software: you can redistribute it and/or modify
14
  * it under the terms of the GNU General Public License as published by
21
  * GNU General Public License for more details.
22
  *
23
  * You should have received a copy of the GNU General Public License
24
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
25
  *
26
  */
27
 
28
+ if ( ! function_exists( 'action_scheduler_register_3_dot_0_dot_1' ) ) {
29
 
30
  if ( ! class_exists( 'ActionScheduler_Versions' ) ) {
31
  require_once( 'classes/ActionScheduler_Versions.php' );
32
  add_action( 'plugins_loaded', array( 'ActionScheduler_Versions', 'initialize_latest_version' ), 1, 0 );
33
  }
34
 
35
+ add_action( 'plugins_loaded', 'action_scheduler_register_3_dot_0_dot_1', 0, 0 );
36
 
37
+ function action_scheduler_register_3_dot_0_dot_1() {
38
  $versions = ActionScheduler_Versions::instance();
39
+ $versions->register( '3.0.1', 'action_scheduler_initialize_3_dot_0_dot_1' );
40
  }
41
 
42
+ function action_scheduler_initialize_3_dot_0_dot_1() {
43
+ require_once( 'classes/abstracts/ActionScheduler.php' );
44
  ActionScheduler::init( __FILE__ );
45
  }
46
 
47
+ // Support usage in themes - load this version if no plugin has loaded a version yet.
48
+ if ( did_action( 'plugins_loaded' ) && ! class_exists( 'ActionScheduler' ) ) {
49
+ action_scheduler_register_3_dot_0_dot_1();
50
+ do_action( 'action_scheduler_pre_theme_init' );
51
+ ActionScheduler_Versions::initialize_latest_version();
52
+ }
53
  }
includes/vendor/action-scheduler/classes/ActionScheduler.php DELETED
@@ -1,133 +0,0 @@
1
- <?php
2
-
3
- /**
4
- * Class ActionScheduler
5
- * @codeCoverageIgnore
6
- */
7
- abstract class ActionScheduler {
8
- private static $plugin_file = '';
9
- /** @var ActionScheduler_ActionFactory */
10
- private static $factory = NULL;
11
-
12
- public static function factory() {
13
- if ( !isset(self::$factory) ) {
14
- self::$factory = new ActionScheduler_ActionFactory();
15
- }
16
- return self::$factory;
17
- }
18
-
19
- public static function store() {
20
- return ActionScheduler_Store::instance();
21
- }
22
-
23
- public static function logger() {
24
- return ActionScheduler_Logger::instance();
25
- }
26
-
27
- public static function runner() {
28
- return ActionScheduler_QueueRunner::instance();
29
- }
30
-
31
- public static function admin_view() {
32
- return ActionScheduler_AdminView::instance();
33
- }
34
-
35
- /**
36
- * Get the absolute system path to the plugin directory, or a file therein
37
- * @static
38
- * @param string $path
39
- * @return string
40
- */
41
- public static function plugin_path( $path ) {
42
- $base = dirname(self::$plugin_file);
43
- if ( $path ) {
44
- return trailingslashit($base).$path;
45
- } else {
46
- return untrailingslashit($base);
47
- }
48
- }
49
-
50
- /**
51
- * Get the absolute URL to the plugin directory, or a file therein
52
- * @static
53
- * @param string $path
54
- * @return string
55
- */
56
- public static function plugin_url( $path ) {
57
- return plugins_url($path, self::$plugin_file);
58
- }
59
-
60
- public static function autoload( $class ) {
61
- $d = DIRECTORY_SEPARATOR;
62
- if ( 'Deprecated' === substr( $class, -10 ) ) {
63
- $dir = self::plugin_path('deprecated'.$d);
64
- } elseif ( strpos( $class, 'ActionScheduler' ) === 0 ) {
65
- $dir = self::plugin_path('classes'.$d);
66
- } elseif ( strpos( $class, 'CronExpression' ) === 0 ) {
67
- $dir = self::plugin_path('lib'.$d.'cron-expression'.$d);
68
- } else {
69
- return;
70
- }
71
-
72
- if ( file_exists( "{$dir}{$class}.php" ) ) {
73
- include( "{$dir}{$class}.php" );
74
- return;
75
- }
76
- }
77
-
78
- /**
79
- * Initialize the plugin
80
- *
81
- * @static
82
- * @param string $plugin_file
83
- */
84
- public static function init( $plugin_file ) {
85
- self::$plugin_file = $plugin_file;
86
- spl_autoload_register( array( __CLASS__, 'autoload' ) );
87
-
88
- /**
89
- * Fires in the early stages of Action Scheduler init hook.
90
- */
91
- do_action( 'action_scheduler_pre_init' );
92
-
93
- $store = self::store();
94
- add_action( 'init', array( $store, 'init' ), 1, 0 );
95
-
96
- $logger = self::logger();
97
- add_action( 'init', array( $logger, 'init' ), 1, 0 );
98
-
99
- $runner = self::runner();
100
- add_action( 'init', array( $runner, 'init' ), 1, 0 );
101
-
102
- $admin_view = self::admin_view();
103
- add_action( 'init', array( $admin_view, 'init' ), 0, 0 ); // run before $store::init()
104
-
105
- require_once( self::plugin_path('functions.php') );
106
-
107
- if ( apply_filters( 'action_scheduler_load_deprecated_functions', true ) ) {
108
- require_once( self::plugin_path('deprecated/functions.php') );
109
- }
110
-
111
- if ( defined( 'WP_CLI' ) && WP_CLI ) {
112
- WP_CLI::add_command( 'action-scheduler', 'ActionScheduler_WPCLI_Scheduler_command' );
113
- }
114
- }
115
-
116
-
117
- final public function __clone() {
118
- trigger_error("Singleton. No cloning allowed!", E_USER_ERROR);
119
- }
120
-
121
- final public function __wakeup() {
122
- trigger_error("Singleton. No serialization allowed!", E_USER_ERROR);
123
- }
124
-
125
- final private function __construct() {}
126
-
127
- /** Deprecated **/
128
-
129
- public static function get_datetime_object( $when = null, $timezone = 'UTC' ) {
130
- _deprecated_function( __METHOD__, '2.0', 'wcs_add_months()' );
131
- return as_get_datetime_object( $when, $timezone );
132
- }
133
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
includes/vendor/action-scheduler/classes/ActionScheduler_ActionFactory.php CHANGED
@@ -22,6 +22,9 @@ class ActionScheduler_ActionFactory {
22
  break;
23
  case ActionScheduler_Store::STATUS_CANCELED :
24
  $action_class = 'ActionScheduler_CanceledAction';
 
 
 
25
  break;
26
  default :
27
  $action_class = 'ActionScheduler_FinishedAction';
@@ -44,6 +47,28 @@ class ActionScheduler_ActionFactory {
44
  return apply_filters( 'action_scheduler_stored_action_instance', $action, $hook, $args, $schedule, $group );
45
  }
46
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
47
  /**
48
  * @param string $hook The hook to trigger when this action runs
49
  * @param array $args Args to pass when the hook is triggered
@@ -60,6 +85,8 @@ class ActionScheduler_ActionFactory {
60
  }
61
 
62
  /**
 
 
63
  * @param string $hook The hook to trigger when this action runs
64
  * @param array $args Args to pass when the hook is triggered
65
  * @param int $first Unix timestamp for the first run
@@ -78,27 +105,68 @@ class ActionScheduler_ActionFactory {
78
  return $this->store( $action );
79
  }
80
 
81
-
82
  /**
 
 
83
  * @param string $hook The hook to trigger when this action runs
84
  * @param array $args Args to pass when the hook is triggered
85
- * @param int $first Unix timestamp for the first run
 
 
86
  * @param int $schedule A cron definition string
87
  * @param string $group A group to put the action in
88
  *
89
  * @return string The ID of the stored action
90
  */
91
- public function cron( $hook, $args = array(), $first = null, $schedule = null, $group = '' ) {
92
  if ( empty($schedule) ) {
93
- return $this->single( $hook, $args, $first, $group );
94
  }
95
- $date = as_get_datetime_object( $first );
96
  $cron = CronExpression::factory( $schedule );
97
  $schedule = new ActionScheduler_CronSchedule( $date, $cron );
98
  $action = new ActionScheduler_Action( $hook, $args, $schedule, $group );
99
  return $this->store( $action );
100
  }
101
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
102
  /**
103
  * @param ActionScheduler_Action $action
104
  *
22
  break;
23
  case ActionScheduler_Store::STATUS_CANCELED :
24
  $action_class = 'ActionScheduler_CanceledAction';
25
+ if ( ! is_null( $schedule ) && ! is_a( $schedule, 'ActionScheduler_CanceledSchedule' ) ) {
26
+ $schedule = new ActionScheduler_CanceledSchedule( $schedule->get_date() );
27
+ }
28
  break;
29
  default :
30
  $action_class = 'ActionScheduler_FinishedAction';
47
  return apply_filters( 'action_scheduler_stored_action_instance', $action, $hook, $args, $schedule, $group );
48
  }
49
 
50
+ /**
51
+ * Enqueue an action to run one time, as soon as possible (rather a specific scheduled time).
52
+ *
53
+ * This method creates a new action with the NULLSchedule. This schedule maps to a MySQL datetime string of
54
+ * 0000-00-00 00:00:00. This is done to create a psuedo "async action" type that is fully backward compatible.
55
+ * Existing queries to claim actions claim by date, meaning actions scheduled for 0000-00-00 00:00:00 will
56
+ * always be claimed prior to actions scheduled for a specific date. This makes sure that any async action is
57
+ * given priority in queue processing. This has the added advantage of making sure async actions can be
58
+ * claimed by both the existing WP Cron and WP CLI runners, as well as a new async request runner.
59
+ *
60
+ * @param string $hook The hook to trigger when this action runs
61
+ * @param array $args Args to pass when the hook is triggered
62
+ * @param string $group A group to put the action in
63
+ *
64
+ * @return string The ID of the stored action
65
+ */
66
+ public function async( $hook, $args = array(), $group = '' ) {
67
+ $schedule = new ActionScheduler_NullSchedule();
68
+ $action = new ActionScheduler_Action( $hook, $args, $schedule, $group );
69
+ return $this->store( $action );
70
+ }
71
+
72
  /**
73
  * @param string $hook The hook to trigger when this action runs
74
  * @param array $args Args to pass when the hook is triggered
85
  }
86
 
87
  /**
88
+ * Create the first instance of an action recurring on a given interval.
89
+ *
90
  * @param string $hook The hook to trigger when this action runs
91
  * @param array $args Args to pass when the hook is triggered
92
  * @param int $first Unix timestamp for the first run
105
  return $this->store( $action );
106
  }
107
 
 
108
  /**
109
+ * Create the first instance of an action recurring on a Cron schedule.
110
+ *
111
  * @param string $hook The hook to trigger when this action runs
112
  * @param array $args Args to pass when the hook is triggered
113
+ * @param int $base_timestamp The first instance of the action will be scheduled
114
+ * to run at a time calculated after this timestamp matching the cron
115
+ * expression. This can be used to delay the first instance of the action.
116
  * @param int $schedule A cron definition string
117
  * @param string $group A group to put the action in
118
  *
119
  * @return string The ID of the stored action
120
  */
121
+ public function cron( $hook, $args = array(), $base_timestamp = null, $schedule = null, $group = '' ) {
122
  if ( empty($schedule) ) {
123
+ return $this->single( $hook, $args, $base_timestamp, $group );
124
  }
125
+ $date = as_get_datetime_object( $base_timestamp );
126
  $cron = CronExpression::factory( $schedule );
127
  $schedule = new ActionScheduler_CronSchedule( $date, $cron );
128
  $action = new ActionScheduler_Action( $hook, $args, $schedule, $group );
129
  return $this->store( $action );
130
  }
131
 
132
+ /**
133
+ * Create a successive instance of a recurring or cron action.
134
+ *
135
+ * Importantly, the action will be rescheduled to run based on the current date/time.
136
+ * That means when the action is scheduled to run in the past, the next scheduled date
137
+ * will be pushed forward. For example, if a recurring action set to run every hour
138
+ * was scheduled to run 5 seconds ago, it will be next scheduled for 1 hour in the
139
+ * future, which is 1 hour and 5 seconds from when it was last scheduled to run.
140
+ *
141
+ * Alternatively, if the action is scheduled to run in the future, and is run early,
142
+ * likely via manual intervention, then its schedule will change based on the time now.
143
+ * For example, if a recurring action set to run every day, and is run 12 hours early,
144
+ * it will run again in 24 hours, not 36 hours.
145
+ *
146
+ * This slippage is less of an issue with Cron actions, as the specific run time can
147
+ * be set for them to run, e.g. 1am each day. In those cases, and entire period would
148
+ * need to be missed before there was any change is scheduled, e.g. in the case of an
149
+ * action scheduled for 1am each day, the action would need to run an entire day late.
150
+ *
151
+ * @param ActionScheduler_Action $action The existing action.
152
+ *
153
+ * @return string The ID of the stored action
154
+ * @throws InvalidArgumentException If $action is not a recurring action.
155
+ */
156
+ public function repeat( $action ) {
157
+ $schedule = $action->get_schedule();
158
+ $next = $schedule->get_next( as_get_datetime_object() );
159
+
160
+ if ( is_null( $next ) || ! $schedule->is_recurring() ) {
161
+ throw new InvalidArgumentException( __( 'Invalid action - must be a recurring action.', 'action-scheduler' ) );
162
+ }
163
+
164
+ $schedule_class = get_class( $schedule );
165
+ $new_schedule = new $schedule( $next, $schedule->get_recurrence(), $schedule->get_first_date() );
166
+ $new_action = new ActionScheduler_Action( $action->get_hook(), $action->get_args(), $new_schedule, $action->get_group() );
167
+ return $this->store( $new_action );
168
+ }
169
+
170
  /**
171
  * @param ActionScheduler_Action $action
172
  *
includes/vendor/action-scheduler/classes/ActionScheduler_AdminView.php CHANGED
@@ -8,8 +8,10 @@ class ActionScheduler_AdminView extends ActionScheduler_AdminView_Deprecated {
8
 
9
  private static $admin_view = NULL;
10
 
 
 
11
  /**
12
- * @return ActionScheduler_QueueRunner
13
  * @codeCoverageIgnore
14
  */
15
  public static function instance() {
@@ -35,6 +37,8 @@ class ActionScheduler_AdminView extends ActionScheduler_AdminView_Deprecated {
35
  }
36
 
37
  add_action( 'admin_menu', array( $this, 'register_menu' ) );
 
 
38
  }
39
  }
40
 
@@ -63,7 +67,7 @@ class ActionScheduler_AdminView extends ActionScheduler_AdminView_Deprecated {
63
  * System Status page, and for sites where WooCommerce isn't active.
64
  */
65
  public function register_menu() {
66
- add_submenu_page(
67
  'tools.php',
68
  __( 'Scheduled Actions', 'action-scheduler' ),
69
  __( 'Scheduled Actions', 'action-scheduler' ),
@@ -71,6 +75,15 @@ class ActionScheduler_AdminView extends ActionScheduler_AdminView_Deprecated {
71
  'action-scheduler',
72
  array( $this, 'render_admin_ui' )
73
  );
 
 
 
 
 
 
 
 
 
74
  }
75
 
76
  /**
@@ -80,4 +93,45 @@ class ActionScheduler_AdminView extends ActionScheduler_AdminView_Deprecated {
80
  $table = new ActionScheduler_ListTable( ActionScheduler::store(), ActionScheduler::logger(), ActionScheduler::runner() );
81
  $table->display_page();
82
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
83
  }
8
 
9
  private static $admin_view = NULL;
10
 
11
+ private static $screen_id = 'tools_page_action-scheduler';
12
+
13
  /**
14
+ * @return ActionScheduler_AdminView
15
  * @codeCoverageIgnore
16
  */
17
  public static function instance() {
37
  }
38
 
39
  add_action( 'admin_menu', array( $this, 'register_menu' ) );
40
+
41
+ add_action( 'current_screen', array( $this, 'add_help_tabs' ) );
42
  }
43
  }
44
 
67
  * System Status page, and for sites where WooCommerce isn't active.
68
  */
69
  public function register_menu() {
70
+ $hook_suffix = add_submenu_page(
71
  'tools.php',
72
  __( 'Scheduled Actions', 'action-scheduler' ),
73
  __( 'Scheduled Actions', 'action-scheduler' ),
75
  'action-scheduler',
76
  array( $this, 'render_admin_ui' )
77
  );
78
+ add_action( 'load-' . $hook_suffix , array( $this, 'process_admin_ui' ) );
79
+ }
80
+
81
+ /**
82
+ * Triggers processing of any pending actions.
83
+ */
84
+ public function process_admin_ui() {
85
+ $table = new ActionScheduler_ListTable( ActionScheduler::store(), ActionScheduler::logger(), ActionScheduler::runner() );
86
+ $table->process_actions();
87
  }
88
 
89
  /**
93
  $table = new ActionScheduler_ListTable( ActionScheduler::store(), ActionScheduler::logger(), ActionScheduler::runner() );
94
  $table->display_page();
95
  }
96
+
97
+ /**
98
+ * Provide more information about the screen and its data in the help tab.
99
+ */
100
+ public function add_help_tabs() {
101
+ $screen = get_current_screen();
102
+
103
+ if ( ! $screen || self::$screen_id != $screen->id ) {
104
+ return;
105
+ }
106
+
107
+ $screen->add_help_tab(
108
+ array(
109
+ 'id' => 'action_scheduler_about',
110
+ 'title' => __( 'About', 'action-scheduler' ),
111
+ 'content' =>
112
+ '<h2>' . __( 'About Action Scheduler', 'action-scheduler' ) . '</h2>' .
113
+ '<p>' .
114
+ __( 'Action Scheduler is a scalable, traceable job queue for background processing large sets of actions. Action Scheduler works by triggering an action hook to run at some time in the future. Scheduled actions can also be scheduled to run on a recurring schedule.', 'action-scheduler' ) .
115
+ '</p>',
116
+ )
117
+ );
118
+
119
+ $screen->add_help_tab(
120
+ array(
121
+ 'id' => 'action_scheduler_columns',
122
+ 'title' => __( 'Columns', 'action-scheduler' ),
123
+ 'content' =>
124
+ '<h2>' . __( 'Scheduled Action Columns', 'action-scheduler' ) . '</h2>' .
125
+ '<ul>' .
126
+ sprintf( '<li><strong>%1$s</strong>: %2$s</li>', __( 'Hook', 'action-scheduler' ), __( 'Name of the action hook that will be triggered.', 'action-scheduler' ) ) .
127
+ sprintf( '<li><strong>%1$s</strong>: %2$s</li>', __( 'Status', 'action-scheduler' ), __( 'Action statuses are Pending, Complete, Canceled, Failed', 'action-scheduler' ) ) .
128
+ sprintf( '<li><strong>%1$s</strong>: %2$s</li>', __( 'Arguments', 'action-scheduler' ), __( 'Optional data array passed to the action hook.', 'action-scheduler' ) ) .
129
+ sprintf( '<li><strong>%1$s</strong>: %2$s</li>', __( 'Group', 'action-scheduler' ), __( 'Optional action group.', 'action-scheduler' ) ) .
130
+ sprintf( '<li><strong>%1$s</strong>: %2$s</li>', __( 'Recurrence', 'action-scheduler' ), __( 'The action\'s schedule frequency.', 'action-scheduler' ) ) .
131
+ sprintf( '<li><strong>%1$s</strong>: %2$s</li>', __( 'Scheduled', 'action-scheduler' ), __( 'The date/time the action is/was scheduled to run.', 'action-scheduler' ) ) .
132
+ sprintf( '<li><strong>%1$s</strong>: %2$s</li>', __( 'Log', 'action-scheduler' ), __( 'Activity log for the action.', 'action-scheduler' ) ) .
133
+ '</ul>',
134
+ )
135
+ );
136
+ }
137
  }
includes/vendor/action-scheduler/classes/ActionScheduler_AsyncRequest_QueueRunner.php ADDED
@@ -0,0 +1,96 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * ActionScheduler_AsyncRequest_QueueRunner
4
+ */
5
+
6
+ defined( 'ABSPATH' ) || exit;
7
+
8
+ /**
9
+ * ActionScheduler_AsyncRequest_QueueRunner class.
10
+ */
11
+ class ActionScheduler_AsyncRequest_QueueRunner extends WP_Async_Request {
12
+
13
+ /**
14
+ * Data store for querying actions
15
+ *
16
+ * @var ActionScheduler_Store
17
+ * @access protected
18
+ */
19
+ protected $store;
20
+
21
+ /**
22
+ * Prefix for ajax hooks
23
+ *
24
+ * @var string
25
+ * @access protected
26
+ */
27
+ protected $prefix = 'as';
28
+
29
+ /**
30
+ * Action for ajax hooks
31
+ *
32
+ * @var string
33
+ * @access protected
34
+ */
35
+ protected $action = 'async_request_queue_runner';
36
+
37
+ /**
38
+ * Initiate new async request
39
+ */
40
+ public function __construct( ActionScheduler_Store $store ) {
41
+ parent::__construct();
42
+ $this->store = $store;
43
+ }
44
+
45
+ /**
46
+ * Handle async requests
47
+ *
48
+ * Run a queue, and maybe dispatch another async request to run another queue
49
+ * if there are still pending actions after completing a queue in this request.
50
+ */
51
+ protected function handle() {
52
+ do_action( 'action_scheduler_run_queue', 'Async Request' ); // run a queue in the same way as WP Cron, but declare the Async Request context
53
+
54
+ $sleep_seconds = $this->get_sleep_seconds();
55
+
56
+ if ( $sleep_seconds ) {
57
+ sleep( $sleep_seconds );
58
+ }
59
+
60
+ $this->maybe_dispatch();
61
+ }
62
+
63
+ /**
64
+ * If the async request runner is needed and allowed to run, dispatch a request.
65
+ */
66
+ public function maybe_dispatch() {
67
+ if ( ! $this->allow() ) {
68
+ return;
69
+ }
70
+
71
+ $this->dispatch();
72
+ }
73
+
74
+ /**
75
+ * Only allow async requests when needed.
76
+ *
77
+ * Also allow 3rd party code to disable running actions via async requests.
78
+ */
79
+ protected function allow() {
80
+
81
+ if ( ! has_action( 'action_scheduler_run_queue' ) || ActionScheduler::runner()->has_maximum_concurrent_batches() || ! $this->store->has_pending_actions_due() ) {
82
+ $allow = false;
83
+ } else {
84
+ $allow = true;
85
+ }
86
+
87
+ return apply_filters( 'action_scheduler_allow_async_request_runner', $allow );
88
+ }
89
+
90
+ /**
91
+ * Chaining async requests can crash MySQL. A brief sleep call in PHP prevents that.
92
+ */
93
+ protected function get_sleep_seconds() {
94
+ return apply_filters( 'action_scheduler_async_request_sleep_seconds', 1, $this );
95
+ }
96
+ }
includes/vendor/action-scheduler/classes/ActionScheduler_CronSchedule.php DELETED
@@ -1,57 +0,0 @@
1
- <?php
2
-
3
- /**
4
- * Class ActionScheduler_CronSchedule
5
- */
6
- class ActionScheduler_CronSchedule implements ActionScheduler_Schedule {
7
- /** @var DateTime */
8
- private $start = NULL;
9
- private $start_timestamp = 0;
10
- /** @var CronExpression */
11
- private $cron = NULL;
12
-
13
- public function __construct( DateTime $start, CronExpression $cron ) {
14
- $this->start = $start;
15
- $this->cron = $cron;
16
- }
17
-
18
- /**
19
- * @param DateTime $after
20
- * @return DateTime|null
21
- */
22
- public function next( DateTime $after = NULL ) {
23
- $after = empty($after) ? clone $this->start : clone $after;
24
- return $this->cron->getNextRunDate($after, 0, false);
25
- }
26
-
27
- /**
28
- * @return bool
29
- */
30
- public function is_recurring() {
31
- return true;
32
- }
33
-
34
- /**
35
- * @return string
36
- */
37
- public function get_recurrence() {
38
- return strval($this->cron);
39
- }
40
-
41
- /**
42
- * For PHP 5.2 compat, since DateTime objects can't be serialized
43
- * @return array
44
- */
45
- public function __sleep() {
46
- $this->start_timestamp = $this->start->getTimestamp();
47
- return array(
48
- 'start_timestamp',
49
- 'cron'
50
- );
51
- }
52
-
53
- public function __wakeup() {
54
- $this->start = as_get_datetime_object($this->start_timestamp);
55
- }
56
- }
57
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
includes/vendor/action-scheduler/classes/ActionScheduler_DataController.php ADDED
@@ -0,0 +1,177 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ use Action_Scheduler\Migration\Controller;
4
+
5
+ /**
6
+ * Class ActionScheduler_DataController
7
+ *
8
+ * The main plugin/initialization class for the data stores.
9
+ *
10
+ * Responsible for hooking everything up with WordPress.
11
+ *
12
+ * @package Action_Scheduler
13
+ *
14
+ * @since 3.0.0
15
+ */
16
+ class ActionScheduler_DataController {
17
+ /** Action data store class name. */
18
+ const DATASTORE_CLASS = 'ActionScheduler_DBStore';
19
+
20
+ /** Logger data store class name. */
21
+ const LOGGER_CLASS = 'ActionScheduler_DBLogger';
22
+
23
+ /** Migration status option name. */
24
+ const STATUS_FLAG = 'action_scheduler_migration_status';
25
+
26
+ /** Migration status option value. */
27
+ const STATUS_COMPLETE = 'complete';
28
+
29
+ /** Migration minimum required PHP version. */
30
+ const MIN_PHP_VERSION = '5.5';
31
+
32
+ /** @var ActionScheduler_DataController */
33
+ private static $instance;
34
+
35
+ /** @var int */
36
+ private static $sleep_time = 0;
37
+
38
+ /** @var int */
39
+ private static $free_ticks = 50;
40
+
41
+ /**
42
+ * Get a flag indicating whether the migration environment dependencies are met.
43
+ *
44
+ * @return bool
45
+ */
46
+ public static function dependencies_met() {
47
+ $php_support = version_compare( PHP_VERSION, self::MIN_PHP_VERSION, '>=' );
48
+ return $php_support && apply_filters( 'action_scheduler_migration_dependencies_met', true );
49
+ }
50
+
51
+ /**
52
+ * Get a flag indicating whether the migration is complete.
53
+ *
54
+ * @return bool Whether the flag has been set marking the migration as complete
55
+ */
56
+ public static function is_migration_complete() {
57
+ return get_option( self::STATUS_FLAG ) === self::STATUS_COMPLETE;
58
+ }
59
+
60
+ /**
61
+ * Mark the migration as complete.
62
+ */
63
+ public static function mark_migration_complete() {
64
+ update_option( self::STATUS_FLAG, self::STATUS_COMPLETE );
65
+ }
66
+
67
+ /**
68
+ * Set the action store class name.
69
+ *
70
+ * @param string $class Classname of the store class.
71
+ *
72
+ * @return string
73
+ */
74
+ public static function set_store_class( $class ) {
75
+ return self::DATASTORE_CLASS;
76
+ }
77
+
78
+ /**
79
+ * Set the action logger class name.
80
+ *
81
+ * @param string $class Classname of the logger class.
82
+ *
83
+ * @return string
84
+ */
85
+ public static function set_logger_class( $class ) {
86
+ return self::LOGGER_CLASS;
87
+ }
88
+
89
+ /**
90
+ * Set the sleep time in seconds.
91
+ *
92
+ * @param integer $sleep_time The number of seconds to pause before resuming operation.
93
+ */
94
+ public static function set_sleep_time( $sleep_time ) {
95
+ self::$sleep_time = $sleep_time;
96
+ }
97
+
98
+ /**
99
+ * Set the tick count required for freeing memory.
100
+ *
101
+ * @param integer $free_ticks The number of ticks to free memory on.
102
+ */
103
+ public static function set_free_ticks( $free_ticks ) {
104
+ self::$free_ticks = $free_ticks;
105
+ }
106
+
107
+ /**
108
+ * Free memory if conditions are met.
109
+ *
110
+ * @param int $ticks Current tick count.
111
+ */
112
+ public static function maybe_free_memory( $ticks ) {
113
+ if ( self::$free_ticks && 0 === $ticks % self::$free_ticks ) {
114
+ self::free_memory();
115
+ }
116
+ }
117
+
118
+ /**
119
+ * Reduce memory footprint by clearing the database query and object caches.
120
+ */
121
+ public static function free_memory() {
122
+ if ( 0 < self::$sleep_time ) {
123
+ /* translators: %d: amount of time */
124
+ \WP_CLI::warning( sprintf( _n( 'Stopped the insanity for %d second', 'Stopped the insanity for %d seconds', self::$sleep_time, 'action-scheduler' ), self::$sleep_time ) );
125
+ sleep( self::$sleep_time );
126
+ }
127
+
128
+ \WP_CLI::warning( __( 'Attempting to reduce used memory...', 'action-scheduler' ) );
129
+
130
+ /**
131
+ * @var $wpdb \wpdb
132
+ * @var $wp_object_cache \WP_Object_Cache
133
+ */
134
+ global $wpdb, $wp_object_cache;
135
+
136
+ $wpdb->queries = array();
137
+
138
+ if ( ! is_a( $wp_object_cache, 'WP_Object_Cache' ) ) {
139
+ return;
140
+ }
141
+
142
+ $wp_object_cache->group_ops = array();
143
+ $wp_object_cache->stats = array();
144
+ $wp_object_cache->memcache_debug = array();
145
+ $wp_object_cache->cache = array();
146
+
147
+ if ( is_callable( array( $wp_object_cache, '__remoteset' ) ) ) {
148
+ call_user_func( array( $wp_object_cache, '__remoteset' ) ); // important
149
+ }
150
+ }
151
+
152
+ /**
153
+ * Connect to table datastores if migration is complete.
154
+ * Otherwise, proceed with the migration if the dependencies have been met.
155
+ */
156
+ public static function init() {
157
+ if ( self::is_migration_complete() ) {
158
+ add_filter( 'action_scheduler_store_class', array( 'ActionScheduler_DataController', 'set_store_class' ), 100 );
159
+ add_filter( 'action_scheduler_logger_class', array( 'ActionScheduler_DataController', 'set_logger_class' ), 100 );
160
+ } elseif ( self::dependencies_met() ) {
161
+ Controller::init();
162
+ }
163
+
164
+ add_action( 'action_scheduler/progress_tick', array( 'ActionScheduler_DataController', 'maybe_free_memory' ) );
165
+ }
166
+
167
+ /**
168
+ * Singleton factory.
169
+ */
170
+ public static function instance() {
171
+ if ( ! isset( self::$instance ) ) {
172
+ self::$instance = new static();
173
+ }
174
+
175
+ return self::$instance;
176
+ }
177
+ }
includes/vendor/action-scheduler/classes/ActionScheduler_Exception.php CHANGED
@@ -5,7 +5,7 @@
5
  *
6
  * Facilitates catching Exceptions unique to Action Scheduler.
7
  *
8
- * @package Prospress\ActionScheduler
9
  * @since %VERSION%
10
  */
11
  interface ActionScheduler_Exception {}
5
  *
6
  * Facilitates catching Exceptions unique to Action Scheduler.
7
  *
8
+ * @package ActionScheduler
9
  * @since %VERSION%
10
  */
11
  interface ActionScheduler_Exception {}
includes/vendor/action-scheduler/classes/ActionScheduler_IntervalSchedule.php DELETED
@@ -1,60 +0,0 @@
1
- <?php
2
-
3
- /**
4
- * Class ActionScheduler_IntervalSchedule
5
- */
6
- class ActionScheduler_IntervalSchedule implements ActionScheduler_Schedule {
7
- /** @var DateTime */
8
- private $start = NULL;
9
- private $start_timestamp = 0;
10
- private $interval_in_seconds = 0;
11
-
12
- public function __construct( DateTime $start, $interval ) {
13
- $this->start = $start;
14
- $this->interval_in_seconds = (int)$interval;
15
- }
16
-
17
- /**
18
- * @param DateTime $after
19
- *
20
- * @return DateTime|null
21
- */
22
- public function next( DateTime $after = NULL ) {
23
- $after = empty($after) ? as_get_datetime_object('@0') : clone $after;
24
- if ( $after > $this->start ) {
25
- $after->modify('+'.$this->interval_in_seconds.' seconds');
26
- return $after;
27
- }
28
- return clone $this->start;
29
- }
30
-
31
- /**
32
- * @return bool
33
- */
34
- public function is_recurring() {
35
- return true;
36
- }
37
-
38
- /**
39
- * @return int
40
- */
41
- public function interval_in_seconds() {
42
- return $this->interval_in_seconds;
43
- }
44
-
45
- /**
46
- * For PHP 5.2 compat, since DateTime objects can't be serialized
47
- * @return array
48
- */
49
- public function __sleep() {
50
- $this->start_timestamp = $this->start->getTimestamp();
51
- return array(
52
- 'start_timestamp',
53
- 'interval_in_seconds'
54
- );
55
- }
56
-
57
- public function __wakeup() {
58
- $this->start = as_get_datetime_object($this->start_timestamp);
59
- }
60
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
includes/vendor/action-scheduler/classes/ActionScheduler_InvalidActionException.php CHANGED
@@ -5,10 +5,27 @@
5
  *
6
  * Used for identifying actions that are invalid in some way.
7
  *
8
- * @package Prospress\ActionScheduler
9
  */
10
  class ActionScheduler_InvalidActionException extends \InvalidArgumentException implements ActionScheduler_Exception {
11
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
12
  /**
13
  * Create a new exception when the action's args cannot be decoded to an array.
14
  *
@@ -17,10 +34,12 @@ class ActionScheduler_InvalidActionException extends \InvalidArgumentException i
17
  * @param string $action_id The action ID with bad args.
18
  * @return static
19
  */
20
- public static function from_decoding_args( $action_id ) {
21
  $message = sprintf(
22
- __( 'Action [%s] has invalid arguments. It cannot be JSON decoded to an array.', 'action-scheduler' ),
23
- $action_id
 
 
24
  );
25
 
26
  return new static( $message );
5
  *
6
  * Used for identifying actions that are invalid in some way.
7
  *
8
+ * @package ActionScheduler
9
  */
10
  class ActionScheduler_InvalidActionException extends \InvalidArgumentException implements ActionScheduler_Exception {
11
 
12
+ /**
13
+ * Create a new exception when the action's schedule cannot be fetched.
14
+ *
15
+ * @param string $action_id The action ID with bad args.
16
+ * @return static
17
+ */
18
+ public static function from_schedule( $action_id, $schedule ) {
19
+ $message = sprintf(
20
+ /* translators: 1: action ID 2: schedule */
21
+ __( 'Action [%1$s] has an invalid schedule: %2$s', 'action-scheduler' ),
22
+ $action_id,
23
+ var_export( $schedule, true )
24
+ );
25
+
26
+ return new static( $message );
27
+ }
28
+
29
  /**
30
  * Create a new exception when the action's args cannot be decoded to an array.
31
  *
34
  * @param string $action_id The action ID with bad args.
35
  * @return static
36
  */
37
+ public static function from_decoding_args( $action_id, $args = array() ) {
38
  $message = sprintf(
39
+ /* translators: 1: action ID 2: arguments */
40
+ __( 'Action [%1$s] has invalid arguments. It cannot be JSON decoded to an array. $args = %2$s', 'action-scheduler' ),
41
+ $action_id,
42
+ var_export( $args, true )
43
  );
44
 
45
  return new static( $message );
includes/vendor/action-scheduler/classes/ActionScheduler_ListTable.php CHANGED
@@ -140,30 +140,37 @@ class ActionScheduler_ListTable extends ActionScheduler_Abstract_ListTable {
140
  self::$time_periods = array(
141
  array(
142
  'seconds' => YEAR_IN_SECONDS,
 
143
  'names' => _n_noop( '%s year', '%s years', 'action-scheduler' ),
144
  ),
145
  array(
146
  'seconds' => MONTH_IN_SECONDS,
 
147
  'names' => _n_noop( '%s month', '%s months', 'action-scheduler' ),
148
  ),
149
  array(
150
  'seconds' => WEEK_IN_SECONDS,
 
151
  'names' => _n_noop( '%s week', '%s weeks', 'action-scheduler' ),
152
  ),
153
  array(
154
  'seconds' => DAY_IN_SECONDS,
 
155
  'names' => _n_noop( '%s day', '%s days', 'action-scheduler' ),
156
  ),
157
  array(
158
  'seconds' => HOUR_IN_SECONDS,
 
159
  'names' => _n_noop( '%s hour', '%s hours', 'action-scheduler' ),
160
  ),
161
  array(
162
  'seconds' => MINUTE_IN_SECONDS,
 
163
  'names' => _n_noop( '%s minute', '%s minutes', 'action-scheduler' ),
164
  ),
165
  array(
166
  'seconds' => 1,
 
167
  'names' => _n_noop( '%s second', '%s seconds', 'action-scheduler' ),
168
  ),
169
  );
@@ -221,14 +228,15 @@ class ActionScheduler_ListTable extends ActionScheduler_Abstract_ListTable {
221
  * @return string
222
  */
223
  protected function get_recurrence( $action ) {
224
- $recurrence = $action->get_schedule();
225
- if ( $recurrence->is_recurring() ) {
226
- if ( method_exists( $recurrence, 'interval_in_seconds' ) ) {
227
- return sprintf( __( 'Every %s', 'action-scheduler' ), self::human_interval( $recurrence->interval_in_seconds() ) );
228
- }
229
 
230
- if ( method_exists( $recurrence, 'get_recurrence' ) ) {
231
- return sprintf( __( 'Cron %s', 'action-scheduler' ), $recurrence->get_recurrence() );
 
 
 
232
  }
233
  }
234
 
@@ -315,10 +323,32 @@ class ActionScheduler_ListTable extends ActionScheduler_Abstract_ListTable {
315
  */
316
  public function display_admin_notices() {
317
 
318
- if ( $this->store->get_claim_count() >= $this->runner->get_allowed_concurrent_batches() ) {
319
  $this->admin_notices[] = array(
320
  'class' => 'updated',
321
- 'message' => sprintf( __( 'Maximum simultaneous batches already in progress (%s queues). No actions will be processed until the current batches are complete.', 'action-scheduler' ), $this->store->get_claim_count() ),
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
322
  );
323
  }
324
 
@@ -333,18 +363,22 @@ class ActionScheduler_ListTable extends ActionScheduler_Abstract_ListTable {
333
  $class = 'updated';
334
  switch ( $notification['row_action_type'] ) {
335
  case 'run' :
 
336
  $action_message_html = sprintf( __( 'Successfully executed action: %s', 'action-scheduler' ), $action_hook_html );
337
  break;
338
  case 'cancel' :
 
339
  $action_message_html = sprintf( __( 'Successfully canceled action: %s', 'action-scheduler' ), $action_hook_html );
340
  break;
341
  default :
 
342
  $action_message_html = sprintf( __( 'Successfully processed change for action: %s', 'action-scheduler' ), $action_hook_html );
343
  break;
344
  }
345
  } else {
346
  $class = 'error';
347
- $action_message_html = sprintf( __( 'Could not process change for action: "%s" (ID: %d). Error: %s', 'action-scheduler' ), $action_hook_html, esc_html( $notification['action_id'] ), esc_html( $notification['error_message'] ) );
 
348
  }
349
 
350
  $action_message_html = apply_filters( 'action_scheduler_admin_notice_html', $action_message_html, $action, $notification );
@@ -379,18 +413,20 @@ class ActionScheduler_ListTable extends ActionScheduler_Abstract_ListTable {
379
 
380
  $schedule_display_string = '';
381
 
382
- if ( ! $schedule->next() ) {
383
- return $schedule_display_string;
384
  }
385
 
386
- $next_timestamp = $schedule->next()->getTimestamp();
387
 
388
- $schedule_display_string .= $schedule->next()->format( 'Y-m-d H:i:s O' );
389
  $schedule_display_string .= '<br/>';
390
 
391
  if ( gmdate( 'U' ) > $next_timestamp ) {
 
392
  $schedule_display_string .= sprintf( __( ' (%s ago)', 'action-scheduler' ), self::human_interval( gmdate( 'U' ) - $next_timestamp ) );
393
  } else {
 
394
  $schedule_display_string .= sprintf( __( ' (%s)', 'action-scheduler' ), self::human_interval( $next_timestamp - gmdate( 'U' ) ) );
395
  }
396
 
@@ -442,7 +478,7 @@ class ActionScheduler_ListTable extends ActionScheduler_Abstract_ListTable {
442
  try {
443
  switch ( $row_action_type ) {
444
  case 'run' :
445
- $this->runner->process_action( $action_id );
446
  break;
447
  case 'cancel' :
448
  $this->store->cancel_action( $action_id );
@@ -462,16 +498,6 @@ class ActionScheduler_ListTable extends ActionScheduler_Abstract_ListTable {
462
  * {@inheritDoc}
463
  */
464
  public function prepare_items() {
465
- $this->process_bulk_action();
466
-
467
- $this->process_row_actions();
468
-
469
- if ( ! empty( $_REQUEST['_wp_http_referer'] ) ) {
470
- // _wp_http_referer is used only on bulk actions, we remove it to keep the $_GET shorter
471
- wp_redirect( remove_query_arg( array( '_wp_http_referer', '_wpnonce' ), wp_unslash( $_SERVER['REQUEST_URI'] ) ) );
472
- exit;
473
- }
474
-
475
  $this->prepare_column_headers();
476
 
477
  $per_page = $this->get_items_per_page( $this->package . '_items_per_page', $this->items_per_page );
140
  self::$time_periods = array(
141
  array(
142
  'seconds' => YEAR_IN_SECONDS,
143
+ /* translators: %s: amount of time */
144
  'names' => _n_noop( '%s year', '%s years', 'action-scheduler' ),
145
  ),
146
  array(
147
  'seconds' => MONTH_IN_SECONDS,
148
+ /* translators: %s: amount of time */
149
  'names' => _n_noop( '%s month', '%s months', 'action-scheduler' ),
150
  ),
151
  array(
152
  'seconds' => WEEK_IN_SECONDS,
153
+ /* translators: %s: amount of time */
154
  'names' => _n_noop( '%s week', '%s weeks', 'action-scheduler' ),
155
  ),
156
  array(
157
  'seconds' => DAY_IN_SECONDS,
158
+ /* translators: %s: amount of time */
159
  'names' => _n_noop( '%s day', '%s days', 'action-scheduler' ),
160
  ),
161
  array(
162
  'seconds' => HOUR_IN_SECONDS,
163
+ /* translators: %s: amount of time */
164
  'names' => _n_noop( '%s hour', '%s hours', 'action-scheduler' ),
165
  ),
166
  array(
167
  'seconds' => MINUTE_IN_SECONDS,
168
+ /* translators: %s: amount of time */
169
  'names' => _n_noop( '%s minute', '%s minutes', 'action-scheduler' ),
170
  ),
171
  array(
172
  'seconds' => 1,
173
+ /* translators: %s: amount of time */
174
  'names' => _n_noop( '%s second', '%s seconds', 'action-scheduler' ),
175
  ),
176
  );
228
  * @return string
229
  */
230
  protected function get_recurrence( $action ) {
231
+ $schedule = $action->get_schedule();
232
+ if ( $schedule->is_recurring() ) {
233
+ $recurrence = $schedule->get_recurrence();
 
 
234
 
235
+ if ( is_numeric( $recurrence ) ) {
236
+ /* translators: %s: time interval */
237
+ return sprintf( __( 'Every %s', 'action-scheduler' ), self::human_interval( $recurrence ) );
238
+ } else {
239
+ return $recurrence;
240
  }
241
  }
242
 
323
  */
324
  public function display_admin_notices() {
325
 
326
+ if ( $this->runner->has_maximum_concurrent_batches() ) {
327
  $this->admin_notices[] = array(
328
  'class' => 'updated',
329
+ 'message' => sprintf(
330
+ /* translators: %s: amount of claims */
331
+ __( 'Maximum simultaneous queues already in progress (%s queues). No additional queues will begin processing until the current queues are complete.', 'action-scheduler' ),
332
+ $this->store->get_claim_count()
333
+ ),
334
+ );
335
+ } elseif ( $this->store->has_pending_actions_due() ) {
336
+
337
+ $async_request_lock_expiration = ActionScheduler::lock()->get_expiration( 'async-request-runner' );
338
+
339
+ // No lock set or lock expired
340
+ if ( false === $async_request_lock_expiration || $async_request_lock_expiration < time() ) {
341
+ $in_progress_url = add_query_arg( 'status', 'in-progress', remove_query_arg( 'status' ) );
342
+ /* translators: %s: process URL */
343
+ $async_request_message = sprintf( __( 'A new queue has begun processing. <a href="%s">View actions in-progress &raquo;</a>', 'action-scheduler' ), esc_url( $in_progress_url ) );
344
+ } else {
345
+ /* translators: %d: seconds */
346
+ $async_request_message = sprintf( __( 'The next queue will begin processing in approximately %d seconds.', 'action-scheduler' ), $async_request_lock_expiration - time() );
347
+ }
348
+
349
+ $this->admin_notices[] = array(
350
+ 'class' => 'notice notice-info',
351
+ 'message' => $async_request_message,
352
  );
353
  }
354
 
363
  $class = 'updated';
364
  switch ( $notification['row_action_type'] ) {
365
  case 'run' :
366
+ /* translators: %s: action HTML */
367
  $action_message_html = sprintf( __( 'Successfully executed action: %s', 'action-scheduler' ), $action_hook_html );
368
  break;
369
  case 'cancel' :
370
+ /* translators: %s: action HTML */
371
  $action_message_html = sprintf( __( 'Successfully canceled action: %s', 'action-scheduler' ), $action_hook_html );
372
  break;
373
  default :
374
+ /* translators: %s: action HTML */
375
  $action_message_html = sprintf( __( 'Successfully processed change for action: %s', 'action-scheduler' ), $action_hook_html );
376
  break;
377
  }
378
  } else {
379
  $class = 'error';
380
+ /* translators: 1: action HTML 2: action ID 3: error message */
381
+ $action_message_html = sprintf( __( 'Could not process change for action: "%1$s" (ID: %2$d). Error: %3$s', 'action-scheduler' ), $action_hook_html, esc_html( $notification['action_id'] ), esc_html( $notification['error_message'] ) );
382
  }
383
 
384
  $action_message_html = apply_filters( 'action_scheduler_admin_notice_html', $action_message_html, $action, $notification );
413
 
414
  $schedule_display_string = '';
415
 
416
+ if ( ! $schedule->get_date() ) {
417
+ return '0000-00-00 00:00:00';
418
  }
419
 
420
+ $next_timestamp = $schedule->get_date()->getTimestamp();
421
 
422
+ $schedule_display_string .= $schedule->get_date()->format( 'Y-m-d H:i:s O' );
423
  $schedule_display_string .= '<br/>';
424
 
425
  if ( gmdate( 'U' ) > $next_timestamp ) {
426
+ /* translators: %s: date interval */
427
  $schedule_display_string .= sprintf( __( ' (%s ago)', 'action-scheduler' ), self::human_interval( gmdate( 'U' ) - $next_timestamp ) );
428
  } else {
429
+ /* translators: %s: date interval */
430
  $schedule_display_string .= sprintf( __( ' (%s)', 'action-scheduler' ), self::human_interval( $next_timestamp - gmdate( 'U' ) ) );
431
  }
432
 
478
  try {
479
  switch ( $row_action_type ) {
480
  case 'run' :
481
+ $this->runner->process_action( $action_id, 'Admin List Table' );
482
  break;
483
  case 'cancel' :
484
  $this->store->cancel_action( $action_id );
498
  * {@inheritDoc}
499
  */
500
  public function prepare_items() {
 
 
 
 
 
 
 
 
 
 
501
  $this->prepare_column_headers();
502
 
503
  $per_page = $this->get_items_per_page( $this->package . '_items_per_page', $this->items_per_page );
includes/vendor/action-scheduler/classes/ActionScheduler_Logger.php DELETED
@@ -1,102 +0,0 @@
1
- <?php
2
-
3
- /**
4
- * Class ActionScheduler_Logger
5
- * @codeCoverageIgnore
6
- */
7
- abstract class ActionScheduler_Logger {
8
- private static $logger = NULL;
9
-
10
- /**
11
- * @return ActionScheduler_Logger
12
- */
13
- public static function instance() {
14
- if ( empty(self::$logger) ) {
15
- $class = apply_filters('action_scheduler_logger_class', 'ActionScheduler_wpCommentLogger');
16
- self::$logger = new $class();
17
- }
18
- return self::$logger;
19
- }
20
-
21
- /**
22
- * @param string $action_id
23
- * @param string $message
24
- * @param DateTime $date
25
- *
26
- * @return string The log entry ID
27
- */
28
- abstract public function log( $action_id, $message, DateTime $date = NULL );
29
-
30
- /**
31
- * @param string $entry_id
32
- *
33
- * @return ActionScheduler_LogEntry
34
- */
35
- abstract public function get_entry( $entry_id );
36
-
37
- /**
38
- * @param string $action_id
39
- *
40
- * @return ActionScheduler_LogEntry[]
41
- */
42
- abstract public function get_logs( $action_id );
43
-
44
-
45
- /**
46
- * @codeCoverageIgnore
47
- */
48
- public function init() {
49
- add_action( 'action_scheduler_stored_action', array( $this, 'log_stored_action' ), 10, 1 );
50
- add_action( 'action_scheduler_canceled_action', array( $this, 'log_canceled_action' ), 10, 1 );
51
- add_action( 'action_scheduler_before_execute', array( $this, 'log_started_action' ), 10, 1 );
52
- add_action( 'action_scheduler_after_execute', array( $this, 'log_completed_action' ), 10, 1 );
53
- add_action( 'action_scheduler_failed_execution', array( $this, 'log_failed_action' ), 10, 2 );
54
- add_action( 'action_scheduler_failed_action', array( $this, 'log_timed_out_action' ), 10, 2 );
55
- add_action( 'action_scheduler_unexpected_shutdown', array( $this, 'log_unexpected_shutdown' ), 10, 2 );
56
- add_action( 'action_scheduler_reset_action', array( $this, 'log_reset_action' ), 10, 1 );
57
- add_action( 'action_scheduler_execution_ignored', array( $this, 'log_ignored_action' ), 10, 1 );
58
- add_action( 'action_scheduler_failed_fetch_action', array( $this, 'log_failed_fetch_action' ), 10, 1 );
59
- }
60
-
61
- public function log_stored_action( $action_id ) {
62
- $this->log( $action_id, __( 'action created', 'action-scheduler' ) );
63
- }
64
-
65
- public function log_canceled_action( $action_id ) {
66
- $this->log( $action_id, __( 'action canceled', 'action-scheduler' ) );
67
- }
68
-
69
- public function log_started_action( $action_id ) {
70
- $this->log( $action_id, __( 'action started', 'action-scheduler' ) );
71
- }
72
-
73
- public function log_completed_action( $action_id ) {
74
- $this->log( $action_id, __( 'action complete', 'action-scheduler' ) );
75
- }
76
-
77
- public function log_failed_action( $action_id, Exception $exception ) {
78
- $this->log( $action_id, sprintf( __( 'action failed: %s', 'action-scheduler' ), $exception->getMessage() ) );
79
- }
80
-
81
- public function log_timed_out_action( $action_id, $timeout ) {
82
- $this->log( $action_id, sprintf( __( 'action timed out after %s seconds', 'action-scheduler' ), $timeout ) );
83
- }
84
-
85
- public function log_unexpected_shutdown( $action_id, $error ) {
86
- if ( ! empty( $error ) ) {
87
- $this->log( $action_id, sprintf( __( 'unexpected shutdown: PHP Fatal error %s in %s on line %s', 'action-scheduler' ), $error['message'], $error['file'], $error['line'] ) );
88
- }
89
- }
90
-
91
- public function log_reset_action( $action_id ) {
92
- $this->log( $action_id, __( 'action reset', 'action_scheduler' ) );
93
- }
94
-
95
- public function log_ignored_action( $action_id ) {
96
- $this->log( $action_id, __( 'action ignored', 'action-scheduler' ) );
97
- }
98
-
99
- public function log_failed_fetch_action( $action_id ) {
100
- $this->log( $action_id, __( 'There was a failure fetching this action', 'action-scheduler' ) );
101
- }
102
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
includes/vendor/action-scheduler/classes/ActionScheduler_NullSchedule.php DELETED
@@ -1,19 +0,0 @@
1
- <?php
2
-
3
- /**
4
- * Class ActionScheduler_NullSchedule
5
- */
6
- class ActionScheduler_NullSchedule implements ActionScheduler_Schedule {
7
-
8
- public function next( DateTime $after = NULL ) {
9
- return NULL;
10
- }
11
-
12
- /**
13
- * @return bool
14
- */
15
- public function is_recurring() {
16
- return false;
17
- }
18
- }
19
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
includes/vendor/action-scheduler/classes/ActionScheduler_OptionLock.php ADDED
@@ -0,0 +1,49 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Provide a way to set simple transient locks to block behaviour
5
+ * for up-to a given duration.
6
+ *
7
+ * Class ActionScheduler_OptionLock
8
+ * @since 3.0.0
9
+ */
10
+ class ActionScheduler_OptionLock extends ActionScheduler_Lock {
11
+
12
+ /**
13
+ * Set a lock using options for a given amount of time (60 seconds by default).
14
+ *
15
+ * Using an autoloaded option avoids running database queries or other resource intensive tasks
16
+ * on frequently triggered hooks, like 'init' or 'shutdown'.
17
+ *
18
+ * For example, ActionScheduler_QueueRunner->maybe_dispatch_async_request() uses a lock to avoid
19
+ * calling ActionScheduler_QueueRunner->has_maximum_concurrent_batches() every time the 'shutdown',
20
+ * hook is triggered, because that method calls ActionScheduler_QueueRunner->store->get_claim_count()
21
+ * to find the current number of claims in the database.
22
+ *
23
+ * @param string $lock_type A string to identify different lock types.
24
+ * @bool True if lock value has changed, false if not or if set failed.
25
+ */
26
+ public function set( $lock_type ) {
27
+ return update_option( $this->get_key( $lock_type ), time() + $this->get_duration( $lock_type ) );
28
+ }
29
+
30
+ /**
31
+ * If a lock is set, return the timestamp it was set to expiry.
32
+ *
33
+ * @param string $lock_type A string to identify different lock types.
34
+ * @return bool|int False if no lock is set, otherwise the timestamp for when the lock is set to expire.
35
+ */
36
+ public function get_expiration( $lock_type ) {
37
+ return get_option( $this->get_key( $lock_type ) );
38
+ }
39
+
40
+ /**
41
+ * Get the key to use for storing the lock in the transient
42
+ *
43
+ * @param string $lock_type A string to identify different lock types.
44
+ * @return string
45
+ */
46
+ protected function get_key( $lock_type ) {
47
+ return sprintf( 'action_scheduler_lock_%s', $lock_type );
48
+ }
49
+ }
includes/vendor/action-scheduler/classes/ActionScheduler_QueueRunner.php CHANGED
@@ -8,6 +8,9 @@ class ActionScheduler_QueueRunner extends ActionScheduler_Abstract_QueueRunner {
8
 
9
  const WP_CRON_SCHEDULE = 'every_minute';
10
 
 
 
 
11
  /** @var ActionScheduler_QueueRunner */
12
  private static $runner = null;
13
 
@@ -30,8 +33,14 @@ class ActionScheduler_QueueRunner extends ActionScheduler_Abstract_QueueRunner {
30
  * @param ActionScheduler_FatalErrorMonitor $monitor
31
  * @param ActionScheduler_QueueCleaner $cleaner
32
  */
33
- public function __construct( ActionScheduler_Store $store = null, ActionScheduler_FatalErrorMonitor $monitor = null, ActionScheduler_QueueCleaner $cleaner = null ) {
34
  parent::__construct( $store, $monitor, $cleaner );
 
 
 
 
 
 
35
  }
36
 
37
  /**
@@ -41,24 +50,74 @@ class ActionScheduler_QueueRunner extends ActionScheduler_Abstract_QueueRunner {
41
 
42
  add_filter( 'cron_schedules', array( self::instance(), 'add_wp_cron_schedule' ) );
43
 
44
- if ( !wp_next_scheduled(self::WP_CRON_HOOK) ) {
 
 
 
 
 
 
 
 
 
45
  $schedule = apply_filters( 'action_scheduler_run_schedule', self::WP_CRON_SCHEDULE );
46
- wp_schedule_event( time(), $schedule, self::WP_CRON_HOOK );
47
  }
48
 
49
  add_action( self::WP_CRON_HOOK, array( self::instance(), 'run' ) );
 
 
50
  }
51
 
52
- public function run() {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
53
  ActionScheduler_Compatibility::raise_memory_limit();
54
  ActionScheduler_Compatibility::raise_time_limit( $this->get_time_limit() );
55
  do_action( 'action_scheduler_before_process_queue' );
56
  $this->run_cleanup();
57
  $processed_actions = 0;
58
- if ( $this->store->get_claim_count() < $this->get_allowed_concurrent_batches() ) {
59
  $batch_size = apply_filters( 'action_scheduler_queue_runner_batch_size', 25 );
60
  do {
61
- $processed_actions_in_batch = $this->do_batch( $batch_size );
62
  $processed_actions += $processed_actions_in_batch;
63
  } while ( $processed_actions_in_batch > 0 && ! $this->batch_limits_exceeded( $processed_actions ) ); // keep going until we run out of actions, time, or memory
64
  }
@@ -67,7 +126,18 @@ class ActionScheduler_QueueRunner extends ActionScheduler_Abstract_QueueRunner {
67
  return $processed_actions;
68
  }
69
 
70
- protected function do_batch( $size = 100 ) {
 
 
 
 
 
 
 
 
 
 
 
71
  $claim = $this->store->stake_claim($size);
72
  $this->monitor->attach($claim);
73
  $processed_actions = 0;
@@ -77,7 +147,7 @@ class ActionScheduler_QueueRunner extends ActionScheduler_Abstract_QueueRunner {
77
  if ( ! in_array( $action_id, $this->store->find_actions_by_claim_id( $claim->get_id() ) ) ) {
78
  break;
79
  }
80
- $this->process_action( $action_id );
81
  $processed_actions++;
82
 
83
  if ( $this->batch_limits_exceeded( $processed_actions ) ) {
@@ -107,7 +177,7 @@ class ActionScheduler_QueueRunner extends ActionScheduler_Abstract_QueueRunner {
107
  public function add_wp_cron_schedule( $schedules ) {
108
  $schedules['every_minute'] = array(
109
  'interval' => 60, // in seconds
110
- 'display' => __( 'Every minute' ),
111
  );
112
 
113
  return $schedules;
8
 
9
  const WP_CRON_SCHEDULE = 'every_minute';
10
 
11
+ /** @var ActionScheduler_AsyncRequest_QueueRunner */
12
+ protected $async_request;
13
+
14
  /** @var ActionScheduler_QueueRunner */
15
  private static $runner = null;
16
 
33
  * @param ActionScheduler_FatalErrorMonitor $monitor
34
  * @param ActionScheduler_QueueCleaner $cleaner
35
  */
36
+ public function __construct( ActionScheduler_Store $store = null, ActionScheduler_FatalErrorMonitor $monitor = null, ActionScheduler_QueueCleaner $cleaner = null, ActionScheduler_AsyncRequest_QueueRunner $async_request = null ) {
37
  parent::__construct( $store, $monitor, $cleaner );
38
+
39
+ if ( is_null( $async_request ) ) {
40
+ $async_request = new ActionScheduler_AsyncRequest_QueueRunner( $this->store );
41
+ }
42
+
43
+ $this->async_request = $async_request;
44
  }
45
 
46
  /**
50
 
51
  add_filter( 'cron_schedules', array( self::instance(), 'add_wp_cron_schedule' ) );
52
 
53
+ $cron_context = array( 'WP Cron' );
54
+
55
+ if ( ! wp_next_scheduled( self::WP_CRON_HOOK, $cron_context ) ) {
56
+
57
+ // Check for and remove any WP Cron hook scheduled by Action Scheduler < 3.0.0, which didn't include the $context param
58
+ $next_timestamp = wp_next_scheduled( self::WP_CRON_HOOK );
59
+ if ( $next_timestamp ) {
60
+ wp_unschedule_event( $next_timestamp, self::WP_CRON_HOOK );
61
+ }
62
+
63
  $schedule = apply_filters( 'action_scheduler_run_schedule', self::WP_CRON_SCHEDULE );
64
+ wp_schedule_event( time(), $schedule, self::WP_CRON_HOOK, $cron_context );
65
  }
66
 
67
  add_action( self::WP_CRON_HOOK, array( self::instance(), 'run' ) );
68
+
69
+ add_filter( 'shutdown', array( $this, 'maybe_dispatch_async_request' ) );
70
  }
71
 
72
+ /**
73
+ * Check if we should dispatch an async request to process actions.
74
+ *
75
+ * This method is attached to 'shutdown', so is called frequently. To avoid slowing down
76
+ * the site, it mitigates the work performed in each request by:
77
+ * 1. checking if it's in the admin context and then
78
+ * 2. haven't run on the 'shutdown' hook within the lock time (60 seconds by default)
79
+ * 3. haven't exceeded the number of allowed batches.
80
+ *
81
+ * The order of these checks is important, because they run from a check on a value:
82
+ * 1. in memory - is_admin() maps to $GLOBALS or the WP_ADMIN constant
83
+ * 2. in memory - transients use autoloaded options by default
84
+ * 3. from a database query - has_maximum_concurrent_batches() run the query
85
+ * $this->store->get_claim_count() to find the current number of claims in the DB.
86
+ *
87
+ * If all of these conditions are met, then we request an async runner check whether it
88
+ * should dispatch a request to process pending actions.
89
+ */
90
+ public function maybe_dispatch_async_request() {
91
+ if ( is_admin() && ! ActionScheduler::lock()->is_locked( 'async-request-runner' ) ) {
92
+ // Only start an async queue at most once every 60 seconds
93
+ ActionScheduler::lock()->set( 'async-request-runner' );
94
+ $this->async_request->maybe_dispatch();
95
+ }
96
+ }
97
+
98
+ /**
99
+ * Process actions in the queue. Attached to self::WP_CRON_HOOK i.e. 'action_scheduler_run_queue'
100
+ *
101
+ * The $context param of this method defaults to 'WP Cron', because prior to Action Scheduler 3.0.0
102
+ * that was the only context in which this method was run, and the self::WP_CRON_HOOK hook had no context
103
+ * passed along with it. New code calling this method directly, or by triggering the self::WP_CRON_HOOK,
104
+ * should set a context as the first parameter. For an example of this, refer to the code seen in
105
+ * @see ActionScheduler_AsyncRequest_QueueRunner::handle()
106
+ *
107
+ * @param string $context Optional identifer for the context in which this action is being processed, e.g. 'WP CLI' or 'WP Cron'
108
+ * Generally, this should be capitalised and not localised as it's a proper noun.
109
+ * @return int The number of actions processed.
110
+ */
111
+ public function run( $context = 'WP Cron' ) {
112
  ActionScheduler_Compatibility::raise_memory_limit();
113
  ActionScheduler_Compatibility::raise_time_limit( $this->get_time_limit() );
114
  do_action( 'action_scheduler_before_process_queue' );
115
  $this->run_cleanup();
116
  $processed_actions = 0;
117
+ if ( false === $this->has_maximum_concurrent_batches() ) {
118
  $batch_size = apply_filters( 'action_scheduler_queue_runner_batch_size', 25 );
119
  do {
120
+ $processed_actions_in_batch = $this->do_batch( $batch_size, $context );
121
  $processed_actions += $processed_actions_in_batch;
122
  } while ( $processed_actions_in_batch > 0 && ! $this->batch_limits_exceeded( $processed_actions ) ); // keep going until we run out of actions, time, or memory
123
  }
126
  return $processed_actions;
127
  }
128
 
129
+ /**
130
+ * Process a batch of actions pending in the queue.
131
+ *
132
+ * Actions are processed by claiming a set of pending actions then processing each one until either the batch
133
+ * size is completed, or memory or time limits are reached, defined by @see $this->batch_limits_exceeded().
134
+ *
135
+ * @param int $size The maximum number of actions to process in the batch.
136
+ * @param string $context Optional identifer for the context in which this action is being processed, e.g. 'WP CLI' or 'WP Cron'
137
+ * Generally, this should be capitalised and not localised as it's a proper noun.
138
+ * @return int The number of actions processed.
139
+ */
140
+ protected function do_batch( $size = 100, $context = '' ) {
141
  $claim = $this->store->stake_claim($size);
142
  $this->monitor->attach($claim);
143
  $processed_actions = 0;
147
  if ( ! in_array( $action_id, $this->store->find_actions_by_claim_id( $claim->get_id() ) ) ) {
148
  break;
149
  }
150
+ $this->process_action( $action_id, $context );
151
  $processed_actions++;
152
 
153
  if ( $this->batch_limits_exceeded( $processed_actions ) ) {
177
  public function add_wp_cron_schedule( $schedules ) {
178
  $schedules['every_minute'] = array(
179
  'interval' => 60, // in seconds
180
+ 'display' => __( 'Every minute', 'action-scheduler' ),
181
  );
182
 
183
  return $schedules;
includes/vendor/action-scheduler/classes/ActionScheduler_SimpleSchedule.php DELETED
@@ -1,44 +0,0 @@
1
- <?php
2
-
3
- /**
4
- * Class ActionScheduler_SimpleSchedule
5
- */
6
- class ActionScheduler_SimpleSchedule implements ActionScheduler_Schedule {
7
- private $date = NULL;
8
- private $timestamp = 0;
9
- public function __construct( DateTime $date ) {
10
- $this->date = clone $date;
11
- }
12
-
13
- /**
14
- * @param DateTime $after
15
- *
16
- * @return DateTime|null
17
- */
18
- public function next( DateTime $after = NULL ) {
19
- $after = empty($after) ? as_get_datetime_object('@0') : $after;
20
- return ( $after > $this->date ) ? NULL : clone $this->date;
21
- }
22
-
23
- /**
24
- * @return bool
25
- */
26
- public function is_recurring() {
27
- return false;
28
- }
29
-
30
- /**
31
- * For PHP 5.2 compat, since DateTime objects can't be serialized
32
- * @return array
33
- */
34
- public function __sleep() {
35
- $this->timestamp = $this->date->getTimestamp();
36
- return array(
37
- 'timestamp',
38
- );
39
- }
40
-
41
- public function __wakeup() {
42
- $this->date = as_get_datetime_object($this->timestamp);
43
- }
44
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
includes/vendor/action-scheduler/classes/ActionScheduler_Store.php DELETED
@@ -1,212 +0,0 @@
1
- <?php
2
-
3
- /**
4
- * Class ActionScheduler_Store
5
- * @codeCoverageIgnore
6
- */
7
- abstract class ActionScheduler_Store {
8
- const STATUS_COMPLETE = 'complete';
9
- const STATUS_PENDING = 'pending';
10
- const STATUS_RUNNING = 'in-progress';
11
- const STATUS_FAILED = 'failed';
12
- const STATUS_CANCELED = 'canceled';
13
-
14
- /** @var ActionScheduler_Store */
15
- private static $store = NULL;
16
-
17
- /**
18
- * @param ActionScheduler_Action $action
19
- * @param DateTime $scheduled_date Optional Date of the first instance
20
- * to store. Otherwise uses the first date of the action's
21
- * schedule.
22
- *
23
- * @return string The action ID
24
- */
25
- abstract public function save_action( ActionScheduler_Action $action, DateTime $scheduled_date = NULL );
26
-
27
- /**
28
- * @param string $action_id
29
- *
30
- * @return ActionScheduler_Action
31
- */
32
- abstract public function fetch_action( $action_id );
33
-
34
- /**
35
- * @param string $hook
36
- * @param array $params
37
- * @return string ID of the next action matching the criteria
38
- */
39
- abstract public function find_action( $hook, $params = array() );
40
-
41
- /**
42
- * @param array $query
43
- * @return array The IDs of actions matching the query
44
- */
45
- abstract public function query_actions( $query = array() );
46
-
47
- /**
48
- * Get a count of all actions in the store, grouped by status
49
- *
50
- * @return array
51
- */
52
- abstract public function action_counts();
53
-
54
- /**
55
- * @param string $action_id
56
- */
57
- abstract public function cancel_action( $action_id );
58
-
59
- /**
60
- * @param string $action_id
61
- */
62
- abstract public function delete_action( $action_id );
63
-
64
- /**
65
- * @param string $action_id
66
- *
67
- * @return DateTime The date the action is schedule to run, or the date that it ran.
68
- */
69
- abstract public function get_date( $action_id );
70
-
71
-
72
- /**
73
- * @param int $max_actions
74
- * @param DateTime $before_date Claim only actions schedule before the given date. Defaults to now.
75
- * @param array $hooks Claim only actions with a hook or hooks.
76
- * @param string $group Claim only actions in the given group.
77
- *
78
- * @return ActionScheduler_ActionClaim
79
- */
80
- abstract public function stake_claim( $max_actions = 10, DateTime $before_date = null, $hooks = array(), $group = '' );
81
-
82
- /**
83
- * @return int
84
- */
85
- abstract public function get_claim_count();
86
-
87
- /**
88
- * @param ActionScheduler_ActionClaim $claim
89
- */
90
- abstract public function release_claim( ActionScheduler_ActionClaim $claim );
91
-
92
- /**
93
- * @param string $action_id
94
- */
95
- abstract public function unclaim_action( $action_id );
96
-
97
- /**
98
- * @param string $action_id
99
- */
100
- abstract public function mark_failure( $action_id );
101
-
102
- /**
103
- * @param string $action_id
104
- */
105
- abstract public function log_execution( $action_id );
106
-
107
- /**
108
- * @param string $action_id
109
- */
110
- abstract public function mark_complete( $action_id );
111
-
112
- /**
113
- * @param string $action_id
114
- *
115
- * @return string
116
- */
117
- abstract public function get_status( $action_id );
118
-
119
- /**
120
- * @param string $action_id
121
- * @return mixed
122
- */
123
- abstract public function get_claim_id( $action_id );
124
-
125
- /**
126
- * @param string $claim_id
127
- * @return array
128
- */
129
- abstract public function find_actions_by_claim_id( $claim_id );
130
-
131
- /**
132
- * @param string $comparison_operator
133
- * @return string
134
- */
135
- protected function validate_sql_comparator( $comparison_operator ) {
136
- if ( in_array( $comparison_operator, array('!=', '>', '>=', '<', '<=', '=') ) ) {
137
- return $comparison_operator;
138
- }
139
- return '=';
140
- }
141
-
142
- /**
143
- * Get the time MySQL formated date/time string for an action's (next) scheduled date.
144
- *
145
- * @param ActionScheduler_Action $action
146
- * @param DateTime $scheduled_date (optional)
147
- * @return string
148
- */
149
- protected function get_scheduled_date_string( ActionScheduler_Action $action, DateTime $scheduled_date = NULL ) {
150
- $next = null === $scheduled_date ? $action->get_schedule()->next() : $scheduled_date;
151
- if ( ! $next ) {
152
- throw new InvalidArgumentException( __( 'Invalid schedule. Cannot save action.', 'action-scheduler' ) );
153
- }
154
- $next->setTimezone( new DateTimeZone( 'UTC' ) );
155
-
156
- return $next->format( 'Y-m-d H:i:s' );
157
- }
158
-
159
- /**
160
- * Get the time MySQL formated date/time string for an action's (next) scheduled date.
161
- *
162
- * @param ActionScheduler_Action $action
163
- * @param DateTime $scheduled_date (optional)
164
- * @return string
165
- */
166
- protected function get_scheduled_date_string_local( ActionScheduler_Action $action, DateTime $scheduled_date = NULL ) {
167
- $next = null === $scheduled_date ? $action->get_schedule()->next() : $scheduled_date;
168
- if ( ! $next ) {
169
- throw new InvalidArgumentException( __( 'Invalid schedule. Cannot save action.', 'action-scheduler' ) );
170
- }
171
-
172
- ActionScheduler_TimezoneHelper::set_local_timezone( $next );
173
- return $next->format( 'Y-m-d H:i:s' );
174
- }
175
-
176
- /**
177
- * @return array
178
- */
179
- public function get_status_labels() {
180
- return array(
181
- self::STATUS_COMPLETE => __( 'Complete', 'action-scheduler' ),
182
- self::STATUS_PENDING => __( 'Pending', 'action-scheduler' ),
183
- self::STATUS_RUNNING => __( 'In-progress', 'action-scheduler' ),
184
- self::STATUS_FAILED => __( 'Failed', 'action-scheduler' ),
185
- self::STATUS_CANCELED => __( 'Canceled', 'action-scheduler' ),
186
- );
187
- }
188
-
189
- public function init() {}
190
-
191
- /**
192
- * @return ActionScheduler_Store
193
- */
194
- public static function instance() {
195
- if ( empty(self::$store) ) {
196
- $class = apply_filters('action_scheduler_store_class', 'ActionScheduler_wpPostStore');
197
- self::$store = new $class();
198
- }
199
- return self::$store;
200
- }
201
-
202
- /**
203
- * Get the site's local time.
204
- *
205
- * @deprecated 2.1.0
206
- * @return DateTimeZone
207
- */
208
- protected function get_local_timezone() {
209
- _deprecated_function( __FUNCTION__, '2.1.0', 'ActionScheduler_TimezoneHelper::set_local_timezone()' );
210
- return ActionScheduler_TimezoneHelper::get_local_timezone();
211
- }
212
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
includes/vendor/action-scheduler/classes/ActionScheduler_WPCommentCleaner.php ADDED
@@ -0,0 +1,108 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Class ActionScheduler_WPCommentCleaner
5
+ *
6
+ * @since 3.0.0
7
+ */
8
+ class ActionScheduler_WPCommentCleaner {
9
+
10
+ /**
11
+ * Post migration hook used to cleanup the WP comment table.
12
+ *
13
+ * @var string
14
+ */
15
+ protected static $cleanup_hook = 'action_scheduler/cleanup_wp_comment_logs';
16
+
17
+ /**
18
+ * An instance of the ActionScheduler_wpCommentLogger class to interact with the comments table.
19
+ *
20
+ * This instance should only be used as an interface. It should not be initialized.
21
+ *
22
+ * @var ActionScheduler_wpCommentLogger
23
+ */
24
+ protected static $wp_comment_logger = null;
25
+
26
+ /**
27
+ * The key used to store the cached value of whether there are logs in the WP comment table.
28
+ *
29
+ * @var string
30
+ */
31
+ protected static $has_logs_option_key = 'as_has_wp_comment_logs';
32
+
33
+ /**
34
+ * Initialize the class and attach callbacks.
35
+ */
36
+ public static function init() {
37
+ if ( empty( self::$wp_comment_logger ) ) {
38
+ self::$wp_comment_logger = new ActionScheduler_wpCommentLogger();
39
+ }
40
+
41
+ add_action( self::$cleanup_hook, array( __CLASS__, 'delete_all_action_comments' ) );
42
+
43
+ // While there are orphaned logs left in the comments table, we need to attach the callbacks which filter comment counts.
44
+ add_action( 'pre_get_comments', array( self::$wp_comment_logger, 'filter_comment_queries' ), 10, 1 );
45
+ add_action( 'wp_count_comments', array( self::$wp_comment_logger, 'filter_comment_count' ), 20, 2 ); // run after WC_Comments::wp_count_comments() to make sure we exclude order notes and action logs
46
+ add_action( 'comment_feed_where', array( self::$wp_comment_logger, 'filter_comment_feed' ), 10, 2 );
47
+
48
+ // Action Scheduler may be displayed as a Tools screen or WooCommerce > Status administration screen
49
+ add_action( 'load-tools_page_action-scheduler', array( __CLASS__, 'print_admin_notice' ) );
50
+ add_action( 'load-woocommerce_page_wc-status', array( __CLASS__, 'print_admin_notice' ) );
51
+ }
52
+
53
+ /**
54
+ * Determines if there are log entries in the wp comments table.
55
+ *
56
+ * Uses the flag set on migration completion set by @see self::maybe_schedule_cleanup().
57
+ *
58
+ * @return boolean Whether there are scheduled action comments in the comments table.
59
+ */
60
+ public static function has_logs() {
61
+ return 'yes' === get_option( self::$has_logs_option_key );
62
+ }
63
+
64
+ /**
65
+ * Schedules the WP Post comment table cleanup to run in 6 months if it's not already scheduled.
66
+ * Attached to the migration complete hook 'action_scheduler/migration_complete'.
67
+ */
68
+ public static function maybe_schedule_cleanup() {
69
+ if ( (bool) get_comments( array( 'type' => ActionScheduler_wpCommentLogger::TYPE, 'number' => 1, 'fields' => 'ids' ) ) ) {
70
+ update_option( self::$has_logs_option_key, 'yes' );
71
+
72
+ if ( ! as_next_scheduled_action( self::$cleanup_hook ) ) {
73
+ as_schedule_single_action( gmdate( 'U' ) + ( 6 * MONTH_IN_SECONDS ), self::$cleanup_hook );
74
+ }
75
+ }
76
+ }
77
+
78
+ /**
79
+ * Delete all action comments from the WP Comments table.
80
+ */
81
+ public static function delete_all_action_comments() {
82
+ global $wpdb;
83
+ $wpdb->delete( $wpdb->comments, array( 'comment_type' => ActionScheduler_wpCommentLogger::TYPE, 'comment_agent' => ActionScheduler_wpCommentLogger::AGENT ) );
84
+ delete_option( self::$has_logs_option_key );
85
+ }
86
+
87
+ /**
88
+ * Prints details about the orphaned action logs and includes information on where to learn more.
89
+ */
90
+ public static function print_admin_notice() {
91
+ $next_cleanup_message = '';
92
+ $next_scheduled_cleanup_hook = as_next_scheduled_action( self::$cleanup_hook );
93
+
94
+ if ( $next_scheduled_cleanup_hook ) {
95
+ /* translators: %s: date interval */
96
+ $next_cleanup_message = sprintf( __( 'This data will be deleted in %s.', 'action-scheduler' ), human_time_diff( gmdate( 'U' ), $next_scheduled_cleanup_hook ) );
97
+ }
98
+
99
+ $notice = sprintf(
100
+ /* translators: 1: next cleanup message 2: github issue URL */
101
+ __( 'Action Scheduler has migrated data to custom tables; however, orphaned log entries exist in the WordPress Comments table. %1$s <a href="%2$s">Learn more &raquo;</a>', 'action-scheduler' ),
102
+ $next_cleanup_message,
103
+ 'https://github.com/woocommerce/action-scheduler/issues/368'
104
+ );
105
+
106
+ echo '<div class="notice notice-warning"><p>' . wp_kses_post( $notice ) . '</p></div>';
107
+ }
108
+ }
includes/vendor/action-scheduler/classes/ActionScheduler_wcSystemStatus.php CHANGED
@@ -129,8 +129,8 @@ class ActionScheduler_wcSystemStatus {
129
  /**
130
  * is triggered when invoking inaccessible methods in an object context.
131
  *
132
- * @param $name string
133
- * @param $arguments array
134
  *
135
  * @return mixed
136
  * @link https://php.net/manual/en/language.oop5.overloading.php#language.oop5.overloading.methods
129
  /**
130
  * is triggered when invoking inaccessible methods in an object context.
131
  *
132
+ * @param string $name
133
+ * @param array $arguments
134
  *
135
  * @return mixed
136
  * @link https://php.net/manual/en/language.oop5.overloading.php#language.oop5.overloading.methods
includes/vendor/action-scheduler/classes/{ActionScheduler_WPCLI_QueueRunner.php → WP_CLI/ActionScheduler_WPCLI_QueueRunner.php} RENAMED
@@ -1,5 +1,7 @@
1
  <?php
2
 
 
 
3
  /**
4
  * WP CLI Queue runner.
5
  *
@@ -52,9 +54,7 @@ class ActionScheduler_WPCLI_QueueRunner extends ActionScheduler_Abstract_QueueRu
52
  $this->add_hooks();
53
 
54
  // Check to make sure there aren't too many concurrent processes running.
55
- $claim_count = $this->store->get_claim_count();
56
- $too_many = $claim_count >= $this->get_allowed_concurrent_batches();
57
- if ( $too_many ) {
58
  if ( $force ) {
59
  WP_CLI::warning( __( 'There are too many concurrent batches, but the run is forced to continue.', 'action-scheduler' ) );
60
  } else {
@@ -88,7 +88,8 @@ class ActionScheduler_WPCLI_QueueRunner extends ActionScheduler_Abstract_QueueRu
88
  */
89
  protected function setup_progress_bar() {
90
  $count = count( $this->actions );
91
- $this->progress_bar = \WP_CLI\Utils\make_progress_bar(
 
92
  sprintf( _n( 'Running %d action', 'Running %d actions', $count, 'action-scheduler' ), number_format_i18n( $count ) ),
93
  $count
94
  );
@@ -98,9 +99,12 @@ class ActionScheduler_WPCLI_QueueRunner extends ActionScheduler_Abstract_QueueRu
98
  * Process actions in the queue.
99
  *
100
  * @author Jeremy Pry
 
 
 
101
  * @return int The number of actions processed.
102
  */
103
- public function run() {
104
  do_action( 'action_scheduler_before_process_queue' );
105
  $this->setup_progress_bar();
106
  foreach ( $this->actions as $action_id ) {
@@ -110,9 +114,8 @@ class ActionScheduler_WPCLI_QueueRunner extends ActionScheduler_Abstract_QueueRu
110
  break;
111
  }
112
 
113
- $this->process_action( $action_id );
114
  $this->progress_bar->tick();
115
- $this->maybe_stop_the_insanity();
116
  }
117
 
118
  $completed = $this->progress_bar->current();
@@ -148,8 +151,8 @@ class ActionScheduler_WPCLI_QueueRunner extends ActionScheduler_Abstract_QueueRu
148
  if ( null === $action ) {
149
  $action = $this->store->fetch_action( $action_id );
150
  }
151
- /* translators: %s refers to the action ID */
152
- WP_CLI::log( sprintf( __( 'Completed processing action %s with hook: %s', 'action-scheduler' ), $action_id, $action->get_hook() ) );
153
  }
154
 
155
  /**
@@ -163,7 +166,7 @@ class ActionScheduler_WPCLI_QueueRunner extends ActionScheduler_Abstract_QueueRu
163
  */
164
  public function action_failed( $action_id, $exception ) {
165
  WP_CLI::error(
166
- /* translators: %1$s refers to the action ID, %2$s refers to the Exception message */
167
  sprintf( __( 'Error processing action %1$s: %2$s', 'action-scheduler' ), $action_id, $exception->getMessage() ),
168
  false
169
  );
@@ -173,35 +176,12 @@ class ActionScheduler_WPCLI_QueueRunner extends ActionScheduler_Abstract_QueueRu
173
  * Sleep and help avoid hitting memory limit
174
  *
175
  * @param int $sleep_time Amount of seconds to sleep
 
176
  */
177
  protected function stop_the_insanity( $sleep_time = 0 ) {
178
- if ( 0 < $sleep_time ) {
179
- WP_CLI::warning( sprintf( 'Stopped the insanity for %d %s', $sleep_time, _n( 'second', 'seconds', $sleep_time ) ) );
180
- sleep( $sleep_time );
181
- }
182
-
183
- WP_CLI::warning( __( 'Attempting to reduce used memory...', 'action-scheduler' ) );
184
 
185
- /**
186
- * @var $wpdb \wpdb
187
- * @var $wp_object_cache \WP_Object_Cache
188
- */
189
- global $wpdb, $wp_object_cache;
190
-
191
- $wpdb->queries = array();
192
-
193
- if ( ! is_object( $wp_object_cache ) ) {
194
- return;
195
- }
196
-
197
- $wp_object_cache->group_ops = array();
198
- $wp_object_cache->stats = array();
199
- $wp_object_cache->memcache_debug = array();
200
- $wp_object_cache->cache = array();
201
-
202
- if ( is_callable( array( $wp_object_cache, '__remoteset' ) ) ) {
203
- call_user_func( array( $wp_object_cache, '__remoteset' ) ); // important
204
- }
205
  }
206
 
207
  /**
1
  <?php
2
 
3
+ use Action_Scheduler\WP_CLI\ProgressBar;
4
+
5
  /**
6
  * WP CLI Queue runner.
7
  *
54
  $this->add_hooks();
55
 
56
  // Check to make sure there aren't too many concurrent processes running.
57
+ if ( $this->has_maximum_concurrent_batches() ) {
 
 
58
  if ( $force ) {
59
  WP_CLI::warning( __( 'There are too many concurrent batches, but the run is forced to continue.', 'action-scheduler' ) );
60
  } else {
88
  */
89
  protected function setup_progress_bar() {
90
  $count = count( $this->actions );
91
+ $this->progress_bar = new ProgressBar(
92
+ /* translators: %d: amount of actions */
93
  sprintf( _n( 'Running %d action', 'Running %d actions', $count, 'action-scheduler' ), number_format_i18n( $count ) ),
94
  $count
95
  );
99
  * Process actions in the queue.
100
  *
101
  * @author Jeremy Pry
102
+ *
103
+ * @param string $context Optional runner context. Default 'WP CLI'.
104
+ *
105
  * @return int The number of actions processed.
106
  */
107
+ public function run( $context = 'WP CLI' ) {
108
  do_action( 'action_scheduler_before_process_queue' );
109
  $this->setup_progress_bar();
110
  foreach ( $this->actions as $action_id ) {
114
  break;
115
  }
116
 
117
+ $this->process_action( $action_id, $context );
118
  $this->progress_bar->tick();
 
119
  }
120
 
121
  $completed = $this->progress_bar->current();
151
  if ( null === $action ) {
152
  $action = $this->store->fetch_action( $action_id );
153
  }
154
+ /* translators: 1: action ID 2: hook name */
155
+ WP_CLI::log( sprintf( __( 'Completed processing action %1$s with hook: %2$s', 'action-scheduler' ), $action_id, $action->get_hook() ) );
156
  }
157
 
158
  /**
166
  */
167
  public function action_failed( $action_id, $exception ) {
168
  WP_CLI::error(
169
+ /* translators: 1: action ID 2: exception message */
170
  sprintf( __( 'Error processing action %1$s: %2$s', 'action-scheduler' ), $action_id, $exception->getMessage() ),
171
  false
172
  );
176
  * Sleep and help avoid hitting memory limit
177
  *
178
  * @param int $sleep_time Amount of seconds to sleep
179
+ * @deprecated 3.0.0
180
  */
181
  protected function stop_the_insanity( $sleep_time = 0 ) {
182
+ _deprecated_function( 'ActionScheduler_WPCLI_QueueRunner::stop_the_insanity', '3.0.0', 'ActionScheduler_DataController::free_memory' );
 
 
 
 
 
183
 
184
+ ActionScheduler_DataController::free_memory();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
185
  }
186
 
187
  /**
includes/vendor/action-scheduler/classes/{ActionScheduler_WPCLI_Scheduler_command.php → WP_CLI/ActionScheduler_WPCLI_Scheduler_command.php} RENAMED
@@ -1,7 +1,7 @@
1
  <?php
2
 
3
  /**
4
- * Commands for the Action Scheduler by Prospress.
5
  */
6
  class ActionScheduler_WPCLI_Scheduler_command extends WP_CLI_Command {
7
 
@@ -25,12 +25,20 @@ class ActionScheduler_WPCLI_Scheduler_command extends WP_CLI_Command {
25
  * [--group=<group>]
26
  * : Only run actions from the specified group. Omitting this option runs actions from all groups.
27
  *
 
 
 
 
 
 
28
  * [--force]
29
  * : Whether to force execution despite the maximum number of concurrent processes being exceeded.
30
  *
31
  * @param array $args Positional arguments.
32
  * @param array $assoc_args Keyed arguments.
33
  * @throws \WP_CLI\ExitException When an error occurs.
 
 
34
  */
35
  public function run( $args, $assoc_args ) {
36
  // Handle passed arguments.
@@ -40,8 +48,13 @@ class ActionScheduler_WPCLI_Scheduler_command extends WP_CLI_Command {
40
  $hooks = explode( ',', WP_CLI\Utils\get_flag_value( $assoc_args, 'hooks', '' ) );
41
  $hooks = array_filter( array_map( 'trim', $hooks ) );
42
  $group = \WP_CLI\Utils\get_flag_value( $assoc_args, 'group', '' );
 
 
43
  $force = \WP_CLI\Utils\get_flag_value( $assoc_args, 'force', false );
44
 
 
 
 
45
  $batches_completed = 0;
46
  $actions_completed = 0;
47
  $unlimited = $batches === 0;
@@ -119,7 +132,7 @@ class ActionScheduler_WPCLI_Scheduler_command extends WP_CLI_Command {
119
  protected function print_error( Exception $e ) {
120
  WP_CLI::error(
121
  sprintf(
122
- /* translators: %s refers to the exception error message. */
123
  __( 'There was an error running the action scheduler: %s', 'action-scheduler' ),
124
  $e->getMessage()
125
  )
1
  <?php
2
 
3
  /**
4
+ * Commands for Action Scheduler.
5
  */
6
  class ActionScheduler_WPCLI_Scheduler_command extends WP_CLI_Command {
7
 
25
  * [--group=<group>]
26
  * : Only run actions from the specified group. Omitting this option runs actions from all groups.
27
  *
28
+ * [--free-memory-on=<count>]
29
+ * : The number of actions to process between freeing memory. 0 disables freeing memory. Default 50.
30
+ *
31
+ * [--pause=<seconds>]
32
+ * : The number of seconds to pause when freeing memory. Default no pause.
33
+ *
34
  * [--force]
35
  * : Whether to force execution despite the maximum number of concurrent processes being exceeded.
36
  *
37
  * @param array $args Positional arguments.
38
  * @param array $assoc_args Keyed arguments.
39
  * @throws \WP_CLI\ExitException When an error occurs.
40
+ *
41
+ * @subcommand run
42
  */
43
  public function run( $args, $assoc_args ) {
44
  // Handle passed arguments.
48
  $hooks = explode( ',', WP_CLI\Utils\get_flag_value( $assoc_args, 'hooks', '' ) );
49
  $hooks = array_filter( array_map( 'trim', $hooks ) );
50
  $group = \WP_CLI\Utils\get_flag_value( $assoc_args, 'group', '' );
51
+ $free_on = \WP_CLI\Utils\get_flag_value( $assoc_args, 'free-memory-on', '' );
52
+ $sleep = \WP_CLI\Utils\get_flag_value( $assoc_args, 'pause', '' );
53
  $force = \WP_CLI\Utils\get_flag_value( $assoc_args, 'force', false );
54
 
55
+ ActionScheduler_DataController::set_free_ticks( $free_on );
56
+ ActionScheduler_DataController::set_sleep_time( $sleep );
57
+
58
  $batches_completed = 0;
59
  $actions_completed = 0;
60
  $unlimited = $batches === 0;
132
  protected function print_error( Exception $e ) {
133
  WP_CLI::error(
134
  sprintf(
135
+ /* translators: %s refers to the exception error message */
136
  __( 'There was an error running the action scheduler: %s', 'action-scheduler' ),
137
  $e->getMessage()
138
  )
includes/vendor/action-scheduler/classes/WP_CLI/Migration_Command.php ADDED
@@ -0,0 +1,148 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+
4
+ namespace Action_Scheduler\WP_CLI;
5
+
6
+ use Action_Scheduler\Migration\Config;
7
+ use Action_Scheduler\Migration\Runner;
8
+ use Action_Scheduler\Migration\Scheduler;
9
+ use Action_Scheduler\Migration\Controller;
10
+ use WP_CLI;
11
+ use WP_CLI_Command;
12
+
13
+ /**
14
+ * Class Migration_Command
15
+ *
16
+ * @package Action_Scheduler\WP_CLI
17
+ *
18
+ * @since 3.0.0
19
+ *
20
+ * @codeCoverageIgnore
21
+ */
22
+ class Migration_Command extends WP_CLI_Command {
23
+
24
+ /** @var int */
25
+ private $total_processed = 0;
26
+
27
+ /**
28
+ * Register the command with WP-CLI
29
+ */
30
+ public function register() {
31
+ if ( ! defined( 'WP_CLI' ) || ! WP_CLI ) {
32
+ return;
33
+ }
34
+
35
+ WP_CLI::add_command( 'action-scheduler migrate', [ $this, 'migrate' ], [
36
+ 'shortdesc' => 'Migrates actions to the DB tables store',
37
+ 'synopsis' => [
38
+ [
39
+ 'type' => 'assoc',
40
+ 'name' => 'batch-size',
41
+ 'optional' => true,
42
+ 'default' => 100,
43
+ 'description' => 'The number of actions to process in each batch',
44
+ ],
45
+ [
46
+ 'type' => 'assoc',
47
+ 'name' => 'free-memory-on',
48
+ 'optional' => true,
49
+ 'default' => 50,
50
+ 'description' => 'The number of actions to process between freeing memory. 0 disables freeing memory',
51
+ ],
52
+ [
53
+ 'type' => 'assoc',
54
+ 'name' => 'pause',
55
+ 'optional' => true,
56
+ 'default' => 0,
57
+ 'description' => 'The number of seconds to pause when freeing memory',
58
+ ],
59
+ [
60
+ 'type' => 'flag',
61
+ 'name' => 'dry-run',
62
+ 'optional' => true,
63
+ 'description' => 'Reports on the actions that would have been migrated, but does not change any data',
64
+ ],
65
+ ],
66
+ ] );
67
+ }
68
+
69
+ /**
70
+ * Process the data migration.
71
+ *
72
+ * @param array $positional_args Required for WP CLI. Not used in migration.
73
+ * @param array $assoc_args Optional arguments.
74
+ *
75
+ * @return void
76
+ */
77
+ public function migrate( $positional_args, $assoc_args ) {
78
+ $this->init_logging();
79
+
80
+ $config = $this->get_migration_config( $assoc_args );
81
+ $runner = new Runner( $config );
82
+ $runner->init_destination();
83
+
84
+ $batch_size = isset( $assoc_args[ 'batch-size' ] ) ? (int) $assoc_args[ 'batch-size' ] : 100;
85
+ $free_on = isset( $assoc_args[ 'free-memory-on' ] ) ? (int) $assoc_args[ 'free-memory-on' ] : 50;
86
+ $sleep = isset( $assoc_args[ 'pause' ] ) ? (int) $assoc_args[ 'pause' ] : 0;
87
+ \ActionScheduler_DataController::set_free_ticks( $free_on );
88
+ \ActionScheduler_DataController::set_sleep_time( $sleep );
89
+
90
+ do {
91
+ $actions_processed = $runner->run( $batch_size );
92
+ $this->total_processed += $actions_processed;
93
+ } while ( $actions_processed > 0 );
94
+
95
+ if ( ! $config->get_dry_run() ) {
96
+ // let the scheduler know that there's nothing left to do
97
+ $scheduler = new Scheduler();
98
+ $scheduler->mark_complete();
99
+ }
100
+
101
+ WP_CLI::success( sprintf( '%s complete. %d actions processed.', $config->get_dry_run() ? 'Dry run' : 'Migration', $this->total_processed ) );
102
+ }
103
+
104
+ /**
105
+ * Build the config object used to create the Runner
106
+ *
107
+ * @param array $args Optional arguments.
108
+ *
109
+ * @return ActionScheduler\Migration\Config
110
+ */
111
+ private function get_migration_config( $args ) {
112
+ $args = wp_parse_args( $args, [
113
+ 'dry-run' => false,
114
+ ] );
115
+
116
+ $config = Controller::instance()->get_migration_config_object();
117
+ $config->set_dry_run( ! empty( $args[ 'dry-run' ] ) );
118
+
119
+ return $config;
120
+ }
121
+
122
+ /**
123
+ * Hook command line logging into migration actions.
124
+ */
125
+ private function init_logging() {
126
+ add_action( 'action_scheduler/migrate_action_dry_run', function ( $action_id ) {
127
+ WP_CLI::debug( sprintf( 'Dry-run: migrated action %d', $action_id ) );
128
+ }, 10, 1 );
129
+ add_action( 'action_scheduler/no_action_to_migrate', function ( $action_id ) {
130
+ WP_CLI::debug( sprintf( 'No action found to migrate for ID %d', $action_id ) );
131
+ }, 10, 1 );
132
+ add_action( 'action_scheduler/migrate_action_failed', function ( $action_id ) {
133
+ WP_CLI::warning( sprintf( 'Failed migrating action with ID %d', $action_id ) );
134
+ }, 10, 1 );
135
+ add_action( 'action_scheduler/migrate_action_incomplete', function ( $source_id, $destination_id ) {
136
+ WP_CLI::warning( sprintf( 'Unable to remove source action with ID %d after migrating to new ID %d', $source_id, $destination_id ) );
137
+ }, 10, 2 );
138
+ add_action( 'action_scheduler/migrated_action', function ( $source_id, $destination_id ) {
139
+ WP_CLI::debug( sprintf( 'Migrated source action with ID %d to new store with ID %d', $source_id, $destination_id ) );
140
+ }, 10, 2 );
141
+ add_action( 'action_scheduler/migration_batch_starting', function ( $batch ) {
142
+ WP_CLI::debug( 'Beginning migration of batch: ' . print_r( $batch, true ) );
143
+ }, 10, 1 );
144
+ add_action( 'action_scheduler/migration_batch_complete', function ( $batch ) {
145
+ WP_CLI::log( sprintf( 'Completed migration of %d actions', count( $batch ) ) );
146
+ }, 10, 1 );
147
+ }
148
+ }
includes/vendor/action-scheduler/classes/WP_CLI/ProgressBar.php ADDED
@@ -0,0 +1,119 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace Action_Scheduler\WP_CLI;
4
+
5
+ /**
6
+ * WP_CLI progress bar for Action Scheduler.
7
+ */
8
+
9
+ /**
10
+ * Class ProgressBar
11
+ *
12
+ * @package Action_Scheduler\WP_CLI
13
+ *
14
+ * @since 3.0.0
15
+ *
16
+ * @codeCoverageIgnore
17
+ */
18
+ class ProgressBar {
19
+
20
+ /** @var integer */
21
+ protected $total_ticks;
22
+
23
+ /** @var integer */
24
+ protected $count;
25
+
26
+ /** @var integer */
27
+ protected $interval;
28
+
29
+ /** @var string */
30
+ protected $message;
31
+
32
+ /** @var \cli\progress\Bar */
33
+ protected $progress_bar;
34
+
35
+ /**
36
+ * ProgressBar constructor.
37
+ *
38
+ * @param string $message Text to display before the progress bar.
39
+ * @param integer $count Total number of ticks to be performed.
40
+ * @param integer $interval Optional. The interval in milliseconds between updates. Default 100.
41
+ *
42
+ * @throws Exception When this is not run within WP CLI
43
+ */
44
+ public function __construct( $message, $count, $interval = 100 ) {
45
+ if ( ! ( defined( 'WP_CLI' ) && WP_CLI ) ) {
46
+ /* translators: %s php class name */
47
+ throw new \Exception( sprintf( __( 'The %s class can only be run within WP CLI.', 'action-scheduler' ), __CLASS__ ) );
48
+ }
49
+
50
+ $this->total_ticks = 0;
51
+ $this->message = $message;
52
+ $this->count = $count;
53
+ $this->interval = $interval;
54
+ }
55
+
56
+ /**
57
+ * Increment the progress bar ticks.
58
+ */
59
+ public function tick() {
60
+ if ( null === $this->progress_bar ) {
61
+ $this->setup_progress_bar();
62
+ }
63
+
64
+ $this->progress_bar->tick();
65
+ $this->total_ticks++;
66
+
67
+ do_action( 'action_scheduler/progress_tick', $this->total_ticks );
68
+ }
69
+
70
+ /**
71
+ * Get the progress bar tick count.
72
+ *
73
+ * @return int
74
+ */
75
+ public function current() {
76
+ return $this->progress_bar ? $this->progress_bar->current() : 0;
77
+ }
78
+
79
+ /**
80
+ * Finish the current progress bar.
81
+ */
82
+ public function finish() {
83
+ if ( null !== $this->progress_bar ) {
84
+ $this->progress_bar->finish();
85
+ }
86
+
87
+ $this->progress_bar = null;
88
+ }
89
+
90
+ /**
91
+ * Set the message used when creating the progress bar.
92
+ *
93
+ * @param string $message The message to be used when the next progress bar is created.
94
+ */
95
+ public function set_message( $message ) {
96
+ $this->message = $message;
97
+ }
98
+
99
+ /**
100
+ * Set the count for a new progress bar.
101
+ *
102
+ * @param integer $count The total number of ticks expected to complete.
103
+ */
104
+ public function set_count( $count ) {
105
+ $this->count = $count;
106
+ $this->finish();
107
+ }
108
+
109
+ /**
110
+ * Set up the progress bar.
111
+ */
112
+ protected function setup_progress_bar() {
113
+ $this->progress_bar = \WP_CLI\Utils\make_progress_bar(
114
+ $this->message,
115
+ $this->count,
116
+ $this->interval
117
+ );
118
+ }
119
+ }
includes/vendor/action-scheduler/classes/abstracts/ActionScheduler.php ADDED
@@ -0,0 +1,269 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ use Action_Scheduler\WP_CLI\Migration_Command;
4
+ use Action_Scheduler\Migration\Controller;
5
+
6
+ /**
7
+ * Class ActionScheduler
8
+ * @codeCoverageIgnore
9
+ */
10
+ abstract class ActionScheduler {
11
+ private static $plugin_file = '';
12
+ /** @var ActionScheduler_ActionFactory */
13
+ private static $factory = NULL;
14
+
15
+ public static function factory() {
16
+ if ( !isset(self::$factory) ) {
17
+ self::$factory = new ActionScheduler_ActionFactory();
18
+ }
19
+ return self::$factory;
20
+ }
21
+
22
+ public static function store() {
23
+ return ActionScheduler_Store::instance();
24
+ }
25
+
26
+ public static function lock() {
27
+ return ActionScheduler_Lock::instance();
28
+ }
29
+
30
+ public static function logger() {
31
+ return ActionScheduler_Logger::instance();
32
+ }
33
+
34
+ public static function runner() {
35
+ return ActionScheduler_QueueRunner::instance();
36
+ }
37
+
38
+ public static function admin_view() {
39
+ return ActionScheduler_AdminView::instance();
40
+ }
41
+
42
+ /**
43
+ * Get the absolute system path to the plugin directory, or a file therein
44
+ * @static
45
+ * @param string $path
46
+ * @return string
47
+ */
48
+ public static function plugin_path( $path ) {
49
+ $base = dirname(self::$plugin_file);
50
+ if ( $path ) {
51
+ return trailingslashit($base).$path;
52
+ } else {
53
+ return untrailingslashit($base);
54
+ }
55
+ }
56
+
57
+ /**
58
+ * Get the absolute URL to the plugin directory, or a file therein
59
+ * @static
60
+ * @param string $path
61
+ * @return string
62
+ */
63
+ public static function plugin_url( $path ) {
64
+ return plugins_url($path, self::$plugin_file);
65
+ }
66
+
67
+ public static function autoload( $class ) {
68
+ $d = DIRECTORY_SEPARATOR;
69
+ $classes_dir = self::plugin_path( 'classes' . $d );
70
+ $separator = strrpos( $class, '\\' );
71
+ if ( false !== $separator ) {
72
+ if ( 0 !== strpos( $class, 'Action_Scheduler' ) ) {
73
+ return;
74
+ }
75
+ $class = substr( $class, $separator + 1 );
76
+ }
77
+
78
+ if ( 'Deprecated' === substr( $class, -10 ) ) {
79
+ $dir = self::plugin_path( 'deprecated' . $d );
80
+ } elseif ( self::is_class_abstract( $class ) ) {
81
+ $dir = $classes_dir . 'abstracts' . $d;
82
+ } elseif ( self::is_class_migration( $class ) ) {
83
+ $dir = $classes_dir . 'migration' . $d;
84
+ } elseif ( 'Schedule' === substr( $class, -8 ) ) {
85
+ $dir = $classes_dir . 'schedules' . $d;
86
+ } elseif ( 'Action' === substr( $class, -6 ) ) {
87
+ $dir = $classes_dir . 'actions' . $d;
88
+ } elseif ( 'Schema' === substr( $class, -6 ) ) {
89
+ $dir = $classes_dir . 'schema' . $d;
90
+ } elseif ( strpos( $class, 'ActionScheduler' ) === 0 ) {
91
+ $segments = explode( '_', $class );
92
+ $type = isset( $segments[ 1 ] ) ? $segments[ 1 ] : '';
93
+
94
+ switch ( $type ) {
95
+ case 'WPCLI':
96
+ $dir = $classes_dir . 'WP_CLI' . $d;
97
+ break;
98
+ case 'DBLogger':
99
+ case 'DBStore':
100
+ case 'HybridStore':
101
+ case 'wpPostStore':
102
+ case 'wpCommentLogger':
103
+ $dir = $classes_dir . 'data-stores' . $d;
104
+ break;
105
+ default:
106
+ $dir = $classes_dir;
107
+ break;
108
+ }
109
+ } elseif ( self::is_class_cli( $class ) ) {
110
+ $dir = $classes_dir . 'WP_CLI' . $d;
111
+ } elseif ( strpos( $class, 'CronExpression' ) === 0 ) {
112
+ $dir = self::plugin_path( 'lib' . $d . 'cron-expression' . $d );
113
+ } elseif ( strpos( $class, 'WP_Async_Request' ) === 0 ) {
114
+ $dir = self::plugin_path( 'lib' . $d );
115
+ } else {
116
+ return;
117
+ }
118
+
119
+ if ( file_exists( "{$dir}{$class}.php" ) ) {
120
+ include( "{$dir}{$class}.php" );
121
+ return;
122
+ }
123
+ }
124
+
125
+ /**
126
+ * Initialize the plugin
127
+ *
128
+ * @static
129
+ * @param string $plugin_file
130
+ */
131
+ public static function init( $plugin_file ) {
132
+ self::$plugin_file = $plugin_file;
133
+ spl_autoload_register( array( __CLASS__, 'autoload' ) );
134
+
135
+ /**
136
+ * Fires in the early stages of Action Scheduler init hook.
137
+ */
138
+ do_action( 'action_scheduler_pre_init' );
139
+
140
+ require_once( self::plugin_path('functions.php') );
141
+ ActionScheduler_DataController::init();
142
+
143
+ $store = self::store();
144
+ add_action( 'init', array( $store, 'init' ), 1, 0 );
145
+
146
+ $logger = self::logger();
147
+ add_action( 'init', array( $logger, 'init' ), 1, 0 );
148
+
149
+ $runner = self::runner();
150
+ add_action( 'init', array( $runner, 'init' ), 1, 0 );
151
+
152
+ $admin_view = self::admin_view();
153
+ add_action( 'init', array( $admin_view, 'init' ), 0, 0 ); // run before $store::init()
154
+
155
+ if ( apply_filters( 'action_scheduler_load_deprecated_functions', true ) ) {
156
+ require_once( self::plugin_path('deprecated/functions.php') );
157
+ }
158
+
159
+ if ( defined( 'WP_CLI' ) && WP_CLI ) {
160
+ WP_CLI::add_command( 'action-scheduler', 'ActionScheduler_WPCLI_Scheduler_command' );
161
+ if ( ! ActionScheduler_DataController::is_migration_complete() && Controller::instance()->allow_migration() ) {
162
+ $command = new Migration_Command();
163
+ $command->register();
164
+ }
165
+ }
166
+
167
+ /**
168
+ * Handle WP comment cleanup after migration.
169
+ */
170
+ if ( is_a( $logger, 'ActionScheduler_DBLogger' ) && ActionScheduler_DataController::is_migration_complete() && ActionScheduler_WPCommentCleaner::has_logs() ) {
171
+ ActionScheduler_WPCommentCleaner::init();
172
+ }
173
+
174
+ add_action( 'action_scheduler/migration_complete', 'ActionScheduler_WPCommentCleaner::maybe_schedule_cleanup' );
175
+ }
176
+
177
+ /**
178
+ * Determine if the class is one of our abstract classes.
179
+ *
180
+ * @since 3.0.0
181
+ *
182
+ * @param string $class The class name.
183
+ *
184
+ * @return bool
185
+ */
186
+ protected static function is_class_abstract( $class ) {
187
+ static $abstracts = array(
188
+ 'ActionScheduler' => true,
189
+ 'ActionScheduler_Abstract_ListTable' => true,
190
+ 'ActionScheduler_Abstract_QueueRunner' => true,
191
+ 'ActionScheduler_Abstract_Schedule' => true,
192
+ 'ActionScheduler_Abstract_RecurringSchedule' => true,
193
+ 'ActionScheduler_Lock' => true,
194
+ 'ActionScheduler_Logger' => true,
195
+ 'ActionScheduler_Abstract_Schema' => true,
196
+ 'ActionScheduler_Store' => true,
197
+ 'ActionScheduler_TimezoneHelper' => true,
198
+ );
199
+
200
+ return isset( $abstracts[ $class ] ) && $abstracts[ $class ];
201
+ }
202
+
203
+ /**
204
+ * Determine if the class is one of our migration classes.
205
+ *
206
+ * @since 3.0.0
207
+ *
208
+ * @param string $class The class name.
209
+ *
210
+ * @return bool
211
+ */
212
+ protected static function is_class_migration( $class ) {
213
+ static $migration_segments = array(
214
+ 'ActionMigrator' => true,
215
+ 'BatchFetcher' => true,
216
+ 'DBStoreMigrator' => true,
217
+ 'DryRun' => true,
218
+ 'LogMigrator' => true,
219
+ 'Config' => true,
220
+ 'Controller' => true,
221
+ 'Runner' => true,
222
+ 'Scheduler' => true,
223
+ );
224
+
225
+ $segments = explode( '_', $class );
226
+ $segment = isset( $segments[ 1 ] ) ? $segments[ 1 ] : $class;
227
+
228
+ return isset( $migration_segments[ $segment ] ) && $migration_segments[ $segment ];
229
+ }
230
+
231
+ /**
232
+ * Determine if the class is one of our WP CLI classes.
233
+ *
234
+ * @since 3.0.0
235
+ *
236
+ * @param string $class The class name.
237
+ *
238
+ * @return bool
239
+ */
240
+ protected static function is_class_cli( $class ) {
241
+ static $cli_segments = array(
242
+ 'QueueRunner' => true,
243
+ 'Command' => true,
244
+ 'ProgressBar' => true,
245
+ );
246
+
247
+ $segments = explode( '_', $class );
248
+ $segment = isset( $segments[ 1 ] ) ? $segments[ 1 ] : $class;
249
+
250
+ return isset( $cli_segments[ $segment ] ) && $cli_segments[ $segment ];
251
+ }
252
+
253
+ final public function __clone() {
254
+ trigger_error("Singleton. No cloning allowed!", E_USER_ERROR);
255
+ }
256
+
257
+ final public function __wakeup() {
258
+ trigger_error("Singleton. No serialization allowed!", E_USER_ERROR);
259
+ }
260
+
261
+ final private function __construct() {}
262
+
263
+ /** Deprecated **/
264
+
265
+ public static function get_datetime_object( $when = null, $timezone = 'UTC' ) {
266
+ _deprecated_function( __METHOD__, '2.0', 'wcs_add_months()' );
267
+ return as_get_datetime_object( $when, $timezone );
268
+ }
269
+ }
includes/vendor/action-scheduler/classes/{ActionScheduler_Abstract_ListTable.php → abstracts/ActionScheduler_Abstract_ListTable.php} RENAMED
@@ -29,7 +29,7 @@ abstract class ActionScheduler_Abstract_ListTable extends WP_List_Table {
29
  protected $table_name;
30
 
31
  /**
32
- * Package name, used in translations
33
  */
34
  protected $package;
35
 
@@ -104,10 +104,12 @@ abstract class ActionScheduler_Abstract_ListTable extends WP_List_Table {
104
 
105
  /**
106
  * Makes translation easier, it basically just wraps
107
- * `_x` with some default (the package name)
 
 
108
  */
109
  protected function translate( $text, $context = '' ) {
110
- return _x( $text, $context, $this->package );
111
  }
112
 
113
  /**
@@ -123,7 +125,7 @@ abstract class ActionScheduler_Abstract_ListTable extends WP_List_Table {
123
  throw new RuntimeException( "The bulk action $action does not have a callback method" );
124
  }
125
 
126
- $actions[ $action ] = $this->translate( $label );
127
  }
128
 
129
  return $actions;
@@ -199,7 +201,7 @@ abstract class ActionScheduler_Abstract_ListTable extends WP_List_Table {
199
  public function get_columns() {
200
  $columns = array_merge(
201
  array( 'cb' => '<input type="checkbox" />' ),
202
- array_map( array( $this, 'translate' ), $this->columns )
203
  );
204
 
205
  return $columns;
@@ -355,7 +357,7 @@ abstract class ActionScheduler_Abstract_ListTable extends WP_List_Table {
355
 
356
  $filter = array();
357
  foreach ( $this->search_by as $column ) {
358
- $filter[] = '`' . $column . '` like "%' . $wpdb->esc_like( $_GET['s'] ) . '%"';
359
  }
360
  return implode( ' OR ', $filter );
361
  }
@@ -455,14 +457,14 @@ abstract class ActionScheduler_Abstract_ListTable extends WP_List_Table {
455
 
456
  foreach ( $options as $value => $label ) {
457
  echo '<option value="' . esc_attr( $value ) . '" ' . esc_html( $value == $default ? 'selected' : '' ) .'>'
458
- . esc_html( $this->translate( $label ) )
459
  . '</option>';
460
  }
461
 
462
  echo '</select>';
463
  }
464
 
465
- submit_button( $this->translate( 'Filter' ), '', 'filter_action', false, array( 'id' => 'post-query-submit' ) );
466
  echo '</div>';
467
  }
468
 
@@ -561,7 +563,8 @@ abstract class ActionScheduler_Abstract_ListTable extends WP_List_Table {
561
  protected function display_header() {
562
  echo '<h1 class="wp-heading-inline">' . esc_attr( $this->table_header ) . '</h1>';
563
  if ( $this->get_request_search_query() ) {
564
- echo '<span class="subtitle">' . esc_attr( $this->translate( sprintf( 'Search results for "%s"', $this->get_request_search_query() ) ) ) . '</span>';
 
565
  }
566
  echo '<hr class="wp-header-end">';
567
  }
@@ -633,6 +636,21 @@ abstract class ActionScheduler_Abstract_ListTable extends WP_List_Table {
633
  echo '</form>';
634
  }
635
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
636
  /**
637
  * Render the list table page, including header, notices, status filters and table.
638
  */
@@ -651,6 +669,6 @@ abstract class ActionScheduler_Abstract_ListTable extends WP_List_Table {
651
  * Get the text to display in the search box on the list table.
652
  */
653
  protected function get_search_box_placeholder() {
654
- return $this->translate( 'Search' );
655
  }
656
  }
29
  protected $table_name;
30
 
31
  /**
32
+ * Package name, used to get options from WP_List_Table::get_items_per_page.
33
  */
34
  protected $package;
35
 
104
 
105
  /**
106
  * Makes translation easier, it basically just wraps
107
+ * `_x` with some default (the package name).
108
+ *
109
+ * @deprecated 3.0.0
110
  */
111
  protected function translate( $text, $context = '' ) {
112
+ return $text;
113
  }
114
 
115
  /**
125
  throw new RuntimeException( "The bulk action $action does not have a callback method" );
126
  }
127
 
128
+ $actions[ $action ] = $label;
129
  }
130
 
131
  return $actions;
201
  public function get_columns() {
202
  $columns = array_merge(
203
  array( 'cb' => '<input type="checkbox" />' ),
204
+ $this->columns
205
  );
206
 
207
  return $columns;
357
 
358
  $filter = array();
359
  foreach ( $this->search_by as $column ) {
360
+ $filter[] = $wpdb->prepare('`' . $column . '` like "%%s%"', $wpdb->esc_like( $_GET['s'] ));
361
  }
362
  return implode( ' OR ', $filter );
363
  }
457
 
458
  foreach ( $options as $value => $label ) {
459
  echo '<option value="' . esc_attr( $value ) . '" ' . esc_html( $value == $default ? 'selected' : '' ) .'>'
460
+ . esc_html( $label )
461
  . '</option>';
462
  }
463
 
464
  echo '</select>';
465
  }
466
 
467
+ submit_button( esc_html__( 'Filter', 'action-scheduler' ), '', 'filter_action', false, array( 'id' => 'post-query-submit' ) );
468
  echo '</div>';
469
  }
470
 
563
  protected function display_header() {
564
  echo '<h1 class="wp-heading-inline">' . esc_attr( $this->table_header ) . '</h1>';
565
  if ( $this->get_request_search_query() ) {
566
+ /* translators: %s: search query */
567
+ echo '<span class="subtitle">' . esc_attr( sprintf( __( 'Search results for "%s"', 'action-scheduler' ), $this->get_request_search_query() ) ) . '</span>';
568
  }
569
  echo '<hr class="wp-header-end">';
570
  }
636
  echo '</form>';
637
  }
638
 
639
+ /**
640
+ * Process any pending actions.
641
+ */
642
+ public function process_actions() {
643
+ $this->process_bulk_action();
644
+
645
+ $this->process_row_actions();
646
+
647
+ if ( ! empty( $_REQUEST['_wp_http_referer'] ) ) {
648
+ // _wp_http_referer is used only on bulk actions, we remove it to keep the $_GET shorter
649
+ wp_redirect( remove_query_arg( array( '_wp_http_referer', '_wpnonce' ), wp_unslash( $_SERVER['REQUEST_URI'] ) ) );
650
+ exit;
651
+ }
652
+ }
653
+
654
  /**
655
  * Render the list table page, including header, notices, status filters and table.
656
  */
669
  * Get the text to display in the search box on the list table.
670
  */
671
  protected function get_search_box_placeholder() {
672
+ return esc_html__( 'Search', 'action-scheduler' );
673
  }
674
  }
includes/vendor/action-scheduler/classes/{ActionScheduler_Abstract_QueueRunner.php → abstracts/ActionScheduler_Abstract_QueueRunner.php} RENAMED
@@ -44,28 +44,30 @@ abstract class ActionScheduler_Abstract_QueueRunner extends ActionScheduler_Abst
44
  * Process an individual action.
45
  *
46
  * @param int $action_id The action ID to process.
 
 
47
  */
48
- public function process_action( $action_id ) {
49
  try {
50
- do_action( 'action_scheduler_before_execute', $action_id );
51
 
52
  if ( ActionScheduler_Store::STATUS_PENDING !== $this->store->get_status( $action_id ) ) {
53
- do_action( 'action_scheduler_execution_ignored', $action_id );
54
  return;
55
  }
56
 
57
  $action = $this->store->fetch_action( $action_id );
58
  $this->store->log_execution( $action_id );
59
  $action->execute();
60
- do_action( 'action_scheduler_after_execute', $action_id, $action );
61
  $this->store->mark_complete( $action_id );
62
  } catch ( Exception $e ) {
63
  $this->store->mark_failure( $action_id );
64
- do_action( 'action_scheduler_failed_execution', $action_id, $e );
65
  }
66
 
67
- if ( isset( $action ) && is_a( $action, 'ActionScheduler_Action' ) ) {
68
- $this->schedule_next_instance( $action );
69
  }
70
  }
71
 
@@ -73,13 +75,13 @@ abstract class ActionScheduler_Abstract_QueueRunner extends ActionScheduler_Abst
73
  * Schedule the next instance of the action if necessary.
74
  *
75
  * @param ActionScheduler_Action $action
 
76
  */
77
- protected function schedule_next_instance( ActionScheduler_Action $action ) {
78
- $schedule = $action->get_schedule();
79
- $next = $schedule->next( as_get_datetime_object() );
80
-
81
- if ( ! is_null( $next ) && $schedule->is_recurring() ) {
82
- $this->store->save_action( $action, $next );
83
  }
84
  }
85
 
@@ -98,7 +100,16 @@ abstract class ActionScheduler_Abstract_QueueRunner extends ActionScheduler_Abst
98
  * @return int
99
  */
100
  public function get_allowed_concurrent_batches() {
101
- return apply_filters( 'action_scheduler_queue_runner_concurrent_batches', 5 );
 
 
 
 
 
 
 
 
 
102
  }
103
 
104
  /**
@@ -213,7 +224,9 @@ abstract class ActionScheduler_Abstract_QueueRunner extends ActionScheduler_Abst
213
  * Process actions in the queue.
214
  *
215
  * @author Jeremy Pry
 
 
216
  * @return int The number of actions processed.
217
  */
218
- abstract public function run();
219
  }
44
  * Process an individual action.
45
  *
46
  * @param int $action_id The action ID to process.
47
+ * @param string $context Optional identifer for the context in which this action is being processed, e.g. 'WP CLI' or 'WP Cron'
48
+ * Generally, this should be capitalised and not localised as it's a proper noun.
49
  */
50
+ public function process_action( $action_id, $context = '' ) {
51
  try {
52
+ do_action( 'action_scheduler_before_execute', $action_id, $context );
53
 
54
  if ( ActionScheduler_Store::STATUS_PENDING !== $this->store->get_status( $action_id ) ) {
55
+ do_action( 'action_scheduler_execution_ignored', $action_id, $context );
56
  return;
57
  }
58
 
59
  $action = $this->store->fetch_action( $action_id );
60
  $this->store->log_execution( $action_id );
61
  $action->execute();
62
+ do_action( 'action_scheduler_after_execute', $action_id, $action, $context );
63
  $this->store->mark_complete( $action_id );
64
  } catch ( Exception $e ) {
65
  $this->store->mark_failure( $action_id );
66
+ do_action( 'action_scheduler_failed_execution', $action_id, $e, $context );
67
  }
68
 
69
+ if ( isset( $action ) && is_a( $action, 'ActionScheduler_Action' ) && $action->get_schedule()->is_recurring() ) {
70
+ $this->schedule_next_instance( $action, $action_id );
71
  }
72
  }
73
 
75
  * Schedule the next instance of the action if necessary.
76
  *
77
  * @param ActionScheduler_Action $action
78
+ * @param int $action_id
79
  */
80
+ protected function schedule_next_instance( ActionScheduler_Action $action, $action_id ) {
81
+ try {
82
+ ActionScheduler::factory()->repeat( $action );
83
+ } catch ( Exception $e ) {
84
+ do_action( 'action_scheduler_failed_to_schedule_next_instance', $action_id, $e, $action );
 
85
  }
86
  }
87
 
100
  * @return int
101
  */
102
  public function get_allowed_concurrent_batches() {
103
+ return apply_filters( 'action_scheduler_queue_runner_concurrent_batches', 1 );
104
+ }
105
+
106
+ /**
107
+ * Check if the number of allowed concurrent batches is met or exceeded.
108
+ *
109
+ * @return bool
110
+ */
111
+ public function has_maximum_concurrent_batches() {
112
+ return $this->store->get_claim_count() >= $this->get_allowed_concurrent_batches();
113
  }
114
 
115
  /**
224
  * Process actions in the queue.
225
  *
226
  * @author Jeremy Pry
227
+ * @param string $context Optional identifer for the context in which this action is being processed, e.g. 'WP CLI' or 'WP Cron'
228
+ * Generally, this should be capitalised and not localised as it's a proper noun.
229
  * @return int The number of actions processed.
230
  */
231
+ abstract public function run( $context = '' );
232
  }
includes/vendor/action-scheduler/classes/abstracts/ActionScheduler_Abstract_RecurringSchedule.php ADDED
@@ -0,0 +1,102 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Class ActionScheduler_Abstract_RecurringSchedule
5
+ */
6
+ abstract class ActionScheduler_Abstract_RecurringSchedule extends ActionScheduler_Abstract_Schedule {
7
+
8
+ /**
9
+ * The date & time the first instance of this schedule was setup to run (which may not be this instance).
10
+ *
11
+ * Schedule objects are attached to an action object. Each schedule stores the run date for that
12
+ * object as the start date - @see $this->start - and logic to calculate the next run date after
13
+ * that - @see $this->calculate_next(). The $first_date property also keeps a record of when the very
14
+ * first instance of this chain of schedules ran.
15
+ *
16
+ * @var DateTime
17
+ */
18
+ private $first_date = NULL;
19
+
20
+ /**
21
+ * Timestamp equivalent of @see $this->first_date
22
+ *
23
+ * @var int
24
+ */
25
+ protected $first_timestamp = NULL;
26
+
27
+ /**
28
+ * The recurrance between each time an action is run using this schedule.
29
+ * Used to calculate the start date & time. Can be a number of seconds, in the
30
+ * case of ActionScheduler_IntervalSchedule, or a cron expression, as in the
31
+ * case of ActionScheduler_CronSchedule. Or something else.
32
+ *
33
+ * @var mixed
34
+ */
35
+ protected $recurrence;
36
+
37
+ /**
38
+ * @param DateTime $date The date & time to run the action.
39
+ * @param mixed $recurrence The data used to determine the schedule's recurrance.
40
+ * @param DateTime|null $first (Optional) The date & time the first instance of this interval schedule ran. Default null, meaning this is the first instance.
41
+ */
42
+ public function __construct( DateTime $date, $recurrence, DateTime $first = null ) {
43
+ parent::__construct( $date );
44
+ $this->first_date = empty( $first ) ? $date : $first;
45
+ $this->recurrence = $recurrence;
46
+ }
47
+
48
+ /**
49
+ * @return bool
50
+ */
51
+ public function is_recurring() {
52
+ return true;
53
+ }
54
+
55
+ /**
56
+ * Get the date & time of the first schedule in this recurring series.
57
+ *
58
+ * @return DateTime|null
59
+ */
60
+ public function get_first_date() {
61
+ return clone $this->first_date;
62
+ }
63
+
64
+ /**
65
+ * @return string
66
+ */
67
+ public function get_recurrence() {
68
+ return $this->recurrence;
69
+ }
70
+
71
+ /**
72
+ * For PHP 5.2 compat, since DateTime objects can't be serialized
73
+ * @return array
74
+ */
75
+ public function __sleep() {
76
+ $sleep_params = parent::__sleep();
77
+ $this->first_timestamp = $this->first_date->getTimestamp();
78
+ return array_merge( $sleep_params, array(
79
+ 'first_timestamp',
80
+ 'recurrence'
81
+ ) );
82
+ }
83
+
84
+ /**
85
+ * Unserialize recurring schedules serialized/stored prior to AS 3.0.0
86
+ *
87
+ * Prior to Action Scheduler 3.0.0, schedules used different property names to refer
88
+ * to equivalent data. For example, ActionScheduler_IntervalSchedule::start_timestamp
89
+ * was the same as ActionScheduler_SimpleSchedule::timestamp. This was addressed in
90
+ * Action Scheduler 3.0.0, where properties and property names were aligned for better
91
+ * inheritance. To maintain backward compatibility with scheduled serialized and stored
92
+ * prior to 3.0, we need to correctly map the old property names.
93
+ */
94
+ public function __wakeup() {
95
+ parent::__wakeup();
96
+ if ( $this->first_timestamp > 0 ) {
97
+ $this->first_date = as_get_datetime_object( $this->first_timestamp );
98
+ } else {
99
+ $this->first_date = $this->get_date();
100
+ }
101
+ }
102
+ }
includes/vendor/action-scheduler/classes/abstracts/ActionScheduler_Abstract_Schedule.php ADDED
@@ -0,0 +1,83 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Class ActionScheduler_Abstract_Schedule
5
+ */
6
+ abstract class ActionScheduler_Abstract_Schedule extends ActionScheduler_Schedule_Deprecated {
7
+
8
+ /**
9
+ * The date & time the schedule is set to run.
10
+ *
11
+ * @var DateTime
12
+ */
13
+ private $scheduled_date = NULL;
14
+
15
+ /**
16
+ * Timestamp equivalent of @see $this->scheduled_date
17
+ *
18
+ * @var int
19
+ */
20
+ protected $scheduled_timestamp = NULL;
21
+
22
+ /**
23
+ * @param DateTime $date The date & time to run the action.
24
+ */
25
+ public function __construct( DateTime $date ) {
26
+ $this->scheduled_date = $date;
27
+ }
28
+
29
+ /**
30
+ * Check if a schedule should recur.
31
+ *
32
+ * @return bool
33
+ */
34
+ abstract public function is_recurring();
35
+
36
+ /**
37
+ * Calculate when the next instance of this schedule would run based on a given date & time.
38
+ *
39
+ * @param DateTime $after
40
+ * @return DateTime
41
+ */
42
+ abstract protected function calculate_next( DateTime $after );
43
+
44
+ /**
45
+ * Get the next date & time when this schedule should run after a given date & time.
46
+ *
47
+ * @param DateTime $after
48
+ * @return DateTime|null
49
+ */
50
+ public function get_next( DateTime $after ) {
51
+ $after = clone $after;
52
+ if ( $after > $this->scheduled_date ) {
53
+ $after = $this->calculate_next( $after );
54
+ return $after;
55
+ }
56
+ return clone $this->scheduled_date;
57
+ }
58
+
59
+ /**
60
+ * Get the date & time the schedule is set to run.
61
+ *
62
+ * @return DateTime|null
63
+ */
64
+ public function get_date() {
65
+ return $this->scheduled_date;
66
+ }
67
+
68
+ /**
69
+ * For PHP 5.2 compat, since DateTime objects can't be serialized
70
+ * @return array
71
+ */
72
+ public function __sleep() {
73
+ $this->scheduled_timestamp = $this->scheduled_date->getTimestamp();
74
+ return array(
75
+ 'scheduled_timestamp',
76
+ );
77
+ }
78
+
79
+ public function __wakeup() {
80
+ $this->scheduled_date = as_get_datetime_object( $this->scheduled_timestamp );
81
+ unset( $this->scheduled_timestamp );
82
+ }
83
+ }
includes/vendor/action-scheduler/classes/abstracts/ActionScheduler_Abstract_Schema.php ADDED
@@ -0,0 +1,133 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+
4
+ /**
5
+ * Class ActionScheduler_Abstract_Schema
6
+ *
7
+ * @package Action_Scheduler
8
+ *
9
+ * @codeCoverageIgnore
10
+ *
11
+ * Utility class for creating/updating custom tables
12
+ */
13
+ abstract class ActionScheduler_Abstract_Schema {
14
+
15
+ /**
16
+ * @var int Increment this value in derived class to trigger a schema update.
17
+ */
18
+ protected $schema_version = 1;
19
+
20
+ /**
21
+ * @var array Names of tables that will be registered by this class.
22
+ */
23
+ protected $tables = [];
24
+
25
+ /**
26
+ * Register tables with WordPress, and create them if needed.
27
+ *
28
+ * @return void
29
+ */
30
+ public function register_tables() {
31
+ global $wpdb;
32
+
33
+ // make WP aware of our tables
34
+ foreach ( $this->tables as $table ) {
35
+ $wpdb->tables[] = $table;
36
+ $name = $this->get_full_table_name( $table );
37
+ $wpdb->$table = $name;
38
+ }
39
+
40
+ // create the tables
41
+ if ( $this->schema_update_required() ) {
42
+ foreach ( $this->tables as $table ) {
43
+ $this->update_table( $table );
44
+ }
45
+ $this->mark_schema_update_complete();
46
+ }
47
+ }
48
+
49
+ /**
50
+ * @param string $table The name of the table
51
+ *
52
+ * @return string The CREATE TABLE statement, suitable for passing to dbDelta
53
+ */
54
+ abstract protected function get_table_definition( $table );
55
+
56
+ /**
57
+ * Determine if the database schema is out of date
58
+ * by comparing the integer found in $this->schema_version
59
+ * with the option set in the WordPress options table
60
+ *
61
+ * @return bool
62
+ */
63
+ private function schema_update_required() {
64
+ $option_name = 'schema-' . static::class;
65
+ $version_found_in_db = get_option( $option_name, 0 );
66
+
67
+ // Check for schema option stored by the Action Scheduler Custom Tables plugin in case site has migrated from that plugin with an older schema
68
+ if ( 0 === $version_found_in_db ) {
69
+
70
+ $plugin_option_name = 'schema-';
71
+
72
+ switch ( static::class ) {
73
+ case 'ActionScheduler_StoreSchema' :
74
+ $plugin_option_name .= 'Action_Scheduler\Custom_Tables\DB_Store_Table_Maker';
75
+ break;
76
+ case 'ActionScheduler_LoggerSchema' :
77
+ $plugin_option_name .= 'Action_Scheduler\Custom_Tables\DB_Logger_Table_Maker';
78
+ break;
79
+ }
80
+
81
+ $version_found_in_db = get_option( $plugin_option_name, 0 );
82
+
83
+ delete_option( $plugin_option_name );
84
+ }
85
+
86
+ return version_compare( $version_found_in_db, $this->schema_version, '<' );
87
+ }
88
+
89
+ /**
90
+ * Update the option in WordPress to indicate that
91
+ * our schema is now up to date
92
+ *
93
+ * @return void
94
+ */
95
+ private function mark_schema_update_complete() {
96
+ $option_name = 'schema-' . static::class;
97
+
98
+ // work around race conditions and ensure that our option updates
99
+ $value_to_save = (string) $this->schema_version . '.0.' . time();
100
+
101
+ update_option( $option_name, $value_to_save );
102
+ }
103
+
104
+ /**
105
+ * Update the schema for the given table
106
+ *
107
+ * @param string $table The name of the table to update
108
+ *
109
+ * @return void
110
+ */
111
+ private function update_table( $table ) {
112
+ require_once( ABSPATH . 'wp-admin/includes/upgrade.php' );
113
+ $definition = $this->get_table_definition( $table );
114
+ if ( $definition ) {
115
+ $updated = dbDelta( $definition );
116
+ foreach ( $updated as $updated_table => $update_description ) {
117
+ if ( strpos( $update_description, 'Created table' ) === 0 ) {
118
+ do_action( 'action_scheduler/created_table', $updated_table, $table );
119
+ }
120
+ }
121
+ }
122
+ }
123
+
124
+ /**
125
+ * @param string $table
126
+ *
127
+ * @return string The full name of the table, including the
128
+ * table prefix for the current blog
129
+ */
130
+ protected function get_full_table_name( $table ) {
131
+ return $GLOBALS[ 'wpdb' ]->prefix . $table;
132
+ }
133
+ }
includes/vendor/action-scheduler/classes/abstracts/ActionScheduler_Lock.php ADDED
@@ -0,0 +1,62 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Abstract class for setting a basic lock to throttle some action.
5
+ *
6
+ * Class ActionScheduler_Lock
7
+ */
8
+ abstract class ActionScheduler_Lock {
9
+
10
+ /** @var ActionScheduler_Lock */
11
+ private static $locker = NULL;
12
+
13
+ /** @var int */
14
+ protected static $lock_duration = MINUTE_IN_SECONDS;
15
+
16
+ /**
17
+ * Check if a lock is set for a given lock type.
18
+ *
19
+ * @param string $lock_type A string to identify different lock types.
20
+ * @return bool
21
+ */
22
+ public function is_locked( $lock_type ) {
23
+ return ( $this->get_expiration( $lock_type ) >= time() );
24
+ }
25
+
26
+ /**
27
+ * Set a lock.
28
+ *
29
+ * @param string $lock_type A string to identify different lock types.
30
+ * @return bool
31
+ */
32
+ abstract public function set( $lock_type );
33
+
34
+ /**
35
+ * If a lock is set, return the timestamp it was set to expiry.
36
+ *
37
+ * @param string $lock_type A string to identify different lock types.
38
+ * @return bool|int False if no lock is set, otherwise the timestamp for when the lock is set to expire.
39
+ */
40
+ abstract public function get_expiration( $lock_type );
41
+
42
+ /**
43
+ * Get the amount of time to set for a given lock. 60 seconds by default.
44
+ *
45
+ * @param string $lock_type A string to identify different lock types.
46
+ * @return int
47
+ */
48
+ protected function get_duration( $lock_type ) {
49
+ return apply_filters( 'action_scheduler_lock_duration', self::$lock_duration, $lock_type );
50
+ }
51
+
52
+ /**
53
+ * @return ActionScheduler_Lock
54
+ */
55
+ public static function instance() {
56
+ if ( empty( self::$locker ) ) {
57
+ $class = apply_filters( 'action_scheduler_lock_class', 'ActionScheduler_OptionLock' );
58
+ self::$locker = new $class();
59
+ }
60
+ return self::$locker;
61
+ }
62
+ }
includes/vendor/action-scheduler/classes/abstracts/ActionScheduler_Logger.php ADDED
@@ -0,0 +1,176 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Class ActionScheduler_Logger
5
+ * @codeCoverageIgnore
6
+ */
7
+ abstract class ActionScheduler_Logger {
8
+ private static $logger = NULL;
9
+
10
+ /**
11
+ * @return ActionScheduler_Logger
12
+ */
13
+ public static function instance() {
14
+ if ( empty(self::$logger) ) {
15
+ $class = apply_filters('action_scheduler_logger_class', 'ActionScheduler_wpCommentLogger');
16
+ self::$logger = new $class();
17
+ }
18
+ return self::$logger;
19
+ }
20
+
21
+ /**
22
+ * @param string $action_id
23
+ * @param string $message
24
+ * @param DateTime $date
25
+ *
26
+ * @return string The log entry ID
27
+ */
28
+ abstract public function log( $action_id, $message, DateTime $date = NULL );
29
+
30
+ /**
31
+ * @param string $entry_id
32
+ *
33
+ * @return ActionScheduler_LogEntry
34
+ */
35
+ abstract public function get_entry( $entry_id );
36
+
37
+ /**
38
+ * @param string $action_id
39
+ *
40
+ * @return ActionScheduler_LogEntry[]
41
+ */
42
+ abstract public function get_logs( $action_id );
43
+
44
+
45
+ /**
46
+ * @codeCoverageIgnore
47
+ */
48
+ public function init() {
49
+ $this->hook_stored_action();
50
+ add_action( 'action_scheduler_canceled_action', array( $this, 'log_canceled_action' ), 10, 1 );
51
+ add_action( 'action_scheduler_before_execute', array( $this, 'log_started_action' ), 10, 2 );
52
+ add_action( 'action_scheduler_after_execute', array( $this, 'log_completed_action' ), 10, 3 );
53
+ add_action( 'action_scheduler_failed_execution', array( $this, 'log_failed_action' ), 10, 3 );
54
+ add_action( 'action_scheduler_failed_action', array( $this, 'log_timed_out_action' ), 10, 2 );
55
+ add_action( 'action_scheduler_unexpected_shutdown', array( $this, 'log_unexpected_shutdown' ), 10, 2 );
56
+ add_action( 'action_scheduler_reset_action', array( $this, 'log_reset_action' ), 10, 1 );
57
+ add_action( 'action_scheduler_execution_ignored', array( $this, 'log_ignored_action' ), 10, 2 );
58
+ add_action( 'action_scheduler_failed_fetch_action', array( $this, 'log_failed_fetch_action' ), 10, 2 );
59
+ add_action( 'action_scheduler_failed_to_schedule_next_instance', array( $this, 'log_failed_schedule_next_instance' ), 10, 2 );
60
+ add_action( 'action_scheduler_bulk_cancel_actions', array( $this, 'bulk_log_cancel_actions' ), 10, 1 );
61
+ }
62
+
63
+ public function hook_stored_action() {
64
+ add_action( 'action_scheduler_stored_action', array( $this, 'log_stored_action' ) );
65
+ }
66
+
67
+ public function unhook_stored_action() {
68
+ remove_action( 'action_scheduler_stored_action', array( $this, 'log_stored_action' ) );
69
+ }
70
+
71
+ public function log_stored_action( $action_id ) {
72
+ $this->log( $action_id, __( 'action created', 'action-scheduler' ) );
73
+ }
74
+
75
+ public function log_canceled_action( $action_id ) {
76
+ $this->log( $action_id, __( 'action canceled', 'action-scheduler' ) );
77
+ }
78
+
79
+ public function log_started_action( $action_id, $context = '' ) {
80
+ if ( ! empty( $context ) ) {
81
+ /* translators: %s: context */
82
+ $message = sprintf( __( 'action started via %s', 'action-scheduler' ), $context );
83
+ } else {
84
+ $message = __( 'action started', 'action-scheduler' );
85
+ }
86
+ $this->log( $action_id, $message );
87
+ }
88
+
89
+ public function log_completed_action( $action_id, $action = NULL, $context = '' ) {
90
+ if ( ! empty( $context ) ) {
91
+ /* translators: %s: context */
92
+ $message = sprintf( __( 'action complete via %s', 'action-scheduler' ), $context );
93
+ } else {
94
+ $message = __( 'action complete', 'action-scheduler' );
95
+ }
96
+ $this->log( $action_id, $message );
97
+ }
98
+
99
+ public function log_failed_action( $action_id, Exception $exception, $context = '' ) {
100
+ if ( ! empty( $context ) ) {
101
+ /* translators: 1: context 2: exception message */
102
+ $message = sprintf( __( 'action failed via %1$s: %2$s', 'action-scheduler' ), $context, $exception->getMessage() );
103
+ } else {
104
+ /* translators: %s: exception message */
105
+ $message = sprintf( __( 'action failed: %s', 'action-scheduler' ), $exception->getMessage() );
106
+ }
107
+ $this->log( $action_id, $message );
108
+ }
109
+
110
+ public function log_timed_out_action( $action_id, $timeout ) {
111
+ /* translators: %s: amount of time */
112
+ $this->log( $action_id, sprintf( __( 'action timed out after %s seconds', 'action-scheduler' ), $timeout ) );
113
+ }
114
+
115
+ public function log_unexpected_shutdown( $action_id, $error ) {
116
+ if ( ! empty( $error ) ) {
117
+ /* translators: 1: error message 2: filename 3: line */
118
+ $this->log( $action_id, sprintf( __( 'unexpected shutdown: PHP Fatal error %1$s in %2$s on line %3$s', 'action-scheduler' ), $error['message'], $error['file'], $error['line'] ) );
119
+ }
120
+ }
121
+
122
+ public function log_reset_action( $action_id ) {
123
+ $this->log( $action_id, __( 'action reset', 'action-scheduler' ) );
124
+ }
125
+
126
+ public function log_ignored_action( $action_id, $context = '' ) {
127
+ if ( ! empty( $context ) ) {
128
+ /* translators: %s: context */
129
+ $message = sprintf( __( 'action ignored via %s', 'action-scheduler' ), $context );
130
+ } else {
131
+ $message = __( 'action ignored', 'action-scheduler' );
132
+ }
133
+ $this->log( $action_id, __( 'action ignored', 'action-scheduler' ) );
134
+ }
135
+
136
+ /**
137
+ * @param string $action_id
138
+ * @param Exception|NULL $exception The exception which occured when fetching the action. NULL by default for backward compatibility.
139
+ *
140
+ * @return ActionScheduler_LogEntry[]
141
+ */
142
+ public function log_failed_fetch_action( $action_id, Exception $exception = NULL ) {
143
+
144
+ if ( ! is_null( $exception ) ) {
145
+ /* translators: %s: exception message */
146
+ $log_message = sprintf( __( 'There was a failure fetching this action: %s', 'action-scheduler' ), $exception->getMessage() );
147
+ } else {
148
+ $log_message = __( 'There was a failure fetching this action', 'action-scheduler' );
149
+ }
150
+
151
+ $this->log( $action_id, $log_message );
152
+ }
153
+
154
+ public function log_failed_schedule_next_instance( $action_id, Exception $exception ) {
155
+ /* translators: %s: exception message */
156
+ $this->log( $action_id, sprintf( __( 'There was a failure scheduling the next instance of this action: %s', 'action-scheduler' ), $exception->getMessage() ) );
157
+ }
158
+
159
+ /**
160
+ * Bulk add cancel action log entries.
161
+ *
162
+ * Implemented here for backward compatibility. Should be implemented in parent loggers
163
+ * for more performant bulk logging.
164
+ *
165
+ * @param array $action_ids List of action ID.
166
+ */
167
+ public function bulk_log_cancel_actions( $action_ids ) {
168
+ if ( empty( $action_ids ) ) {
169
+ return;
170
+ }
171
+
172
+ foreach ( $action_ids as $action_id ) {
173
+ $this->log_canceled_action( $action_id );
174
+ }
175
+ }
176
+ }
includes/vendor/action-scheduler/classes/abstracts/ActionScheduler_Store.php ADDED
@@ -0,0 +1,345 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Class ActionScheduler_Store
5
+ * @codeCoverageIgnore
6
+ */
7
+ abstract class ActionScheduler_Store extends ActionScheduler_Store_Deprecated {
8
+ const STATUS_COMPLETE = 'complete';
9
+ const STATUS_PENDING = 'pending';
10
+ const STATUS_RUNNING = 'in-progress';
11
+ const STATUS_FAILED = 'failed';
12
+ const STATUS_CANCELED = 'canceled';
13
+ const DEFAULT_CLASS = 'ActionScheduler_wpPostStore';
14
+
15
+ /** @var ActionScheduler_Store */
16
+ private static $store = NULL;
17
+
18
+ /** @var int */
19
+ private static $max_index_length = 191;
20
+
21
+ /**
22
+ * @param ActionScheduler_Action $action
23
+ * @param DateTime $scheduled_date Optional Date of the first instance
24
+ * to store. Otherwise uses the first date of the action's
25
+ * schedule.
26
+ *
27
+ * @return string The action ID
28
+ */
29
+ abstract public function save_action( ActionScheduler_Action $action, DateTime $scheduled_date = NULL );
30
+
31
+ /**
32
+ * @param string $action_id
33
+ *
34
+ * @return ActionScheduler_Action
35
+ */
36
+ abstract public function fetch_action( $action_id );
37
+
38
+ /**
39
+ * @param string $hook Hook name/slug.
40
+ * @param array $params Hook arguments.
41
+ * @return string ID of the next action matching the criteria.
42
+ */
43
+ abstract public function find_action( $hook, $params = array() );
44
+
45
+ /**
46
+ * @param array $query Query parameters.
47
+ * @param string $query_type Whether to select or count the results. Default, select.
48
+ *
49
+ * @return array|int The IDs of or count of actions matching the query.
50
+ */
51
+ abstract public function query_actions( $query = array(), $query_type = 'select' );
52
+
53
+ /**
54
+ * Get a count of all actions in the store, grouped by status
55
+ *
56
+ * @return array
57
+ */
58
+ abstract public function action_counts();
59
+
60
+ /**
61
+ * @param string $action_id
62
+ */
63
+ abstract public function cancel_action( $action_id );
64
+
65
+ /**
66
+ * @param string $action_id
67
+ */
68
+ abstract public function delete_action( $action_id );
69
+
70
+ /**
71
+ * @param string $action_id
72
+ *
73
+ * @return DateTime The date the action is schedule to run, or the date that it ran.
74
+ */
75
+ abstract public function get_date( $action_id );
76
+
77
+
78
+ /**
79
+ * @param int $max_actions
80
+ * @param DateTime $before_date Claim only actions schedule before the given date. Defaults to now.
81
+ * @param array $hooks Claim only actions with a hook or hooks.
82
+ * @param string $group Claim only actions in the given group.
83
+ *
84
+ * @return ActionScheduler_ActionClaim
85
+ */
86
+ abstract public function stake_claim( $max_actions = 10, DateTime $before_date = null, $hooks = array(), $group = '' );
87
+
88
+ /**
89
+ * @return int
90
+ */
91
+ abstract public function get_claim_count();
92
+
93
+ /**
94
+ * @param ActionScheduler_ActionClaim $claim
95
+ */
96
+ abstract public function release_claim( ActionScheduler_ActionClaim $claim );
97
+
98
+ /**
99
+ * @param string $action_id
100
+ */
101
+ abstract public function unclaim_action( $action_id );
102
+
103
+ /**
104
+ * @param string $action_id
105
+ */
106
+ abstract public function mark_failure( $action_id );
107
+
108
+ /**
109
+ * @param string $action_id
110
+ */
111
+ abstract public function log_execution( $action_id );
112
+
113
+ /**
114
+ * @param string $action_id
115
+ */
116
+ abstract public function mark_complete( $action_id );
117
+
118
+ /**
119
+ * @param string $action_id
120
+ *
121
+ * @return string
122
+ */
123
+ abstract public function get_status( $action_id );
124
+
125
+ /**
126
+ * @param string $action_id
127
+ * @return mixed
128
+ */
129
+ abstract public function get_claim_id( $action_id );
130
+
131
+ /**
132
+ * @param string $claim_id
133
+ * @return array
134
+ */
135
+ abstract public function find_actions_by_claim_id( $claim_id );
136
+
137
+ /**
138
+ * @param string $comparison_operator
139
+ * @return string
140
+ */
141
+ protected function validate_sql_comparator( $comparison_operator ) {
142
+ if ( in_array( $comparison_operator, array('!=', '>', '>=', '<', '<=', '=') ) ) {
143
+ return $comparison_operator;
144
+ }
145
+ return '=';
146
+ }
147
+
148
+ /**
149
+ * Get the time MySQL formated date/time string for an action's (next) scheduled date.
150
+ *
151
+ * @param ActionScheduler_Action $action
152
+ * @param DateTime $scheduled_date (optional)
153
+ * @return string
154
+ */
155
+ protected function get_scheduled_date_string( ActionScheduler_Action $action, DateTime $scheduled_date = NULL ) {
156
+ $next = null === $scheduled_date ? $action->get_schedule()->get_date() : $scheduled_date;
157
+ if ( ! $next ) {
158
+ return '0000-00-00 00:00:00';
159
+ }
160
+ $next->setTimezone( new DateTimeZone( 'UTC' ) );
161
+
162
+ return $next->format( 'Y-m-d H:i:s' );
163
+ }
164
+
165
+ /**
166
+ * Get the time MySQL formated date/time string for an action's (next) scheduled date.
167
+ *
168
+ * @param ActionScheduler_Action $action
169
+ * @param DateTime $scheduled_date (optional)
170
+ * @return string
171
+ */
172
+ protected function get_scheduled_date_string_local( ActionScheduler_Action $action, DateTime $scheduled_date = NULL ) {
173
+ $next = null === $scheduled_date ? $action->get_schedule()->get_date() : $scheduled_date;
174
+ if ( ! $next ) {
175
+ return '0000-00-00 00:00:00';
176
+ }
177
+
178
+ ActionScheduler_TimezoneHelper::set_local_timezone( $next );
179
+ return $next->format( 'Y-m-d H:i:s' );
180
+ }
181
+
182
+ /**
183
+ * Validate that we could decode action arguments.
184
+ *
185
+ * @param mixed $args The decoded arguments.
186
+ * @param int $action_id The action ID.
187
+ *
188
+ * @throws ActionScheduler_InvalidActionException When the decoded arguments are invalid.
189
+ */
190
+ protected function validate_args( $args, $action_id ) {
191
+ // Ensure we have an array of args.
192
+ if ( ! is_array( $args ) ) {
193
+ throw ActionScheduler_InvalidActionException::from_decoding_args( $action_id );
194
+ }
195
+
196
+ // Validate JSON decoding if possible.
197
+ if ( function_exists( 'json_last_error' ) && JSON_ERROR_NONE !== json_last_error() ) {
198
+ throw ActionScheduler_InvalidActionException::from_decoding_args( $action_id, $args );
199
+ }
200
+ }
201
+
202
+ /**
203
+ * Validate a ActionScheduler_Schedule object.
204
+ *
205
+ * @param mixed $schedule The unserialized ActionScheduler_Schedule object.
206
+ * @param int $action_id The action ID.
207
+ *
208
+ * @throws ActionScheduler_InvalidActionException When the schedule is invalid.
209
+ */
210
+ protected function validate_schedule( $schedule, $action_id ) {
211
+ if ( empty( $schedule ) || ! is_a( $schedule, 'ActionScheduler_Schedule' ) ) {
212
+ throw ActionScheduler_InvalidActionException::from_schedule( $action_id, $schedule );
213
+ }
214
+ }
215
+
216
+ /**
217
+ * InnoDB indexes have a maximum size of 767 bytes by default, which is only 191 characters with utf8mb4.
218
+ *
219
+ * Previously, AS wasn't concerned about args length, as we used the (unindex) post_content column. However,
220
+ * as we prepare to move to custom tables, and can use an indexed VARCHAR column instead, we want to warn
221
+ * developers of this impending requirement.
222
+ *
223
+ * @param ActionScheduler_Action $action
224
+ */
225
+ protected function validate_action( ActionScheduler_Action $action ) {
226
+ if ( strlen( json_encode( $action->get_args() ) ) > self::$max_index_length ) {
227
+ throw new InvalidArgumentException( __( 'ActionScheduler_Action::$args too long. To ensure the args column can be indexed, action args should not be more than 191 characters when encoded as JSON.', 'action-scheduler' ) );
228
+ }
229
+ }
230
+
231
+ /**
232
+ * Cancel pending actions by hook.
233
+ *
234
+ * @since 3.0.0
235
+ *
236
+ * @param string $hook Hook name.
237
+ *
238
+ * @return void
239
+ */
240
+ public function cancel_actions_by_hook( $hook ) {
241
+ $action_ids = true;
242
+ while ( ! empty( $action_ids ) ) {
243
+ $action_ids = $this->query_actions(
244
+ array(
245
+ 'hook' => $hook,
246
+ 'status' => self::STATUS_PENDING,
247
+ 'per_page' => 1000,
248
+ )
249
+ );
250
+
251
+ $this->bulk_cancel_actions( $action_ids );
252
+ }
253
+ }
254
+
255
+ /**
256
+ * Cancel pending actions by group.
257
+ *
258
+ * @since 3.0.0
259
+ *
260
+ * @param string $group Group slug.
261
+ *
262
+ * @return void
263
+ */
264
+ public function cancel_actions_by_group( $group ) {
265
+ $action_ids = true;
266
+ while ( ! empty( $action_ids ) ) {
267
+ $action_ids = $this->query_actions(
268
+ array(
269
+ 'group' => $group,
270
+ 'status' => self::STATUS_PENDING,
271
+ 'per_page' => 1000,
272
+ )
273
+ );
274
+
275
+ $this->bulk_cancel_actions( $action_ids );
276
+ }
277
+ }
278
+
279
+ /**
280
+ * Cancel a set of action IDs.
281
+ *
282
+ * @since 3.0.0
283
+ *
284
+ * @param array $action_ids List of action IDs.
285
+ *
286
+ * @return void
287
+ */
288
+ private function bulk_cancel_actions( $action_ids ) {
289
+ foreach ( $action_ids as $action_id ) {
290
+ $this->cancel_action( $action_id );
291
+ }
292
+
293
+ do_action( 'action_scheduler_bulk_cancel_actions', $action_ids );
294
+ }
295
+
296
+ /**
297
+ * @return array
298
+ */
299
+ public function get_status_labels() {
300
+ return array(
301
+ self::STATUS_COMPLETE => __( 'Complete', 'action-scheduler' ),
302
+ self::STATUS_PENDING => __( 'Pending', 'action-scheduler' ),
303
+ self::STATUS_RUNNING => __( 'In-progress', 'action-scheduler' ),
304
+ self::STATUS_FAILED => __( 'Failed', 'action-scheduler' ),
305
+ self::STATUS_CANCELED => __( 'Canceled', 'action-scheduler' ),
306
+ );
307
+ }
308
+
309
+ /**
310
+ * Check if there are any pending scheduled actions due to run.
311
+ *
312
+ * @param ActionScheduler_Action $action
313
+ * @param DateTime $scheduled_date (optional)
314
+ * @return string
315
+ */
316
+ public function has_pending_actions_due() {
317
+ $pending_actions = $this->query_actions( array(
318
+ 'date' => as_get_datetime_object(),
319
+ 'status' => ActionScheduler_Store::STATUS_PENDING,
320
+ ) );
321
+
322
+ return ! empty( $pending_actions );
323
+ }
324
+
325
+ /**
326
+ * Callable initialization function optionally overridden in derived classes.
327
+ */
328
+ public function init() {}
329
+
330
+ /**
331
+ * Callable function to mark an action as migrated optionally overridden in derived classes.
332
+ */
333
+ public function mark_migrated( $action_id ) {}
334
+
335
+ /**
336
+ * @return ActionScheduler_Store
337
+ */
338
+ public static function instance() {
339
+ if ( empty( self::$store ) ) {
340
+ $class = apply_filters( 'action_scheduler_store_class', self::DEFAULT_CLASS );
341
+ self::$store = new $class();
342
+ }
343
+ return self::$store;
344
+ }
345
+ }
includes/vendor/action-scheduler/classes/{ActionScheduler_TimezoneHelper.php → abstracts/ActionScheduler_TimezoneHelper.php} RENAMED
File without changes
includes/vendor/action-scheduler/classes/{ActionScheduler_Action.php → actions/ActionScheduler_Action.php} RENAMED
File without changes
includes/vendor/action-scheduler/classes/{ActionScheduler_CanceledAction.php → actions/ActionScheduler_CanceledAction.php} RENAMED
@@ -16,6 +16,8 @@ class ActionScheduler_CanceledAction extends ActionScheduler_FinishedAction {
16
  */
17
  public function __construct( $hook, array $args = array(), ActionScheduler_Schedule $schedule = null, $group = '' ) {
18
  parent::__construct( $hook, $args, $schedule, $group );
19
- $this->set_schedule( new ActionScheduler_NullSchedule() );
 
 
20
  }
21
  }
16
  */
17
  public function __construct( $hook, array $args = array(), ActionScheduler_Schedule $schedule = null, $group = '' ) {
18
  parent::__construct( $hook, $args, $schedule, $group );
19
+ if ( is_null( $schedule ) ) {
20
+ $this->set_schedule( new ActionScheduler_NullSchedule() );
21
+ }
22
  }
23
  }
includes/vendor/action-scheduler/classes/{ActionScheduler_FinishedAction.php → actions/ActionScheduler_FinishedAction.php} RENAMED
File without changes
includes/vendor/action-scheduler/classes/{ActionScheduler_NullAction.php → actions/ActionScheduler_NullAction.php} RENAMED
File without changes
includes/vendor/action-scheduler/classes/data-stores/ActionScheduler_DBLogger.php ADDED
@@ -0,0 +1,146 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Class ActionScheduler_DBLogger
5
+ *
6
+ * Action logs data table data store.
7
+ *
8
+ * @since 3.0.0
9
+ */
10
+ class ActionScheduler_DBLogger extends ActionScheduler_Logger {
11
+
12
+ /**
13
+ * Add a record to an action log.
14
+ *
15
+ * @param int $action_id Action ID.
16
+ * @param string $message Message to be saved in the log entry.
17
+ * @param DateTime $date Timestamp of the log entry.
18
+ *
19
+ * @return int The log entry ID.
20
+ */
21
+ public function log( $action_id, $message, DateTime $date = null ) {
22
+ if ( empty( $date ) ) {
23
+ $date = as_get_datetime_object();
24
+ } else {
25
+ $date = clone $date;
26
+ }
27
+
28
+ $date_gmt = $date->format( 'Y-m-d H:i:s' );
29
+ ActionScheduler_TimezoneHelper::set_local_timezone( $date );
30
+ $date_local = $date->format( 'Y-m-d H:i:s' );
31
+
32
+ /** @var \wpdb $wpdb */
33
+ global $wpdb;
34
+ $wpdb->insert( $wpdb->actionscheduler_logs, [
35
+ 'action_id' => $action_id,
36
+ 'message' => $message,
37
+ 'log_date_gmt' => $date_gmt,
38
+ 'log_date_local' => $date_local,
39
+ ], [ '%d', '%s', '%s', '%s' ] );
40
+
41
+ return $wpdb->insert_id;
42
+ }
43
+
44
+ /**
45
+ * Retrieve an action log entry.
46
+ *
47
+ * @param int $entry_id Log entry ID.
48
+ *
49
+ * @return ActionScheduler_LogEntry
50
+ */
51
+ public function get_entry( $entry_id ) {
52
+ /** @var \wpdb $wpdb */
53
+ global $wpdb;
54
+ $entry = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$wpdb->actionscheduler_logs} WHERE log_id=%d", $entry_id ) );
55
+
56
+ return $this->create_entry_from_db_record( $entry );
57
+ }
58
+
59
+ /**
60
+ * Create an action log entry from a database record.
61
+ *
62
+ * @param object $record Log entry database record object.
63
+ *
64
+ * @return ActionScheduler_LogEntry
65
+ */
66
+ private function create_entry_from_db_record( $record ) {
67
+ if ( empty( $record ) ) {
68
+ return new ActionScheduler_NullLogEntry();
69
+ }
70
+
71
+ $date = as_get_datetime_object( $record->log_date_gmt );
72
+
73
+ return new ActionScheduler_LogEntry( $record->action_id, $record->message, $date );
74
+ }
75
+
76
+ /**
77
+ * Retrieve the an action's log entries from the database.
78
+ *
79
+ * @param int $action_id Action ID.
80
+ *
81
+ * @return ActionScheduler_LogEntry[]
82
+ */
83
+ public function get_logs( $action_id ) {
84
+ /** @var \wpdb $wpdb */
85
+ global $wpdb;
86
+
87
+ $records = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM {$wpdb->actionscheduler_logs} WHERE action_id=%d", $action_id ) );
88
+
89
+ return array_map( [ $this, 'create_entry_from_db_record' ], $records );
90
+ }
91
+
92
+ /**
93
+ * Initialize the data store.
94
+ *
95
+ * @codeCoverageIgnore
96
+ */
97
+ public function init() {
98
+
99
+ $table_maker = new ActionScheduler_LoggerSchema();
100
+ $table_maker->register_tables();
101
+
102
+ parent::init();
103
+
104
+ add_action( 'action_scheduler_deleted_action', [ $this, 'clear_deleted_action_logs' ], 10, 1 );
105
+ }
106
+
107
+ /**
108
+ * Delete the action logs for an action.
109
+ *
110
+ * @param int $action_id Action ID.
111
+ */
112
+ public function clear_deleted_action_logs( $action_id ) {
113
+ /** @var \wpdb $wpdb */
114
+ global $wpdb;
115
+ $wpdb->delete( $wpdb->actionscheduler_logs, [ 'action_id' => $action_id, ], [ '%d' ] );
116
+ }
117
+
118
+ /**
119
+ * Bulk add cancel action log entries.
120
+ *
121
+ * @param array $action_ids List of action ID.
122
+ */
123
+ public function bulk_log_cancel_actions( $action_ids ) {
124
+ if ( empty( $action_ids ) ) {
125
+ return;
126
+ }
127
+
128
+ /** @var \wpdb $wpdb */
129
+ global $wpdb;
130
+ $date = as_get_datetime_object();
131
+ $date_gmt = $date->format( 'Y-m-d H:i:s' );
132
+ ActionScheduler_TimezoneHelper::set_local_timezone( $date );
133
+ $date_local = $date->format( 'Y-m-d H:i:s' );
134
+ $message = __( 'action canceled', 'action-scheduler' );
135
+ $format = '(%d, ' . $wpdb->prepare( '%s, %s, %s', $message, $date_gmt, $date_local ) . ')';
136
+ $sql_query = "INSERT {$wpdb->actionscheduler_logs} (action_id, message, log_date_gmt, log_date_local) VALUES ";
137
+ $value_rows = [];
138
+
139
+ foreach ( $action_ids as $action_id ) {
140
+ $value_rows[] = $wpdb->prepare( $format, $action_id );
141
+ }
142
+ $sql_query .= implode( ',', $value_rows );
143
+
144
+ $wpdb->query( $sql_query );
145
+ }
146
+ }
includes/vendor/action-scheduler/classes/data-stores/ActionScheduler_DBStore.php ADDED
@@ -0,0 +1,803 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Class ActionScheduler_DBStore
5
+ *
6
+ * Action data table data store.
7
+ *
8
+ * @since 3.0.0
9
+ */
10
+ class ActionScheduler_DBStore extends ActionScheduler_Store {
11
+
12
+ /**
13
+ * Initialize the data store
14
+ *
15
+ * @codeCoverageIgnore
16
+ */
17
+ public function init() {
18
+ $table_maker = new ActionScheduler_StoreSchema();
19
+ $table_maker->register_tables();
20
+ }
21
+
22
+ /**
23
+ * Save an action.
24
+ *
25
+ * @param ActionScheduler_Action $action Action object.
26
+ * @param DateTime $date Optional schedule date. Default null.
27
+ *
28
+ * @return int Action ID.
29
+ */
30
+ public function save_action( ActionScheduler_Action $action, \DateTime $date = null ) {
31
+ try {
32
+
33
+ $this->validate_action( $action );
34
+
35
+ /** @var \wpdb $wpdb */
36
+ global $wpdb;
37
+ $data = [
38
+ 'hook' => $action->get_hook(),
39
+ 'status' => ( $action->is_finished() ? self::STATUS_COMPLETE : self::STATUS_PENDING ),
40
+ 'scheduled_date_gmt' => $this->get_scheduled_date_string( $action, $date ),
41
+ 'scheduled_date_local' => $this->get_scheduled_date_string_local( $action, $date ),
42
+ 'args' => json_encode( $action->get_args() ),
43
+ 'schedule' => serialize( $action->get_schedule() ),
44
+ 'group_id' => $this->get_group_id( $action->get_group() ),
45
+ ];
46
+ $wpdb->insert( $wpdb->actionscheduler_actions, $data );
47
+ $action_id = $wpdb->insert_id;
48
+
49
+ if ( is_wp_error( $action_id ) ) {
50
+ throw new RuntimeException( $action_id->get_error_message() );
51
+ }
52
+ elseif ( empty( $action_id ) ) {
53
+ throw new RuntimeException( $wpdb->last_error ? $wpdb->last_error : __( 'Database error.', 'action-scheduler' ) );
54
+ }
55
+
56
+ do_action( 'action_scheduler_stored_action', $action_id );
57
+
58
+ return $action_id;
59
+ } catch ( \Exception $e ) {
60
+ /* translators: %s: error message */
61
+ throw new \RuntimeException( sprintf( __( 'Error saving action: %s', 'action-scheduler' ), $e->getMessage() ), 0 );
62
+ }
63
+ }
64
+
65
+ /**
66
+ * Get a group's ID based on its name/slug.
67
+ *
68
+ * @param string $slug The string name of a group.
69
+ * @param bool $create_if_not_exists Whether to create the group if it does not already exist. Default, true - create the group.
70
+ *
71
+ * @return int The group's ID, if it exists or is created, or 0 if it does not exist and is not created.
72
+ */
73
+ protected function get_group_id( $slug, $create_if_not_exists = true ) {
74
+ if ( empty( $slug ) ) {
75
+ return 0;
76
+ }
77
+ /** @var \wpdb $wpdb */
78
+ global $wpdb;
79
+ $group_id = (int) $wpdb->get_var( $wpdb->prepare( "SELECT group_id FROM {$wpdb->actionscheduler_groups} WHERE slug=%s", $slug ) );
80
+ if ( empty( $group_id ) && $create_if_not_exists ) {
81
+ $group_id = $this->create_group( $slug );
82
+ }
83
+
84
+ return $group_id;
85
+ }
86
+
87
+ /**
88
+ * Create an action group.
89
+ *
90
+ * @param string $slug Group slug.
91
+ *
92
+ * @return int Group ID.
93
+ */
94
+ protected function create_group( $slug ) {
95
+ /** @var \wpdb $wpdb */
96
+ global $wpdb;
97
+ $wpdb->insert( $wpdb->actionscheduler_groups, [ 'slug' => $slug ] );
98
+
99
+ return (int) $wpdb->insert_id;
100
+ }
101
+
102
+ /**
103
+ * Retrieve an action.
104
+ *
105
+ * @param int $action_id Action ID.
106
+ *
107
+ * @return ActionScheduler_Action
108
+ */
109
+ public function fetch_action( $action_id ) {
110
+ /** @var \wpdb $wpdb */
111
+ global $wpdb;
112
+ $data = $wpdb->get_row( $wpdb->prepare(
113
+ "SELECT a.*, g.slug AS `group` FROM {$wpdb->actionscheduler_actions} a LEFT JOIN {$wpdb->actionscheduler_groups} g ON a.group_id=g.group_id WHERE a.action_id=%d",
114
+ $action_id
115
+ ) );
116
+
117
+ if ( empty( $data ) ) {
118
+ return $this->get_null_action();
119
+ }
120
+
121
+ try {
122
+ $action = $this->make_action_from_db_record( $data );
123
+ } catch ( ActionScheduler_InvalidActionException $exception ) {
124
+ do_action( 'action_scheduler_failed_fetch_action', $action_id, $exception );
125
+ return $this->get_null_action();
126
+ }
127
+
128
+ return $action;
129
+ }
130
+
131
+ /**
132
+ * Create a null action.
133
+ *
134
+ * @return ActionScheduler_NullAction
135
+ */
136
+ protected function get_null_action() {
137
+ return new ActionScheduler_NullAction();
138
+ }
139
+
140
+ /**
141
+ * Create an action from a database record.
142
+ *
143
+ * @param object $data Action database record.
144
+ *
145
+ * @return ActionScheduler_Action|ActionScheduler_CanceledAction|ActionScheduler_FinishedAction
146
+ */
147
+ protected function make_action_from_db_record( $data ) {
148
+
149
+ $hook = $data->hook;
150
+ $args = json_decode( $data->args, true );
151
+ $schedule = unserialize( $data->schedule );
152
+
153
+ $this->validate_args( $args, $data->action_id );
154
+ $this->validate_schedule( $schedule, $data->action_id );
155
+
156
+ if ( empty( $schedule ) ) {
157
+ $schedule = new ActionScheduler_NullSchedule();
158
+ }
159
+ $group = $data->group ? $data->group : '';
160
+
161
+ return ActionScheduler::factory()->get_stored_action( $data->status, $data->hook, $args, $schedule, $group );
162
+ }
163
+
164
+ /**
165
+ * Find an action.
166
+ *
167
+ * @param string $hook Action hook.
168
+ * @param array $params Parameters of the action to find.
169
+ *
170
+ * @return string|null ID of the next action matching the criteria or NULL if not found.
171
+ */
172
+ public function find_action( $hook, $params = [] ) {
173
+ $params = wp_parse_args( $params, [
174
+ 'args' => null,
175
+ 'status' => self::STATUS_PENDING,
176
+ 'group' => '',
177
+ ] );
178
+
179
+ /** @var wpdb $wpdb */
180
+ global $wpdb;
181
+ $query = "SELECT a.action_id FROM {$wpdb->actionscheduler_actions} a";
182
+ $args = [];
183
+ if ( ! empty( $params[ 'group' ] ) ) {
184
+ $query .= " INNER JOIN {$wpdb->actionscheduler_groups} g ON g.group_id=a.group_id AND g.slug=%s";
185
+ $args[] = $params[ 'group' ];
186
+ }
187
+ $query .= " WHERE a.hook=%s";
188
+ $args[] = $hook;
189
+ if ( ! is_null( $params[ 'args' ] ) ) {
190
+ $query .= " AND a.args=%s";
191
+ $args[] = json_encode( $params[ 'args' ] );
192
+ }
193
+
194
+ $order = 'ASC';
195
+ if ( ! empty( $params[ 'status' ] ) ) {
196
+ $query .= " AND a.status=%s";
197
+ $args[] = $params[ 'status' ];
198
+
199
+ if ( self::STATUS_PENDING == $params[ 'status' ] ) {
200
+ $order = 'ASC'; // Find the next action that matches.
201
+ } else {
202
+ $order = 'DESC'; // Find the most recent action that matches.
203
+ }
204
+ }
205
+
206
+ $query .= " ORDER BY scheduled_date_gmt $order LIMIT 1";
207
+
208
+ $query = $wpdb->prepare( $query, $args );
209
+
210
+ $id = $wpdb->get_var( $query );
211
+
212
+ return $id;
213
+ }
214
+
215
+ /**
216
+ * Returns the SQL statement to query (or count) actions.
217
+ *
218
+ * @param array $query Filtering options.
219
+ * @param string $select_or_count Whether the SQL should select and return the IDs or just the row count.
220
+ *
221
+ * @return string SQL statement already properly escaped.
222
+ */
223
+ protected function get_query_actions_sql( array $query, $select_or_count = 'select' ) {
224
+
225
+ if ( ! in_array( $select_or_count, array( 'select', 'count' ) ) ) {
226
+ throw new InvalidArgumentException( __( 'Invalid value for select or count parameter. Cannot query actions.', 'action-scheduler' ) );
227
+ }
228
+
229
+ $query = wp_parse_args( $query, [
230
+ 'hook' => '',
231
+ 'args' => null,
232
+ 'date' => null,
233
+ 'date_compare' => '<=',
234
+ 'modified' => null,
235
+ 'modified_compare' => '<=',
236
+ 'group' => '',
237
+ 'status' => '',
238
+ 'claimed' => null,
239
+ 'per_page' => 5,
240
+ 'offset' => 0,
241
+ 'orderby' => 'date',
242
+ 'order' => 'ASC',
243
+ ] );
244
+
245
+ /** @var \wpdb $wpdb */
246
+ global $wpdb;
247
+ $sql = ( 'count' === $select_or_count ) ? 'SELECT count(a.action_id)' : 'SELECT a.action_id';
248
+ $sql .= " FROM {$wpdb->actionscheduler_actions} a";
249
+ $sql_params = [];
250
+
251
+ if ( ! empty( $query[ 'group' ] ) || 'group' === $query[ 'orderby' ] ) {
252
+ $sql .= " LEFT JOIN {$wpdb->actionscheduler_groups} g ON g.group_id=a.group_id";
253
+ }
254
+
255
+ $sql .= " WHERE 1=1";
256
+
257
+ if ( ! empty( $query[ 'group' ] ) ) {
258
+ $sql .= " AND g.slug=%s";
259
+ $sql_params[] = $query[ 'group' ];
260
+ }
261
+
262
+ if ( $query[ 'hook' ] ) {
263
+ $sql .= " AND a.hook=%s";
264
+ $sql_params[] = $query[ 'hook' ];
265
+ }
266
+ if ( ! is_null( $query[ 'args' ] ) ) {
267
+ $sql .= " AND a.args=%s";
268
+ $sql_params[] = json_encode( $query[ 'args' ] );
269
+ }
270
+
271
+ if ( $query[ 'status' ] ) {
272
+ $sql .= " AND a.status=%s";
273
+ $sql_params[] = $query[ 'status' ];
274
+ }
275
+
276
+ if ( $query[ 'date' ] instanceof \DateTime ) {
277
+ $date = clone $query[ 'date' ];
278
+ $date->setTimezone( new \DateTimeZone( 'UTC' ) );
279
+ $date_string = $date->format( 'Y-m-d H:i:s' );
280
+ $comparator = $this->validate_sql_comparator( $query[ 'date_compare' ] );
281
+ $sql .= " AND a.scheduled_date_gmt $comparator %s";
282
+ $sql_params[] = $date_string;
283
+ }
284
+
285
+ if ( $query[ 'modified' ] instanceof \DateTime ) {
286
+ $modified = clone $query[ 'modified' ];
287
+ $modified->setTimezone( new \DateTimeZone( 'UTC' ) );
288
+ $date_string = $modified->format( 'Y-m-d H:i:s' );
289
+ $comparator = $this->validate_sql_comparator( $query[ 'modified_compare' ] );
290
+ $sql .= " AND a.last_attempt_gmt $comparator %s";
291
+ $sql_params[] = $date_string;
292
+ }
293
+
294
+ if ( $query[ 'claimed' ] === true ) {
295
+ $sql .= " AND a.claim_id != 0";
296
+ } elseif ( $query[ 'claimed' ] === false ) {
297
+ $sql .= " AND a.claim_id = 0";
298
+ } elseif ( ! is_null( $query[ 'claimed' ] ) ) {
299
+ $sql .= " AND a.claim_id = %d";
300
+ $sql_params[] = $query[ 'claimed' ];
301
+ }
302
+
303
+ if ( ! empty( $query['search'] ) ) {
304
+ $sql .= " AND (a.hook LIKE %s OR a.args LIKE %s";
305
+ for( $i = 0; $i < 2; $i++ ) {
306
+ $sql_params[] = sprintf( '%%%s%%', $query['search'] );
307
+ }
308
+
309
+ $search_claim_id = (int) $query['search'];
310
+ if ( $search_claim_id ) {
311
+ $sql .= ' OR a.claim_id = %d';
312
+ $sql_params[] = $search_claim_id;
313
+ }
314
+
315
+ $sql .= ')';
316
+ }
317
+
318
+ if ( 'select' === $select_or_count ) {
319
+ switch ( $query['orderby'] ) {
320
+ case 'hook':
321
+ $orderby = 'a.hook';
322
+ break;
323
+ case 'group':
324
+ $orderby = 'g.slug';
325
+ break;
326
+ case 'modified':
327
+ $orderby = 'a.last_attempt_gmt';
328
+ break;
329
+ case 'date':
330
+ default:
331
+ $orderby = 'a.scheduled_date_gmt';
332
+ break;
333
+ }
334
+ if ( strtoupper( $query[ 'order' ] ) == 'ASC' ) {
335
+ $order = 'ASC';
336
+ } else {
337
+ $order = 'DESC';
338
+ }
339
+ $sql .= " ORDER BY $orderby $order";
340
+ if ( $query[ 'per_page' ] > 0 ) {
341
+ $sql .= " LIMIT %d, %d";
342
+ $sql_params[] = $query[ 'offset' ];
343
+ $sql_params[] = $query[ 'per_page' ];
344
+ }
345
+ }
346
+
347
+ if ( ! empty( $sql_params ) ) {
348
+ $sql = $wpdb->prepare( $sql, $sql_params );
349
+ }
350
+
351
+ return $sql;
352
+ }
353
+
354
+ /**
355
+ * Query for action count of list of action IDs.
356
+ *
357
+ * @param array $query Query parameters.
358
+ * @param string $query_type Whether to select or count the results. Default, select.
359
+ *
360
+ * @return null|string|array The IDs of actions matching the query
361
+ */
362
+ public function query_actions( $query = [], $query_type = 'select' ) {
363
+ /** @var wpdb $wpdb */
364
+ global $wpdb;
365
+
366
+ $sql = $this->get_query_actions_sql( $query, $query_type );
367
+
368
+ return ( 'count' === $query_type ) ? $wpdb->get_var( $sql ) : $wpdb->get_col( $sql );
369
+ }
370
+
371
+ /**
372
+ * Get a count of all actions in the store, grouped by status.
373
+ *
374
+ * @return array Set of 'status' => int $count pairs for statuses with 1 or more actions of that status.
375
+ */
376
+ public function action_counts() {
377
+ global $wpdb;
378
+
379
+ $sql = "SELECT a.status, count(a.status) as 'count'";
380
+ $sql .= " FROM {$wpdb->actionscheduler_actions} a";
381
+ $sql .= " GROUP BY a.status";
382
+
383
+ $actions_count_by_status = array();
384
+ $action_stati_and_labels = $this->get_status_labels();
385
+
386
+ foreach ( $wpdb->get_results( $sql ) as $action_data ) {
387
+ // Ignore any actions with invalid status
388
+ if ( array_key_exists( $action_data->status, $action_stati_and_labels ) ) {
389
+ $actions_count_by_status[ $action_data->status ] = $action_data->count;
390
+ }
391
+ }
392
+
393
+ return $actions_count_by_status;
394
+ }
395
+
396
+ /**
397
+ * Cancel an action.
398
+ *
399
+ * @param int $action_id Action ID.
400
+ *
401
+ * @return void
402
+ */
403
+ public function cancel_action( $action_id ) {
404
+ /** @var \wpdb $wpdb */
405
+ global $wpdb;
406
+
407
+ $updated = $wpdb->update(
408
+ $wpdb->actionscheduler_actions,
409
+ [ 'status' => self::STATUS_CANCELED ],
410
+ [ 'action_id' => $action_id ],
411
+ [ '%s' ],
412
+ [ '%d' ]
413
+ );
414
+ if ( empty( $updated ) ) {
415
+ /* translators: %s: action ID */
416
+ throw new \InvalidArgumentException( sprintf( __( 'Unidentified action %s', 'action-scheduler' ), $action_id ) );
417
+ }
418
+ do_action( 'action_scheduler_canceled_action', $action_id );
419
+ }
420
+
421
+ /**
422
+ * Cancel pending actions by hook.
423
+ *
424
+ * @since 3.0.0
425
+ *
426
+ * @param string $hook Hook name.
427
+ *
428
+ * @return void
429
+ */
430
+ public function cancel_actions_by_hook( $hook ) {
431
+ $this->bulk_cancel_actions( [ 'hook' => $hook ] );
432
+ }
433
+
434
+ /**
435
+ * Cancel pending actions by group.
436
+ *
437
+ * @param string $group Group slug.
438
+ *
439
+ * @return void
440
+ */
441
+ public function cancel_actions_by_group( $group ) {
442
+ $this->bulk_cancel_actions( [ 'group' => $group ] );
443
+ }
444
+
445
+ /**
446
+ * Bulk cancel actions.
447
+ *
448
+ * @since 3.0.0
449
+ *
450
+ * @param array $query_args Query parameters.
451
+ */
452
+ protected function bulk_cancel_actions( $query_args ) {
453
+ /** @var \wpdb $wpdb */
454
+ global $wpdb;
455
+
456
+ if ( ! is_array( $query_args ) ) {
457
+ return;
458
+ }
459
+
460
+ // Don't cancel actions that are already canceled.
461
+ if ( isset( $query_args['status'] ) && $query_args['status'] == self::STATUS_CANCELED ) {
462
+ return;
463
+ }
464
+
465
+ $action_ids = true;
466
+ $query_args = wp_parse_args(
467
+ $query_args,
468
+ [
469
+ 'per_page' => 1000,
470
+ 'status' => self::STATUS_PENDING,
471
+ ]
472
+ );
473
+
474
+ while ( $action_ids ) {
475
+ $action_ids = $this->query_actions( $query_args );
476
+ if ( empty( $action_ids ) ) {
477
+ break;
478
+ }
479
+
480
+ $format = array_fill( 0, count( $action_ids ), '%d' );
481
+ $query_in = '(' . implode( ',', $format ) . ')';
482
+ $parameters = $action_ids;
483
+ array_unshift( $parameters, self::STATUS_CANCELED );
484
+
485
+ $wpdb->query(
486
+ $wpdb->prepare( // wpcs: PreparedSQLPlaceholders replacement count ok.
487
+ "UPDATE {$wpdb->actionscheduler_actions} SET status = %s WHERE action_id IN {$query_in}",
488
+ $parameters
489
+ )
490
+ );
491
+
492
+ do_action( 'action_scheduler_bulk_cancel_actions', $action_ids );
493
+ }
494
+ }
495
+
496
+ /**
497
+ * Delete an action.
498
+ *
499
+ * @param int $action_id Action ID.
500
+ */
501
+ public function delete_action( $action_id ) {
502
+ /** @var \wpdb $wpdb */
503
+ global $wpdb;
504
+ $deleted = $wpdb->delete( $wpdb->actionscheduler_actions, [ 'action_id' => $action_id ], [ '%d' ] );
505
+ if ( empty( $deleted ) ) {
506
+ throw new \InvalidArgumentException( sprintf( __( 'Unidentified action %s', 'action-scheduler' ), $action_id ) );
507
+ }
508
+ do_action( 'action_scheduler_deleted_action', $action_id );
509
+ }
510
+
511
+ /**
512
+ * Get the schedule date for an action.
513
+ *
514
+ * @param string $action_id Action ID.
515
+ *
516
+ * @throws \InvalidArgumentException
517
+ * @return \DateTime The local date the action is scheduled to run, or the date that it ran.
518
+ */
519
+ public function get_date( $action_id ) {
520
+ $date = $this->get_date_gmt( $action_id );
521
+ ActionScheduler_TimezoneHelper::set_local_timezone( $date );
522
+ return $date;
523
+ }
524
+
525
+ /**
526
+ * Get the GMT schedule date for an action.
527
+ *
528
+ * @param int $action_id Action ID.
529
+ *
530
+ * @throws \InvalidArgumentException
531
+ * @return \DateTime The GMT date the action is scheduled to run, or the date that it ran.
532
+ */
533
+ protected function get_date_gmt( $action_id ) {
534
+ /** @var \wpdb $wpdb */
535
+ global $wpdb;
536
+ $record = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$wpdb->actionscheduler_actions} WHERE action_id=%d", $action_id ) );
537
+ if ( empty( $record ) ) {
538
+ throw new \InvalidArgumentException( sprintf( __( 'Unidentified action %s', 'action-scheduler' ), $action_id ) );
539
+ }
540
+ if ( $record->status == self::STATUS_PENDING ) {
541
+ return as_get_datetime_object( $record->scheduled_date_gmt );
542
+ } else {
543
+ return as_get_datetime_object( $record->last_attempt_gmt );
544
+ }
545
+ }
546
+
547
+ /**
548
+ * Stake a claim on actions.
549
+ *
550
+ * @param int $max_actions Maximum number of action to include in claim.
551
+ * @param \DateTime $before_date Jobs must be schedule before this date. Defaults to now.
552
+ *
553
+ * @return ActionScheduler_ActionClaim
554
+ */
555
+ public function stake_claim( $max_actions = 10, \DateTime $before_date = null, $hooks = array(), $group = '' ) {
556
+ $claim_id = $this->generate_claim_id();
557
+ $this->claim_actions( $claim_id, $max_actions, $before_date, $hooks, $group );
558
+ $action_ids = $this->find_actions_by_claim_id( $claim_id );
559
+
560
+ return new ActionScheduler_ActionClaim( $claim_id, $action_ids );
561
+ }
562
+
563
+ /**
564
+ * Generate a new action claim.
565
+ *
566
+ * @return int Claim ID.
567
+ */
568
+ protected function generate_claim_id() {
569
+ /** @var \wpdb $wpdb */
570
+ global $wpdb;
571
+ $now = as_get_datetime_object();
572
+ $wpdb->insert( $wpdb->actionscheduler_claims, [ 'date_created_gmt' => $now->format( 'Y-m-d H:i:s' ) ] );
573
+
574
+ return $wpdb->insert_id;
575
+ }
576
+
577
+ /**
578
+ * Mark actions claimed.
579
+ *
580
+ * @param string $claim_id Claim Id.
581
+ * @param int $limit Number of action to include in claim.
582
+ * @param \DateTime $before_date Should use UTC timezone.
583
+ *
584
+ * @return int The number of actions that were claimed.
585
+ * @throws \RuntimeException
586
+ */
587
+ protected function claim_actions( $claim_id, $limit, \DateTime $before_date = null, $hooks = array(), $group = '' ) {
588
+ /** @var \wpdb $wpdb */
589
+ global $wpdb;
590
+
591
+ $now = as_get_datetime_object();
592
+ $date = is_null( $before_date ) ? $now : clone $before_date;
593
+
594
+ // can't use $wpdb->update() because of the <= condition
595
+ $update = "UPDATE {$wpdb->actionscheduler_actions} SET claim_id=%d, last_attempt_gmt=%s, last_attempt_local=%s";
596
+ $params = array(
597
+ $claim_id,
598
+ $now->format( 'Y-m-d H:i:s' ),
599
+ current_time( 'mysql' ),
600
+ );
601
+
602
+ $where = "WHERE claim_id = 0 AND scheduled_date_gmt <= %s AND status=%s";
603
+ $params[] = $date->format( 'Y-m-d H:i:s' );
604
+ $params[] = self::STATUS_PENDING;
605
+
606
+ if ( ! empty( $hooks ) ) {
607
+ $placeholders = array_fill( 0, count( $hooks ), '%s' );
608
+ $where .= ' AND hook IN (' . join( ', ', $placeholders ) . ')';
609
+ $params = array_merge( $params, array_values( $hooks ) );
610
+ }
611
+
612
+ if ( ! empty( $group ) ) {
613
+
614
+ $group_id = $this->get_group_id( $group, false );
615
+
616
+ // throw exception if no matching group found, this matches ActionScheduler_wpPostStore's behaviour
617
+ if ( empty( $group_id ) ) {
618
+ /* translators: %s: group name */
619
+ throw new InvalidArgumentException( sprintf( __( 'The group "%s" does not exist.', 'action-scheduler' ), $group ) );
620
+ }
621
+
622
+ $where .= ' AND group_id = %d';
623
+ $params[] = $group_id;
624
+ }
625
+
626
+ $order = "ORDER BY attempts ASC, scheduled_date_gmt ASC, action_id ASC LIMIT %d";
627
+ $params[] = $limit;
628
+
629
+ $sql = $wpdb->prepare( "{$update} {$where} {$order}", $params );
630
+
631
+ $rows_affected = $wpdb->query( $sql );
632
+ if ( $rows_affected === false ) {
633
+ throw new \RuntimeException( __( 'Unable to claim actions. Database error.', 'action-scheduler' ) );
634
+ }
635
+
636
+ return (int) $rows_affected;
637
+ }
638
+
639
+ /**
640
+ * Get the number of active claims.
641
+ *
642
+ * @return int
643
+ */
644
+ public function get_claim_count() {
645
+ global $wpdb;
646
+
647
+ $sql = "SELECT COUNT(DISTINCT claim_id) FROM {$wpdb->actionscheduler_actions} WHERE claim_id != 0 AND status IN ( %s, %s)";
648
+ $sql = $wpdb->prepare( $sql, [ self::STATUS_PENDING, self::STATUS_RUNNING ] );
649
+
650
+ return (int) $wpdb->get_var( $sql );
651
+ }
652
+
653
+ /**
654
+ * Return an action's claim ID, as stored in the claim_id column.
655
+ *
656
+ * @param string $action_id Action ID.
657
+ * @return mixed
658
+ */
659
+ public function get_claim_id( $action_id ) {
660
+ /** @var \wpdb $wpdb */
661
+ global $wpdb;
662
+
663
+ $sql = "SELECT claim_id FROM {$wpdb->actionscheduler_actions} WHERE action_id=%d";
664
+ $sql = $wpdb->prepare( $sql, $action_id );
665
+
666
+ return (int) $wpdb->get_var( $sql );
667
+ }
668
+
669
+ /**
670
+ * Retrieve the action IDs of action in a claim.
671
+ *
672
+ * @param string $claim_id Claim ID.
673
+ *
674
+ * @return int[]
675
+ */
676
+ public function find_actions_by_claim_id( $claim_id ) {
677
+ /** @var \wpdb $wpdb */
678
+ global $wpdb;
679
+
680
+ $sql = "SELECT action_id FROM {$wpdb->actionscheduler_actions} WHERE claim_id=%d";
681
+ $sql = $wpdb->prepare( $sql, $claim_id );
682
+
683
+ $action_ids = $wpdb->get_col( $sql );
684
+
685
+ return array_map( 'intval', $action_ids );
686
+ }
687
+
688
+ /**
689
+ * Release actions from a claim and delete the claim.
690
+ *
691
+ * @param ActionScheduler_ActionClaim $claim Claim object.
692
+ */
693
+ public function release_claim( ActionScheduler_ActionClaim $claim ) {
694
+ /** @var \wpdb $wpdb */
695
+ global $wpdb;
696
+ $wpdb->update( $wpdb->actionscheduler_actions, [ 'claim_id' => 0 ], [ 'claim_id' => $claim->get_id() ], [ '%d' ], [ '%d' ] );
697
+ $wpdb->delete( $wpdb->actionscheduler_claims, [ 'claim_id' => $claim->get_id() ], [ '%d' ] );
698
+ }
699
+
700
+ /**
701
+ * Remove the claim from an action.
702
+ *
703
+ * @param int $action_id Action ID.
704
+ *
705
+ * @return void
706
+ */
707
+ public function unclaim_action( $action_id ) {
708
+ /** @var \wpdb $wpdb */
709
+ global $wpdb;
710
+ $wpdb->update(
711
+ $wpdb->actionscheduler_actions,
712
+ [ 'claim_id' => 0 ],
713
+ [ 'action_id' => $action_id ],
714
+ [ '%s' ],
715
+ [ '%d' ]
716
+ );
717
+ }
718
+
719
+ /**
720
+ * Mark an action as failed.
721
+ *
722
+ * @param int $action_id Action ID.
723
+ */
724
+ public function mark_failure( $action_id ) {
725
+ /** @var \wpdb $wpdb */
726
+ global $wpdb;
727
+ $updated = $wpdb->update(
728
+ $wpdb->actionscheduler_actions,
729
+ [ 'status' => self::STATUS_FAILED ],
730
+ [ 'action_id' => $action_id ],
731
+ [ '%s' ],
732
+ [ '%d' ]
733
+ );
734
+ if ( empty( $updated ) ) {
735
+ throw new \InvalidArgumentException( sprintf( __( 'Unidentified action %s', 'action-scheduler' ), $action_id ) );
736
+ }
737
+ }
738
+
739
+ /**
740
+ * Add execution message to action log.
741
+ *
742
+ * @param int $action_id Action ID.
743
+ *
744
+ * @return void
745
+ */
746
+ public function log_execution( $action_id ) {
747
+ /** @var \wpdb $wpdb */
748
+ global $wpdb;
749
+
750
+ $sql = "UPDATE {$wpdb->actionscheduler_actions} SET attempts = attempts+1, status=%s, last_attempt_gmt = %s, last_attempt_local = %s WHERE action_id = %d";
751
+ $sql = $wpdb->prepare( $sql, self::STATUS_RUNNING, current_time( 'mysql', true ), current_time( 'mysql' ), $action_id );
752
+ $wpdb->query( $sql );
753
+ }
754
+
755
+ /**
756
+ * Mark an action as complete.
757
+ *
758
+ * @param int $action_id Action ID.
759
+ *
760
+ * @return void
761
+ */
762
+ public function mark_complete( $action_id ) {
763
+ /** @var \wpdb $wpdb */
764
+ global $wpdb;
765
+ $updated = $wpdb->update(
766
+ $wpdb->actionscheduler_actions,
767
+ [
768
+ 'status' => self::STATUS_COMPLETE,
769
+ 'last_attempt_gmt' => current_time( 'mysql', true ),
770
+ 'last_attempt_local' => current_time( 'mysql' ),
771
+ ],
772
+ [ 'action_id' => $action_id ],
773
+ [ '%s' ],
774
+ [ '%d' ]
775
+ );
776
+ if ( empty( $updated ) ) {
777
+ throw new \InvalidArgumentException( sprintf( __( 'Unidentified action %s', 'action-scheduler' ), $action_id ) );
778
+ }
779
+ }
780
+
781
+ /**
782
+ * Get an action's status.
783
+ *
784
+ * @param int $action_id Action ID.
785
+ *
786
+ * @return string
787
+ */
788
+ public function get_status( $action_id ) {
789
+ /** @var \wpdb $wpdb */
790
+ global $wpdb;
791
+ $sql = "SELECT status FROM {$wpdb->actionscheduler_actions} WHERE action_id=%d";
792
+ $sql = $wpdb->prepare( $sql, $action_id );
793
+ $status = $wpdb->get_var( $sql );
794
+
795
+ if ( $status === null ) {
796
+ throw new \InvalidArgumentException( __( 'Invalid action ID. No status found.', 'action-scheduler' ) );
797
+ } elseif ( empty( $status ) ) {
798
+ throw new \RuntimeException( __( 'Unknown status found for action.', 'action-scheduler' ) );
799
+ } else {
800
+ return $status;
801
+ }
802
+ }
803
+ }
includes/vendor/action-scheduler/classes/data-stores/ActionScheduler_HybridStore.php ADDED
@@ -0,0 +1,380 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ use ActionScheduler_Store as Store;
4
+ use Action_Scheduler\Migration\Runner;
5
+ use Action_Scheduler\Migration\Config;
6
+ use Action_Scheduler\Migration\Controller;
7
+
8
+ /**
9
+ * Class ActionScheduler_HybridStore
10
+ *
11
+ * A wrapper around multiple stores that fetches data from both.
12
+ *
13
+ * @since 3.0.0
14
+ */
15
+ class ActionScheduler_HybridStore extends Store {
16
+ const DEMARKATION_OPTION = 'action_scheduler_hybrid_store_demarkation';
17
+
18
+ private $primary_store;
19
+ private $secondary_store;
20
+ private $migration_runner;
21
+
22
+ /**
23
+ * @var int The dividing line between IDs of actions created
24
+ * by the primary and secondary stores.
25
+ *
26
+ * Methods that accept an action ID will compare the ID against
27
+ * this to determine which store will contain that ID. In almost
28
+ * all cases, the ID should come from the primary store, but if
29
+ * client code is bypassing the API functions and fetching IDs
30
+ * from elsewhere, then there is a chance that an unmigrated ID
31
+ * might be requested.
32
+ */
33
+ private $demarkation_id = 0;
34
+
35
+ /**
36
+ * ActionScheduler_HybridStore constructor.
37
+ *
38
+ * @param Config $config Migration config object.
39
+ */
40
+ public function __construct( Config $config = null ) {
41
+ $this->demarkation_id = (int) get_option( self::DEMARKATION_OPTION, 0 );
42
+ if ( empty( $config ) ) {
43
+ $config = Controller::instance()->get_migration_config_object();
44
+ }
45
+ $this->primary_store = $config->get_destination_store();
46
+ $this->secondary_store = $config->get_source_store();
47
+ $this->migration_runner = new Runner( $config );
48
+ }
49
+
50
+ /**
51
+ * Initialize the table data store tables.
52
+ *
53
+ * @codeCoverageIgnore
54
+ */
55
+ public function init() {
56
+ add_action( 'action_scheduler/created_table', [ $this, 'set_autoincrement' ], 10, 2 );
57
+ $this->primary_store->init();
58
+ $this->secondary_store->init();
59
+ remove_action( 'action_scheduler/created_table', [ $this, 'set_autoincrement' ], 10 );
60
+ }
61
+
62
+ /**
63
+ * When the actions table is created, set its autoincrement
64
+ * value to be one higher than the posts table to ensure that
65
+ * there are no ID collisions.
66
+ *
67
+ * @param string $table_name
68
+ * @param string $table_suffix
69
+ *
70
+ * @return void
71
+ * @codeCoverageIgnore
72
+ */
73
+ public function set_autoincrement( $table_name, $table_suffix ) {
74
+ if ( ActionScheduler_StoreSchema::ACTIONS_TABLE === $table_suffix ) {
75
+ if ( empty( $this->demarkation_id ) ) {
76
+ $this->demarkation_id = $this->set_demarkation_id();
77
+ }
78
+ /** @var \wpdb $wpdb */
79
+ global $wpdb;
80
+ $wpdb->insert(
81
+ $wpdb->{ActionScheduler_StoreSchema::ACTIONS_TABLE},
82
+ [
83
+ 'action_id' => $this->demarkation_id,
84
+ 'hook' => '',
85
+ 'status' => '',
86
+ ]
87
+ );
88
+ $wpdb->delete(
89
+ $wpdb->{ActionScheduler_StoreSchema::ACTIONS_TABLE},
90
+ [ 'action_id' => $this->demarkation_id ]
91
+ );
92
+ }
93
+ }
94
+
95
+ /**
96
+ * Store the demarkation id in WP options.
97
+ *
98
+ * @param int $id The ID to set as the demarkation point between the two stores
99
+ * Leave null to use the next ID from the WP posts table.
100
+ *
101
+ * @return int The new ID.
102
+ *
103
+ * @codeCoverageIgnore
104
+ */
105
+ private function set_demarkation_id( $id = null ) {
106
+ if ( empty( $id ) ) {
107
+ /** @var \wpdb $wpdb */
108
+ global $wpdb;
109
+ $id = (int) $wpdb->get_var( "SELECT MAX(ID) FROM $wpdb->posts" );
110
+ $id ++;
111
+ }
112
+ update_option( self::DEMARKATION_OPTION, $id );
113
+
114
+ return $id;
115
+ }
116
+
117
+ /**
118
+ * Find the first matching action from the secondary store.
119
+ * If it exists, migrate it to the primary store immediately.
120
+ * After it migrates, the secondary store will logically contain
121
+ * the next matching action, so return the result thence.
122
+ *
123
+ * @param string $hook
124
+ * @param array $params
125
+ *
126
+ * @return string
127
+ */
128
+ public function find_action( $hook, $params = [] ) {
129
+ $found_unmigrated_action = $this->secondary_store->find_action( $hook, $params );
130
+ if ( ! empty( $found_unmigrated_action ) ) {
131
+ $this->migrate( [ $found_unmigrated_action ] );
132
+ }
133
+
134
+ return $this->primary_store->find_action( $hook, $params );
135
+ }
136
+
137
+ /**
138
+ * Find actions matching the query in the secondary source first.
139
+ * If any are found, migrate them immediately. Then the secondary
140
+ * store will contain the canonical results.
141
+ *
142
+ * @param array $query
143
+ * @param string $query_type Whether to select or count the results. Default, select.
144
+ *
145
+ * @return int[]
146
+ */
147
+ public function query_actions( $query = [], $query_type = 'select' ) {
148
+ $found_unmigrated_actions = $this->secondary_store->query_actions( $query, 'select' );
149
+ if ( ! empty( $found_unmigrated_actions ) ) {
150
+ $this->migrate( $found_unmigrated_actions );
151
+ }
152
+
153
+ return $this->primary_store->query_actions( $query, $query_type );
154
+ }
155
+
156
+ /**
157
+ * Get a count of all actions in the store, grouped by status
158
+ *
159
+ * @return array Set of 'status' => int $count pairs for statuses with 1 or more actions of that status.
160
+ */
161
+ public function action_counts() {
162
+ $unmigrated_actions_count = $this->secondary_store->action_counts();
163
+ $migrated_actions_count = $this->primary_store->action_counts();
164
+ $actions_count_by_status = array();
165
+
166
+ foreach ( $this->get_status_labels() as $status_key => $status_label ) {
167
+
168
+ $count = 0;
169
+
170
+ if ( isset( $unmigrated_actions_count[ $status_key ] ) ) {
171
+ $count += $unmigrated_actions_count[ $status_key ];
172
+ }
173
+
174
+ if ( isset( $migrated_actions_count[ $status_key ] ) ) {
175
+ $count += $migrated_actions_count[ $status_key ];
176
+ }
177
+
178
+ $actions_count_by_status[ $status_key ] = $count;
179
+ }
180
+
181
+ $actions_count_by_status = array_filter( $actions_count_by_status );
182
+
183
+ return $actions_count_by_status;
184
+ }
185
+
186
+ /**
187
+ * If any actions would have been claimed by the secondary store,
188
+ * migrate them immediately, then ask the primary store for the
189
+ * canonical claim.
190
+ *
191
+ * @param int $max_actions
192
+ * @param DateTime|null $before_date
193
+ *
194
+ * @return ActionScheduler_ActionClaim
195
+ */
196
+ public function stake_claim( $max_actions = 10, DateTime $before_date = null, $hooks = array(), $group = '' ) {
197
+ $claim = $this->secondary_store->stake_claim( $max_actions, $before_date, $hooks, $group );
198
+
199
+ $claimed_actions = $claim->get_actions();
200
+ if ( ! empty( $claimed_actions ) ) {
201
+ $this->migrate( $claimed_actions );
202
+ }
203
+
204
+ $this->secondary_store->release_claim( $claim );
205
+
206
+ return $this->primary_store->stake_claim( $max_actions, $before_date, $hooks, $group );
207
+ }
208
+
209
+ /**
210
+ * Migrate a list of actions to the table data store.
211
+ *
212
+ * @param array $action_ids List of action IDs.
213
+ */
214
+ private function migrate( $action_ids ) {
215
+ $this->migration_runner->migrate_actions( $action_ids );
216
+ }
217
+
218
+ /**
219
+ * Save an action to the primary store.
220
+ *
221
+ * @param ActionScheduler_Action $action Action object to be saved.
222
+ * @param DateTime $date Optional. Schedule date. Default null.
223
+ */
224
+ public function save_action( ActionScheduler_Action $action, DateTime $date = null ) {
225
+ return $this->primary_store->save_action( $action, $date );
226
+ }
227
+
228
+ /**
229
+ * Retrieve an existing action whether migrated or not.
230
+ *
231
+ * @param int $action_id Action ID.
232
+ */
233
+ public function fetch_action( $action_id ) {
234
+ if ( $action_id < $this->demarkation_id ) {
235
+ return $this->secondary_store->fetch_action( $action_id );
236
+ } else {
237
+ return $this->primary_store->fetch_action( $action_id );
238
+ }
239
+ }
240
+
241
+ /**
242
+ * Cancel an existing action whether migrated or not.
243
+ *
244
+ * @param int $action_id Action ID.
245
+ */
246
+ public function cancel_action( $action_id ) {
247
+ if ( $action_id < $this->demarkation_id ) {
248
+ $this->secondary_store->cancel_action( $action_id );
249
+ } else {
250
+ $this->primary_store->cancel_action( $action_id );
251
+ }
252
+ }
253
+
254
+ /**
255
+ * Delete an existing action whether migrated or not.
256
+ *
257
+ * @param int $action_id Action ID.
258
+ */
259
+ public function delete_action( $action_id ) {
260
+ if ( $action_id < $this->demarkation_id ) {
261
+ $this->secondary_store->delete_action( $action_id );
262
+ } else {
263
+ $this->primary_store->delete_action( $action_id );
264
+ }
265
+ }
266
+
267
+ /**
268
+ * Get the schedule date an existing action whether migrated or not.
269
+ *
270
+ * @param int $action_id Action ID.
271
+ */
272
+ public function get_date( $action_id ) {
273
+ if ( $action_id < $this->demarkation_id ) {
274
+ return $this->secondary_store->get_date( $action_id );
275
+ } else {
276
+ return $this->primary_store->get_date( $action_id );
277
+ }
278
+ }
279
+
280
+ /**
281
+ * Mark an existing action as failed whether migrated or not.
282
+ *
283
+ * @param int $action_id Action ID.
284
+ */
285
+ public function mark_failure( $action_id ) {
286
+ if ( $action_id < $this->demarkation_id ) {
287
+ $this->secondary_store->mark_failure( $action_id );
288
+ } else {
289
+ $this->primary_store->mark_failure( $action_id );
290
+ }
291
+ }
292
+
293
+ /**
294
+ * Log the execution of an existing action whether migrated or not.
295
+ *
296
+ * @param int $action_id Action ID.
297
+ */
298
+ public function log_execution( $action_id ) {
299
+ if ( $action_id < $this->demarkation_id ) {
300
+ $this->secondary_store->log_execution( $action_id );
301
+ } else {
302
+ $this->primary_store->log_execution( $action_id );
303
+ }
304
+ }
305
+
306
+ /**
307
+ * Mark an existing action complete whether migrated or not.
308
+ *
309
+ * @param int $action_id Action ID.
310
+ */
311
+ public function mark_complete( $action_id ) {
312
+ if ( $action_id < $this->demarkation_id ) {
313
+ $this->secondary_store->mark_complete( $action_id );
314
+ } else {
315
+ $this->primary_store->mark_complete( $action_id );
316
+ }
317
+ }
318
+
319
+ /**
320
+ * Get an existing action status whether migrated or not.
321
+ *
322
+ * @param int $action_id Action ID.
323
+ */
324
+ public function get_status( $action_id ) {
325
+ if ( $action_id < $this->demarkation_id ) {
326
+ return $this->secondary_store->get_status( $action_id );
327
+ } else {
328
+ return $this->primary_store->get_status( $action_id );
329
+ }
330
+ }
331
+
332
+
333
+ /* * * * * * * * * * * * * * * * * * * * * * * * * * *
334
+ * All claim-related functions should operate solely
335
+ * on the primary store.
336
+ * * * * * * * * * * * * * * * * * * * * * * * * * * */
337
+
338
+ /**
339
+ * Get the claim count from the table data store.
340
+ */
341
+ public function get_claim_count() {
342
+ return $this->primary_store->get_claim_count();
343
+ }
344
+
345
+ /**
346
+ * Retrieve the claim ID for an action from the table data store.
347
+ *
348
+ * @param int $action_id Action ID.
349
+ */
350
+ public function get_claim_id( $action_id ) {
351
+ return $this->primary_store->get_claim_id( $action_id );
352
+ }
353
+
354
+ /**
355
+ * Release a claim in the table data store.
356
+ *
357
+ * @param ActionScheduler_ActionClaim $claim Claim object.
358
+ */
359
+ public function release_claim( ActionScheduler_ActionClaim $claim ) {
360
+ $this->primary_store->release_claim( $claim );
361
+ }
362
+
363
+ /**
364
+ * Release claims on an action in the table data store.
365
+ *
366
+ * @param int $action_id Action ID.
367
+ */
368
+ public function unclaim_action( $action_id ) {
369
+ $this->primary_store->unclaim_action( $action_id );
370
+ }
371
+
372
+ /**
373
+ * Retrieve a list of action IDs by claim.
374
+ *
375
+ * @param int $claim_id Claim ID.
376
+ */
377
+ public function find_actions_by_claim_id( $claim_id ) {
378
+ return $this->primary_store->find_actions_by_claim_id( $claim_id );
379
+ }
380
+ }
includes/vendor/action-scheduler/classes/{ActionScheduler_wpCommentLogger.php → data-stores/ActionScheduler_wpCommentLogger.php} RENAMED
File without changes
includes/vendor/action-scheduler/classes/{ActionScheduler_wpPostStore.php → data-stores/ActionScheduler_wpPostStore.php} RENAMED
@@ -7,25 +7,17 @@ class ActionScheduler_wpPostStore extends ActionScheduler_Store {
7
  const POST_TYPE = 'scheduled-action';
8
  const GROUP_TAXONOMY = 'action-group';
9
  const SCHEDULE_META_KEY = '_action_manager_schedule';
 
10
 
11
  /** @var DateTimeZone */
12
  protected $local_timezone = NULL;
13
 
14
- /** @var int */
15
- private static $max_index_length = 191;
16
-
17
  public function save_action( ActionScheduler_Action $action, DateTime $scheduled_date = NULL ){
18
  try {
19
  $this->validate_action( $action );
20
  $post_array = $this->create_post_array( $action, $scheduled_date );
21
  $post_id = $this->save_post_array( $post_array );
22
- $schedule = $action->get_schedule();
23
-
24
- if ( ! is_null( $scheduled_date ) && $schedule->is_recurring() ) {
25
- $schedule = new ActionScheduler_IntervalSchedule( $scheduled_date, $schedule->interval_in_seconds() );
26
- }
27
-
28
- $this->save_post_schedule( $post_id, $schedule );
29
  $this->save_action_group( $post_id, $action->get_group() );
30
  do_action( 'action_scheduler_stored_action', $post_id );
31
  return $post_id;
@@ -49,7 +41,20 @@ class ActionScheduler_wpPostStore extends ActionScheduler_Store {
49
  protected function save_post_array( $post_array ) {
50
  add_filter( 'wp_insert_post_data', array( $this, 'filter_insert_post_data' ), 10, 1 );
51
  add_filter( 'pre_wp_unique_post_slug', array( $this, 'set_unique_post_slug' ), 10, 5 );
 
 
 
 
 
 
 
 
52
  $post_id = wp_insert_post($post_array);
 
 
 
 
 
53
  remove_filter( 'wp_insert_post_data', array( $this, 'filter_insert_post_data' ), 10 );
54
  remove_filter( 'pre_wp_unique_post_slug', array( $this, 'set_unique_post_slug' ), 10 );
55
 
@@ -87,7 +92,7 @@ class ActionScheduler_wpPostStore extends ActionScheduler_Store {
87
  * action's slug, being probably unique is good enough.
88
  *
89
  * For more backstory on this issue, see:
90
- * - https://github.com/Prospress/action-scheduler/issues/44 and
91
  * - https://core.trac.wordpress.org/ticket/21112
92
  *
93
  * @param string $override_slug Short-circuit return value.
@@ -121,7 +126,15 @@ class ActionScheduler_wpPostStore extends ActionScheduler_Store {
121
  if ( empty($post) || $post->post_type != self::POST_TYPE ) {
122
  return $this->get_null_action();
123
  }
124
- return $this->make_action_from_post($post);
 
 
 
 
 
 
 
 
125
  }
126
 
127
  protected function get_post( $action_id ) {
@@ -138,19 +151,11 @@ class ActionScheduler_wpPostStore extends ActionScheduler_Store {
138
  protected function make_action_from_post( $post ) {
139
  $hook = $post->post_title;
140
 
141
- try {
142
- $args = json_decode( $post->post_content, true );
143
- $this->validate_args( $args, $post->ID );
144
 
145
- $schedule = get_post_meta( $post->ID, self::SCHEDULE_META_KEY, true );
146
- if ( empty( $schedule ) || ! is_a( $schedule, 'ActionScheduler_Schedule' ) ) {
147
- throw ActionScheduler_InvalidActionException::from_decoding_args( $post->ID );
148
- }
149
- } catch ( ActionScheduler_InvalidActionException $exception ) {
150
- $schedule = new ActionScheduler_NullSchedule();
151
- $args = array();
152
- do_action( 'action_scheduler_failed_fetch_action', $post->ID );
153
- }
154
 
155
  $group = wp_get_object_terms( $post->ID, self::GROUP_TAXONOMY, array('fields' => 'names') );
156
  $group = empty( $group ) ? '' : reset($group);
@@ -300,15 +305,16 @@ class ActionScheduler_wpPostStore extends ActionScheduler_Store {
300
  $sql = ( 'count' === $select_or_count ) ? 'SELECT count(p.ID)' : 'SELECT p.ID ';
301
  $sql .= "FROM {$wpdb->posts} p";
302
  $sql_params = array();
303
- if ( ! empty( $query['group'] ) || 'group' === $query['orderby'] ) {
 
 
 
 
304
  $sql .= " INNER JOIN {$wpdb->term_relationships} tr ON tr.object_id=p.ID";
305
  $sql .= " INNER JOIN {$wpdb->term_taxonomy} tt ON tr.term_taxonomy_id=tt.term_taxonomy_id";
306
  $sql .= " INNER JOIN {$wpdb->terms} t ON tt.term_id=t.term_id";
307
-
308
- if ( ! empty( $query['group'] ) ) {
309
- $sql .= " AND t.slug=%s";
310
- $sql_params[] = $query['group'];
311
- }
312
  }
313
  $sql .= " WHERE post_type=%s";
314
  $sql_params[] = self::POST_TYPE;
@@ -462,7 +468,8 @@ class ActionScheduler_wpPostStore extends ActionScheduler_Store {
462
  throw new InvalidArgumentException(sprintf(__('Unidentified action %s', 'action-scheduler'), $action_id));
463
  }
464
  do_action( 'action_scheduler_deleted_action', $action_id );
465
- wp_delete_post($action_id, TRUE);
 
466
  }
467
 
468
  /**
@@ -678,6 +685,7 @@ class ActionScheduler_wpPostStore extends ActionScheduler_Store {
678
  $sql = $wpdb->prepare( $sql, array( $claim->get_id() ) );
679
  $result = $wpdb->query($sql);
680
  if ( $result === false ) {
 
681
  throw new RuntimeException( sprintf( __('Unable to unlock claim %s. Database error.', 'action-scheduler'), $claim->get_id() ) );
682
  }
683
  }
@@ -692,6 +700,7 @@ class ActionScheduler_wpPostStore extends ActionScheduler_Store {
692
  $sql = $wpdb->prepare( $sql, $action_id, self::POST_TYPE );
693
  $result = $wpdb->query($sql);
694
  if ( $result === false ) {
 
695
  throw new RuntimeException( sprintf( __('Unable to unlock claim on action %s. Database error.', 'action-scheduler'), $action_id ) );
696
  }
697
  }
@@ -703,6 +712,7 @@ class ActionScheduler_wpPostStore extends ActionScheduler_Store {
703
  $sql = $wpdb->prepare( $sql, self::STATUS_FAILED, $action_id, self::POST_TYPE );
704
  $result = $wpdb->query($sql);
705
  if ( $result === false ) {
 
706
  throw new RuntimeException( sprintf( __('Unable to mark failure on action %s. Database error.', 'action-scheduler'), $action_id ) );
707
  }
708
  }
@@ -751,7 +761,12 @@ class ActionScheduler_wpPostStore extends ActionScheduler_Store {
751
  $wpdb->query($sql);
752
  }
753
 
754
-
 
 
 
 
 
755
  public function mark_complete( $action_id ) {
756
  $post = get_post($action_id);
757
  if ( empty($post) || ($post->post_type != self::POST_TYPE) ) {
@@ -770,6 +785,43 @@ class ActionScheduler_wpPostStore extends ActionScheduler_Store {
770
  }
771
  }
772
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
773
  /**
774
  * InnoDB indexes have a maximum size of 767 bytes by default, which is only 191 characters with utf8mb4.
775
  *
@@ -780,8 +832,11 @@ class ActionScheduler_wpPostStore extends ActionScheduler_Store {
780
  * @param ActionScheduler_Action $action
781
  */
782
  protected function validate_action( ActionScheduler_Action $action ) {
783
- if ( strlen( json_encode( $action->get_args() ) ) > self::$max_index_length ) {
784
- _doing_it_wrong( 'ActionScheduler_Action::$args', sprintf( 'To ensure the action args column can be indexed, action args should not be more than %d characters when encoded as JSON. Support for strings longer than this will be removed in a future version.', self::$max_index_length ), '2.1.0' );
 
 
 
785
  }
786
  }
787
 
@@ -789,6 +844,8 @@ class ActionScheduler_wpPostStore extends ActionScheduler_Store {
789
  * @codeCoverageIgnore
790
  */
791
  public function init() {
 
 
792
  $post_type_registrar = new ActionScheduler_wpPostStore_PostTypeRegistrar();
793
  $post_type_registrar->register();
794
 
@@ -798,24 +855,4 @@ class ActionScheduler_wpPostStore extends ActionScheduler_Store {
798
  $taxonomy_registrar = new ActionScheduler_wpPostStore_TaxonomyRegistrar();
799
  $taxonomy_registrar->register();
800
  }
801
-
802
- /**
803
- * Validate that we could decode action arguments.
804
- *
805
- * @param mixed $args The decoded arguments.
806
- * @param int $action_id The action ID.
807
- *
808
- * @throws ActionScheduler_InvalidActionException When the decoded arguments are invalid.
809
- */
810
- private function validate_args( $args, $action_id ) {
811
- // Ensure we have an array of args.
812
- if ( ! is_array( $args ) ) {
813
- throw ActionScheduler_InvalidActionException::from_decoding_args( $action_id );
814
- }
815
-
816
- // Validate JSON decoding if possible.
817
- if ( function_exists( 'json_last_error' ) && JSON_ERROR_NONE !== json_last_error() ) {
818
- throw ActionScheduler_InvalidActionException::from_decoding_args( $action_id );
819
- }
820
- }
821
  }
7
  const POST_TYPE = 'scheduled-action';
8
  const GROUP_TAXONOMY = 'action-group';
9
  const SCHEDULE_META_KEY = '_action_manager_schedule';
10
+ const DEPENDENCIES_MET = 'as-post-store-dependencies-met';
11
 
12
  /** @var DateTimeZone */
13
  protected $local_timezone = NULL;
14
 
 
 
 
15
  public function save_action( ActionScheduler_Action $action, DateTime $scheduled_date = NULL ){
16
  try {
17
  $this->validate_action( $action );
18
  $post_array = $this->create_post_array( $action, $scheduled_date );
19
  $post_id = $this->save_post_array( $post_array );
20
+ $this->save_post_schedule( $post_id, $action->get_schedule() );
 
 
 
 
 
 
21
  $this->save_action_group( $post_id, $action->get_group() );
22
  do_action( 'action_scheduler_stored_action', $post_id );
23
  return $post_id;
41
  protected function save_post_array( $post_array ) {
42
  add_filter( 'wp_insert_post_data', array( $this, 'filter_insert_post_data' ), 10, 1 );
43
  add_filter( 'pre_wp_unique_post_slug', array( $this, 'set_unique_post_slug' ), 10, 5 );
44
+
45
+ $has_kses = false !== has_filter( 'content_save_pre', 'wp_filter_post_kses' );
46
+
47
+ if ( $has_kses ) {
48
+ // Prevent KSES from corrupting JSON in post_content.
49
+ kses_remove_filters();
50
+ }
51
+
52
  $post_id = wp_insert_post($post_array);
53
+
54
+ if ( $has_kses ) {
55
+ kses_init_filters();
56
+ }
57
+
58
  remove_filter( 'wp_insert_post_data', array( $this, 'filter_insert_post_data' ), 10 );
59
  remove_filter( 'pre_wp_unique_post_slug', array( $this, 'set_unique_post_slug' ), 10 );
60
 
92
  * action's slug, being probably unique is good enough.
93
  *
94
  * For more backstory on this issue, see:
95
+ * - https://github.com/woocommerce/action-scheduler/issues/44 and
96
  * - https://core.trac.wordpress.org/ticket/21112
97
  *
98
  * @param string $override_slug Short-circuit return value.
126
  if ( empty($post) || $post->post_type != self::POST_TYPE ) {
127
  return $this->get_null_action();
128
  }
129
+
130
+ try {
131
+ $action = $this->make_action_from_post( $post );
132
+ } catch ( ActionScheduler_InvalidActionException $exception ) {
133
+ do_action( 'action_scheduler_failed_fetch_action', $post->ID, $exception );
134
+ return $this->get_null_action();
135
+ }
136
+
137
+ return $action;
138
  }
139
 
140
  protected function get_post( $action_id ) {
151
  protected function make_action_from_post( $post ) {
152
  $hook = $post->post_title;
153
 
154
+ $args = json_decode( $post->post_content, true );
155
+ $this->validate_args( $args, $post->ID );
 
156
 
157
+ $schedule = get_post_meta( $post->ID, self::SCHEDULE_META_KEY, true );
158
+ $this->validate_schedule( $schedule, $post->ID );
 
 
 
 
 
 
 
159
 
160
  $group = wp_get_object_terms( $post->ID, self::GROUP_TAXONOMY, array('fields' => 'names') );
161
  $group = empty( $group ) ? '' : reset($group);
305
  $sql = ( 'count' === $select_or_count ) ? 'SELECT count(p.ID)' : 'SELECT p.ID ';
306
  $sql .= "FROM {$wpdb->posts} p";
307
  $sql_params = array();
308
+ if ( empty( $query['group'] ) && 'group' === $query['orderby'] ) {
309
+ $sql .= " LEFT JOIN {$wpdb->term_relationships} tr ON tr.object_id=p.ID";
310
+ $sql .= " LEFT JOIN {$wpdb->term_taxonomy} tt ON tr.term_taxonomy_id=tt.term_taxonomy_id";
311
+ $sql .= " LEFT JOIN {$wpdb->terms} t ON tt.term_id=t.term_id";
312
+ } elseif ( ! empty( $query['group'] ) ) {
313
  $sql .= " INNER JOIN {$wpdb->term_relationships} tr ON tr.object_id=p.ID";
314
  $sql .= " INNER JOIN {$wpdb->term_taxonomy} tt ON tr.term_taxonomy_id=tt.term_taxonomy_id";
315
  $sql .= " INNER JOIN {$wpdb->terms} t ON tt.term_id=t.term_id";
316
+ $sql .= " AND t.slug=%s";
317
+ $sql_params[] = $query['group'];
 
 
 
318
  }
319
  $sql .= " WHERE post_type=%s";
320
  $sql_params[] = self::POST_TYPE;
468
  throw new InvalidArgumentException(sprintf(__('Unidentified action %s', 'action-scheduler'), $action_id));
469
  }
470
  do_action( 'action_scheduler_deleted_action', $action_id );
471
+
472
+ wp_delete_post( $action_id, TRUE );
473
  }
474
 
475
  /**
685
  $sql = $wpdb->prepare( $sql, array( $claim->get_id() ) );
686
  $result = $wpdb->query($sql);
687
  if ( $result === false ) {
688
+ /* translators: %s: claim ID */
689
  throw new RuntimeException( sprintf( __('Unable to unlock claim %s. Database error.', 'action-scheduler'), $claim->get_id() ) );
690
  }
691
  }
700
  $sql = $wpdb->prepare( $sql, $action_id, self::POST_TYPE );
701
  $result = $wpdb->query($sql);
702
  if ( $result === false ) {
703
+ /* translators: %s: action ID */
704
  throw new RuntimeException( sprintf( __('Unable to unlock claim on action %s. Database error.', 'action-scheduler'), $action_id ) );
705
  }
706
  }
712
  $sql = $wpdb->prepare( $sql, self::STATUS_FAILED, $action_id, self::POST_TYPE );
713
  $result = $wpdb->query($sql);
714
  if ( $result === false ) {
715
+ /* translators: %s: action ID */
716
  throw new RuntimeException( sprintf( __('Unable to mark failure on action %s. Database error.', 'action-scheduler'), $action_id ) );
717
  }
718
  }
761
  $wpdb->query($sql);
762
  }
763
 
764
+ /**
765
+ * Record that an action was completed.
766
+ *
767
+ * @param int $action_id ID of the completed action.
768
+ * @throws InvalidArgumentException|RuntimeException
769
+ */
770
  public function mark_complete( $action_id ) {
771
  $post = get_post($action_id);
772
  if ( empty($post) || ($post->post_type != self::POST_TYPE) ) {
785
  }
786
  }
787
 
788
+ /**
789
+ * Mark action as migrated when there is an error deleting the action.
790
+ *
791
+ * @param int $action_id Action ID.
792
+ */
793
+ public function mark_migrated( $action_id ) {
794
+ wp_update_post(
795
+ array(
796
+ 'ID' => $action_id,
797
+ 'post_status' => 'migrated'
798
+ )
799
+ );
800
+ }
801
+
802
+ /**
803
+ * Determine whether the post store can be migrated.
804
+ *
805
+ * @return bool
806
+ */
807
+ public function migration_dependencies_met( $setting ) {
808
+ global $wpdb;
809
+
810
+ $dependencies_met = get_transient( self::DEPENDENCIES_MET );
811
+ if ( empty( $dependencies_met ) ) {
812
+ $found_action = $wpdb->get_var(
813
+ $wpdb->prepare(
814
+ "SELECT ID FROM {$wpdb->posts} WHERE post_type = %s AND CHAR_LENGTH(post_content) > 191 LIMIT 1",
815
+ self::POST_TYPE
816
+ )
817
+ );
818
+ $dependencies_met = $found_action ? 'no' : 'yes';
819
+ set_transient( self::DEPENDENCIES_MET, $dependencies_met, DAY_IN_SECONDS );
820
+ }
821
+
822
+ return 'yes' == $dependencies_met ? $setting : false;
823
+ }
824
+
825
  /**
826
  * InnoDB indexes have a maximum size of 767 bytes by default, which is only 191 characters with utf8mb4.
827
  *
832
  * @param ActionScheduler_Action $action
833
  */
834
  protected function validate_action( ActionScheduler_Action $action ) {
835
+ try {
836
+ parent::validate_action( $action );
837
+ } catch ( Exception $e ) {
838
+ $message = sprintf( __( '%s Support for strings longer than this will be removed in a future version.', 'action-scheduler' ), $e->getMessage() );
839
+ _doing_it_wrong( 'ActionScheduler_Action::$args', $message, '2.1.0' );
840
  }
841
  }
842
 
844
  * @codeCoverageIgnore
845
  */
846
  public function init() {
847
+ add_filter( 'action_scheduler_migration_dependencies_met', array( $this, 'migration_dependencies_met' ) );
848
+
849
  $post_type_registrar = new ActionScheduler_wpPostStore_PostTypeRegistrar();
850
  $post_type_registrar->register();
851
 
855
  $taxonomy_registrar = new ActionScheduler_wpPostStore_TaxonomyRegistrar();
856
  $taxonomy_registrar->register();
857
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
858
  }
includes/vendor/action-scheduler/classes/{ActionScheduler_wpPostStore_PostStatusRegistrar.php → data-stores/ActionScheduler_wpPostStore_PostStatusRegistrar.php} RENAMED
@@ -33,8 +33,9 @@ class ActionScheduler_wpPostStore_PostStatusRegistrar {
33
  */
34
  protected function post_status_failed_labels() {
35
  $labels = array(
36
- 'label' => _x( 'Failed', 'post' ),
37
- 'label_count' => _n_noop( 'Failed <span class="count">(%s)</span>', 'Failed <span class="count">(%s)</span>' ),
 
38
  );
39
 
40
  return apply_filters( 'action_scheduler_post_status_failed_labels', $labels );
@@ -47,11 +48,11 @@ class ActionScheduler_wpPostStore_PostStatusRegistrar {
47
  */
48
  protected function post_status_running_labels() {
49
  $labels = array(
50
- 'label' => _x( 'In-Progress', 'post' ),
51
- 'label_count' => _n_noop( 'In-Progress <span class="count">(%s)</span>', 'In-Progress <span class="count">(%s)</span>' ),
 
52
  );
53
 
54
  return apply_filters( 'action_scheduler_post_status_running_labels', $labels );
55
  }
56
  }
57
-
33
  */
34
  protected function post_status_failed_labels() {
35
  $labels = array(
36
+ 'label' => _x( 'Failed', 'post', 'action-scheduler' ),
37
+ /* translators: %s: count */
38
+ 'label_count' => _n_noop( 'Failed <span class="count">(%s)</span>', 'Failed <span class="count">(%s)</span>', 'action-scheduler' ),
39
  );
40
 
41
  return apply_filters( 'action_scheduler_post_status_failed_labels', $labels );
48
  */
49
  protected function post_status_running_labels() {
50
  $labels = array(
51
+ 'label' => _x( 'In-Progress', 'post', 'action-scheduler' ),
52
+ /* translators: %s: count */
53
+ 'label_count' => _n_noop( 'In-Progress <span class="count">(%s)</span>', 'In-Progress <span class="count">(%s)</span>', 'action-scheduler' ),
54
  );
55
 
56
  return apply_filters( 'action_scheduler_post_status_running_labels', $labels );
57
  }
58
  }
 
includes/vendor/action-scheduler/classes/{ActionScheduler_wpPostStore_PostTypeRegistrar.php → data-stores/ActionScheduler_wpPostStore_PostTypeRegistrar.php} RENAMED
File without changes
includes/vendor/action-scheduler/classes/{ActionScheduler_wpPostStore_TaxonomyRegistrar.php → data-stores/ActionScheduler_wpPostStore_TaxonomyRegistrar.php} RENAMED
File without changes
includes/vendor/action-scheduler/classes/migration/ActionMigrator.php ADDED
@@ -0,0 +1,109 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+
4
+ namespace Action_Scheduler\Migration;
5
+
6
+ /**
7
+ * Class ActionMigrator
8
+ *
9
+ * @package Action_Scheduler\Migration
10
+ *
11
+ * @since 3.0.0
12
+ *
13
+ * @codeCoverageIgnore
14
+ */
15
+ class ActionMigrator {
16
+ /** var ActionScheduler_Store */
17
+ private $source;
18
+
19
+ /** var ActionScheduler_Store */
20
+ private $destination;
21
+
22
+ /** var LogMigrator */
23
+ private $log_migrator;
24
+
25
+ /**
26
+ * ActionMigrator constructor.
27
+ *
28
+ * @param ActionScheduler_Store $source_store Source store object.
29
+ * @param ActionScheduler_Store $destination_store Destination store object.
30
+ * @param LogMigrator $log_migrator Log migrator object.
31
+ */
32
+ public function __construct( \ActionScheduler_Store $source_store, \ActionScheduler_Store $destination_store, LogMigrator $log_migrator ) {
33
+ $this->source = $source_store;
34
+ $this->destination = $destination_store;
35
+ $this->log_migrator = $log_migrator;
36
+ }
37
+
38
+ /**
39
+ * Migrate an action.
40
+ *
41
+ * @param int $source_action_id Action ID.
42
+ *
43
+ * @return int 0|new action ID
44
+ */
45
+ public function migrate( $source_action_id ) {
46
+ try {
47
+ $action = $this->source->fetch_action( $source_action_id );
48
+ $status = $this->source->get_status( $source_action_id );
49
+ } catch ( \Exception $e ) {
50
+ $action = null;
51
+ $status = '';
52
+ }
53
+
54
+ if ( is_null( $action ) || empty( $status ) || ! $action->get_schedule()->get_date() ) {
55
+ // null action or empty status means the fetch operation failed or the action didn't exist
56
+ // null schedule means it's missing vital data
57
+ // delete it and move on
58
+ try {
59
+ $this->source->delete_action( $source_action_id );
60
+ } catch ( \Exception $e ) {
61
+ // nothing to do, it didn't exist in the first place
62
+ }
63
+ do_action( 'action_scheduler/no_action_to_migrate', $source_action_id, $this->source, $this->destination );
64
+
65
+ return 0;
66
+ }
67
+
68
+ try {
69
+
70
+ // Make sure the last attempt date is set correctly for completed and failed actions
71
+ $last_attempt_date = ( $status !== \ActionScheduler_Store::STATUS_PENDING ) ? $this->source->get_date( $source_action_id ) : null;
72
+
73
+ $destination_action_id = $this->destination->save_action( $action, null, $last_attempt_date );
74
+ } catch ( \Exception $e ) {
75
+ do_action( 'action_scheduler/migrate_action_failed', $source_action_id, $this->source, $this->destination );
76
+
77
+ return 0; // could not save the action in the new store
78
+ }
79
+
80
+ try {
81
+ switch ( $status ) {
82
+ case \ActionScheduler_Store::STATUS_FAILED :
83
+ $this->destination->mark_failure( $destination_action_id );
84
+ break;
85
+ case \ActionScheduler_Store::STATUS_CANCELED :
86
+ $this->destination->cancel_action( $destination_action_id );
87
+ break;
88
+ }
89
+
90
+ $this->log_migrator->migrate( $source_action_id, $destination_action_id );
91
+ $this->source->delete_action( $source_action_id );
92
+
93
+ $test_action = $this->source->fetch_action( $source_action_id );
94
+ if ( ! is_a( $test_action, 'ActionScheduler_NullAction' ) ) {
95
+ throw new \RuntimeException( sprintf( __( 'Unable to remove source migrated action %s', 'action-scheduler' ), $source_action_id ) );
96
+ }
97
+ do_action( 'action_scheduler/migrated_action', $source_action_id, $destination_action_id, $this->source, $this->destination );
98
+
99
+ return $destination_action_id;
100
+ } catch ( \Exception $e ) {
101
+ // could not delete from the old store
102
+ $this->source->mark_migrated( $source_action_id );
103
+ do_action( 'action_scheduler/migrate_action_incomplete', $source_action_id, $destination_action_id, $this->source, $this->destination );
104
+ do_action( 'action_scheduler/migrated_action', $source_action_id, $destination_action_id, $this->source, $this->destination );
105
+
106
+ return $destination_action_id;
107
+ }
108
+ }
109
+ }
includes/vendor/action-scheduler/classes/migration/ActionScheduler_DBStoreMigrator.php ADDED
@@ -0,0 +1,47 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Class ActionScheduler_DBStoreMigrator
5
+ *
6
+ * A class for direct saving of actions to the table data store during migration.
7
+ *
8
+ * @since 3.0.0
9
+ */
10
+ class ActionScheduler_DBStoreMigrator extends ActionScheduler_DBStore {
11
+
12
+ /**
13
+ * Save an action with optional last attempt date.
14
+ *
15
+ * Normally, saving an action sets its attempted date to 0000-00-00 00:00:00 because when an action is first saved,
16
+ * it can't have been attempted yet, but migrated completed actions will have an attempted date, so we need to save
17
+ * that when first saving the action.
18
+ *
19
+ * @param ActionScheduler_Action $action
20
+ * @param \DateTime $scheduled_date Optional date of the first instance to store.
21
+ * @param \DateTime $last_attempt_date Optional date the action was last attempted.
22
+ *
23
+ * @return string The action ID
24
+ * @throws \RuntimeException When the action is not saved.
25
+ */
26
+ public function save_action( ActionScheduler_Action $action, \DateTime $scheduled_date = null, \DateTime $last_attempt_date = null ){
27
+ try {
28
+ /** @var \wpdb $wpdb */
29
+ global $wpdb;
30
+
31
+ $action_id = parent::save_action( $action, $scheduled_date );
32
+
33
+ if ( null !== $last_attempt_date ) {
34
+ $data = [
35
+ 'last_attempt_gmt' => $this->get_scheduled_date_string( $action, $last_attempt_date ),
36
+ 'last_attempt_local' => $this->get_scheduled_date_string_local( $action, $last_attempt_date ),
37
+ ];
38
+
39
+ $wpdb->update( $wpdb->actionscheduler_actions, $data, array( 'action_id' => $action_id ), array( '%s', '%s' ), array( '%d' ) );
40
+ }
41
+
42
+ return $action_id;
43
+ } catch ( \Exception $e ) {
44
+ throw new \RuntimeException( sprintf( __( 'Error saving action: %s', 'action-scheduler' ), $e->getMessage() ), 0 );
45
+ }
46
+ }
47
+ }
includes/vendor/action-scheduler/classes/migration/BatchFetcher.php ADDED
@@ -0,0 +1,86 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+
4
+ namespace Action_Scheduler\Migration;
5
+
6
+
7
+ use ActionScheduler_Store as Store;
8
+
9
+ /**
10
+ * Class BatchFetcher
11
+ *
12
+ * @package Action_Scheduler\Migration
13
+ *
14
+ * @since 3.0.0
15
+ *
16
+ * @codeCoverageIgnore
17
+ */
18
+ class BatchFetcher {
19
+ /** var ActionScheduler_Store */
20
+ private $store;
21
+
22
+ /**
23
+ * BatchFetcher constructor.
24
+ *
25
+ * @param ActionScheduler_Store $source_store Source store object.
26
+ */
27
+ public function __construct( Store $source_store ) {
28
+ $this->store = $source_store;
29
+ }
30
+
31
+ /**
32
+ * Retrieve a list of actions.
33
+ *
34
+ * @param int $count The number of actions to retrieve
35
+ *
36
+ * @return int[] A list of action IDs
37
+ */
38
+ public function fetch( $count = 10 ) {
39
+ foreach ( $this->get_query_strategies( $count ) as $query ) {
40
+ $action_ids = $this->store->query_actions( $query );
41
+ if ( ! empty( $action_ids ) ) {
42
+ return $action_ids;
43
+ }
44
+ }
45
+
46
+ return [];
47
+ }
48
+
49
+ /**
50
+ * Generate a list of prioritized of action search parameters.
51
+ *
52
+ * @param int $count Number of actions to find.
53
+ *
54
+ * @return array
55
+ */
56
+ private function get_query_strategies( $count ) {
57
+ $now = as_get_datetime_object();
58
+ $args = [
59
+ 'date' => $now,
60
+ 'per_page' => $count,
61
+ 'offset' => 0,
62
+ 'orderby' => 'date',
63
+ 'order' => 'ASC',
64
+ ];
65
+
66
+ $priorities = [
67
+ Store::STATUS_PENDING,
68
+ Store::STATUS_FAILED,
69
+ Store::STATUS_CANCELED,
70
+ Store::STATUS_COMPLETE,
71
+ Store::STATUS_RUNNING,
72
+ '', // any other unanticipated status
73
+ ];
74
+
75
+ foreach ( $priorities as $status ) {
76
+ yield wp_parse_args( [
77
+ 'status' => $status,
78
+ 'date_compare' => '<=',
79
+ ], $args );
80
+ yield wp_parse_args( [
81
+ 'status' => $status,
82
+ 'date_compare' => '>=',
83
+ ], $args );
84
+ }
85
+ }
86
+ }
includes/vendor/action-scheduler/classes/migration/Config.php ADDED
@@ -0,0 +1,168 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+
4
+ namespace Action_Scheduler\Migration;
5
+
6
+ use Action_Scheduler\WP_CLI\ProgressBar;
7
+ use ActionScheduler_Logger as Logger;
8
+ use ActionScheduler_Store as Store;
9
+
10
+ /**
11
+ * Class Config
12
+ *
13
+ * @package Action_Scheduler\Migration
14
+ *
15
+ * @since 3.0.0
16
+ *
17
+ * A config builder for the ActionScheduler\Migration\Runner class
18
+ */
19
+ class Config {
20
+ /** @var ActionScheduler_Store */
21
+ private $source_store;
22
+
23
+ /** @var ActionScheduler_Logger */
24
+ private $source_logger;
25
+
26
+ /** @var ActionScheduler_Store */
27
+ private $destination_store;
28
+
29
+ /** @var ActionScheduler_Logger */
30
+ private $destination_logger;
31
+
32
+ /** @var Progress bar */
33
+ private $progress_bar;
34
+
35
+ /** @var bool */
36
+ private $dry_run = false;
37
+
38
+ /**
39
+ * Config constructor.
40
+ */
41
+ public function __construct() {
42
+
43
+ }
44
+
45
+ /**
46
+ * Get the configured source store.
47
+ *
48
+ * @return ActionScheduler_Store
49
+ */
50
+ public function get_source_store() {
51
+ if ( empty( $this->source_store ) ) {
52
+ throw new \RuntimeException( __( 'Source store must be configured before running a migration', 'action-scheduler' ) );
53
+ }
54
+
55
+ return $this->source_store;
56
+ }
57
+
58
+ /**
59
+ * Set the configured source store.
60
+ *
61
+ * @param ActionScheduler_Store $store Source store object.
62
+ */
63
+ public function set_source_store( Store $store ) {
64
+ $this->source_store = $store;
65
+ }
66
+
67
+ /**
68
+ * Get the configured source loger.
69
+ *
70
+ * @return ActionScheduler_Logger
71
+ */
72
+ public function get_source_logger() {
73
+ if ( empty( $this->source_logger ) ) {
74
+ throw new \RuntimeException( __( 'Source logger must be configured before running a migration', 'action-scheduler' ) );
75
+ }
76
+
77
+ return $this->source_logger;
78
+ }
79
+
80
+ /**
81
+ * Set the configured source logger.
82
+ *
83
+ * @param ActionScheduler_Logger $logger
84
+ */
85
+ public function set_source_logger( Logger $logger ) {
86
+ $this->source_logger = $logger;
87
+ }
88
+
89
+ /**
90
+ * Get the configured destination store.
91
+ *
92
+ * @return ActionScheduler_Store
93
+ */
94
+ public function get_destination_store() {
95
+ if ( empty( $this->destination_store ) ) {
96
+ throw new \RuntimeException( __( 'Destination store must be configured before running a migration', 'action-scheduler' ) );
97
+ }
98
+
99
+ return $this->destination_store;
100
+ }
101
+
102
+ /**
103
+ * Set the configured destination store.
104
+ *
105
+ * @param ActionScheduler_Store $store
106
+ */
107
+ public function set_destination_store( Store $store ) {
108
+ $this->destination_store = $store;
109
+ }
110
+
111
+ /**
112
+ * Get the configured destination logger.
113
+ *
114
+ * @return ActionScheduler_Logger
115
+ */
116
+ public function get_destination_logger() {
117
+ if ( empty( $this->destination_logger ) ) {
118
+ throw new \RuntimeException( __( 'Destination logger must be configured before running a migration', 'action-scheduler' ) );
119
+ }
120
+
121
+ return $this->destination_logger;
122
+ }
123
+
124
+ /**
125
+ * Set the configured destination logger.
126
+ *
127
+ * @param ActionScheduler_Logger $logger
128
+ */
129
+ public function set_destination_logger( Logger $logger ) {
130
+ $this->destination_logger = $logger;
131
+ }
132
+
133
+ /**
134
+ * Get flag indicating whether it's a dry run.
135
+ *
136
+ * @return bool
137
+ */
138
+ public function get_dry_run() {
139
+ return $this->dry_run;
140
+ }
141
+
142
+ /**
143
+ * Set flag indicating whether it's a dry run.
144
+ *
145
+ * @param bool $dry_run
146
+ */
147
+ public function set_dry_run( $dry_run ) {
148
+ $this->dry_run = (bool) $dry_run;
149
+ }
150
+
151
+ /**
152
+ * Get progress bar object.
153
+ *
154
+ * @return ActionScheduler\WPCLI\ProgressBar
155
+ */
156
+ public function get_progress_bar() {
157
+ return $this->progress_bar;
158
+ }
159
+
160
+ /**
161
+ * Set progress bar object.
162
+ *
163
+ * @param ActionScheduler\WPCLI\ProgressBar $progress_bar
164
+ */
165
+ public function set_progress_bar( ProgressBar $progress_bar ) {
166
+ $this->progress_bar = $progress_bar;
167
+ }
168
+ }
includes/vendor/action-scheduler/classes/migration/Controller.php ADDED
@@ -0,0 +1,206 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace Action_Scheduler\Migration;
4
+
5
+ use Action_Scheduler\WP_CLI\Migration_Command;
6
+ use Action_Scheduler\WP_CLI\ProgressBar;
7
+
8
+ /**
9
+ * Class Controller
10
+ *
11
+ * The main plugin/initialization class for migration to custom tables.
12
+ *
13
+ * @package Action_Scheduler\Migration
14
+ *
15
+ * @since 3.0.0
16
+ *
17
+ * @codeCoverageIgnore
18
+ */
19
+ class Controller {
20
+ private static $instance;
21
+
22
+ /** @var Action_Scheduler\Migration\Scheduler */
23
+ private $migration_scheduler;
24
+
25
+ /** @var string */
26
+ private $store_classname;
27
+
28
+ /** @var string */
29
+ private $logger_classname;
30
+
31
+ /** @var bool */
32
+ private $migrate_custom_store;
33
+
34
+ /**
35
+ * Controller constructor.
36
+ *
37
+ * @param Scheduler $migration_scheduler Migration scheduler object.
38
+ */
39
+ protected function __construct( Scheduler $migration_scheduler ) {
40
+ $this->migration_scheduler = $migration_scheduler;
41
+ $this->store_classname = '';
42
+ }
43
+
44
+ /**
45
+ * Set the action store class name.
46
+ *
47
+ * @param string $class Classname of the store class.
48
+ *
49
+ * @return string
50
+ */
51
+ public function get_store_class( $class ) {
52
+ if ( \ActionScheduler_DataController::is_migration_complete() ) {
53
+ return \ActionScheduler_DataController::DATASTORE_CLASS;
54
+ } elseif ( \ActionScheduler_Store::DEFAULT_CLASS !== $class ) {
55
+ $this->store_classname = $class;
56
+ return $class;
57
+ } else {
58
+ return 'ActionScheduler_HybridStore';
59
+ }
60
+ }
61
+
62
+ /**
63
+ * Set the action logger class name.
64
+ *
65
+ * @param string $class Classname of the logger class.
66
+ *
67
+ * @return string
68
+ */
69
+ public function get_logger_class( $class ) {
70
+ \ActionScheduler_Store::instance();
71
+
72
+ if ( $this->has_custom_datastore() ) {
73
+ $this->logger_classname = $class;
74
+ return $class;
75
+ } else {
76
+ return \ActionScheduler_DataController::LOGGER_CLASS;
77
+ }
78
+ }
79
+
80
+ /**
81
+ * Get flag indicating whether a custom datastore is in use.
82
+ *
83
+ * @return bool
84
+ */
85
+ public function has_custom_datastore() {
86
+ return (bool) $this->store_classname;
87
+ }
88
+
89
+ /**
90
+ * Set up the background migration process
91
+ *
92
+ * @return void
93
+ */
94
+ public function schedule_migration() {
95
+ if ( \ActionScheduler_DataController::is_migration_complete() || $this->migration_scheduler->is_migration_scheduled() ) {
96
+ return;
97
+ }
98
+
99
+ $this->migration_scheduler->schedule_migration();
100
+ }
101
+
102
+ /**
103
+ * Get the default migration config object
104
+ *
105
+ * @return ActionScheduler\Migration\Config
106
+ */
107
+ public function get_migration_config_object() {
108
+ static $config = null;
109
+
110
+ if ( ! $config ) {
111
+ $source_store = $this->store_classname ? new $this->store_classname() : new \ActionScheduler_wpPostStore();
112
+ $source_logger = $this->logger_classname ? new $this->logger_classname() : new \ActionScheduler_wpCommentLogger();
113
+
114
+ $config = new Config();
115
+ $config->set_source_store( $source_store );
116
+ $config->set_source_logger( $source_logger );
117
+ $config->set_destination_store( new \ActionScheduler_DBStoreMigrator() );
118
+ $config->set_destination_logger( new \ActionScheduler_DBLogger() );
119
+
120
+ if ( defined( 'WP_CLI' ) && WP_CLI ) {
121
+ $config->set_progress_bar( new ProgressBar( '', 0 ) );
122
+ }
123
+ }
124
+
125
+ return apply_filters( 'action_scheduler/migration_config', $config );
126
+ }
127
+
128
+ /**
129
+ * Hook dashboard migration notice.
130
+ */
131
+ public function hook_admin_notices() {
132
+ if ( ! $this->allow_migration() || \ActionScheduler_DataController::is_migration_complete() ) {
133
+ return;
134
+ }
135
+ add_action( 'admin_notices', array( $this, 'display_migration_notice' ), 10, 0 );
136
+ }
137
+
138
+ /**
139
+ * Show a dashboard notice that migration is in progress.
140
+ */
141
+ public function display_migration_notice() {
142
+ printf( '<div class="notice notice-warning"><p>%s</p></div>', __( 'Action Scheduler migration in progress. The list of scheduled actions may be incomplete.', 'action-scheduler' ) );
143
+ }
144
+
145
+ /**
146
+ * Add store classes. Hook migration.
147
+ */
148
+ private function hook() {
149
+ add_filter( 'action_scheduler_store_class', array( $this, 'get_store_class' ), 100, 1 );
150
+ add_filter( 'action_scheduler_logger_class', array( $this, 'get_logger_class' ), 100, 1 );
151
+ add_action( 'init', array( $this, 'maybe_hook_migration' ) );
152
+ add_action( 'shutdown', array( $this, 'schedule_migration' ), 0, 0 );
153
+
154
+ // Action Scheduler may be displayed as a Tools screen or WooCommerce > Status administration screen
155
+ add_action( 'load-tools_page_action-scheduler', array( $this, 'hook_admin_notices' ), 10, 0 );
156
+ add_action( 'load-woocommerce_page_wc-status', array( $this, 'hook_admin_notices' ), 10, 0 );
157
+ }
158
+
159
+ /**
160
+ * Possibly hook the migration scheduler action.
161
+ *
162
+ * @author Jeremy Pry
163
+ */
164
+ public function maybe_hook_migration() {
165
+ if ( ! $this->allow_migration() || \ActionScheduler_DataController::is_migration_complete() ) {
166
+ return;
167
+ }
168
+
169
+ $this->migration_scheduler->hook();
170
+ }
171
+
172
+ /**
173
+ * Allow datastores to enable migration to AS tables.
174
+ */
175
+ public function allow_migration() {
176
+ if ( ! \ActionScheduler_DataController::dependencies_met() ) {
177
+ return false;
178
+ }
179
+
180
+ if ( null === $this->migrate_custom_store ) {
181
+ $this->migrate_custom_store = apply_filters( 'action_scheduler_migrate_data_store', false );
182
+ }
183
+
184
+ return ( ! $this->has_custom_datastore() ) || $this->migrate_custom_store;
185
+ }
186
+
187
+ /**
188
+ * Proceed with the migration if the dependencies have been met.
189
+ */
190
+ public static function init() {
191
+ if ( \ActionScheduler_DataController::dependencies_met() ) {
192
+ self::instance()->hook();
193
+ }
194
+ }
195
+
196
+ /**
197
+ * Singleton factory.
198
+ */
199
+ public static function instance() {
200
+ if ( ! isset( self::$instance ) ) {
201
+ self::$instance = new static( new Scheduler() );
202
+ }
203
+
204
+ return self::$instance;
205
+ }
206
+ }
includes/vendor/action-scheduler/classes/migration/DryRun_ActionMigrator.php ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+
4
+ namespace Action_Scheduler\Migration;
5
+
6
+ /**
7
+ * Class DryRun_ActionMigrator
8
+ *
9
+ * @package Action_Scheduler\Migration
10
+ *
11
+ * @since 3.0.0
12
+ *
13
+ * @codeCoverageIgnore
14
+ */
15
+ class DryRun_ActionMigrator extends ActionMigrator {
16
+ /**
17
+ * Simulate migrating an action.
18
+ *
19
+ * @param int $source_action_id Action ID.
20
+ *
21
+ * @return int
22
+ */
23
+ public function migrate( $source_action_id ) {
24
+ do_action( 'action_scheduler/migrate_action_dry_run', $source_action_id );
25
+
26
+ return 0;
27
+ }
28
+ }
includes/vendor/action-scheduler/classes/migration/DryRun_LogMigrator.php ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+
4
+ namespace Action_Scheduler\Migration;
5
+
6
+ /**
7
+ * Class DryRun_LogMigrator
8
+ *
9
+ * @package Action_Scheduler\Migration
10
+ *
11
+ * @codeCoverageIgnore
12
+ */
13
+ class DryRun_LogMigrator extends LogMigrator {
14
+ /**
15
+ * Simulate migrating an action log.
16
+ *
17
+ * @param int $source_action_id Source logger object.
18
+ * @param int $destination_action_id Destination logger object.
19
+ */
20
+ public function migrate( $source_action_id, $destination_action_id ) {
21
+ // no-op
22
+ }
23
+ }
includes/vendor/action-scheduler/classes/migration/LogMigrator.php ADDED
@@ -0,0 +1,49 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+
4
+ namespace Action_Scheduler\Migration;
5
+
6
+ use ActionScheduler_Logger;
7
+
8
+ /**
9
+ * Class LogMigrator
10
+ *
11
+ * @package Action_Scheduler\Migration
12
+ *
13
+ * @since 3.0.0
14
+ *
15
+ * @codeCoverageIgnore
16
+ */
17
+ class LogMigrator {
18
+ /** @var ActionScheduler_Logger */
19
+ private $source;
20
+
21
+ /** @var ActionScheduler_Logger */
22
+ private $destination;
23
+
24
+ /**
25
+ * ActionMigrator constructor.
26
+ *
27
+ * @param ActionScheduler_Logger $source_logger Source logger object.
28
+ * @param ActionScheduler_Logger $destination_Logger Destination logger object.
29
+ */
30
+ public function __construct( ActionScheduler_Logger $source_logger, ActionScheduler_Logger $destination_Logger ) {
31
+ $this->source = $source_logger;
32
+ $this->destination = $destination_Logger;
33
+ }
34
+
35
+ /**
36
+ * Migrate an action log.
37
+ *
38
+ * @param int $source_action_id Source logger object.
39
+ * @param int $destination_action_id Destination logger object.
40
+ */
41
+ public function migrate( $source_action_id, $destination_action_id ) {
42
+ $logs = $this->source->get_logs( $source_action_id );
43
+ foreach ( $logs as $log ) {
44
+ if ( $log->get_action_id() == $source_action_id ) {
45
+ $this->destination->log( $destination_action_id, $log->get_message(), $log->get_date() );
46
+ }
47
+ }
48
+ }
49
+ }
includes/vendor/action-scheduler/classes/migration/Runner.php ADDED
@@ -0,0 +1,136 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+
4
+ namespace Action_Scheduler\Migration;
5
+
6
+ /**
7
+ * Class Runner
8
+ *
9
+ * @package Action_Scheduler\Migration
10
+ *
11
+ * @since 3.0.0
12
+ *
13
+ * @codeCoverageIgnore
14
+ */
15
+ class Runner {
16
+ /** @var ActionScheduler_Store */
17
+ private $source_store;
18
+
19
+ /** @var ActionScheduler_Store */
20
+ private $destination_store;
21
+
22
+ /** @var ActionScheduler_Logger */
23
+ private $source_logger;
24
+
25
+ /** @var ActionScheduler_Logger */
26
+ private $destination_logger;
27
+
28
+ /** @var BatchFetcher */
29
+ private $batch_fetcher;
30
+
31
+ /** @var ActionMigrator */
32
+ private $action_migrator;
33
+
34
+ /** @var LogMigrator */
35
+ private $log_migrator;
36
+
37
+ /** @var ProgressBar */
38
+ private $progress_bar;
39
+
40
+ /**
41
+ * Runner constructor.
42
+ *
43
+ * @param Config $config Migration configuration object.
44
+ */
45
+ public function __construct( Config $config ) {
46
+ $this->source_store = $config->get_source_store();
47
+ $this->destination_store = $config->get_destination_store();
48
+ $this->source_logger = $config->get_source_logger();
49
+ $this->destination_logger = $config->get_destination_logger();
50
+
51
+ $this->batch_fetcher = new BatchFetcher( $this->source_store );
52
+ if ( $config->get_dry_run() ) {
53
+ $this->log_migrator = new DryRun_LogMigrator( $this->source_logger, $this->destination_logger );
54
+ $this->action_migrator = new DryRun_ActionMigrator( $this->source_store, $this->destination_store, $this->log_migrator );
55
+ } else {
56
+ $this->log_migrator = new LogMigrator( $this->source_logger, $this->destination_logger );
57
+ $this->action_migrator = new ActionMigrator( $this->source_store, $this->destination_store, $this->log_migrator );
58
+ }
59
+
60
+ if ( defined( 'WP_CLI' ) && WP_CLI ) {
61
+ $this->progress_bar = $config->get_progress_bar();
62
+ }
63
+ }
64
+
65
+ /**
66
+ * Run migration batch.
67
+ *
68
+ * @param int $batch_size Optional batch size. Default 10.
69
+ *
70
+ * @return int Size of batch processed.
71
+ */
72
+ public function run( $batch_size = 10 ) {
73
+ $batch = $this->batch_fetcher->fetch( $batch_size );
74
+ $batch_size = count( $batch );
75
+
76
+ if ( ! $batch_size ) {
77
+ return 0;
78
+ }
79
+
80
+ if ( $this->progress_bar ) {
81
+ /* translators: %d: amount of actions */
82
+ $this->progress_bar->set_message( sprintf( _n( 'Migrating %d action', 'Migrating %d actions', $batch_size, 'action-scheduler' ), number_format_i18n( $batch_size ) ) );
83
+ $this->progress_bar->set_count( $batch_size );
84
+ }
85
+
86
+ $this->migrate_actions( $batch );
87
+
88
+ return $batch_size;
89
+ }
90
+
91
+ /**
92
+ * Migration a batch of actions.
93
+ *
94
+ * @param array $action_ids List of action IDs to migrate.
95
+ */
96
+ public function migrate_actions( array $action_ids ) {
97
+ do_action( 'action_scheduler/migration_batch_starting', $action_ids );
98
+
99
+ \ActionScheduler::logger()->unhook_stored_action();
100
+ $this->destination_logger->unhook_stored_action();
101
+
102
+ foreach ( $action_ids as $source_action_id ) {
103
+ $destination_action_id = $this->action_migrator->migrate( $source_action_id );
104
+ if ( $destination_action_id ) {
105
+ $this->destination_logger->log( $destination_action_id, sprintf(
106
+ /* translators: 1: source action ID 2: source store class 3: destination action ID 4: destination store class */
107
+ __( 'Migrated action with ID %1$d in %2$s to ID %3$d in %4$s', 'action-scheduler' ),
108
+ $source_action_id,
109
+ get_class( $this->source_store ),
110
+ $destination_action_id,
111
+ get_class( $this->destination_store )
112
+ ) );
113
+ }
114
+
115
+ if ( $this->progress_bar ) {
116
+ $this->progress_bar->tick();
117
+ }
118
+ }
119
+
120
+ if ( $this->progress_bar ) {
121
+ $this->progress_bar->finish();
122
+ }
123
+
124
+ \ActionScheduler::logger()->hook_stored_action();
125
+
126
+ do_action( 'action_scheduler/migration_batch_complete', $action_ids );
127
+ }
128
+
129
+ /**
130
+ * Initialize destination store and logger.
131
+ */
132
+ public function init_destination() {
133
+ $this->destination_store->init();
134
+ $this->destination_logger->init();
135
+ }
136
+ }
includes/vendor/action-scheduler/classes/migration/Scheduler.php ADDED
@@ -0,0 +1,128 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+
4
+ namespace Action_Scheduler\Migration;
5
+
6
+ /**
7
+ * Class Scheduler
8
+ *
9
+ * @package Action_Scheduler\WP_CLI
10
+ *
11
+ * @since 3.0.0
12
+ *
13
+ * @codeCoverageIgnore
14
+ */
15
+ class Scheduler {
16
+ /** Migration action hook. */
17
+ const HOOK = 'action_scheduler/migration_hook';
18
+
19
+ /** Migration action group. */
20
+ const GROUP = 'action-scheduler-migration';
21
+
22
+ /**
23
+ * Set up the callback for the scheduled job.
24
+ */
25
+ public function hook() {
26
+ add_action( self::HOOK, array( $this, 'run_migration' ), 10, 0 );
27
+ }
28
+
29
+ /**
30
+ * Remove the callback for the scheduled job.
31
+ */
32
+ public function unhook() {
33
+ remove_action( self::HOOK, array( $this, 'run_migration' ), 10 );
34
+ }
35
+
36
+ /**
37
+ * The migration callback.
38
+ */
39
+ public function run_migration() {
40
+ $migration_runner = $this->get_migration_runner();
41
+ $count = $migration_runner->run( $this->get_batch_size() );
42
+
43
+ if ( $count === 0 ) {
44
+ $this->mark_complete();
45
+ } else {
46
+ $this->schedule_migration( time() + $this->get_schedule_interval() );
47
+ }
48
+ }
49
+
50
+ /**
51
+ * Mark the migration complete.
52
+ */
53
+ public function mark_complete() {
54
+ $this->unschedule_migration();
55
+
56
+ \ActionScheduler_DataController::mark_migration_complete();
57
+ do_action( 'action_scheduler/migration_complete' );
58
+ }
59
+
60
+ /**
61
+ * Get a flag indicating whether the migration is scheduled.
62
+ *
63
+ * @return bool Whether there is a pending action in the store to handle the migration
64
+ */
65
+ public function is_migration_scheduled() {
66
+ $next = as_next_scheduled_action( self::HOOK );
67
+
68
+ return ! empty( $next );
69
+ }
70
+
71
+ /**
72
+ * Schedule the migration.
73
+ *
74
+ * @param int $when Optional timestamp to run the next migration batch. Defaults to now.
75
+ *
76
+ * @return string The action ID
77
+ */
78
+ public function schedule_migration( $when = 0 ) {
79
+ $next = as_next_scheduled_action( self::HOOK );
80
+
81
+ if ( ! empty( $next ) ) {
82
+ return $next;
83
+ }
84
+
85
+ if ( empty( $when ) ) {
86
+ $when = time();
87
+ }
88
+
89
+ return as_schedule_single_action( $when, self::HOOK, array(), self::GROUP );
90
+ }
91
+
92
+ /**
93
+ * Remove the scheduled migration action.
94
+ */
95
+ public function unschedule_migration() {
96
+ as_unschedule_action( self::HOOK, null, self::GROUP );
97
+ }
98
+
99
+ /**
100
+ * Get migration batch schedule interval.
101
+ *
102
+ * @return int Seconds between migration runs. Defaults to 0 seconds to allow chaining migration via Async Runners.
103
+ */
104
+ private function get_schedule_interval() {
105
+ return (int) apply_filters( 'action_scheduler/migration_interval', 0 );
106
+ }
107
+
108
+ /**
109
+ * Get migration batch size.
110
+ *
111
+ * @return int Number of actions to migrate in each batch. Defaults to 250.
112
+ */
113
+ private function get_batch_size() {
114
+ return (int) apply_filters( 'action_scheduler/migration_batch_size', 250 );
115
+ }
116
+
117
+ /**
118
+ * Get migration runner object.
119
+ *
120
+ * @return Runner
121
+ */
122
+ private function get_migration_runner() {
123
+ $config = Controller::instance()->get_migration_config_object();
124
+
125
+ return new Runner( $config );
126
+ }
127
+
128
+ }
includes/vendor/action-scheduler/classes/schedules/ActionScheduler_CanceledSchedule.php ADDED
@@ -0,0 +1,57 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Class ActionScheduler_SimpleSchedule
5
+ */
6
+ class ActionScheduler_CanceledSchedule extends ActionScheduler_SimpleSchedule {
7
+
8
+ /**
9
+ * Deprecated property @see $this->__wakeup() for details.
10
+ **/
11
+ private $timestamp = NULL;
12
+
13
+ /**
14
+ * @param DateTime $after
15
+ *
16
+ * @return DateTime|null
17
+ */
18
+ public function calculate_next( DateTime $after ) {
19
+ return null;
20
+ }
21
+
22
+ /**
23
+ * Cancelled actions should never have a next schedule, even if get_next()
24
+ * is called with $after < $this->scheduled_date.
25
+ *
26
+ * @param DateTime $after
27
+ * @return DateTime|null
28
+ */
29
+ public function get_next( DateTime $after ) {
30
+ return null;
31
+ }
32
+
33
+ /**
34
+ * @return bool
35
+ */
36
+ public function is_recurring() {
37
+ return false;
38
+ }
39
+
40
+ /**
41
+ * Unserialize recurring schedules serialized/stored prior to AS 3.0.0
42
+ *
43
+ * Prior to Action Scheduler 3.0.0, schedules used different property names to refer
44
+ * to equivalent data. For example, ActionScheduler_IntervalSchedule::start_timestamp
45
+ * was the same as ActionScheduler_SimpleSchedule::timestamp. Action Scheduler 3.0.0
46
+ * aligned properties and property names for better inheritance. To maintain backward
47
+ * compatibility with schedules serialized and stored prior to 3.0, we need to correctly
48
+ * map the old property names with matching visibility.
49
+ */
50
+ public function __wakeup() {
51
+ if ( ! is_null( $this->timestamp ) ) {
52
+ $this->scheduled_timestamp = $this->timestamp;
53
+ unset( $this->timestamp );
54
+ }
55
+ parent::__wakeup();
56
+ }
57
+ }
includes/vendor/action-scheduler/classes/schedules/ActionScheduler_CronSchedule.php ADDED
@@ -0,0 +1,102 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Class ActionScheduler_CronSchedule
5
+ */
6
+ class ActionScheduler_CronSchedule extends ActionScheduler_Abstract_RecurringSchedule implements ActionScheduler_Schedule {
7
+
8
+ /**
9
+ * Deprecated property @see $this->__wakeup() for details.
10
+ **/
11
+ private $start_timestamp = NULL;
12
+
13
+ /**
14
+ * Deprecated property @see $this->__wakeup() for details.
15
+ **/
16
+ private $cron = NULL;
17
+
18
+ /**
19
+ * Wrapper for parent constructor to accept a cron expression string and map it to a CronExpression for this
20
+ * objects $recurrence property.
21
+ *
22
+ * @param DateTime $start The date & time to run the action at or after. If $start aligns with the CronSchedule passed via $recurrence, it will be used. If it does not align, the first matching date after it will be used.
23
+ * @param CronExpression|string $recurrence The CronExpression used to calculate the schedule's next instance.
24
+ * @param DateTime|null $first (Optional) The date & time the first instance of this interval schedule ran. Default null, meaning this is the first instance.
25
+ */
26
+ public function __construct( DateTime $start, $recurrence, DateTime $first = null ) {
27
+ if ( ! is_a( $recurrence, 'CronExpression' ) ) {
28
+ $recurrence = CronExpression::factory( $recurrence );
29
+ }
30
+
31
+ // For backward compatibility, we need to make sure the date is set to the first matching cron date, not whatever date is passed in. Importantly, by passing true as the 3rd param, if $start matches the cron expression, then it will be used. This was previously handled in the now deprecated next() method.
32
+ $date = $recurrence->getNextRunDate( $start, 0, true );
33
+
34
+ // parent::__construct() will set this to $date by default, but that may be different to $start now.
35
+ $first = empty( $first ) ? $start : $first;
36
+
37
+ parent::__construct( $date, $recurrence, $first );
38
+ }
39
+
40
+ /**
41
+ * Calculate when an instance of this schedule would start based on a given
42
+ * date & time using its the CronExpression.
43
+ *
44
+ * @param DateTime $after
45
+ * @return DateTime
46
+ */
47
+ protected function calculate_next( DateTime $after ) {
48
+ return $this->recurrence->getNextRunDate( $after, 0, false );
49
+ }
50
+
51
+ /**
52
+ * @return string
53
+ */
54
+ public function get_recurrence() {
55
+ return strval( $this->recurrence );
56
+ }
57
+
58
+ /**
59
+ * Serialize cron schedules with data required prior to AS 3.0.0
60
+ *
61
+ * Prior to Action Scheduler 3.0.0, reccuring schedules used different property names to
62
+ * refer to equivalent data. For example, ActionScheduler_IntervalSchedule::start_timestamp
63
+ * was the same as ActionScheduler_SimpleSchedule::timestamp. Action Scheduler 3.0.0
64
+ * aligned properties and property names for better inheritance. To guard against the
65
+ * possibility of infinite loops if downgrading to Action Scheduler < 3.0.0, we need to
66
+ * also store the data with the old property names so if it's unserialized in AS < 3.0,
67
+ * the schedule doesn't end up with a null recurrence.
68
+ *
69
+ * @return array
70
+ */
71
+ public function __sleep() {
72
+
73
+ $sleep_params = parent::__sleep();
74
+
75
+ $this->start_timestamp = $this->scheduled_timestamp;
76
+ $this->cron = $this->recurrence;
77
+
78
+ return array_merge( $sleep_params, array(
79
+ 'start_timestamp',
80
+ 'cron'
81
+ ) );
82
+ }
83
+
84
+ /**
85
+ * Unserialize cron schedules serialized/stored prior to AS 3.0.0
86
+ *
87
+ * For more background, @see ActionScheduler_Abstract_RecurringSchedule::__wakeup().
88
+ */
89
+ public function __wakeup() {
90
+ if ( is_null( $this->scheduled_timestamp ) && ! is_null( $this->start_timestamp ) ) {
91
+ $this->scheduled_timestamp = $this->start_timestamp;
92
+ unset( $this->start_timestamp );
93
+ }
94
+
95
+ if ( is_null( $this->recurrence ) && ! is_null( $this->cron ) ) {
96
+ $this->recurrence = $this->cron;
97
+ unset( $this->cron );
98
+ }
99
+ parent::__wakeup();
100
+ }
101
+ }
102
+
includes/vendor/action-scheduler/classes/schedules/ActionScheduler_IntervalSchedule.php ADDED
@@ -0,0 +1,81 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Class ActionScheduler_IntervalSchedule
5
+ */
6
+ class ActionScheduler_IntervalSchedule extends ActionScheduler_Abstract_RecurringSchedule implements ActionScheduler_Schedule {
7
+
8
+ /**
9
+ * Deprecated property @see $this->__wakeup() for details.
10
+ **/
11
+ private $start_timestamp = NULL;
12
+
13
+ /**
14
+ * Deprecated property @see $this->__wakeup() for details.
15
+ **/
16
+ private $interval_in_seconds = NULL;
17
+
18
+ /**
19
+ * Calculate when this schedule should start after a given date & time using
20
+ * the number of seconds between recurrences.
21
+ *
22
+ * @param DateTime $after
23
+ * @return DateTime
24
+ */
25
+ protected function calculate_next( DateTime $after ) {
26
+ $after->modify( '+' . (int) $this->get_recurrence() . ' seconds' );
27
+ return $after;
28
+ }
29
+
30
+ /**
31
+ * @return int
32
+ */
33
+ public function interval_in_seconds() {
34
+ _deprecated_function( __METHOD__, '3.0.0', '(int)ActionScheduler_Abstract_RecurringSchedule::get_recurrence()' );
35
+ return (int) $this->get_recurrence();
36
+ }
37
+
38
+ /**
39
+ * Serialize interval schedules with data required prior to AS 3.0.0
40
+ *
41
+ * Prior to Action Scheduler 3.0.0, reccuring schedules used different property names to
42
+ * refer to equivalent data. For example, ActionScheduler_IntervalSchedule::start_timestamp
43
+ * was the same as ActionScheduler_SimpleSchedule::timestamp. Action Scheduler 3.0.0
44
+ * aligned properties and property names for better inheritance. To guard against the
45
+ * possibility of infinite loops if downgrading to Action Scheduler < 3.0.0, we need to
46
+ * also store the data with the old property names so if it's unserialized in AS < 3.0,
47
+ * the schedule doesn't end up with a null/false/0 recurrence.
48
+ *
49
+ * @return array
50
+ */
51
+ public function __sleep() {
52
+
53
+ $sleep_params = parent::__sleep();
54
+
55
+ $this->start_timestamp = $this->scheduled_timestamp;
56
+ $this->interval_in_seconds = $this->recurrence;
57
+
58
+ return array_merge( $sleep_params, array(
59
+ 'start_timestamp',
60
+ 'interval_in_seconds'
61
+ ) );
62
+ }
63
+
64
+ /**
65
+ * Unserialize interval schedules serialized/stored prior to AS 3.0.0
66
+ *
67
+ * For more background, @see ActionScheduler_Abstract_RecurringSchedule::__wakeup().
68
+ */
69
+ public function __wakeup() {
70
+ if ( is_null( $this->scheduled_timestamp ) && ! is_null( $this->start_timestamp ) ) {
71
+ $this->scheduled_timestamp = $this->start_timestamp;
72
+ unset( $this->start_timestamp );
73
+ }
74
+
75
+ if ( is_null( $this->recurrence ) && ! is_null( $this->interval_in_seconds ) ) {
76
+ $this->recurrence = $this->interval_in_seconds;
77
+ unset( $this->interval_in_seconds );
78
+ }
79
+ parent::__wakeup();
80
+ }
81
+ }
includes/vendor/action-scheduler/classes/schedules/ActionScheduler_NullSchedule.php ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Class ActionScheduler_NullSchedule
5
+ */
6
+ class ActionScheduler_NullSchedule extends ActionScheduler_SimpleSchedule {
7
+
8
+ /**
9
+ * Make the $date param optional and default to null.
10
+ *
11
+ * @param null $date The date & time to run the action.
12
+ */
13
+ public function __construct( DateTime $date = null ) {
14
+ $this->scheduled_date = null;
15
+ }
16
+
17
+ /**
18
+ * This schedule has no scheduled DateTime, so we need to override the parent __sleep()
19
+ * @return array
20
+ */
21
+ public function __sleep() {
22
+ return array();
23
+ }
24
+
25
+ public function __wakeup() {
26
+ $this->scheduled_date = null;
27
+ }
28
+ }
includes/vendor/action-scheduler/classes/{ActionScheduler_Schedule.php → schedules/ActionScheduler_Schedule.php} RENAMED
File without changes
includes/vendor/action-scheduler/classes/schedules/ActionScheduler_SimpleSchedule.php ADDED
@@ -0,0 +1,71 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Class ActionScheduler_SimpleSchedule
5
+ */
6
+ class ActionScheduler_SimpleSchedule extends ActionScheduler_Abstract_Schedule {
7
+
8
+ /**
9
+ * Deprecated property @see $this->__wakeup() for details.
10
+ **/
11
+ private $timestamp = NULL;
12
+
13
+ /**
14
+ * @param DateTime $after
15
+ *
16
+ * @return DateTime|null
17
+ */
18
+ public function calculate_next( DateTime $after ) {
19
+ return null;
20
+ }
21
+
22
+ /**
23
+ * @return bool
24
+ */
25
+ public function is_recurring() {
26
+ return false;
27
+ }
28
+
29
+ /**
30
+ * Serialize schedule with data required prior to AS 3.0.0
31
+ *
32
+ * Prior to Action Scheduler 3.0.0, schedules used different property names to refer
33
+ * to equivalent data. For example, ActionScheduler_IntervalSchedule::start_timestamp
34
+ * was the same as ActionScheduler_SimpleSchedule::timestamp. Action Scheduler 3.0.0
35
+ * aligned properties and property names for better inheritance. To guard against the
36
+ * scheduled date for single actions always being seen as "now" if downgrading to
37
+ * Action Scheduler < 3.0.0, we need to also store the data with the old property names
38
+ * so if it's unserialized in AS < 3.0, the schedule doesn't end up with a null recurrence.
39
+ *
40
+ * @return array
41
+ */
42
+ public function __sleep() {
43
+
44
+ $sleep_params = parent::__sleep();
45
+
46
+ $this->timestamp = $this->scheduled_timestamp;
47
+
48
+ return array_merge( $sleep_params, array(
49
+ 'timestamp',
50
+ ) );
51
+ }
52
+
53
+ /**
54
+ * Unserialize recurring schedules serialized/stored prior to AS 3.0.0
55
+ *
56
+ * Prior to Action Scheduler 3.0.0, schedules used different property names to refer
57
+ * to equivalent data. For example, ActionScheduler_IntervalSchedule::start_timestamp
58
+ * was the same as ActionScheduler_SimpleSchedule::timestamp. Action Scheduler 3.0.0
59
+ * aligned properties and property names for better inheritance. To maintain backward
60
+ * compatibility with schedules serialized and stored prior to 3.0, we need to correctly
61
+ * map the old property names with matching visibility.
62
+ */
63
+ public function __wakeup() {
64
+
65
+ if ( is_null( $this->scheduled_timestamp ) && ! is_null( $this->timestamp ) ) {
66
+ $this->scheduled_timestamp = $this->timestamp;
67
+ unset( $this->timestamp );
68
+ }
69
+ parent::__wakeup();
70
+ }
71
+ }
includes/vendor/action-scheduler/classes/schema/ActionScheduler_LoggerSchema.php ADDED
@@ -0,0 +1,48 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Class ActionScheduler_LoggerSchema
5
+ *
6
+ * @codeCoverageIgnore
7
+ *
8
+ * Creates a custom table for storing action logs
9
+ */
10
+ class ActionScheduler_LoggerSchema extends ActionScheduler_Abstract_Schema {
11
+ const LOG_TABLE = 'actionscheduler_logs';
12
+
13
+ /**
14
+ * @var int Increment this value to trigger a schema update.
15
+ */
16
+ protected $schema_version = 2;
17
+
18
+ public function __construct() {
19
+ $this->tables = [
20
+ self::LOG_TABLE,
21
+ ];
22
+ }
23
+
24
+ protected function get_table_definition( $table ) {
25
+ global $wpdb;
26
+ $table_name = $wpdb->$table;
27
+ $charset_collate = $wpdb->get_charset_collate();
28
+ $max_index_length = 191; // @see wp_get_db_schema()
29
+ switch ( $table ) {
30
+
31
+ case self::LOG_TABLE:
32
+
33
+ return "CREATE TABLE {$table_name} (
34
+ log_id bigint(20) unsigned NOT NULL auto_increment,
35
+ action_id bigint(20) unsigned NOT NULL,
36
+ message text NOT NULL,
37
+ log_date_gmt datetime NOT NULL default '0000-00-00 00:00:00',
38
+ log_date_local datetime NOT NULL default '0000-00-00 00:00:00',
39
+ PRIMARY KEY (log_id),
40
+ KEY action_id (action_id),
41
+ KEY log_date_gmt (log_date_gmt)
42
+ ) $charset_collate";
43
+
44
+ default:
45
+ return '';
46
+ }
47
+ }
48
+ }
includes/vendor/action-scheduler/classes/schema/ActionScheduler_StoreSchema.php ADDED
@@ -0,0 +1,82 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Class ActionScheduler_StoreSchema
5
+ *
6
+ * @codeCoverageIgnore
7
+ *
8
+ * Creates custom tables for storing scheduled actions
9
+ */
10
+ class ActionScheduler_StoreSchema extends ActionScheduler_Abstract_Schema {
11
+ const ACTIONS_TABLE = 'actionscheduler_actions';
12
+ const CLAIMS_TABLE = 'actionscheduler_claims';
13
+ const GROUPS_TABLE = 'actionscheduler_groups';
14
+
15
+ /**
16
+ * @var int Increment this value to trigger a schema update.
17
+ */
18
+ protected $schema_version = 2;
19
+
20
+ public function __construct() {
21
+ $this->tables = [
22
+ self::ACTIONS_TABLE,
23
+ self::CLAIMS_TABLE,
24
+ self::GROUPS_TABLE,
25
+ ];
26
+ }
27
+
28
+ protected function get_table_definition( $table ) {
29
+ global $wpdb;
30
+ $table_name = $wpdb->$table;
31
+ $charset_collate = $wpdb->get_charset_collate();
32
+ $max_index_length = 191; // @see wp_get_db_schema()
33
+ switch ( $table ) {
34
+
35
+ case self::ACTIONS_TABLE:
36
+
37
+ return "CREATE TABLE {$table_name} (
38
+ action_id bigint(20) unsigned NOT NULL auto_increment,
39
+ hook varchar(191) NOT NULL,
40
+ status varchar(20) NOT NULL,
41
+ scheduled_date_gmt datetime NOT NULL default '0000-00-00 00:00:00',
42
+ scheduled_date_local datetime NOT NULL default '0000-00-00 00:00:00',
43
+ args varchar($max_index_length),
44
+ schedule longtext,
45
+ group_id bigint(20) unsigned NOT NULL default '0',
46
+ attempts int(11) NOT NULL default '0',
47
+ last_attempt_gmt datetime NOT NULL default '0000-00-00 00:00:00',
48
+ last_attempt_local datetime NOT NULL default '0000-00-00 00:00:00',
49
+ claim_id bigint(20) unsigned NOT NULL default '0',
50
+ PRIMARY KEY (action_id),
51
+ KEY hook (hook($max_index_length)),
52
+ KEY status (status),
53
+ KEY scheduled_date_gmt (scheduled_date_gmt),
54
+ KEY args (args($max_index_length)),
55
+ KEY group_id (group_id),
56
+ KEY last_attempt_gmt (last_attempt_gmt),
57
+ KEY claim_id (claim_id)
58
+ ) $charset_collate";
59
+
60
+ case self::CLAIMS_TABLE:
61
+
62
+ return "CREATE TABLE {$table_name} (
63
+ claim_id bigint(20) unsigned NOT NULL auto_increment,
64
+ date_created_gmt datetime NOT NULL default '0000-00-00 00:00:00',
65
+ PRIMARY KEY (claim_id),
66
+ KEY date_created_gmt (date_created_gmt)
67
+ ) $charset_collate";
68
+
69
+ case self::GROUPS_TABLE:
70
+
71
+ return "CREATE TABLE {$table_name} (
72
+ group_id bigint(20) unsigned NOT NULL auto_increment,
73
+ slug varchar(255) NOT NULL,
74
+ PRIMARY KEY (group_id),
75
+ KEY slug (slug($max_index_length))
76
+ ) $charset_collate";
77
+
78
+ default:
79
+ return '';
80
+ }
81
+ }
82
+ }
includes/vendor/action-scheduler/composer.json CHANGED
@@ -1,11 +1,36 @@
1
  {
2
- "name": "prospress/action-scheduler",
3
  "description": "Action Scheduler for WordPress and WooCommerce",
 
4
  "type": "wordpress-plugin",
5
- "license": "GPL-3.0",
 
6
  "minimum-stability": "dev",
7
  "require": {},
8
  "require-dev": {
9
- "wp-cli/wp-cli": "1.5.1"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
10
  }
11
  }
1
  {
2
+ "name": "woocommerce/action-scheduler",
3
  "description": "Action Scheduler for WordPress and WooCommerce",
4
+ "homepage": "https://actionscheduler.org/",
5
  "type": "wordpress-plugin",
6
+ "license": "GPL-3.0-or-later",
7
+ "prefer-stable": true,
8
  "minimum-stability": "dev",
9
  "require": {},
10
  "require-dev": {
11
+ "phpunit/phpunit": "^5.6",
12
+ "wp-cli/wp-cli": "~1.5.1",
13
+ "woocommerce/woocommerce-sniffs": "0.0.8"
14
+ },
15
+ "scripts": {
16
+ "test": [
17
+ "phpunit"
18
+ ],
19
+ "phpcs": [
20
+ "phpcs -s -p"
21
+ ],
22
+ "phpcs-pre-commit": [
23
+ "phpcs -s -p -n"
24
+ ],
25
+ "phpcbf": [
26
+ "phpcbf -p"
27
+ ]
28
+ },
29
+ "extra": {
30
+ "scripts-description": {
31
+ "test": "Run unit tests",
32
+ "phpcs": "Analyze code against the WordPress coding standards with PHP_CodeSniffer",
33
+ "phpcbf": "Fix coding standards warnings/errors automatically with PHP Code Beautifier"
34
+ }
35
  }
36
  }
includes/vendor/action-scheduler/composer.lock CHANGED
@@ -1,38 +1,35 @@
1
  {
2
  "_readme": [
3
  "This file locks the dependencies of your project to a known state",
4
- "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
5
  "This file is @generated automatically"
6
  ],
7
- "content-hash": "f4556531e7b95173d1b769b3d7350926",
8
  "packages": [],
9
  "packages-dev": [
10
  {
11
  "name": "composer/ca-bundle",
12
- "version": "dev-master",
13
  "source": {
14
  "type": "git",
15
  "url": "https://github.com/composer/ca-bundle.git",
16
- "reference": "b17e6153cb7f33c7e44eb59578dc12eee5dc8e12"
17
  },
18
  "dist": {
19
  "type": "zip",
20
- "url": "https://api.github.com/repos/composer/ca-bundle/zipball/b17e6153cb7f33c7e44eb59578dc12eee5dc8e12",
21
- "reference": "b17e6153cb7f33c7e44eb59578dc12eee5dc8e12",
22
  "shasum": ""
23
  },
24
  "require": {
25
  "ext-openssl": "*",
26
  "ext-pcre": "*",
27
- "php": "^5.3.2 || ^7.0"
28
  },
29
  "require-dev": {
30
- "phpunit/phpunit": "^4.5",
31
  "psr/log": "^1.0",
32
- "symfony/process": "^2.5 || ^3.0"
33
- },
34
- "suggest": {
35
- "symfony/process": "This is necessary to reliably check whether openssl_x509_parse is vulnerable on older php versions, but can be ignored on PHP 5.5.6+"
36
  },
37
  "type": "library",
38
  "extra": {
@@ -64,39 +61,42 @@
64
  "ssl",
65
  "tls"
66
  ],
67
- "time": "2017-03-06T11:59:08+00:00"
68
  },
69
  {
70
  "name": "composer/composer",
71
- "version": "dev-master",
72
  "source": {
73
  "type": "git",
74
  "url": "https://github.com/composer/composer.git",
75
- "reference": "82c27a68bc5cb76f3d00b82c27496e3cdbb6d4ff"
76
  },
77
  "dist": {
78
  "type": "zip",
79
- "url": "https://api.github.com/repos/composer/composer/zipball/82c27a68bc5cb76f3d00b82c27496e3cdbb6d4ff",
80
- "reference": "82c27a68bc5cb76f3d00b82c27496e3cdbb6d4ff",
81
  "shasum": ""
82
  },
83
  "require": {
84
  "composer/ca-bundle": "^1.0",
85
  "composer/semver": "^1.0",
86
- "composer/spdx-licenses": "^1.0",
 
87
  "justinrainbow/json-schema": "^3.0 || ^4.0 || ^5.0",
88
  "php": "^5.3.2 || ^7.0",
89
  "psr/log": "^1.0",
90
- "seld/cli-prompt": "^1.0",
91
  "seld/jsonlint": "^1.4",
92
  "seld/phar-utils": "^1.0",
93
- "symfony/console": "^2.7 || ^3.0",
94
- "symfony/filesystem": "^2.7 || ^3.0",
95
- "symfony/finder": "^2.7 || ^3.0",
96
- "symfony/process": "^2.7 || ^3.0"
 
 
 
97
  },
98
  "require-dev": {
99
- "phpunit/phpunit": "^4.5 || ^5.0.5",
100
  "phpunit/phpunit-mock-objects": "^2.3 || ^3.0"
101
  },
102
  "suggest": {
@@ -110,7 +110,7 @@
110
  "type": "library",
111
  "extra": {
112
  "branch-alias": {
113
- "dev-master": "1.6-dev"
114
  }
115
  },
116
  "autoload": {
@@ -134,27 +134,27 @@
134
  "homepage": "http://seld.be"
135
  }
136
  ],
137
- "description": "Composer helps you declare, manage and install dependencies of PHP projects, ensuring you have the right stack everywhere.",
138
  "homepage": "https://getcomposer.org/",
139
  "keywords": [
140
  "autoload",
141
  "dependency",
142
  "package"
143
  ],
144
- "time": "2017-08-09T14:23:46+00:00"
145
  },
146
  {
147
  "name": "composer/semver",
148
- "version": "dev-master",
149
  "source": {
150
  "type": "git",
151
  "url": "https://github.com/composer/semver.git",
152
- "reference": "7ea669582e6396857cf6d1c0a6cd2728f4e7e383"
153
  },
154
  "dist": {
155
  "type": "zip",
156
- "url": "https://api.github.com/repos/composer/semver/zipball/7ea669582e6396857cf6d1c0a6cd2728f4e7e383",
157
- "reference": "7ea669582e6396857cf6d1c0a6cd2728f4e7e383",
158
  "shasum": ""
159
  },
160
  "require": {
@@ -203,28 +203,27 @@
203
  "validation",
204
  "versioning"
205
  ],
206
- "time": "2017-05-15T12:49:06+00:00"
207
  },
208
  {
209
  "name": "composer/spdx-licenses",
210
- "version": "dev-master",
211
  "source": {
212
  "type": "git",
213
  "url": "https://github.com/composer/spdx-licenses.git",
214
- "reference": "2603a0d7ddc00a015deb576fa5297ca43dee6b1c"
215
  },
216
  "dist": {
217
  "type": "zip",
218
- "url": "https://api.github.com/repos/composer/spdx-licenses/zipball/2603a0d7ddc00a015deb576fa5297ca43dee6b1c",
219
- "reference": "2603a0d7ddc00a015deb576fa5297ca43dee6b1c",
220
  "shasum": ""
221
  },
222
  "require": {
223
- "php": "^5.3.2 || ^7.0"
224
  },
225
  "require-dev": {
226
- "phpunit/phpunit": "^4.5 || ^5.0.5",
227
- "phpunit/phpunit-mock-objects": "2.3.0 || ^3.0"
228
  },
229
  "type": "library",
230
  "extra": {
@@ -264,29 +263,195 @@
264
  "spdx",
265
  "validator"
266
  ],
267
- "time": "2017-04-03T19:08:52+00:00"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
268
  },
269
  {
270
  "name": "justinrainbow/json-schema",
271
- "version": "5.x-dev",
272
  "source": {
273
  "type": "git",
274
  "url": "https://github.com/justinrainbow/json-schema.git",
275
- "reference": "36ed4d935f8f5eb958dbd29e1fa5a241ec3ece4d"
276
  },
277
  "dist": {
278
  "type": "zip",
279
- "url": "https://api.github.com/repos/justinrainbow/json-schema/zipball/36ed4d935f8f5eb958dbd29e1fa5a241ec3ece4d",
280
- "reference": "36ed4d935f8f5eb958dbd29e1fa5a241ec3ece4d",
281
  "shasum": ""
282
  },
283
  "require": {
284
  "php": ">=5.3.3"
285
  },
286
  "require-dev": {
287
- "friendsofphp/php-cs-fixer": "^2.1",
288
  "json-schema/json-schema-test-suite": "1.2.0",
289
- "phpunit/phpunit": "^4.8.22"
290
  },
291
  "bin": [
292
  "bin/validate-json"
@@ -330,7 +495,7 @@
330
  "json",
331
  "schema"
332
  ],
333
- "time": "2017-06-23T11:43:36+00:00"
334
  },
335
  {
336
  "name": "mustache/mustache",
@@ -378,6 +543,54 @@
378
  ],
379
  "time": "2017-07-11T12:54:05+00:00"
380
  },
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
381
  {
382
  "name": "nb/oxymel",
383
  "version": "v0.1.0",
@@ -420,221 +633,253 @@
420
  "time": "2013-02-24T15:01:54+00:00"
421
  },
422
  {
423
- "name": "psr/container",
424
- "version": "dev-master",
425
  "source": {
426
  "type": "git",
427
- "url": "https://github.com/php-fig/container.git",
428
- "reference": "2cc4a01788191489dc7459446ba832fa79a216a7"
429
  },
430
  "dist": {
431
  "type": "zip",
432
- "url": "https://api.github.com/repos/php-fig/container/zipball/2cc4a01788191489dc7459446ba832fa79a216a7",
433
- "reference": "2cc4a01788191489dc7459446ba832fa79a216a7",
434
  "shasum": ""
435
  },
436
  "require": {
437
- "php": ">=5.3.0"
 
438
  },
439
- "type": "library",
440
- "extra": {
441
- "branch-alias": {
442
- "dev-master": "1.0.x-dev"
443
- }
444
  },
445
- "autoload": {
446
- "psr-4": {
447
- "Psr\\Container\\": "src/"
448
- }
 
 
449
  },
 
450
  "notification-url": "https://packagist.org/downloads/",
451
  "license": [
452
- "MIT"
453
  ],
454
  "authors": [
455
  {
456
- "name": "PHP-FIG",
457
- "homepage": "http://www.php-fig.org/"
 
 
 
 
 
 
 
 
 
 
458
  }
459
  ],
460
- "description": "Common Container Interface (PHP FIG PSR-11)",
461
- "homepage": "https://github.com/php-fig/container",
462
  "keywords": [
463
- "PSR-11",
464
- "container",
465
- "container-interface",
466
- "container-interop",
467
- "psr"
468
  ],
469
- "time": "2017-06-28T15:35:32+00:00"
470
  },
471
  {
472
- "name": "psr/log",
473
- "version": "dev-master",
474
  "source": {
475
  "type": "git",
476
- "url": "https://github.com/php-fig/log.git",
477
- "reference": "4ebe3a8bf773a19edfe0a84b6585ba3d401b724d"
478
  },
479
  "dist": {
480
  "type": "zip",
481
- "url": "https://api.github.com/repos/php-fig/log/zipball/4ebe3a8bf773a19edfe0a84b6585ba3d401b724d",
482
- "reference": "4ebe3a8bf773a19edfe0a84b6585ba3d401b724d",
483
  "shasum": ""
484
  },
485
  "require": {
486
- "php": ">=5.3.0"
487
  },
488
- "type": "library",
489
- "extra": {
490
- "branch-alias": {
491
- "dev-master": "1.0.x-dev"
492
- }
493
  },
494
- "autoload": {
495
- "psr-4": {
496
- "Psr\\Log\\": "Psr/Log/"
497
- }
498
  },
 
499
  "notification-url": "https://packagist.org/downloads/",
500
  "license": [
501
- "MIT"
502
  ],
503
  "authors": [
504
  {
505
- "name": "PHP-FIG",
506
- "homepage": "http://www.php-fig.org/"
 
 
 
 
507
  }
508
  ],
509
- "description": "Common interface for logging libraries",
510
- "homepage": "https://github.com/php-fig/log",
511
  "keywords": [
512
- "log",
513
- "psr",
514
- "psr-3"
 
 
515
  ],
516
- "time": "2016-10-10T12:19:37+00:00"
517
  },
518
  {
519
- "name": "ramsey/array_column",
520
- "version": "1.1.3",
521
  "source": {
522
  "type": "git",
523
- "url": "https://github.com/ramsey/array_column.git",
524
- "reference": "f8e52eb28e67eb50e613b451dd916abcf783c1db"
525
  },
526
  "dist": {
527
  "type": "zip",
528
- "url": "https://api.github.com/repos/ramsey/array_column/zipball/f8e52eb28e67eb50e613b451dd916abcf783c1db",
529
- "reference": "f8e52eb28e67eb50e613b451dd916abcf783c1db",
530
  "shasum": ""
531
  },
 
 
 
 
532
  "require-dev": {
533
- "jakub-onderka/php-parallel-lint": "0.8.*",
534
- "phpunit/phpunit": "~4.5",
535
- "satooshi/php-coveralls": "0.6.*",
536
- "squizlabs/php_codesniffer": "~2.2"
537
  },
538
- "type": "library",
539
- "autoload": {
540
- "files": [
541
- "src/array_column.php"
542
- ]
543
  },
 
544
  "notification-url": "https://packagist.org/downloads/",
545
  "license": [
546
- "MIT"
547
  ],
548
  "authors": [
549
  {
550
- "name": "Ben Ramsey",
551
- "homepage": "http://benramsey.com"
 
 
 
 
552
  }
553
  ],
554
- "description": "Provides functionality for array_column() to projects using PHP earlier than version 5.5.",
555
- "homepage": "https://github.com/ramsey/array_column",
556
  "keywords": [
557
- "array",
558
- "array_column",
559
- "column"
 
560
  ],
561
- "time": "2015-03-20T22:07:39+00:00"
562
  },
563
  {
564
- "name": "rmccue/requests",
565
- "version": "v1.7.0",
566
  "source": {
567
  "type": "git",
568
- "url": "https://github.com/rmccue/Requests.git",
569
- "reference": "87932f52ffad70504d93f04f15690cf16a089546"
570
  },
571
  "dist": {
572
  "type": "zip",
573
- "url": "https://api.github.com/repos/rmccue/Requests/zipball/87932f52ffad70504d93f04f15690cf16a089546",
574
- "reference": "87932f52ffad70504d93f04f15690cf16a089546",
575
  "shasum": ""
576
  },
577
  "require": {
578
- "php": ">=5.2"
579
  },
580
  "require-dev": {
581
- "requests/test-server": "dev-master"
582
  },
583
  "type": "library",
 
 
 
 
 
584
  "autoload": {
585
- "psr-0": {
586
- "Requests": "library/"
587
  }
588
  },
589
  "notification-url": "https://packagist.org/downloads/",
590
  "license": [
591
- "ISC"
592
  ],
593
  "authors": [
594
  {
595
- "name": "Ryan McCue",
596
- "homepage": "http://ryanmccue.info"
597
  }
598
  ],
599
- "description": "A HTTP library written in PHP, for human beings.",
600
- "homepage": "http://github.com/rmccue/Requests",
601
  "keywords": [
602
- "curl",
603
- "fsockopen",
604
- "http",
605
- "idna",
606
- "ipv6",
607
- "iri",
608
- "sockets"
609
  ],
610
- "time": "2016-10-13T00:11:37+00:00"
611
  },
612
  {
613
- "name": "seld/cli-prompt",
614
- "version": "dev-master",
615
  "source": {
616
  "type": "git",
617
- "url": "https://github.com/Seldaek/cli-prompt.git",
618
- "reference": "a19a7376a4689d4d94cab66ab4f3c816019ba8dd"
619
  },
620
  "dist": {
621
  "type": "zip",
622
- "url": "https://api.github.com/repos/Seldaek/cli-prompt/zipball/a19a7376a4689d4d94cab66ab4f3c816019ba8dd",
623
- "reference": "a19a7376a4689d4d94cab66ab4f3c816019ba8dd",
624
  "shasum": ""
625
  },
626
  "require": {
627
- "php": ">=5.3"
 
 
 
 
 
 
 
 
628
  },
629
  "type": "library",
630
  "extra": {
631
  "branch-alias": {
632
- "dev-master": "1.x-dev"
633
  }
634
  },
635
  "autoload": {
636
  "psr-4": {
637
- "Seld\\CliPrompt\\": "src/"
 
 
638
  }
639
  },
640
  "notification-url": "https://packagist.org/downloads/",
@@ -643,39 +888,1237 @@
643
  ],
644
  "authors": [
645
  {
646
- "name": "Jordi Boggiano",
647
- "email": "j.boggiano@seld.be"
648
  }
649
  ],
650
- "description": "Allows you to prompt for user input on the command line, and optionally hide the characters they type",
651
- "keywords": [
652
- "cli",
653
- "console",
654
- "hidden",
655
- "input",
656
- "prompt"
657
- ],
658
- "time": "2017-03-18T11:32:45+00:00"
659
  },
660
  {
661
- "name": "seld/jsonlint",
662
- "version": "1.6.1",
663
  "source": {
664
  "type": "git",
665
- "url": "https://github.com/Seldaek/jsonlint.git",
666
- "reference": "50d63f2858d87c4738d5b76a7dcbb99fa8cf7c77"
667
  },
668
  "dist": {
669
  "type": "zip",
670
- "url": "https://api.github.com/repos/Seldaek/jsonlint/zipball/50d63f2858d87c4738d5b76a7dcbb99fa8cf7c77",
671
- "reference": "50d63f2858d87c4738d5b76a7dcbb99fa8cf7c77",
672
  "shasum": ""
673
  },
674
  "require": {
675
- "php": "^5.3 || ^7.0"
 
676
  },
677
  "require-dev": {
678
- "phpunit/phpunit": "^4.5"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
679
  },
680
  "bin": [
681
  "bin/jsonlint"
@@ -704,11 +2147,11 @@
704
  "parser",
705
  "validator"
706
  ],
707
- "time": "2017-06-18T15:11:04+00:00"
708
  },
709
  {
710
  "name": "seld/phar-utils",
711
- "version": "dev-master",
712
  "source": {
713
  "type": "git",
714
  "url": "https://github.com/Seldaek/phar-utils.git",
@@ -748,25 +2191,77 @@
748
  "keywords": [
749
  "phra"
750
  ],
751
- "time": "2015-10-13T18:44:15+00:00"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
752
  },
753
  {
754
  "name": "symfony/config",
755
- "version": "3.4.x-dev",
756
  "source": {
757
  "type": "git",
758
  "url": "https://github.com/symfony/config.git",
759
- "reference": "d668d8c0502d2b485c00d107db65fdbc56c26282"
760
  },
761
  "dist": {
762
  "type": "zip",
763
- "url": "https://api.github.com/repos/symfony/config/zipball/d668d8c0502d2b485c00d107db65fdbc56c26282",
764
- "reference": "d668d8c0502d2b485c00d107db65fdbc56c26282",
765
  "shasum": ""
766
  },
767
  "require": {
768
  "php": "^5.5.9|>=7.0.8",
769
- "symfony/filesystem": "~2.8|~3.0|~4.0"
 
770
  },
771
  "conflict": {
772
  "symfony/dependency-injection": "<3.3",
@@ -774,6 +2269,7 @@
774
  },
775
  "require-dev": {
776
  "symfony/dependency-injection": "~3.3|~4.0",
 
777
  "symfony/finder": "~3.3|~4.0",
778
  "symfony/yaml": "~3.0|~4.0"
779
  },
@@ -810,20 +2306,20 @@
810
  ],
811
  "description": "Symfony Config Component",
812
  "homepage": "https://symfony.com",
813
- "time": "2017-08-05T17:34:46+00:00"
814
  },
815
  {
816
  "name": "symfony/console",
817
- "version": "3.4.x-dev",
818
  "source": {
819
  "type": "git",
820
  "url": "https://github.com/symfony/console.git",
821
- "reference": "0e283478c2d68c9bf9cc52592ad1ef1834083a85"
822
  },
823
  "dist": {
824
  "type": "zip",
825
- "url": "https://api.github.com/repos/symfony/console/zipball/0e283478c2d68c9bf9cc52592ad1ef1834083a85",
826
- "reference": "0e283478c2d68c9bf9cc52592ad1ef1834083a85",
827
  "shasum": ""
828
  },
829
  "require": {
@@ -832,15 +2328,17 @@
832
  "symfony/polyfill-mbstring": "~1.0"
833
  },
834
  "conflict": {
835
- "symfony/dependency-injection": "<3.3",
836
  "symfony/process": "<3.3"
837
  },
 
 
 
838
  "require-dev": {
839
  "psr/log": "~1.0",
840
  "symfony/config": "~3.3|~4.0",
841
- "symfony/dependency-injection": "~3.3|~4.0",
842
  "symfony/event-dispatcher": "~2.8|~3.0|~4.0",
843
- "symfony/http-kernel": "~2.8|~3.0|~4.0",
844
  "symfony/lock": "~3.4|~4.0",
845
  "symfony/process": "~3.3|~4.0"
846
  },
@@ -880,20 +2378,20 @@
880
  ],
881
  "description": "Symfony Console Component",
882
  "homepage": "https://symfony.com",
883
- "time": "2017-08-10T07:07:17+00:00"
884
  },
885
  {
886
  "name": "symfony/debug",
887
- "version": "3.4.x-dev",
888
  "source": {
889
  "type": "git",
890
  "url": "https://github.com/symfony/debug.git",
891
- "reference": "50bda5b4b8641616d45254c6855bcd45f2f64187"
892
  },
893
  "dist": {
894
  "type": "zip",
895
- "url": "https://api.github.com/repos/symfony/debug/zipball/50bda5b4b8641616d45254c6855bcd45f2f64187",
896
- "reference": "50bda5b4b8641616d45254c6855bcd45f2f64187",
897
  "shasum": ""
898
  },
899
  "require": {
@@ -936,20 +2434,20 @@
936
  ],
937
  "description": "Symfony Debug Component",
938
  "homepage": "https://symfony.com",
939
- "time": "2017-08-10T07:07:17+00:00"
940
  },
941
  {
942
  "name": "symfony/dependency-injection",
943
- "version": "3.4.x-dev",
944
  "source": {
945
  "type": "git",
946
  "url": "https://github.com/symfony/dependency-injection.git",
947
- "reference": "aaee88765cb21a838e8da26d6acda4ca2ae3a2ea"
948
  },
949
  "dist": {
950
  "type": "zip",
951
- "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/aaee88765cb21a838e8da26d6acda4ca2ae3a2ea",
952
- "reference": "aaee88765cb21a838e8da26d6acda4ca2ae3a2ea",
953
  "shasum": ""
954
  },
955
  "require": {
@@ -957,7 +2455,7 @@
957
  "psr/container": "^1.0"
958
  },
959
  "conflict": {
960
- "symfony/config": "<3.3.1",
961
  "symfony/finder": "<3.3",
962
  "symfony/proxy-manager-bridge": "<3.4",
963
  "symfony/yaml": "<3.4"
@@ -1007,20 +2505,20 @@
1007
  ],
1008
  "description": "Symfony DependencyInjection Component",
1009
  "homepage": "https://symfony.com",
1010
- "time": "2017-08-10T19:43:00+00:00"
1011
  },
1012
  {
1013
  "name": "symfony/event-dispatcher",
1014
- "version": "3.4.x-dev",
1015
  "source": {
1016
  "type": "git",
1017
  "url": "https://github.com/symfony/event-dispatcher.git",
1018
- "reference": "cd8b015f859e6b60933324db00067c2f060b4d18"
1019
  },
1020
  "dist": {
1021
  "type": "zip",
1022
- "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/cd8b015f859e6b60933324db00067c2f060b4d18",
1023
- "reference": "cd8b015f859e6b60933324db00067c2f060b4d18",
1024
  "shasum": ""
1025
  },
1026
  "require": {
@@ -1070,24 +2568,25 @@
1070
  ],
1071
  "description": "Symfony EventDispatcher Component",
1072
  "homepage": "https://symfony.com",
1073
- "time": "2017-08-03T09:34:20+00:00"
1074
  },
1075
  {
1076
  "name": "symfony/filesystem",
1077
- "version": "3.4.x-dev",
1078
  "source": {
1079
  "type": "git",
1080
  "url": "https://github.com/symfony/filesystem.git",
1081
- "reference": "e4d366b620c8b6e2d4977c154f6a1d5b416db4dd"
1082
  },
1083
  "dist": {
1084
  "type": "zip",
1085
- "url": "https://api.github.com/repos/symfony/filesystem/zipball/e4d366b620c8b6e2d4977c154f6a1d5b416db4dd",
1086
- "reference": "e4d366b620c8b6e2d4977c154f6a1d5b416db4dd",
1087
  "shasum": ""
1088
  },
1089
  "require": {
1090
- "php": "^5.5.9|>=7.0.8"
 
1091
  },
1092
  "type": "library",
1093
  "extra": {
@@ -1119,20 +2618,20 @@
1119
  ],
1120
  "description": "Symfony Filesystem Component",
1121
  "homepage": "https://symfony.com",
1122
- "time": "2017-08-03T09:34:20+00:00"
1123
  },
1124
  {
1125
  "name": "symfony/finder",
1126
- "version": "3.4.x-dev",
1127
  "source": {
1128
  "type": "git",
1129
  "url": "https://github.com/symfony/finder.git",
1130
- "reference": "bf0450cfe7282c5f06539c4733ba64273e91e918"
1131
  },
1132
  "dist": {
1133
  "type": "zip",
1134
- "url": "https://api.github.com/repos/symfony/finder/zipball/bf0450cfe7282c5f06539c4733ba64273e91e918",
1135
- "reference": "bf0450cfe7282c5f06539c4733ba64273e91e918",
1136
  "shasum": ""
1137
  },
1138
  "require": {
@@ -1168,20 +2667,78 @@
1168
  ],
1169
  "description": "Symfony Finder Component",
1170
  "homepage": "https://symfony.com",
1171
- "time": "2017-08-03T09:34:20+00:00"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1172
  },
1173
  {
1174
  "name": "symfony/polyfill-mbstring",
1175
- "version": "dev-master",
1176
  "source": {
1177
  "type": "git",
1178
  "url": "https://github.com/symfony/polyfill-mbstring.git",
1179
- "reference": "7c8fae0ac1d216eb54349e6a8baa57d515fe8803"
1180
  },
1181
  "dist": {
1182
  "type": "zip",
1183
- "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/7c8fae0ac1d216eb54349e6a8baa57d515fe8803",
1184
- "reference": "7c8fae0ac1d216eb54349e6a8baa57d515fe8803",
1185
  "shasum": ""
1186
  },
1187
  "require": {
@@ -1193,7 +2750,7 @@
1193
  "type": "library",
1194
  "extra": {
1195
  "branch-alias": {
1196
- "dev-master": "1.5-dev"
1197
  }
1198
  },
1199
  "autoload": {
@@ -1227,20 +2784,20 @@
1227
  "portable",
1228
  "shim"
1229
  ],
1230
- "time": "2017-06-14T15:44:48+00:00"
1231
  },
1232
  {
1233
  "name": "symfony/process",
1234
- "version": "3.4.x-dev",
1235
  "source": {
1236
  "type": "git",
1237
  "url": "https://github.com/symfony/process.git",
1238
- "reference": "9794f948d9af3be0157185051275d78b24d68b92"
1239
  },
1240
  "dist": {
1241
  "type": "zip",
1242
- "url": "https://api.github.com/repos/symfony/process/zipball/9794f948d9af3be0157185051275d78b24d68b92",
1243
- "reference": "9794f948d9af3be0157185051275d78b24d68b92",
1244
  "shasum": ""
1245
  },
1246
  "require": {
@@ -1276,20 +2833,20 @@
1276
  ],
1277
  "description": "Symfony Process Component",
1278
  "homepage": "https://symfony.com",
1279
- "time": "2017-08-03T09:34:20+00:00"
1280
  },
1281
  {
1282
  "name": "symfony/translation",
1283
- "version": "3.4.x-dev",
1284
  "source": {
1285
  "type": "git",
1286
  "url": "https://github.com/symfony/translation.git",
1287
- "reference": "62bb068e004874bbe39624101e1aae70ca7c05cd"
1288
  },
1289
  "dist": {
1290
  "type": "zip",
1291
- "url": "https://api.github.com/repos/symfony/translation/zipball/62bb068e004874bbe39624101e1aae70ca7c05cd",
1292
- "reference": "62bb068e004874bbe39624101e1aae70ca7c05cd",
1293
  "shasum": ""
1294
  },
1295
  "require": {
@@ -1299,17 +2856,20 @@
1299
  "conflict": {
1300
  "symfony/config": "<2.8",
1301
  "symfony/dependency-injection": "<3.4",
1302
- "symfony/yaml": "<3.3"
1303
  },
1304
  "require-dev": {
1305
  "psr/log": "~1.0",
1306
  "symfony/config": "~2.8|~3.0|~4.0",
1307
  "symfony/dependency-injection": "~3.4|~4.0",
 
 
1308
  "symfony/intl": "^2.8.18|^3.2.5|~4.0",
1309
- "symfony/yaml": "~3.3|~4.0"
 
1310
  },
1311
  "suggest": {
1312
- "psr/log": "To use logging capability in translator",
1313
  "symfony/config": "",
1314
  "symfony/yaml": ""
1315
  },
@@ -1343,27 +2903,31 @@
1343
  ],
1344
  "description": "Symfony Translation Component",
1345
  "homepage": "https://symfony.com",
1346
- "time": "2017-08-03T12:04:31+00:00"
1347
  },
1348
  {
1349
  "name": "symfony/yaml",
1350
- "version": "3.4.x-dev",
1351
  "source": {
1352
  "type": "git",
1353
  "url": "https://github.com/symfony/yaml.git",
1354
- "reference": "1395ddba6f65bf46cdf1d80d59223cbab8ff3ccc"
1355
  },
1356
  "dist": {
1357
  "type": "zip",
1358
- "url": "https://api.github.com/repos/symfony/yaml/zipball/1395ddba6f65bf46cdf1d80d59223cbab8ff3ccc",
1359
- "reference": "1395ddba6f65bf46cdf1d80d59223cbab8ff3ccc",
1360
  "shasum": ""
1361
  },
1362
  "require": {
1363
- "php": "^5.5.9|>=7.0.8"
 
 
 
 
1364
  },
1365
  "require-dev": {
1366
- "symfony/console": "~2.8|~3.0|~4.0"
1367
  },
1368
  "suggest": {
1369
  "symfony/console": "For validating YAML files using the lint command"
@@ -1398,7 +2962,97 @@
1398
  ],
1399
  "description": "Symfony Yaml Component",
1400
  "homepage": "https://symfony.com",
1401
- "time": "2017-08-04T13:29:48+00:00"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1402
  },
1403
  {
1404
  "name": "wp-cli/autoload-splitter",
@@ -1443,16 +3097,16 @@
1443
  },
1444
  {
1445
  "name": "wp-cli/cache-command",
1446
- "version": "dev-master",
1447
  "source": {
1448
  "type": "git",
1449
  "url": "https://github.com/wp-cli/cache-command.git",
1450
- "reference": "485f7cc6630ecabe22bbf9fa9e827958e95a2d21"
1451
  },
1452
  "dist": {
1453
  "type": "zip",
1454
- "url": "https://api.github.com/repos/wp-cli/cache-command/zipball/485f7cc6630ecabe22bbf9fa9e827958e95a2d21",
1455
- "reference": "485f7cc6630ecabe22bbf9fa9e827958e95a2d21",
1456
  "shasum": ""
1457
  },
1458
  "require-dev": {
@@ -1467,7 +3121,20 @@
1467
  "bundled": true,
1468
  "commands": [
1469
  "cache",
1470
- "transient"
 
 
 
 
 
 
 
 
 
 
 
 
 
1471
  ]
1472
  },
1473
  "autoload": {
@@ -1489,27 +3156,27 @@
1489
  "homepage": "https://runcommand.io"
1490
  }
1491
  ],
1492
- "description": "Manage object and transient caches.",
1493
  "homepage": "https://github.com/wp-cli/cache-command",
1494
- "time": "2017-08-04T11:37:19+00:00"
1495
  },
1496
  {
1497
  "name": "wp-cli/checksum-command",
1498
- "version": "dev-master",
1499
  "source": {
1500
  "type": "git",
1501
  "url": "https://github.com/wp-cli/checksum-command.git",
1502
- "reference": "88ccde2e82de5c2232842a9fccc2e6ade232dec6"
1503
  },
1504
  "dist": {
1505
  "type": "zip",
1506
- "url": "https://api.github.com/repos/wp-cli/checksum-command/zipball/88ccde2e82de5c2232842a9fccc2e6ade232dec6",
1507
- "reference": "88ccde2e82de5c2232842a9fccc2e6ade232dec6",
1508
  "shasum": ""
1509
  },
1510
  "require-dev": {
1511
  "behat/behat": "~2.5",
1512
- "wp-cli/wp-cli": "*"
1513
  },
1514
  "type": "wp-cli-package",
1515
  "extra": {
@@ -1518,7 +3185,8 @@
1518
  },
1519
  "bundled": true,
1520
  "commands": [
1521
- "checksum core"
 
1522
  ]
1523
  },
1524
  "autoload": {
@@ -1540,24 +3208,27 @@
1540
  "homepage": "https://runcommand.io"
1541
  }
1542
  ],
1543
- "description": "Verify WordPress core checksums.",
1544
  "homepage": "https://github.com/wp-cli/checksum-command",
1545
- "time": "2017-08-09T23:34:29+00:00"
1546
  },
1547
  {
1548
  "name": "wp-cli/config-command",
1549
- "version": "dev-master",
1550
  "source": {
1551
  "type": "git",
1552
  "url": "https://github.com/wp-cli/config-command.git",
1553
- "reference": "ca83ade8fb2d059b561744610947e38123b10c22"
1554
  },
1555
  "dist": {
1556
  "type": "zip",
1557
- "url": "https://api.github.com/repos/wp-cli/config-command/zipball/ca83ade8fb2d059b561744610947e38123b10c22",
1558
- "reference": "ca83ade8fb2d059b561744610947e38123b10c22",
1559
  "shasum": ""
1560
  },
 
 
 
1561
  "require-dev": {
1562
  "behat/behat": "~2.5",
1563
  "wp-cli/wp-cli": "*"
@@ -1570,9 +3241,14 @@
1570
  "bundled": true,
1571
  "commands": [
1572
  "config",
 
 
1573
  "config create",
1574
  "config get",
1575
- "config path"
 
 
 
1576
  ]
1577
  },
1578
  "autoload": {
@@ -1592,24 +3268,29 @@
1592
  "name": "Daniel Bachhuber",
1593
  "email": "daniel@runcommand.io",
1594
  "homepage": "https://runcommand.io"
 
 
 
 
 
1595
  }
1596
  ],
1597
- "description": "Manage the wp-config.php file.",
1598
  "homepage": "https://github.com/wp-cli/config-command",
1599
- "time": "2017-08-04T23:41:35+00:00"
1600
  },
1601
  {
1602
  "name": "wp-cli/core-command",
1603
- "version": "dev-master",
1604
  "source": {
1605
  "type": "git",
1606
  "url": "https://github.com/wp-cli/core-command.git",
1607
- "reference": "fb743dab792e21b57163c5c0f563987d1471c152"
1608
  },
1609
  "dist": {
1610
  "type": "zip",
1611
- "url": "https://api.github.com/repos/wp-cli/core-command/zipball/fb743dab792e21b57163c5c0f563987d1471c152",
1612
- "reference": "fb743dab792e21b57163c5c0f563987d1471c152",
1613
  "shasum": ""
1614
  },
1615
  "require-dev": {
@@ -1623,6 +3304,7 @@
1623
  },
1624
  "bundled": true,
1625
  "commands": [
 
1626
  "core check-update",
1627
  "core download",
1628
  "core install",
@@ -1653,22 +3335,22 @@
1653
  "homepage": "https://runcommand.io"
1654
  }
1655
  ],
1656
- "description": "Download, install, update and manage a WordPress install.",
1657
  "homepage": "https://github.com/wp-cli/core-command",
1658
- "time": "2017-08-04T12:31:18+00:00"
1659
  },
1660
  {
1661
  "name": "wp-cli/cron-command",
1662
- "version": "dev-master",
1663
  "source": {
1664
  "type": "git",
1665
  "url": "https://github.com/wp-cli/cron-command.git",
1666
- "reference": "92114b695ab0253bb705d9bd3e6d2fb47b51fad2"
1667
  },
1668
  "dist": {
1669
  "type": "zip",
1670
- "url": "https://api.github.com/repos/wp-cli/cron-command/zipball/92114b695ab0253bb705d9bd3e6d2fb47b51fad2",
1671
- "reference": "92114b695ab0253bb705d9bd3e6d2fb47b51fad2",
1672
  "shasum": ""
1673
  },
1674
  "require-dev": {
@@ -1682,11 +3364,14 @@
1682
  },
1683
  "bundled": true,
1684
  "commands": [
 
1685
  "cron test",
 
1686
  "cron event delete",
1687
  "cron event list",
1688
  "cron event run",
1689
  "cron event schedule",
 
1690
  "cron schedule list"
1691
  ]
1692
  },
@@ -1709,29 +3394,27 @@
1709
  "homepage": "https://runcommand.io"
1710
  }
1711
  ],
1712
- "description": "Manage WP-Cron events and schedules.",
1713
  "homepage": "https://github.com/wp-cli/cron-command",
1714
- "time": "2017-08-04T12:45:50+00:00"
1715
  },
1716
  {
1717
  "name": "wp-cli/db-command",
1718
- "version": "dev-master",
1719
  "source": {
1720
  "type": "git",
1721
  "url": "https://github.com/wp-cli/db-command.git",
1722
- "reference": "5c597abb642bcaf329e7da0801c69f4405d41c23"
1723
  },
1724
  "dist": {
1725
  "type": "zip",
1726
- "url": "https://api.github.com/repos/wp-cli/db-command/zipball/5c597abb642bcaf329e7da0801c69f4405d41c23",
1727
- "reference": "5c597abb642bcaf329e7da0801c69f4405d41c23",
1728
  "shasum": ""
1729
  },
1730
- "require": {
1731
- "wp-cli/wp-cli": "*"
1732
- },
1733
  "require-dev": {
1734
- "behat/behat": "~2.5"
 
1735
  },
1736
  "type": "wp-cli-package",
1737
  "extra": {
@@ -1740,6 +3423,7 @@
1740
  },
1741
  "bundled": true,
1742
  "commands": [
 
1743
  "db create",
1744
  "db drop",
1745
  "db reset",
@@ -1753,7 +3437,8 @@
1753
  "db import",
1754
  "db search",
1755
  "db tables",
1756
- "db size"
 
1757
  ]
1758
  },
1759
  "autoload": {
@@ -1775,28 +3460,85 @@
1775
  "homepage": "https://runcommand.io"
1776
  }
1777
  ],
1778
- "description": "Perform basic database operations using credentials stored in wp-config.php.",
1779
  "homepage": "https://github.com/wp-cli/db-command",
1780
- "time": "2017-08-04T23:21:46+00:00"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1781
  },
1782
  {
1783
  "name": "wp-cli/entity-command",
1784
- "version": "dev-master",
1785
  "source": {
1786
  "type": "git",
1787
  "url": "https://github.com/wp-cli/entity-command.git",
1788
- "reference": "d0cd99c14e4d01aad368328da97231df0c01f9dc"
1789
  },
1790
  "dist": {
1791
  "type": "zip",
1792
- "url": "https://api.github.com/repos/wp-cli/entity-command/zipball/d0cd99c14e4d01aad368328da97231df0c01f9dc",
1793
- "reference": "d0cd99c14e4d01aad368328da97231df0c01f9dc",
1794
  "shasum": ""
1795
  },
1796
  "require-dev": {
1797
  "behat/behat": "~2.5",
1798
  "phpunit/phpunit": "^4.8",
1799
- "wp-cli/wp-cli": "*"
1800
  },
1801
  "type": "wp-cli-package",
1802
  "extra": {
@@ -1806,28 +3548,153 @@
1806
  "bundled": true,
1807
  "commands": [
1808
  "comment",
 
 
 
 
 
 
 
 
1809
  "comment meta",
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1810
  "menu",
 
 
1811
  "menu item",
 
 
 
 
 
 
 
1812
  "menu location",
 
 
 
1813
  "network meta",
 
 
 
 
 
 
 
1814
  "option",
1815
  "option add",
1816
  "option delete",
1817
  "option get",
1818
  "option list",
 
 
1819
  "option update",
1820
  "post",
 
 
 
 
 
 
1821
  "post meta",
 
 
 
 
 
 
 
1822
  "post term",
 
 
 
 
 
1823
  "post-type",
 
 
1824
  "site",
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1825
  "taxonomy",
 
 
1826
  "term",
 
 
 
 
 
1827
  "term meta",
 
 
 
 
 
 
 
 
 
1828
  "user",
 
 
 
 
 
 
 
 
 
1829
  "user meta",
1830
- "user term"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1831
  ]
1832
  },
1833
  "autoload": {
@@ -1852,20 +3719,20 @@
1852
  ],
1853
  "description": "Manage WordPress core entities.",
1854
  "homepage": "https://github.com/wp-cli/entity-command",
1855
- "time": "2017-08-11T11:53:04+00:00"
1856
  },
1857
  {
1858
  "name": "wp-cli/eval-command",
1859
- "version": "dev-master",
1860
  "source": {
1861
  "type": "git",
1862
  "url": "https://github.com/wp-cli/eval-command.git",
1863
- "reference": "e3d9502a4f8b8f582130dbb3b8ede76e17ac05a4"
1864
  },
1865
  "dist": {
1866
  "type": "zip",
1867
- "url": "https://api.github.com/repos/wp-cli/eval-command/zipball/e3d9502a4f8b8f582130dbb3b8ede76e17ac05a4",
1868
- "reference": "e3d9502a4f8b8f582130dbb3b8ede76e17ac05a4",
1869
  "shasum": ""
1870
  },
1871
  "require": {
@@ -1904,30 +3771,30 @@
1904
  "homepage": "https://runcommand.io"
1905
  }
1906
  ],
1907
- "description": "Execute arbitrary PHP code.",
1908
  "homepage": "https://github.com/wp-cli/eval-command",
1909
- "time": "2017-08-04T12:46:58+00:00"
1910
  },
1911
  {
1912
  "name": "wp-cli/export-command",
1913
- "version": "dev-master",
1914
  "source": {
1915
  "type": "git",
1916
  "url": "https://github.com/wp-cli/export-command.git",
1917
- "reference": "f5647155830d1275de4cb69cfb79748b9449b8ab"
1918
  },
1919
  "dist": {
1920
  "type": "zip",
1921
- "url": "https://api.github.com/repos/wp-cli/export-command/zipball/f5647155830d1275de4cb69cfb79748b9449b8ab",
1922
- "reference": "f5647155830d1275de4cb69cfb79748b9449b8ab",
1923
  "shasum": ""
1924
  },
1925
  "require": {
1926
- "nb/oxymel": "~0.1.0",
1927
- "wp-cli/wp-cli": "*"
1928
  },
1929
  "require-dev": {
1930
- "behat/behat": "~2.5"
 
1931
  },
1932
  "type": "wp-cli-package",
1933
  "extra": {
@@ -1958,22 +3825,22 @@
1958
  "homepage": "https://runcommand.io"
1959
  }
1960
  ],
1961
- "description": "Export WordPress content to a WXR file.",
1962
  "homepage": "https://github.com/wp-cli/export-command",
1963
- "time": "2017-08-04T13:13:08+00:00"
1964
  },
1965
  {
1966
  "name": "wp-cli/extension-command",
1967
- "version": "dev-master",
1968
  "source": {
1969
  "type": "git",
1970
  "url": "https://github.com/wp-cli/extension-command.git",
1971
- "reference": "08bf48e842b9e1cb579b50cec1b6897cebf65bda"
1972
  },
1973
  "dist": {
1974
  "type": "zip",
1975
- "url": "https://api.github.com/repos/wp-cli/extension-command/zipball/08bf48e842b9e1cb579b50cec1b6897cebf65bda",
1976
- "reference": "08bf48e842b9e1cb579b50cec1b6897cebf65bda",
1977
  "shasum": ""
1978
  },
1979
  "require-dev": {
@@ -1987,6 +3854,7 @@
1987
  },
1988
  "bundled": true,
1989
  "commands": [
 
1990
  "plugin activate",
1991
  "plugin deactivate",
1992
  "plugin delete",
@@ -2000,6 +3868,7 @@
2000
  "plugin toggle",
2001
  "plugin uninstall",
2002
  "plugin update",
 
2003
  "theme activate",
2004
  "theme delete",
2005
  "theme disable",
@@ -2008,19 +3877,20 @@
2008
  "theme install",
2009
  "theme is-installed",
2010
  "theme list",
 
2011
  "theme mod get",
2012
  "theme mod set",
2013
  "theme mod remove",
2014
  "theme path",
2015
  "theme search",
2016
  "theme status",
2017
- "theme update"
 
2018
  ]
2019
  },
2020
  "autoload": {
2021
  "psr-4": {
2022
- "": "src/",
2023
- "WP_CLI\\": "src/WP_CLI"
2024
  },
2025
  "files": [
2026
  "extension-command.php"
@@ -2037,22 +3907,22 @@
2037
  "homepage": "https://runcommand.io"
2038
  }
2039
  ],
2040
- "description": "Manage WordPress plugins and themes.",
2041
  "homepage": "https://github.com/wp-cli/extension-command",
2042
- "time": "2017-08-04T13:43:53+00:00"
2043
  },
2044
  {
2045
  "name": "wp-cli/import-command",
2046
- "version": "dev-master",
2047
  "source": {
2048
  "type": "git",
2049
  "url": "https://github.com/wp-cli/import-command.git",
2050
- "reference": "89d14aa4b8b621effbe7f9bacad2ea8a096598a7"
2051
  },
2052
  "dist": {
2053
  "type": "zip",
2054
- "url": "https://api.github.com/repos/wp-cli/import-command/zipball/89d14aa4b8b621effbe7f9bacad2ea8a096598a7",
2055
- "reference": "89d14aa4b8b621effbe7f9bacad2ea8a096598a7",
2056
  "shasum": ""
2057
  },
2058
  "require": {
@@ -2090,22 +3960,22 @@
2090
  "homepage": "https://runcommand.io"
2091
  }
2092
  ],
2093
- "description": "Import content from a WXR file.",
2094
  "homepage": "https://github.com/wp-cli/import-command",
2095
- "time": "2017-08-04T13:45:57+00:00"
2096
  },
2097
  {
2098
  "name": "wp-cli/language-command",
2099
- "version": "dev-master",
2100
  "source": {
2101
  "type": "git",
2102
  "url": "https://github.com/wp-cli/language-command.git",
2103
- "reference": "aff3fb6c6d7698008c7e5d33a97b25457091ae1b"
2104
  },
2105
  "dist": {
2106
  "type": "zip",
2107
- "url": "https://api.github.com/repos/wp-cli/language-command/zipball/aff3fb6c6d7698008c7e5d33a97b25457091ae1b",
2108
- "reference": "aff3fb6c6d7698008c7e5d33a97b25457091ae1b",
2109
  "shasum": ""
2110
  },
2111
  "require-dev": {
@@ -2118,6 +3988,8 @@
2118
  "dev-master": "1.x-dev"
2119
  },
2120
  "commands": [
 
 
2121
  "language core activate",
2122
  "language core install",
2123
  "language core list",
@@ -2145,40 +4017,40 @@
2145
  "homepage": "https://runcommand.io"
2146
  }
2147
  ],
2148
- "description": "Manage language packs.",
2149
  "homepage": "https://github.com/wp-cli/language-command",
2150
- "time": "2017-08-04T23:23:03+00:00"
2151
  },
2152
  {
2153
  "name": "wp-cli/media-command",
2154
- "version": "dev-master",
2155
  "source": {
2156
  "type": "git",
2157
  "url": "https://github.com/wp-cli/media-command.git",
2158
- "reference": "4a19de54a11c96b21c10719e2b7f9dd131c4261e"
2159
  },
2160
  "dist": {
2161
  "type": "zip",
2162
- "url": "https://api.github.com/repos/wp-cli/media-command/zipball/4a19de54a11c96b21c10719e2b7f9dd131c4261e",
2163
- "reference": "4a19de54a11c96b21c10719e2b7f9dd131c4261e",
2164
  "shasum": ""
2165
  },
2166
- "require": {
2167
- "wp-cli/wp-cli": "*"
2168
- },
2169
  "require-dev": {
2170
- "behat/behat": "~2.5"
 
2171
  },
2172
  "type": "wp-cli-package",
2173
  "extra": {
2174
  "branch-alias": {
2175
  "dev-master": "1.x-dev"
2176
  },
 
2177
  "commands": [
 
2178
  "media import",
2179
- "media regenerate"
2180
- ],
2181
- "bundled": true
2182
  },
2183
  "autoload": {
2184
  "psr-4": {
@@ -2199,9 +4071,9 @@
2199
  "homepage": "https://runcommand.io"
2200
  }
2201
  ],
2202
- "description": "Import new attachments or regenerate existing ones.",
2203
  "homepage": "https://github.com/wp-cli/media-command",
2204
- "time": "2017-08-05T04:54:48+00:00"
2205
  },
2206
  {
2207
  "name": "wp-cli/mustangostang-spyc",
@@ -2253,38 +4125,39 @@
2253
  },
2254
  {
2255
  "name": "wp-cli/package-command",
2256
- "version": "dev-master",
2257
  "source": {
2258
  "type": "git",
2259
  "url": "https://github.com/wp-cli/package-command.git",
2260
- "reference": "744692180a4240ddc75a3196934cafe396dd9178"
2261
  },
2262
  "dist": {
2263
  "type": "zip",
2264
- "url": "https://api.github.com/repos/wp-cli/package-command/zipball/744692180a4240ddc75a3196934cafe396dd9178",
2265
- "reference": "744692180a4240ddc75a3196934cafe396dd9178",
2266
  "shasum": ""
2267
  },
2268
  "require": {
2269
- "composer/composer": "^1.2.0",
2270
- "wp-cli/wp-cli": "*"
2271
  },
2272
  "require-dev": {
2273
- "behat/behat": "~2.5"
 
2274
  },
2275
  "type": "wp-cli-package",
2276
  "extra": {
2277
  "branch-alias": {
2278
  "dev-master": "1.x-dev"
2279
  },
 
2280
  "commands": [
 
2281
  "package browse",
2282
  "package install",
2283
  "package list",
2284
  "package update",
2285
  "package uninstall"
2286
- ],
2287
- "bundled": true
2288
  },
2289
  "autoload": {
2290
  "psr-4": {
@@ -2305,22 +4178,22 @@
2305
  "homepage": "https://runcommand.io"
2306
  }
2307
  ],
2308
- "description": "Manage WP-CLI packages.",
2309
  "homepage": "https://github.com/wp-cli/package-command",
2310
- "time": "2017-08-07T12:21:11+00:00"
2311
  },
2312
  {
2313
  "name": "wp-cli/php-cli-tools",
2314
- "version": "v0.11.6",
2315
  "source": {
2316
  "type": "git",
2317
  "url": "https://github.com/wp-cli/php-cli-tools.git",
2318
- "reference": "d2a4e2eca9f1cd62a5d30f192d10f74e73eb3a05"
2319
  },
2320
  "dist": {
2321
  "type": "zip",
2322
- "url": "https://api.github.com/repos/wp-cli/php-cli-tools/zipball/d2a4e2eca9f1cd62a5d30f192d10f74e73eb3a05",
2323
- "reference": "d2a4e2eca9f1cd62a5d30f192d10f74e73eb3a05",
2324
  "shasum": ""
2325
  },
2326
  "require": {
@@ -2357,20 +4230,20 @@
2357
  "cli",
2358
  "console"
2359
  ],
2360
- "time": "2017-08-04T10:42:04+00:00"
2361
  },
2362
  {
2363
  "name": "wp-cli/rewrite-command",
2364
- "version": "dev-master",
2365
  "source": {
2366
  "type": "git",
2367
  "url": "https://github.com/wp-cli/rewrite-command.git",
2368
- "reference": "e858feac8d3fe053e052d8af43c090ff0b2a4e8a"
2369
  },
2370
  "dist": {
2371
  "type": "zip",
2372
- "url": "https://api.github.com/repos/wp-cli/rewrite-command/zipball/e858feac8d3fe053e052d8af43c090ff0b2a4e8a",
2373
- "reference": "e858feac8d3fe053e052d8af43c090ff0b2a4e8a",
2374
  "shasum": ""
2375
  },
2376
  "require-dev": {
@@ -2383,6 +4256,7 @@
2383
  "dev-master": "1.x-dev"
2384
  },
2385
  "commands": [
 
2386
  "rewrite flush",
2387
  "rewrite list",
2388
  "rewrite structure"
@@ -2408,22 +4282,22 @@
2408
  "homepage": "https://runcommand.io"
2409
  }
2410
  ],
2411
- "description": "Manage rewrite rules.",
2412
  "homepage": "https://github.com/wp-cli/rewrite-command",
2413
- "time": "2017-08-04T15:15:53+00:00"
2414
  },
2415
  {
2416
  "name": "wp-cli/role-command",
2417
- "version": "dev-master",
2418
  "source": {
2419
  "type": "git",
2420
  "url": "https://github.com/wp-cli/role-command.git",
2421
- "reference": "85ddf53525b14ab040830f385710f4493058d295"
2422
  },
2423
  "dist": {
2424
  "type": "zip",
2425
- "url": "https://api.github.com/repos/wp-cli/role-command/zipball/85ddf53525b14ab040830f385710f4493058d295",
2426
- "reference": "85ddf53525b14ab040830f385710f4493058d295",
2427
  "shasum": ""
2428
  },
2429
  "require-dev": {
@@ -2436,11 +4310,13 @@
2436
  "dev-master": "1.x-dev"
2437
  },
2438
  "commands": [
 
2439
  "role create",
2440
  "role delete",
2441
  "role exists",
2442
  "role list",
2443
  "role reset",
 
2444
  "cap add",
2445
  "cap list",
2446
  "cap remove"
@@ -2466,44 +4342,45 @@
2466
  "homepage": "https://runcommand.io"
2467
  }
2468
  ],
2469
- "description": "Manage user roles and capabilities.",
2470
  "homepage": "https://github.com/wp-cli/role-command",
2471
- "time": "2017-08-04T15:17:29+00:00"
2472
  },
2473
  {
2474
  "name": "wp-cli/scaffold-command",
2475
- "version": "dev-master",
2476
  "source": {
2477
  "type": "git",
2478
  "url": "https://github.com/wp-cli/scaffold-command.git",
2479
- "reference": "41f1e1aa41af76b70d6cf3d21d52995e854acf4c"
2480
  },
2481
  "dist": {
2482
  "type": "zip",
2483
- "url": "https://api.github.com/repos/wp-cli/scaffold-command/zipball/41f1e1aa41af76b70d6cf3d21d52995e854acf4c",
2484
- "reference": "41f1e1aa41af76b70d6cf3d21d52995e854acf4c",
2485
  "shasum": ""
2486
  },
2487
  "require-dev": {
2488
  "behat/behat": "~2.5",
2489
- "wp-cli/wp-cli": "*"
2490
  },
2491
  "type": "wp-cli-package",
2492
  "extra": {
2493
  "branch-alias": {
2494
  "dev-master": "1.x-dev"
2495
  },
 
2496
  "commands": [
2497
  "scaffold",
2498
  "scaffold _s",
 
2499
  "scaffold child-theme",
2500
  "scaffold plugin",
2501
  "scaffold plugin-tests",
2502
  "scaffold post-type",
2503
  "scaffold taxonomy",
2504
  "scaffold theme-tests"
2505
- ],
2506
- "bundled": true
2507
  },
2508
  "autoload": {
2509
  "psr-4": {
@@ -2524,44 +4401,41 @@
2524
  "homepage": "https://runcommand.io"
2525
  }
2526
  ],
2527
- "description": "Generate code for post types, taxonomies, plugins, child themes, etc.",
2528
  "homepage": "https://github.com/wp-cli/scaffold-command",
2529
- "time": "2017-08-11T08:07:10+00:00"
2530
  },
2531
  {
2532
  "name": "wp-cli/search-replace-command",
2533
- "version": "dev-master",
2534
  "source": {
2535
  "type": "git",
2536
  "url": "https://github.com/wp-cli/search-replace-command.git",
2537
- "reference": "3e7499a65354e3a322d4d1043123b3fa55ef4f12"
2538
  },
2539
  "dist": {
2540
  "type": "zip",
2541
- "url": "https://api.github.com/repos/wp-cli/search-replace-command/zipball/3e7499a65354e3a322d4d1043123b3fa55ef4f12",
2542
- "reference": "3e7499a65354e3a322d4d1043123b3fa55ef4f12",
2543
  "shasum": ""
2544
  },
2545
- "require": {
2546
- "wp-cli/wp-cli": "*"
2547
- },
2548
  "require-dev": {
2549
- "behat/behat": "~2.5"
 
2550
  },
2551
  "type": "wp-cli-package",
2552
  "extra": {
2553
  "branch-alias": {
2554
  "dev-master": "1.x-dev"
2555
  },
 
2556
  "commands": [
2557
  "search-replace"
2558
- ],
2559
- "bundled": true
2560
  },
2561
  "autoload": {
2562
  "psr-4": {
2563
- "": "src/",
2564
- "WP_CLI\\": "src/WP_CLI"
2565
  },
2566
  "files": [
2567
  "search-replace-command.php"
@@ -2578,22 +4452,22 @@
2578
  "homepage": "https://runcommand.io"
2579
  }
2580
  ],
2581
- "description": "Search/replace strings in the database.",
2582
  "homepage": "https://github.com/wp-cli/search-replace-command",
2583
- "time": "2017-08-08T16:41:49+00:00"
2584
  },
2585
  {
2586
  "name": "wp-cli/server-command",
2587
- "version": "dev-master",
2588
  "source": {
2589
  "type": "git",
2590
  "url": "https://github.com/wp-cli/server-command.git",
2591
- "reference": "ce93df07c33e716adbbd2d329c311a3c1dd3a0b0"
2592
  },
2593
  "dist": {
2594
  "type": "zip",
2595
- "url": "https://api.github.com/repos/wp-cli/server-command/zipball/ce93df07c33e716adbbd2d329c311a3c1dd3a0b0",
2596
- "reference": "ce93df07c33e716adbbd2d329c311a3c1dd3a0b0",
2597
  "shasum": ""
2598
  },
2599
  "require": {
@@ -2631,22 +4505,22 @@
2631
  "homepage": "https://runcommand.io"
2632
  }
2633
  ],
2634
- "description": "Launch PHP's built-in web server for this specific WordPress installation.",
2635
  "homepage": "https://github.com/wp-cli/server-command",
2636
- "time": "2017-08-04T15:19:26+00:00"
2637
  },
2638
  {
2639
  "name": "wp-cli/shell-command",
2640
- "version": "dev-master",
2641
  "source": {
2642
  "type": "git",
2643
  "url": "https://github.com/wp-cli/shell-command.git",
2644
- "reference": "70681666302cc193a1bd41bade9ecc61e74a8c83"
2645
  },
2646
  "dist": {
2647
  "type": "zip",
2648
- "url": "https://api.github.com/repos/wp-cli/shell-command/zipball/70681666302cc193a1bd41bade9ecc61e74a8c83",
2649
- "reference": "70681666302cc193a1bd41bade9ecc61e74a8c83",
2650
  "shasum": ""
2651
  },
2652
  "require": {
@@ -2685,22 +4559,22 @@
2685
  "homepage": "https://runcommand.io"
2686
  }
2687
  ],
2688
- "description": "Interactive PHP console.",
2689
  "homepage": "https://github.com/wp-cli/shell-command",
2690
- "time": "2017-08-04T15:21:52+00:00"
2691
  },
2692
  {
2693
  "name": "wp-cli/super-admin-command",
2694
- "version": "dev-master",
2695
  "source": {
2696
  "type": "git",
2697
  "url": "https://github.com/wp-cli/super-admin-command.git",
2698
- "reference": "b650836d13762c764df2bbe70ad34212c0b773cd"
2699
  },
2700
  "dist": {
2701
  "type": "zip",
2702
- "url": "https://api.github.com/repos/wp-cli/super-admin-command/zipball/b650836d13762c764df2bbe70ad34212c0b773cd",
2703
- "reference": "b650836d13762c764df2bbe70ad34212c0b773cd",
2704
  "shasum": ""
2705
  },
2706
  "require-dev": {
@@ -2713,6 +4587,7 @@
2713
  "dev-master": "1.x-dev"
2714
  },
2715
  "commands": [
 
2716
  "super-admin add",
2717
  "super-admin list",
2718
  "super-admin remove"
@@ -2738,22 +4613,22 @@
2738
  "homepage": "https://runcommand.io"
2739
  }
2740
  ],
2741
- "description": "Manage super admins on WordPress multisite.",
2742
  "homepage": "https://github.com/wp-cli/super-admin-command",
2743
- "time": "2017-08-04T15:45:41+00:00"
2744
  },
2745
  {
2746
  "name": "wp-cli/widget-command",
2747
- "version": "dev-master",
2748
  "source": {
2749
  "type": "git",
2750
  "url": "https://github.com/wp-cli/widget-command.git",
2751
- "reference": "727af7c7b661031bc8c04ad176d4f24b862e3402"
2752
  },
2753
  "dist": {
2754
  "type": "zip",
2755
- "url": "https://api.github.com/repos/wp-cli/widget-command/zipball/727af7c7b661031bc8c04ad176d4f24b862e3402",
2756
- "reference": "727af7c7b661031bc8c04ad176d4f24b862e3402",
2757
  "shasum": ""
2758
  },
2759
  "require-dev": {
@@ -2766,6 +4641,7 @@
2766
  "dev-master": "1.x-dev"
2767
  },
2768
  "commands": [
 
2769
  "widget add",
2770
  "widget deactivate",
2771
  "widget delete",
@@ -2773,6 +4649,7 @@
2773
  "widget move",
2774
  "widget reset",
2775
  "widget update",
 
2776
  "sidebar list"
2777
  ],
2778
  "bundled": true
@@ -2796,27 +4673,28 @@
2796
  "homepage": "https://runcommand.io"
2797
  }
2798
  ],
2799
- "description": "Manage widgets and sidebars.",
2800
  "homepage": "https://github.com/wp-cli/widget-command",
2801
- "time": "2017-08-04T15:24:29+00:00"
2802
  },
2803
  {
2804
  "name": "wp-cli/wp-cli",
2805
- "version": "v1.3.0",
2806
  "source": {
2807
  "type": "git",
2808
  "url": "https://github.com/wp-cli/wp-cli.git",
2809
- "reference": "4ab0d99da0ad5e6ca39453ff5c82d4f06aecb086"
2810
  },
2811
  "dist": {
2812
  "type": "zip",
2813
- "url": "https://api.github.com/repos/wp-cli/wp-cli/zipball/4ab0d99da0ad5e6ca39453ff5c82d4f06aecb086",
2814
- "reference": "4ab0d99da0ad5e6ca39453ff5c82d4f06aecb086",
2815
  "shasum": ""
2816
  },
2817
  "require": {
2818
  "composer/composer": "^1.2.0",
2819
  "composer/semver": "~1.0",
 
2820
  "mustache/mustache": "~2.4",
2821
  "php": ">=5.3.29",
2822
  "ramsey/array_column": "~1.1",
@@ -2838,6 +4716,7 @@
2838
  "wp-cli/core-command": "^1.0",
2839
  "wp-cli/cron-command": "^1.0",
2840
  "wp-cli/db-command": "^1.0",
 
2841
  "wp-cli/entity-command": "^1.0",
2842
  "wp-cli/eval-command": "^1.0",
2843
  "wp-cli/export-command": "^1.0",
@@ -2859,8 +4738,11 @@
2859
  },
2860
  "require-dev": {
2861
  "behat/behat": "2.5.*",
 
2862
  "phpunit/phpunit": "3.7.*",
2863
- "roave/security-advisories": "dev-master"
 
 
2864
  },
2865
  "suggest": {
2866
  "psy/psysh": "Enhanced `wp shell` functionality"
@@ -2871,6 +4753,9 @@
2871
  ],
2872
  "type": "library",
2873
  "extra": {
 
 
 
2874
  "autoload-splitter": {
2875
  "splitter-logic": "WP_CLI\\AutoloadSplitter",
2876
  "splitter-location": "php/WP_CLI/AutoloadSplitter.php",
@@ -2890,19 +4775,105 @@
2890
  "license": [
2891
  "MIT"
2892
  ],
2893
- "description": "A command line interface for WordPress",
2894
- "homepage": "http://wp-cli.org",
2895
  "keywords": [
2896
  "cli",
2897
  "wordpress"
2898
  ],
2899
- "time": "2017-08-08T14:28:58+00:00"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2900
  }
2901
  ],
2902
  "aliases": [],
2903
  "minimum-stability": "dev",
2904
  "stability-flags": [],
2905
- "prefer-stable": false,
2906
  "prefer-lowest": false,
2907
  "platform": [],
2908
  "platform-dev": []
1
  {
2
  "_readme": [
3
  "This file locks the dependencies of your project to a known state",
4
+ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
5
  "This file is @generated automatically"
6
  ],
7
+ "content-hash": "fe700435a00b5cdde47170ab9811f5ae",
8
  "packages": [],
9
  "packages-dev": [
10
  {
11
  "name": "composer/ca-bundle",
12
+ "version": "1.2.4",
13
  "source": {
14
  "type": "git",
15
  "url": "https://github.com/composer/ca-bundle.git",
16
+ "reference": "10bb96592168a0f8e8f6dcde3532d9fa50b0b527"
17
  },
18
  "dist": {
19
  "type": "zip",
20
+ "url": "https://api.github.com/repos/composer/ca-bundle/zipball/10bb96592168a0f8e8f6dcde3532d9fa50b0b527",
21
+ "reference": "10bb96592168a0f8e8f6dcde3532d9fa50b0b527",
22
  "shasum": ""
23
  },
24
  "require": {
25
  "ext-openssl": "*",
26
  "ext-pcre": "*",
27
+ "php": "^5.3.2 || ^7.0 || ^8.0"
28
  },
29
  "require-dev": {
30
+ "phpunit/phpunit": "^4.8.35 || ^5.7 || 6.5 - 8",
31
  "psr/log": "^1.0",
32
+ "symfony/process": "^2.5 || ^3.0 || ^4.0"
 
 
 
33
  },
34
  "type": "library",
35
  "extra": {
61
  "ssl",
62
  "tls"
63
  ],
64
+ "time": "2019-08-30T08:44:50+00:00"
65
  },
66
  {
67
  "name": "composer/composer",
68
+ "version": "1.9.0",
69
  "source": {
70
  "type": "git",
71
  "url": "https://github.com/composer/composer.git",
72
+ "reference": "314aa57fdcfc942065996f59fb73a8b3f74f3fa5"
73
  },
74
  "dist": {
75
  "type": "zip",
76
+ "url": "https://api.github.com/repos/composer/composer/zipball/314aa57fdcfc942065996f59fb73a8b3f74f3fa5",
77
+ "reference": "314aa57fdcfc942065996f59fb73a8b3f74f3fa5",
78
  "shasum": ""
79
  },
80
  "require": {
81
  "composer/ca-bundle": "^1.0",
82
  "composer/semver": "^1.0",
83
+ "composer/spdx-licenses": "^1.2",
84
+ "composer/xdebug-handler": "^1.1",
85
  "justinrainbow/json-schema": "^3.0 || ^4.0 || ^5.0",
86
  "php": "^5.3.2 || ^7.0",
87
  "psr/log": "^1.0",
 
88
  "seld/jsonlint": "^1.4",
89
  "seld/phar-utils": "^1.0",
90
+ "symfony/console": "^2.7 || ^3.0 || ^4.0",
91
+ "symfony/filesystem": "^2.7 || ^3.0 || ^4.0",
92
+ "symfony/finder": "^2.7 || ^3.0 || ^4.0",
93
+ "symfony/process": "^2.7 || ^3.0 || ^4.0"
94
+ },
95
+ "conflict": {
96
+ "symfony/console": "2.8.38"
97
  },
98
  "require-dev": {
99
+ "phpunit/phpunit": "^4.8.35 || ^5.7",
100
  "phpunit/phpunit-mock-objects": "^2.3 || ^3.0"
101
  },
102
  "suggest": {
110
  "type": "library",
111
  "extra": {
112
  "branch-alias": {
113
+ "dev-master": "1.9-dev"
114
  }
115
  },
116
  "autoload": {
134
  "homepage": "http://seld.be"
135
  }
136
  ],
137
+ "description": "Composer helps you declare, manage and install dependencies of PHP projects. It ensures you have the right stack everywhere.",
138
  "homepage": "https://getcomposer.org/",
139
  "keywords": [
140
  "autoload",
141
  "dependency",
142
  "package"
143
  ],
144
+ "time": "2019-08-02T18:55:33+00:00"
145
  },
146
  {
147
  "name": "composer/semver",
148
+ "version": "1.5.0",
149
  "source": {
150
  "type": "git",
151
  "url": "https://github.com/composer/semver.git",
152
+ "reference": "46d9139568ccb8d9e7cdd4539cab7347568a5e2e"
153
  },
154
  "dist": {
155
  "type": "zip",
156
+ "url": "https://api.github.com/repos/composer/semver/zipball/46d9139568ccb8d9e7cdd4539cab7347568a5e2e",
157
+ "reference": "46d9139568ccb8d9e7cdd4539cab7347568a5e2e",
158
  "shasum": ""
159
  },
160
  "require": {
203
  "validation",
204
  "versioning"
205
  ],
206
+ "time": "2019-03-19T17:25:45+00:00"
207
  },
208
  {
209
  "name": "composer/spdx-licenses",
210
+ "version": "1.5.2",
211
  "source": {
212
  "type": "git",
213
  "url": "https://github.com/composer/spdx-licenses.git",
214
+ "reference": "7ac1e6aec371357df067f8a688c3d6974df68fa5"
215
  },
216
  "dist": {
217
  "type": "zip",
218
+ "url": "https://api.github.com/repos/composer/spdx-licenses/zipball/7ac1e6aec371357df067f8a688c3d6974df68fa5",
219
+ "reference": "7ac1e6aec371357df067f8a688c3d6974df68fa5",
220
  "shasum": ""
221
  },
222
  "require": {
223
+ "php": "^5.3.2 || ^7.0 || ^8.0"
224
  },
225
  "require-dev": {
226
+ "phpunit/phpunit": "^4.8.35 || ^5.7 || 6.5 - 7"
 
227
  },
228
  "type": "library",
229
  "extra": {
263
  "spdx",
264
  "validator"
265
  ],
266
+ "time": "2019-07-29T10:31:59+00:00"
267
+ },
268
+ {
269
+ "name": "composer/xdebug-handler",
270
+ "version": "1.3.3",
271
+ "source": {
272
+ "type": "git",
273
+ "url": "https://github.com/composer/xdebug-handler.git",
274
+ "reference": "46867cbf8ca9fb8d60c506895449eb799db1184f"
275
+ },
276
+ "dist": {
277
+ "type": "zip",
278
+ "url": "https://api.github.com/repos/composer/xdebug-handler/zipball/46867cbf8ca9fb8d60c506895449eb799db1184f",
279
+ "reference": "46867cbf8ca9fb8d60c506895449eb799db1184f",
280
+ "shasum": ""
281
+ },
282
+ "require": {
283
+ "php": "^5.3.2 || ^7.0",
284
+ "psr/log": "^1.0"
285
+ },
286
+ "require-dev": {
287
+ "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.5"
288
+ },
289
+ "type": "library",
290
+ "autoload": {
291
+ "psr-4": {
292
+ "Composer\\XdebugHandler\\": "src"
293
+ }
294
+ },
295
+ "notification-url": "https://packagist.org/downloads/",
296
+ "license": [
297
+ "MIT"
298
+ ],
299
+ "authors": [
300
+ {
301
+ "name": "John Stevenson",
302
+ "email": "john-stevenson@blueyonder.co.uk"
303
+ }
304
+ ],
305
+ "description": "Restarts a process without xdebug.",
306
+ "keywords": [
307
+ "Xdebug",
308
+ "performance"
309
+ ],
310
+ "time": "2019-05-27T17:52:04+00:00"
311
+ },
312
+ {
313
+ "name": "dealerdirect/phpcodesniffer-composer-installer",
314
+ "version": "v0.5.0",
315
+ "source": {
316
+ "type": "git",
317
+ "url": "https://github.com/Dealerdirect/phpcodesniffer-composer-installer.git",
318
+ "reference": "e749410375ff6fb7a040a68878c656c2e610b132"
319
+ },
320
+ "dist": {
321
+ "type": "zip",
322
+ "url": "https://api.github.com/repos/Dealerdirect/phpcodesniffer-composer-installer/zipball/e749410375ff6fb7a040a68878c656c2e610b132",
323
+ "reference": "e749410375ff6fb7a040a68878c656c2e610b132",
324
+ "shasum": ""
325
+ },
326
+ "require": {
327
+ "composer-plugin-api": "^1.0",
328
+ "php": "^5.3|^7",
329
+ "squizlabs/php_codesniffer": "^2|^3"
330
+ },
331
+ "require-dev": {
332
+ "composer/composer": "*",
333
+ "phpcompatibility/php-compatibility": "^9.0",
334
+ "sensiolabs/security-checker": "^4.1.0"
335
+ },
336
+ "type": "composer-plugin",
337
+ "extra": {
338
+ "class": "Dealerdirect\\Composer\\Plugin\\Installers\\PHPCodeSniffer\\Plugin"
339
+ },
340
+ "autoload": {
341
+ "psr-4": {
342
+ "Dealerdirect\\Composer\\Plugin\\Installers\\PHPCodeSniffer\\": "src/"
343
+ }
344
+ },
345
+ "notification-url": "https://packagist.org/downloads/",
346
+ "license": [
347
+ "MIT"
348
+ ],
349
+ "authors": [
350
+ {
351
+ "name": "Franck Nijhof",
352
+ "email": "franck.nijhof@dealerdirect.com",
353
+ "homepage": "http://www.frenck.nl",
354
+ "role": "Developer / IT Manager"
355
+ }
356
+ ],
357
+ "description": "PHP_CodeSniffer Standards Composer Installer Plugin",
358
+ "homepage": "http://www.dealerdirect.com",
359
+ "keywords": [
360
+ "PHPCodeSniffer",
361
+ "PHP_CodeSniffer",
362
+ "code quality",
363
+ "codesniffer",
364
+ "composer",
365
+ "installer",
366
+ "phpcs",
367
+ "plugin",
368
+ "qa",
369
+ "quality",
370
+ "standard",
371
+ "standards",
372
+ "style guide",
373
+ "stylecheck",
374
+ "tests"
375
+ ],
376
+ "time": "2018-10-26T13:21:45+00:00"
377
+ },
378
+ {
379
+ "name": "doctrine/instantiator",
380
+ "version": "1.2.0",
381
+ "source": {
382
+ "type": "git",
383
+ "url": "https://github.com/doctrine/instantiator.git",
384
+ "reference": "a2c590166b2133a4633738648b6b064edae0814a"
385
+ },
386
+ "dist": {
387
+ "type": "zip",
388
+ "url": "https://api.github.com/repos/doctrine/instantiator/zipball/a2c590166b2133a4633738648b6b064edae0814a",
389
+ "reference": "a2c590166b2133a4633738648b6b064edae0814a",
390
+ "shasum": ""
391
+ },
392
+ "require": {
393
+ "php": "^7.1"
394
+ },
395
+ "require-dev": {
396
+ "doctrine/coding-standard": "^6.0",
397
+ "ext-pdo": "*",
398
+ "ext-phar": "*",
399
+ "phpbench/phpbench": "^0.13",
400
+ "phpstan/phpstan-phpunit": "^0.11",
401
+ "phpstan/phpstan-shim": "^0.11",
402
+ "phpunit/phpunit": "^7.0"
403
+ },
404
+ "type": "library",
405
+ "extra": {
406
+ "branch-alias": {
407
+ "dev-master": "1.2.x-dev"
408
+ }
409
+ },
410
+ "autoload": {
411
+ "psr-4": {
412
+ "Doctrine\\Instantiator\\": "src/Doctrine/Instantiator/"
413
+ }
414
+ },
415
+ "notification-url": "https://packagist.org/downloads/",
416
+ "license": [
417
+ "MIT"
418
+ ],
419
+ "authors": [
420
+ {
421
+ "name": "Marco Pivetta",
422
+ "email": "ocramius@gmail.com",
423
+ "homepage": "http://ocramius.github.com/"
424
+ }
425
+ ],
426
+ "description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors",
427
+ "homepage": "https://www.doctrine-project.org/projects/instantiator.html",
428
+ "keywords": [
429
+ "constructor",
430
+ "instantiate"
431
+ ],
432
+ "time": "2019-03-17T17:37:11+00:00"
433
  },
434
  {
435
  "name": "justinrainbow/json-schema",
436
+ "version": "5.2.9",
437
  "source": {
438
  "type": "git",
439
  "url": "https://github.com/justinrainbow/json-schema.git",
440
+ "reference": "44c6787311242a979fa15c704327c20e7221a0e4"
441
  },
442
  "dist": {
443
  "type": "zip",
444
+ "url": "https://api.github.com/repos/justinrainbow/json-schema/zipball/44c6787311242a979fa15c704327c20e7221a0e4",
445
+ "reference": "44c6787311242a979fa15c704327c20e7221a0e4",
446
  "shasum": ""
447
  },
448
  "require": {
449
  "php": ">=5.3.3"
450
  },
451
  "require-dev": {
452
+ "friendsofphp/php-cs-fixer": "~2.2.20||~2.15.1",
453
  "json-schema/json-schema-test-suite": "1.2.0",
454
+ "phpunit/phpunit": "^4.8.35"
455
  },
456
  "bin": [
457
  "bin/validate-json"
495
  "json",
496
  "schema"
497
  ],
498
+ "time": "2019-09-25T14:49:45+00:00"
499
  },
500
  {
501
  "name": "mustache/mustache",
543
  ],
544
  "time": "2017-07-11T12:54:05+00:00"
545
  },
546
+ {
547
+ "name": "myclabs/deep-copy",
548
+ "version": "1.9.3",
549
+ "source": {
550
+ "type": "git",
551
+ "url": "https://github.com/myclabs/DeepCopy.git",
552
+ "reference": "007c053ae6f31bba39dfa19a7726f56e9763bbea"
553
+ },
554
+ "dist": {
555
+ "type": "zip",
556
+ "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/007c053ae6f31bba39dfa19a7726f56e9763bbea",
557
+ "reference": "007c053ae6f31bba39dfa19a7726f56e9763bbea",
558
+ "shasum": ""
559
+ },
560
+ "require": {
561
+ "php": "^7.1"
562
+ },
563
+ "replace": {
564
+ "myclabs/deep-copy": "self.version"
565
+ },
566
+ "require-dev": {
567
+ "doctrine/collections": "^1.0",
568
+ "doctrine/common": "^2.6",
569
+ "phpunit/phpunit": "^7.1"
570
+ },
571
+ "type": "library",
572
+ "autoload": {
573
+ "psr-4": {
574
+ "DeepCopy\\": "src/DeepCopy/"
575
+ },
576
+ "files": [
577
+ "src/DeepCopy/deep_copy.php"
578
+ ]
579
+ },
580
+ "notification-url": "https://packagist.org/downloads/",
581
+ "license": [
582
+ "MIT"
583
+ ],
584
+ "description": "Create deep copies (clones) of your objects",
585
+ "keywords": [
586
+ "clone",
587
+ "copy",
588
+ "duplicate",
589
+ "object",
590
+ "object graph"
591
+ ],
592
+ "time": "2019-08-09T12:45:53+00:00"
593
+ },
594
  {
595
  "name": "nb/oxymel",
596
  "version": "v0.1.0",
633
  "time": "2013-02-24T15:01:54+00:00"
634
  },
635
  {
636
+ "name": "phpcompatibility/php-compatibility",
637
+ "version": "9.3.2",
638
  "source": {
639
  "type": "git",
640
+ "url": "https://github.com/PHPCompatibility/PHPCompatibility.git",
641
+ "reference": "bfca2be3992f40e92206e5a7ebe5eaee37280b58"
642
  },
643
  "dist": {
644
  "type": "zip",
645
+ "url": "https://api.github.com/repos/PHPCompatibility/PHPCompatibility/zipball/bfca2be3992f40e92206e5a7ebe5eaee37280b58",
646
+ "reference": "bfca2be3992f40e92206e5a7ebe5eaee37280b58",
647
  "shasum": ""
648
  },
649
  "require": {
650
+ "php": ">=5.3",
651
+ "squizlabs/php_codesniffer": "^2.3 || ^3.0.2"
652
  },
653
+ "conflict": {
654
+ "squizlabs/php_codesniffer": "2.6.2"
 
 
 
655
  },
656
+ "require-dev": {
657
+ "phpunit/phpunit": "~4.5 || ^5.0 || ^6.0 || ^7.0"
658
+ },
659
+ "suggest": {
660
+ "dealerdirect/phpcodesniffer-composer-installer": "^0.5 || This Composer plugin will sort out the PHPCS 'installed_paths' automatically.",
661
+ "roave/security-advisories": "dev-master || Helps prevent installing dependencies with known security issues."
662
  },
663
+ "type": "phpcodesniffer-standard",
664
  "notification-url": "https://packagist.org/downloads/",
665
  "license": [
666
+ "LGPL-3.0-or-later"
667
  ],
668
  "authors": [
669
  {
670
+ "name": "Wim Godden",
671
+ "homepage": "https://github.com/wimg",
672
+ "role": "lead"
673
+ },
674
+ {
675
+ "name": "Juliette Reinders Folmer",
676
+ "homepage": "https://github.com/jrfnl",
677
+ "role": "lead"
678
+ },
679
+ {
680
+ "name": "Contributors",
681
+ "homepage": "https://github.com/PHPCompatibility/PHPCompatibility/graphs/contributors"
682
  }
683
  ],
684
+ "description": "A set of sniffs for PHP_CodeSniffer that checks for PHP cross-version compatibility.",
685
+ "homepage": "http://techblog.wimgodden.be/tag/codesniffer/",
686
  "keywords": [
687
+ "compatibility",
688
+ "phpcs",
689
+ "standards"
 
 
690
  ],
691
+ "time": "2019-10-16T21:24:24+00:00"
692
  },
693
  {
694
+ "name": "phpcompatibility/phpcompatibility-paragonie",
695
+ "version": "1.2.0",
696
  "source": {
697
  "type": "git",
698
+ "url": "https://github.com/PHPCompatibility/PHPCompatibilityParagonie.git",
699
+ "reference": "94b2388c4fe99e9e2ef0772e280fa0eafa1d0603"
700
  },
701
  "dist": {
702
  "type": "zip",
703
+ "url": "https://api.github.com/repos/PHPCompatibility/PHPCompatibilityParagonie/zipball/94b2388c4fe99e9e2ef0772e280fa0eafa1d0603",
704
+ "reference": "94b2388c4fe99e9e2ef0772e280fa0eafa1d0603",
705
  "shasum": ""
706
  },
707
  "require": {
708
+ "phpcompatibility/php-compatibility": "^9.0"
709
  },
710
+ "require-dev": {
711
+ "dealerdirect/phpcodesniffer-composer-installer": "^0.5",
712
+ "paragonie/random_compat": "dev-master",
713
+ "paragonie/sodium_compat": "dev-master"
 
714
  },
715
+ "suggest": {
716
+ "dealerdirect/phpcodesniffer-composer-installer": "^0.5 || This Composer plugin will sort out the PHP_CodeSniffer 'installed_paths' automatically.",
717
+ "roave/security-advisories": "dev-master || Helps prevent installing dependencies with known security issues."
 
718
  },
719
+ "type": "phpcodesniffer-standard",
720
  "notification-url": "https://packagist.org/downloads/",
721
  "license": [
722
+ "LGPL-3.0-or-later"
723
  ],
724
  "authors": [
725
  {
726
+ "name": "Wim Godden",
727
+ "role": "lead"
728
+ },
729
+ {
730
+ "name": "Juliette Reinders Folmer",
731
+ "role": "lead"
732
  }
733
  ],
734
+ "description": "A set of rulesets for PHP_CodeSniffer to check for PHP cross-version compatibility issues in projects, while accounting for polyfills provided by the Paragonie polyfill libraries.",
735
+ "homepage": "http://phpcompatibility.com/",
736
  "keywords": [
737
+ "compatibility",
738
+ "paragonie",
739
+ "phpcs",
740
+ "polyfill",
741
+ "standards"
742
  ],
743
+ "time": "2019-10-16T21:41:26+00:00"
744
  },
745
  {
746
+ "name": "phpcompatibility/phpcompatibility-wp",
747
+ "version": "2.1.0",
748
  "source": {
749
  "type": "git",
750
+ "url": "https://github.com/PHPCompatibility/PHPCompatibilityWP.git",
751
+ "reference": "41bef18ba688af638b7310666db28e1ea9158b2f"
752
  },
753
  "dist": {
754
  "type": "zip",
755
+ "url": "https://api.github.com/repos/PHPCompatibility/PHPCompatibilityWP/zipball/41bef18ba688af638b7310666db28e1ea9158b2f",
756
+ "reference": "41bef18ba688af638b7310666db28e1ea9158b2f",
757
  "shasum": ""
758
  },
759
+ "require": {
760
+ "phpcompatibility/php-compatibility": "^9.0",
761
+ "phpcompatibility/phpcompatibility-paragonie": "^1.0"
762
+ },
763
  "require-dev": {
764
+ "dealerdirect/phpcodesniffer-composer-installer": "^0.5"
 
 
 
765
  },
766
+ "suggest": {
767
+ "dealerdirect/phpcodesniffer-composer-installer": "^0.5 || This Composer plugin will sort out the PHP_CodeSniffer 'installed_paths' automatically.",
768
+ "roave/security-advisories": "dev-master || Helps prevent installing dependencies with known security issues."
 
 
769
  },
770
+ "type": "phpcodesniffer-standard",
771
  "notification-url": "https://packagist.org/downloads/",
772
  "license": [
773
+ "LGPL-3.0-or-later"
774
  ],
775
  "authors": [
776
  {
777
+ "name": "Wim Godden",
778
+ "role": "lead"
779
+ },
780
+ {
781
+ "name": "Juliette Reinders Folmer",
782
+ "role": "lead"
783
  }
784
  ],
785
+ "description": "A ruleset for PHP_CodeSniffer to check for PHP cross-version compatibility issues in projects, while accounting for polyfills provided by WordPress.",
786
+ "homepage": "http://phpcompatibility.com/",
787
  "keywords": [
788
+ "compatibility",
789
+ "phpcs",
790
+ "standards",
791
+ "wordpress"
792
  ],
793
+ "time": "2019-08-28T14:22:28+00:00"
794
  },
795
  {
796
+ "name": "phpdocumentor/reflection-common",
797
+ "version": "2.0.0",
798
  "source": {
799
  "type": "git",
800
+ "url": "https://github.com/phpDocumentor/ReflectionCommon.git",
801
+ "reference": "63a995caa1ca9e5590304cd845c15ad6d482a62a"
802
  },
803
  "dist": {
804
  "type": "zip",
805
+ "url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/63a995caa1ca9e5590304cd845c15ad6d482a62a",
806
+ "reference": "63a995caa1ca9e5590304cd845c15ad6d482a62a",
807
  "shasum": ""
808
  },
809
  "require": {
810
+ "php": ">=7.1"
811
  },
812
  "require-dev": {
813
+ "phpunit/phpunit": "~6"
814
  },
815
  "type": "library",
816
+ "extra": {
817
+ "branch-alias": {
818
+ "dev-master": "2.x-dev"
819
+ }
820
+ },
821
  "autoload": {
822
+ "psr-4": {
823
+ "phpDocumentor\\Reflection\\": "src/"
824
  }
825
  },
826
  "notification-url": "https://packagist.org/downloads/",
827
  "license": [
828
+ "MIT"
829
  ],
830
  "authors": [
831
  {
832
+ "name": "Jaap van Otterdijk",
833
+ "email": "opensource@ijaap.nl"
834
  }
835
  ],
836
+ "description": "Common reflection classes used by phpdocumentor to reflect the code structure",
837
+ "homepage": "http://www.phpdoc.org",
838
  "keywords": [
839
+ "FQSEN",
840
+ "phpDocumentor",
841
+ "phpdoc",
842
+ "reflection",
843
+ "static analysis"
 
 
844
  ],
845
+ "time": "2018-08-07T13:53:10+00:00"
846
  },
847
  {
848
+ "name": "phpdocumentor/reflection-docblock",
849
+ "version": "4.3.2",
850
  "source": {
851
  "type": "git",
852
+ "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git",
853
+ "reference": "b83ff7cfcfee7827e1e78b637a5904fe6a96698e"
854
  },
855
  "dist": {
856
  "type": "zip",
857
+ "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/b83ff7cfcfee7827e1e78b637a5904fe6a96698e",
858
+ "reference": "b83ff7cfcfee7827e1e78b637a5904fe6a96698e",
859
  "shasum": ""
860
  },
861
  "require": {
862
+ "php": "^7.0",
863
+ "phpdocumentor/reflection-common": "^1.0.0 || ^2.0.0",
864
+ "phpdocumentor/type-resolver": "~0.4 || ^1.0.0",
865
+ "webmozart/assert": "^1.0"
866
+ },
867
+ "require-dev": {
868
+ "doctrine/instantiator": "^1.0.5",
869
+ "mockery/mockery": "^1.0",
870
+ "phpunit/phpunit": "^6.4"
871
  },
872
  "type": "library",
873
  "extra": {
874
  "branch-alias": {
875
+ "dev-master": "4.x-dev"
876
  }
877
  },
878
  "autoload": {
879
  "psr-4": {
880
+ "phpDocumentor\\Reflection\\": [
881
+ "src/"
882
+ ]
883
  }
884
  },
885
  "notification-url": "https://packagist.org/downloads/",
888
  ],
889
  "authors": [
890
  {
891
+ "name": "Mike van Riel",
892
+ "email": "me@mikevanriel.com"
893
  }
894
  ],
895
+ "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.",
896
+ "time": "2019-09-12T14:27:41+00:00"
 
 
 
 
 
 
 
897
  },
898
  {
899
+ "name": "phpdocumentor/type-resolver",
900
+ "version": "1.0.1",
901
  "source": {
902
  "type": "git",
903
+ "url": "https://github.com/phpDocumentor/TypeResolver.git",
904
+ "reference": "2e32a6d48972b2c1976ed5d8967145b6cec4a4a9"
905
  },
906
  "dist": {
907
  "type": "zip",
908
+ "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/2e32a6d48972b2c1976ed5d8967145b6cec4a4a9",
909
+ "reference": "2e32a6d48972b2c1976ed5d8967145b6cec4a4a9",
910
  "shasum": ""
911
  },
912
  "require": {
913
+ "php": "^7.1",
914
+ "phpdocumentor/reflection-common": "^2.0"
915
  },
916
  "require-dev": {
917
+ "ext-tokenizer": "^7.1",
918
+ "mockery/mockery": "~1",
919
+ "phpunit/phpunit": "^7.0"
920
+ },
921
+ "type": "library",
922
+ "extra": {
923
+ "branch-alias": {
924
+ "dev-master": "1.x-dev"
925
+ }
926
+ },
927
+ "autoload": {
928
+ "psr-4": {
929
+ "phpDocumentor\\Reflection\\": "src"
930
+ }
931
+ },
932
+ "notification-url": "https://packagist.org/downloads/",
933
+ "license": [
934
+ "MIT"
935
+ ],
936
+ "authors": [
937
+ {
938
+ "name": "Mike van Riel",
939
+ "email": "me@mikevanriel.com"
940
+ }
941
+ ],
942
+ "description": "A PSR-5 based resolver of Class names, Types and Structural Element Names",
943
+ "time": "2019-08-22T18:11:29+00:00"
944
+ },
945
+ {
946
+ "name": "phpspec/prophecy",
947
+ "version": "1.9.0",
948
+ "source": {
949
+ "type": "git",
950
+ "url": "https://github.com/phpspec/prophecy.git",
951
+ "reference": "f6811d96d97bdf400077a0cc100ae56aa32b9203"
952
+ },
953
+ "dist": {
954
+ "type": "zip",
955
+ "url": "https://api.github.com/repos/phpspec/prophecy/zipball/f6811d96d97bdf400077a0cc100ae56aa32b9203",
956
+ "reference": "f6811d96d97bdf400077a0cc100ae56aa32b9203",
957
+ "shasum": ""
958
+ },
959
+ "require": {
960
+ "doctrine/instantiator": "^1.0.2",
961
+ "php": "^5.3|^7.0",
962
+ "phpdocumentor/reflection-docblock": "^2.0|^3.0.2|^4.0|^5.0",
963
+ "sebastian/comparator": "^1.1|^2.0|^3.0",
964
+ "sebastian/recursion-context": "^1.0|^2.0|^3.0"
965
+ },
966
+ "require-dev": {
967
+ "phpspec/phpspec": "^2.5|^3.2",
968
+ "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.5 || ^7.1"
969
+ },
970
+ "type": "library",
971
+ "extra": {
972
+ "branch-alias": {
973
+ "dev-master": "1.8.x-dev"
974
+ }
975
+ },
976
+ "autoload": {
977
+ "psr-4": {
978
+ "Prophecy\\": "src/Prophecy"
979
+ }
980
+ },
981
+ "notification-url": "https://packagist.org/downloads/",
982
+ "license": [
983
+ "MIT"
984
+ ],
985
+ "authors": [
986
+ {
987
+ "name": "Konstantin Kudryashov",
988
+ "email": "ever.zet@gmail.com",
989
+ "homepage": "http://everzet.com"
990
+ },
991
+ {
992
+ "name": "Marcello Duarte",
993
+ "email": "marcello.duarte@gmail.com"
994
+ }
995
+ ],
996
+ "description": "Highly opinionated mocking framework for PHP 5.3+",
997
+ "homepage": "https://github.com/phpspec/prophecy",
998
+ "keywords": [
999
+ "Double",
1000
+ "Dummy",
1001
+ "fake",
1002
+ "mock",
1003
+ "spy",
1004
+ "stub"
1005
+ ],
1006
+ "time": "2019-10-03T11:07:50+00:00"
1007
+ },
1008
+ {
1009
+ "name": "phpunit/php-code-coverage",
1010
+ "version": "4.0.8",
1011
+ "source": {
1012
+ "type": "git",
1013
+ "url": "https://github.com/sebastianbergmann/php-code-coverage.git",
1014
+ "reference": "ef7b2f56815df854e66ceaee8ebe9393ae36a40d"
1015
+ },
1016
+ "dist": {
1017
+ "type": "zip",
1018
+ "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/ef7b2f56815df854e66ceaee8ebe9393ae36a40d",
1019
+ "reference": "ef7b2f56815df854e66ceaee8ebe9393ae36a40d",
1020
+ "shasum": ""
1021
+ },
1022
+ "require": {
1023
+ "ext-dom": "*",
1024
+ "ext-xmlwriter": "*",
1025
+ "php": "^5.6 || ^7.0",
1026
+ "phpunit/php-file-iterator": "^1.3",
1027
+ "phpunit/php-text-template": "^1.2",
1028
+ "phpunit/php-token-stream": "^1.4.2 || ^2.0",
1029
+ "sebastian/code-unit-reverse-lookup": "^1.0",
1030
+ "sebastian/environment": "^1.3.2 || ^2.0",
1031
+ "sebastian/version": "^1.0 || ^2.0"
1032
+ },
1033
+ "require-dev": {
1034
+ "ext-xdebug": "^2.1.4",
1035
+ "phpunit/phpunit": "^5.7"
1036
+ },
1037
+ "suggest": {
1038
+ "ext-xdebug": "^2.5.1"
1039
+ },
1040
+ "type": "library",
1041
+ "extra": {
1042
+ "branch-alias": {
1043
+ "dev-master": "4.0.x-dev"
1044
+ }
1045
+ },
1046
+ "autoload": {
1047
+ "classmap": [
1048
+ "src/"
1049
+ ]
1050
+ },
1051
+ "notification-url": "https://packagist.org/downloads/",
1052
+ "license": [
1053
+ "BSD-3-Clause"
1054
+ ],
1055
+ "authors": [
1056
+ {
1057
+ "name": "Sebastian Bergmann",
1058
+ "email": "sb@sebastian-bergmann.de",
1059
+ "role": "lead"
1060
+ }
1061
+ ],
1062
+ "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.",
1063
+ "homepage": "https://github.com/sebastianbergmann/php-code-coverage",
1064
+ "keywords": [
1065
+ "coverage",
1066
+ "testing",
1067
+ "xunit"
1068
+ ],
1069
+ "time": "2017-04-02T07:44:40+00:00"
1070
+ },
1071
+ {
1072
+ "name": "phpunit/php-file-iterator",
1073
+ "version": "1.4.5",
1074
+ "source": {
1075
+ "type": "git",
1076
+ "url": "https://github.com/sebastianbergmann/php-file-iterator.git",
1077
+ "reference": "730b01bc3e867237eaac355e06a36b85dd93a8b4"
1078
+ },
1079
+ "dist": {
1080
+ "type": "zip",
1081
+ "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/730b01bc3e867237eaac355e06a36b85dd93a8b4",
1082
+ "reference": "730b01bc3e867237eaac355e06a36b85dd93a8b4",
1083
+ "shasum": ""
1084
+ },
1085
+ "require": {
1086
+ "php": ">=5.3.3"
1087
+ },
1088
+ "type": "library",
1089
+ "extra": {
1090
+ "branch-alias": {
1091
+ "dev-master": "1.4.x-dev"
1092
+ }
1093
+ },
1094
+ "autoload": {
1095
+ "classmap": [
1096
+ "src/"
1097
+ ]
1098
+ },
1099
+ "notification-url": "https://packagist.org/downloads/",
1100
+ "license": [
1101
+ "BSD-3-Clause"
1102
+ ],
1103
+ "authors": [
1104
+ {
1105
+ "name": "Sebastian Bergmann",
1106
+ "email": "sb@sebastian-bergmann.de",
1107
+ "role": "lead"
1108
+ }
1109
+ ],
1110
+ "description": "FilterIterator implementation that filters files based on a list of suffixes.",
1111
+ "homepage": "https://github.com/sebastianbergmann/php-file-iterator/",
1112
+ "keywords": [
1113
+ "filesystem",
1114
+ "iterator"
1115
+ ],
1116
+ "time": "2017-11-27T13:52:08+00:00"
1117
+ },
1118
+ {
1119
+ "name": "phpunit/php-text-template",
1120
+ "version": "1.2.1",
1121
+ "source": {
1122
+ "type": "git",
1123
+ "url": "https://github.com/sebastianbergmann/php-text-template.git",
1124
+ "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686"
1125
+ },
1126
+ "dist": {
1127
+ "type": "zip",
1128
+ "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/31f8b717e51d9a2afca6c9f046f5d69fc27c8686",
1129
+ "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686",
1130
+ "shasum": ""
1131
+ },
1132
+ "require": {
1133
+ "php": ">=5.3.3"
1134
+ },
1135
+ "type": "library",
1136
+ "autoload": {
1137
+ "classmap": [
1138
+ "src/"
1139
+ ]
1140
+ },
1141
+ "notification-url": "https://packagist.org/downloads/",
1142
+ "license": [
1143
+ "BSD-3-Clause"
1144
+ ],
1145
+ "authors": [
1146
+ {
1147
+ "name": "Sebastian Bergmann",
1148
+ "email": "sebastian@phpunit.de",
1149
+ "role": "lead"
1150
+ }
1151
+ ],
1152
+ "description": "Simple template engine.",
1153
+ "homepage": "https://github.com/sebastianbergmann/php-text-template/",
1154
+ "keywords": [
1155
+ "template"
1156
+ ],
1157
+ "time": "2015-06-21T13:50:34+00:00"
1158
+ },
1159
+ {
1160
+ "name": "phpunit/php-timer",
1161
+ "version": "1.0.9",
1162
+ "source": {
1163
+ "type": "git",
1164
+ "url": "https://github.com/sebastianbergmann/php-timer.git",
1165
+ "reference": "3dcf38ca72b158baf0bc245e9184d3fdffa9c46f"
1166
+ },
1167
+ "dist": {
1168
+ "type": "zip",
1169
+ "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/3dcf38ca72b158baf0bc245e9184d3fdffa9c46f",
1170
+ "reference": "3dcf38ca72b158baf0bc245e9184d3fdffa9c46f",
1171
+ "shasum": ""
1172
+ },
1173
+ "require": {
1174
+ "php": "^5.3.3 || ^7.0"
1175
+ },
1176
+ "require-dev": {
1177
+ "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.0"
1178
+ },
1179
+ "type": "library",
1180
+ "extra": {
1181
+ "branch-alias": {
1182
+ "dev-master": "1.0-dev"
1183
+ }
1184
+ },
1185
+ "autoload": {
1186
+ "classmap": [
1187
+ "src/"
1188
+ ]
1189
+ },
1190
+ "notification-url": "https://packagist.org/downloads/",
1191
+ "license": [
1192
+ "BSD-3-Clause"
1193
+ ],
1194
+ "authors": [
1195
+ {
1196
+ "name": "Sebastian Bergmann",
1197
+ "email": "sb@sebastian-bergmann.de",
1198
+ "role": "lead"
1199
+ }
1200
+ ],
1201
+ "description": "Utility class for timing",
1202
+ "homepage": "https://github.com/sebastianbergmann/php-timer/",
1203
+ "keywords": [
1204
+ "timer"
1205
+ ],
1206
+ "time": "2017-02-26T11:10:40+00:00"
1207
+ },
1208
+ {
1209
+ "name": "phpunit/php-token-stream",
1210
+ "version": "2.0.2",
1211
+ "source": {
1212
+ "type": "git",
1213
+ "url": "https://github.com/sebastianbergmann/php-token-stream.git",
1214
+ "reference": "791198a2c6254db10131eecfe8c06670700904db"
1215
+ },
1216
+ "dist": {
1217
+ "type": "zip",
1218
+ "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/791198a2c6254db10131eecfe8c06670700904db",
1219
+ "reference": "791198a2c6254db10131eecfe8c06670700904db",
1220
+ "shasum": ""
1221
+ },
1222
+ "require": {
1223
+ "ext-tokenizer": "*",
1224
+ "php": "^7.0"
1225
+ },
1226
+ "require-dev": {
1227
+ "phpunit/phpunit": "^6.2.4"
1228
+ },
1229
+ "type": "library",
1230
+ "extra": {
1231
+ "branch-alias": {
1232
+ "dev-master": "2.0-dev"
1233
+ }
1234
+ },
1235
+ "autoload": {
1236
+ "classmap": [
1237
+ "src/"
1238
+ ]
1239
+ },
1240
+ "notification-url": "https://packagist.org/downloads/",
1241
+ "license": [
1242
+ "BSD-3-Clause"
1243
+ ],
1244
+ "authors": [
1245
+ {
1246
+ "name": "Sebastian Bergmann",
1247
+ "email": "sebastian@phpunit.de"
1248
+ }
1249
+ ],
1250
+ "description": "Wrapper around PHP's tokenizer extension.",
1251
+ "homepage": "https://github.com/sebastianbergmann/php-token-stream/",
1252
+ "keywords": [
1253
+ "tokenizer"
1254
+ ],
1255
+ "time": "2017-11-27T05:48:46+00:00"
1256
+ },
1257
+ {
1258
+ "name": "phpunit/phpunit",
1259
+ "version": "5.7.27",
1260
+ "source": {
1261
+ "type": "git",
1262
+ "url": "https://github.com/sebastianbergmann/phpunit.git",
1263
+ "reference": "b7803aeca3ccb99ad0a506fa80b64cd6a56bbc0c"
1264
+ },
1265
+ "dist": {
1266
+ "type": "zip",
1267
+ "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/b7803aeca3ccb99ad0a506fa80b64cd6a56bbc0c",
1268
+ "reference": "b7803aeca3ccb99ad0a506fa80b64cd6a56bbc0c",
1269
+ "shasum": ""
1270
+ },
1271
+ "require": {
1272
+ "ext-dom": "*",
1273
+ "ext-json": "*",
1274
+ "ext-libxml": "*",
1275
+ "ext-mbstring": "*",
1276
+ "ext-xml": "*",
1277
+ "myclabs/deep-copy": "~1.3",
1278
+ "php": "^5.6 || ^7.0",
1279
+ "phpspec/prophecy": "^1.6.2",
1280
+ "phpunit/php-code-coverage": "^4.0.4",
1281
+ "phpunit/php-file-iterator": "~1.4",
1282
+ "phpunit/php-text-template": "~1.2",
1283
+ "phpunit/php-timer": "^1.0.6",
1284
+ "phpunit/phpunit-mock-objects": "^3.2",
1285
+ "sebastian/comparator": "^1.2.4",
1286
+ "sebastian/diff": "^1.4.3",
1287
+ "sebastian/environment": "^1.3.4 || ^2.0",
1288
+ "sebastian/exporter": "~2.0",
1289
+ "sebastian/global-state": "^1.1",
1290
+ "sebastian/object-enumerator": "~2.0",
1291
+ "sebastian/resource-operations": "~1.0",
1292
+ "sebastian/version": "^1.0.6|^2.0.1",
1293
+ "symfony/yaml": "~2.1|~3.0|~4.0"
1294
+ },
1295
+ "conflict": {
1296
+ "phpdocumentor/reflection-docblock": "3.0.2"
1297
+ },
1298
+ "require-dev": {
1299
+ "ext-pdo": "*"
1300
+ },
1301
+ "suggest": {
1302
+ "ext-xdebug": "*",
1303
+ "phpunit/php-invoker": "~1.1"
1304
+ },
1305
+ "bin": [
1306
+ "phpunit"
1307
+ ],
1308
+ "type": "library",
1309
+ "extra": {
1310
+ "branch-alias": {
1311
+ "dev-master": "5.7.x-dev"
1312
+ }
1313
+ },
1314
+ "autoload": {
1315
+ "classmap": [
1316
+ "src/"
1317
+ ]
1318
+ },
1319
+ "notification-url": "https://packagist.org/downloads/",
1320
+ "license": [
1321
+ "BSD-3-Clause"
1322
+ ],
1323
+ "authors": [
1324
+ {
1325
+ "name": "Sebastian Bergmann",
1326
+ "email": "sebastian@phpunit.de",
1327
+ "role": "lead"
1328
+ }
1329
+ ],
1330
+ "description": "The PHP Unit Testing framework.",
1331
+ "homepage": "https://phpunit.de/",
1332
+ "keywords": [
1333
+ "phpunit",
1334
+ "testing",
1335
+ "xunit"
1336
+ ],
1337
+ "time": "2018-02-01T05:50:59+00:00"
1338
+ },
1339
+ {
1340
+ "name": "phpunit/phpunit-mock-objects",
1341
+ "version": "3.4.4",
1342
+ "source": {
1343
+ "type": "git",
1344
+ "url": "https://github.com/sebastianbergmann/phpunit-mock-objects.git",
1345
+ "reference": "a23b761686d50a560cc56233b9ecf49597cc9118"
1346
+ },
1347
+ "dist": {
1348
+ "type": "zip",
1349
+ "url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/a23b761686d50a560cc56233b9ecf49597cc9118",
1350
+ "reference": "a23b761686d50a560cc56233b9ecf49597cc9118",
1351
+ "shasum": ""
1352
+ },
1353
+ "require": {
1354
+ "doctrine/instantiator": "^1.0.2",
1355
+ "php": "^5.6 || ^7.0",
1356
+ "phpunit/php-text-template": "^1.2",
1357
+ "sebastian/exporter": "^1.2 || ^2.0"
1358
+ },
1359
+ "conflict": {
1360
+ "phpunit/phpunit": "<5.4.0"
1361
+ },
1362
+ "require-dev": {
1363
+ "phpunit/phpunit": "^5.4"
1364
+ },
1365
+ "suggest": {
1366
+ "ext-soap": "*"
1367
+ },
1368
+ "type": "library",
1369
+ "extra": {
1370
+ "branch-alias": {
1371
+ "dev-master": "3.2.x-dev"
1372
+ }
1373
+ },
1374
+ "autoload": {
1375
+ "classmap": [
1376
+ "src/"
1377
+ ]
1378
+ },
1379
+ "notification-url": "https://packagist.org/downloads/",
1380
+ "license": [
1381
+ "BSD-3-Clause"
1382
+ ],
1383
+ "authors": [
1384
+ {
1385
+ "name": "Sebastian Bergmann",
1386
+ "email": "sb@sebastian-bergmann.de",
1387
+ "role": "lead"
1388
+ }
1389
+ ],
1390
+ "description": "Mock Object library for PHPUnit",
1391
+ "homepage": "https://github.com/sebastianbergmann/phpunit-mock-objects/",
1392
+ "keywords": [
1393
+ "mock",
1394
+ "xunit"
1395
+ ],
1396
+ "abandoned": true,
1397
+ "time": "2017-06-30T09:13:00+00:00"
1398
+ },
1399
+ {
1400
+ "name": "psr/container",
1401
+ "version": "1.0.0",
1402
+ "source": {
1403
+ "type": "git",
1404
+ "url": "https://github.com/php-fig/container.git",
1405
+ "reference": "b7ce3b176482dbbc1245ebf52b181af44c2cf55f"
1406
+ },
1407
+ "dist": {
1408
+ "type": "zip",
1409
+ "url": "https://api.github.com/repos/php-fig/container/zipball/b7ce3b176482dbbc1245ebf52b181af44c2cf55f",
1410
+ "reference": "b7ce3b176482dbbc1245ebf52b181af44c2cf55f",
1411
+ "shasum": ""
1412
+ },
1413
+ "require": {
1414
+ "php": ">=5.3.0"
1415
+ },
1416
+ "type": "library",
1417
+ "extra": {
1418
+ "branch-alias": {
1419
+ "dev-master": "1.0.x-dev"
1420
+ }
1421
+ },
1422
+ "autoload": {
1423
+ "psr-4": {
1424
+ "Psr\\Container\\": "src/"
1425
+ }
1426
+ },
1427
+ "notification-url": "https://packagist.org/downloads/",
1428
+ "license": [
1429
+ "MIT"
1430
+ ],
1431
+ "authors": [
1432
+ {
1433
+ "name": "PHP-FIG",
1434
+ "homepage": "http://www.php-fig.org/"
1435
+ }
1436
+ ],
1437
+ "description": "Common Container Interface (PHP FIG PSR-11)",
1438
+ "homepage": "https://github.com/php-fig/container",
1439
+ "keywords": [
1440
+ "PSR-11",
1441
+ "container",
1442
+ "container-interface",
1443
+ "container-interop",
1444
+ "psr"
1445
+ ],
1446
+ "time": "2017-02-14T16:28:37+00:00"
1447
+ },
1448
+ {
1449
+ "name": "psr/log",
1450
+ "version": "1.1.1",
1451
+ "source": {
1452
+ "type": "git",
1453
+ "url": "https://github.com/php-fig/log.git",
1454
+ "reference": "bf73deb2b3b896a9d9c75f3f0d88185d2faa27e2"
1455
+ },
1456
+ "dist": {
1457
+ "type": "zip",
1458
+ "url": "https://api.github.com/repos/php-fig/log/zipball/bf73deb2b3b896a9d9c75f3f0d88185d2faa27e2",
1459
+ "reference": "bf73deb2b3b896a9d9c75f3f0d88185d2faa27e2",
1460
+ "shasum": ""
1461
+ },
1462
+ "require": {
1463
+ "php": ">=5.3.0"
1464
+ },
1465
+ "type": "library",
1466
+ "extra": {
1467
+ "branch-alias": {
1468
+ "dev-master": "1.1.x-dev"
1469
+ }
1470
+ },
1471
+ "autoload": {
1472
+ "psr-4": {
1473
+ "Psr\\Log\\": "Psr/Log/"
1474
+ }
1475
+ },
1476
+ "notification-url": "https://packagist.org/downloads/",
1477
+ "license": [
1478
+ "MIT"
1479
+ ],
1480
+ "authors": [
1481
+ {
1482
+ "name": "PHP-FIG",
1483
+ "homepage": "http://www.php-fig.org/"
1484
+ }
1485
+ ],
1486
+ "description": "Common interface for logging libraries",
1487
+ "homepage": "https://github.com/php-fig/log",
1488
+ "keywords": [
1489
+ "log",
1490
+ "psr",
1491
+ "psr-3"
1492
+ ],
1493
+ "time": "2019-10-25T08:06:51+00:00"
1494
+ },
1495
+ {
1496
+ "name": "ramsey/array_column",
1497
+ "version": "1.1.3",
1498
+ "source": {
1499
+ "type": "git",
1500
+ "url": "https://github.com/ramsey/array_column.git",
1501
+ "reference": "f8e52eb28e67eb50e613b451dd916abcf783c1db"
1502
+ },
1503
+ "dist": {
1504
+ "type": "zip",
1505
+ "url": "https://api.github.com/repos/ramsey/array_column/zipball/f8e52eb28e67eb50e613b451dd916abcf783c1db",
1506
+ "reference": "f8e52eb28e67eb50e613b451dd916abcf783c1db",
1507
+ "shasum": ""
1508
+ },
1509
+ "require-dev": {
1510
+ "jakub-onderka/php-parallel-lint": "0.8.*",
1511
+ "phpunit/phpunit": "~4.5",
1512
+ "satooshi/php-coveralls": "0.6.*",
1513
+ "squizlabs/php_codesniffer": "~2.2"
1514
+ },
1515
+ "type": "library",
1516
+ "autoload": {
1517
+ "files": [
1518
+ "src/array_column.php"
1519
+ ]
1520
+ },
1521
+ "notification-url": "https://packagist.org/downloads/",
1522
+ "license": [
1523
+ "MIT"
1524
+ ],
1525
+ "authors": [
1526
+ {
1527
+ "name": "Ben Ramsey",
1528
+ "homepage": "http://benramsey.com"
1529
+ }
1530
+ ],
1531
+ "description": "Provides functionality for array_column() to projects using PHP earlier than version 5.5.",
1532
+ "homepage": "https://github.com/ramsey/array_column",
1533
+ "keywords": [
1534
+ "array",
1535
+ "array_column",
1536
+ "column"
1537
+ ],
1538
+ "abandoned": true,
1539
+ "time": "2015-03-20T22:07:39+00:00"
1540
+ },
1541
+ {
1542
+ "name": "rmccue/requests",
1543
+ "version": "v1.7.0",
1544
+ "source": {
1545
+ "type": "git",
1546
+ "url": "https://github.com/rmccue/Requests.git",
1547
+ "reference": "87932f52ffad70504d93f04f15690cf16a089546"
1548
+ },
1549
+ "dist": {
1550
+ "type": "zip",
1551
+ "url": "https://api.github.com/repos/rmccue/Requests/zipball/87932f52ffad70504d93f04f15690cf16a089546",
1552
+ "reference": "87932f52ffad70504d93f04f15690cf16a089546",
1553
+ "shasum": ""
1554
+ },
1555
+ "require": {
1556
+ "php": ">=5.2"
1557
+ },
1558
+ "require-dev": {
1559
+ "requests/test-server": "dev-master"
1560
+ },
1561
+ "type": "library",
1562
+ "autoload": {
1563
+ "psr-0": {
1564
+ "Requests": "library/"
1565
+ }
1566
+ },
1567
+ "notification-url": "https://packagist.org/downloads/",
1568
+ "license": [
1569
+ "ISC"
1570
+ ],
1571
+ "authors": [
1572
+ {
1573
+ "name": "Ryan McCue",
1574
+ "homepage": "http://ryanmccue.info"
1575
+ }
1576
+ ],
1577
+ "description": "A HTTP library written in PHP, for human beings.",
1578
+ "homepage": "http://github.com/rmccue/Requests",
1579
+ "keywords": [
1580
+ "curl",
1581
+ "fsockopen",
1582
+ "http",
1583
+ "idna",
1584
+ "ipv6",
1585
+ "iri",
1586
+ "sockets"
1587
+ ],
1588
+ "time": "2016-10-13T00:11:37+00:00"
1589
+ },
1590
+ {
1591
+ "name": "sebastian/code-unit-reverse-lookup",
1592
+ "version": "1.0.1",
1593
+ "source": {
1594
+ "type": "git",
1595
+ "url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git",
1596
+ "reference": "4419fcdb5eabb9caa61a27c7a1db532a6b55dd18"
1597
+ },
1598
+ "dist": {
1599
+ "type": "zip",
1600
+ "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/4419fcdb5eabb9caa61a27c7a1db532a6b55dd18",
1601
+ "reference": "4419fcdb5eabb9caa61a27c7a1db532a6b55dd18",
1602
+ "shasum": ""
1603
+ },
1604
+ "require": {
1605
+ "php": "^5.6 || ^7.0"
1606
+ },
1607
+ "require-dev": {
1608
+ "phpunit/phpunit": "^5.7 || ^6.0"
1609
+ },
1610
+ "type": "library",
1611
+ "extra": {
1612
+ "branch-alias": {
1613
+ "dev-master": "1.0.x-dev"
1614
+ }
1615
+ },
1616
+ "autoload": {
1617
+ "classmap": [
1618
+ "src/"
1619
+ ]
1620
+ },
1621
+ "notification-url": "https://packagist.org/downloads/",
1622
+ "license": [
1623
+ "BSD-3-Clause"
1624
+ ],
1625
+ "authors": [
1626
+ {
1627
+ "name": "Sebastian Bergmann",
1628
+ "email": "sebastian@phpunit.de"
1629
+ }
1630
+ ],
1631
+ "description": "Looks up which function or method a line of code belongs to",
1632
+ "homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/",
1633
+ "time": "2017-03-04T06:30:41+00:00"
1634
+ },
1635
+ {
1636
+ "name": "sebastian/comparator",
1637
+ "version": "1.2.4",
1638
+ "source": {
1639
+ "type": "git",
1640
+ "url": "https://github.com/sebastianbergmann/comparator.git",
1641
+ "reference": "2b7424b55f5047b47ac6e5ccb20b2aea4011d9be"
1642
+ },
1643
+ "dist": {
1644
+ "type": "zip",
1645
+ "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/2b7424b55f5047b47ac6e5ccb20b2aea4011d9be",
1646
+ "reference": "2b7424b55f5047b47ac6e5ccb20b2aea4011d9be",
1647
+ "shasum": ""
1648
+ },
1649
+ "require": {
1650
+ "php": ">=5.3.3",
1651
+ "sebastian/diff": "~1.2",
1652
+ "sebastian/exporter": "~1.2 || ~2.0"
1653
+ },
1654
+ "require-dev": {
1655
+ "phpunit/phpunit": "~4.4"
1656
+ },
1657
+ "type": "library",
1658
+ "extra": {
1659
+ "branch-alias": {
1660
+ "dev-master": "1.2.x-dev"
1661
+ }
1662
+ },
1663
+ "autoload": {
1664
+ "classmap": [
1665
+ "src/"
1666
+ ]
1667
+ },
1668
+ "notification-url": "https://packagist.org/downloads/",
1669
+ "license": [
1670
+ "BSD-3-Clause"
1671
+ ],
1672
+ "authors": [
1673
+ {
1674
+ "name": "Jeff Welch",
1675
+ "email": "whatthejeff@gmail.com"
1676
+ },
1677
+ {
1678
+ "name": "Volker Dusch",
1679
+ "email": "github@wallbash.com"
1680
+ },
1681
+ {
1682
+ "name": "Bernhard Schussek",
1683
+ "email": "bschussek@2bepublished.at"
1684
+ },
1685
+ {
1686
+ "name": "Sebastian Bergmann",
1687
+ "email": "sebastian@phpunit.de"
1688
+ }
1689
+ ],
1690
+ "description": "Provides the functionality to compare PHP values for equality",
1691
+ "homepage": "http://www.github.com/sebastianbergmann/comparator",
1692
+ "keywords": [
1693
+ "comparator",
1694
+ "compare",
1695
+ "equality"
1696
+ ],
1697
+ "time": "2017-01-29T09:50:25+00:00"
1698
+ },
1699
+ {
1700
+ "name": "sebastian/diff",
1701
+ "version": "1.4.3",
1702
+ "source": {
1703
+ "type": "git",
1704
+ "url": "https://github.com/sebastianbergmann/diff.git",
1705
+ "reference": "7f066a26a962dbe58ddea9f72a4e82874a3975a4"
1706
+ },
1707
+ "dist": {
1708
+ "type": "zip",
1709
+ "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/7f066a26a962dbe58ddea9f72a4e82874a3975a4",
1710
+ "reference": "7f066a26a962dbe58ddea9f72a4e82874a3975a4",
1711
+ "shasum": ""
1712
+ },
1713
+ "require": {
1714
+ "php": "^5.3.3 || ^7.0"
1715
+ },
1716
+ "require-dev": {
1717
+ "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.0"
1718
+ },
1719
+ "type": "library",
1720
+ "extra": {
1721
+ "branch-alias": {
1722
+ "dev-master": "1.4-dev"
1723
+ }
1724
+ },
1725
+ "autoload": {
1726
+ "classmap": [
1727
+ "src/"
1728
+ ]
1729
+ },
1730
+ "notification-url": "https://packagist.org/downloads/",
1731
+ "license": [
1732
+ "BSD-3-Clause"
1733
+ ],
1734
+ "authors": [
1735
+ {
1736
+ "name": "Kore Nordmann",
1737
+ "email": "mail@kore-nordmann.de"
1738
+ },
1739
+ {
1740
+ "name": "Sebastian Bergmann",
1741
+ "email": "sebastian@phpunit.de"
1742
+ }
1743
+ ],
1744
+ "description": "Diff implementation",
1745
+ "homepage": "https://github.com/sebastianbergmann/diff",
1746
+ "keywords": [
1747
+ "diff"
1748
+ ],
1749
+ "time": "2017-05-22T07:24:03+00:00"
1750
+ },
1751
+ {
1752
+ "name": "sebastian/environment",
1753
+ "version": "2.0.0",
1754
+ "source": {
1755
+ "type": "git",
1756
+ "url": "https://github.com/sebastianbergmann/environment.git",
1757
+ "reference": "5795ffe5dc5b02460c3e34222fee8cbe245d8fac"
1758
+ },
1759
+ "dist": {
1760
+ "type": "zip",
1761
+ "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/5795ffe5dc5b02460c3e34222fee8cbe245d8fac",
1762
+ "reference": "5795ffe5dc5b02460c3e34222fee8cbe245d8fac",
1763
+ "shasum": ""
1764
+ },
1765
+ "require": {
1766
+ "php": "^5.6 || ^7.0"
1767
+ },
1768
+ "require-dev": {
1769
+ "phpunit/phpunit": "^5.0"
1770
+ },
1771
+ "type": "library",
1772
+ "extra": {
1773
+ "branch-alias": {
1774
+ "dev-master": "2.0.x-dev"
1775
+ }
1776
+ },
1777
+ "autoload": {
1778
+ "classmap": [
1779
+ "src/"
1780
+ ]
1781
+ },
1782
+ "notification-url": "https://packagist.org/downloads/",
1783
+ "license": [
1784
+ "BSD-3-Clause"
1785
+ ],
1786
+ "authors": [
1787
+ {
1788
+ "name": "Sebastian Bergmann",
1789
+ "email": "sebastian@phpunit.de"
1790
+ }
1791
+ ],
1792
+ "description": "Provides functionality to handle HHVM/PHP environments",
1793
+ "homepage": "http://www.github.com/sebastianbergmann/environment",
1794
+ "keywords": [
1795
+ "Xdebug",
1796
+ "environment",
1797
+ "hhvm"
1798
+ ],
1799
+ "time": "2016-11-26T07:53:53+00:00"
1800
+ },
1801
+ {
1802
+ "name": "sebastian/exporter",
1803
+ "version": "2.0.0",
1804
+ "source": {
1805
+ "type": "git",
1806
+ "url": "https://github.com/sebastianbergmann/exporter.git",
1807
+ "reference": "ce474bdd1a34744d7ac5d6aad3a46d48d9bac4c4"
1808
+ },
1809
+ "dist": {
1810
+ "type": "zip",
1811
+ "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/ce474bdd1a34744d7ac5d6aad3a46d48d9bac4c4",
1812
+ "reference": "ce474bdd1a34744d7ac5d6aad3a46d48d9bac4c4",
1813
+ "shasum": ""
1814
+ },
1815
+ "require": {
1816
+ "php": ">=5.3.3",
1817
+ "sebastian/recursion-context": "~2.0"
1818
+ },
1819
+ "require-dev": {
1820
+ "ext-mbstring": "*",
1821
+ "phpunit/phpunit": "~4.4"
1822
+ },
1823
+ "type": "library",
1824
+ "extra": {
1825
+ "branch-alias": {
1826
+ "dev-master": "2.0.x-dev"
1827
+ }
1828
+ },
1829
+ "autoload": {
1830
+ "classmap": [
1831
+ "src/"
1832
+ ]
1833
+ },
1834
+ "notification-url": "https://packagist.org/downloads/",
1835
+ "license": [
1836
+ "BSD-3-Clause"
1837
+ ],
1838
+ "authors": [
1839
+ {
1840
+ "name": "Jeff Welch",
1841
+ "email": "whatthejeff@gmail.com"
1842
+ },
1843
+ {
1844
+ "name": "Volker Dusch",
1845
+ "email": "github@wallbash.com"
1846
+ },
1847
+ {
1848
+ "name": "Bernhard Schussek",
1849
+ "email": "bschussek@2bepublished.at"
1850
+ },
1851
+ {
1852
+ "name": "Sebastian Bergmann",
1853
+ "email": "sebastian@phpunit.de"
1854
+ },
1855
+ {
1856
+ "name": "Adam Harvey",
1857
+ "email": "aharvey@php.net"
1858
+ }
1859
+ ],
1860
+ "description": "Provides the functionality to export PHP variables for visualization",
1861
+ "homepage": "http://www.github.com/sebastianbergmann/exporter",
1862
+ "keywords": [
1863
+ "export",
1864
+ "exporter"
1865
+ ],
1866
+ "time": "2016-11-19T08:54:04+00:00"
1867
+ },
1868
+ {
1869
+ "name": "sebastian/global-state",
1870
+ "version": "1.1.1",
1871
+ "source": {
1872
+ "type": "git",
1873
+ "url": "https://github.com/sebastianbergmann/global-state.git",
1874
+ "reference": "bc37d50fea7d017d3d340f230811c9f1d7280af4"
1875
+ },
1876
+ "dist": {
1877
+ "type": "zip",
1878
+ "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/bc37d50fea7d017d3d340f230811c9f1d7280af4",
1879
+ "reference": "bc37d50fea7d017d3d340f230811c9f1d7280af4",
1880
+ "shasum": ""
1881
+ },
1882
+ "require": {
1883
+ "php": ">=5.3.3"
1884
+ },
1885
+ "require-dev": {
1886
+ "phpunit/phpunit": "~4.2"
1887
+ },
1888
+ "suggest": {
1889
+ "ext-uopz": "*"
1890
+ },
1891
+ "type": "library",
1892
+ "extra": {
1893
+ "branch-alias": {
1894
+ "dev-master": "1.0-dev"
1895
+ }
1896
+ },
1897
+ "autoload": {
1898
+ "classmap": [
1899
+ "src/"
1900
+ ]
1901
+ },
1902
+ "notification-url": "https://packagist.org/downloads/",
1903
+ "license": [
1904
+ "BSD-3-Clause"
1905
+ ],
1906
+ "authors": [
1907
+ {
1908
+ "name": "Sebastian Bergmann",
1909
+ "email": "sebastian@phpunit.de"
1910
+ }
1911
+ ],
1912
+ "description": "Snapshotting of global state",
1913
+ "homepage": "http://www.github.com/sebastianbergmann/global-state",
1914
+ "keywords": [
1915
+ "global state"
1916
+ ],
1917
+ "time": "2015-10-12T03:26:01+00:00"
1918
+ },
1919
+ {
1920
+ "name": "sebastian/object-enumerator",
1921
+ "version": "2.0.1",
1922
+ "source": {
1923
+ "type": "git",
1924
+ "url": "https://github.com/sebastianbergmann/object-enumerator.git",
1925
+ "reference": "1311872ac850040a79c3c058bea3e22d0f09cbb7"
1926
+ },
1927
+ "dist": {
1928
+ "type": "zip",
1929
+ "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/1311872ac850040a79c3c058bea3e22d0f09cbb7",
1930
+ "reference": "1311872ac850040a79c3c058bea3e22d0f09cbb7",
1931
+ "shasum": ""
1932
+ },
1933
+ "require": {
1934
+ "php": ">=5.6",
1935
+ "sebastian/recursion-context": "~2.0"
1936
+ },
1937
+ "require-dev": {
1938
+ "phpunit/phpunit": "~5"
1939
+ },
1940
+ "type": "library",
1941
+ "extra": {
1942
+ "branch-alias": {
1943
+ "dev-master": "2.0.x-dev"
1944
+ }
1945
+ },
1946
+ "autoload": {
1947
+ "classmap": [
1948
+ "src/"
1949
+ ]
1950
+ },
1951
+ "notification-url": "https://packagist.org/downloads/",
1952
+ "license": [
1953
+ "BSD-3-Clause"
1954
+ ],
1955
+ "authors": [
1956
+ {
1957
+ "name": "Sebastian Bergmann",
1958
+ "email": "sebastian@phpunit.de"
1959
+ }
1960
+ ],
1961
+ "description": "Traverses array structures and object graphs to enumerate all referenced objects",
1962
+ "homepage": "https://github.com/sebastianbergmann/object-enumerator/",
1963
+ "time": "2017-02-18T15:18:39+00:00"
1964
+ },
1965
+ {
1966
+ "name": "sebastian/recursion-context",
1967
+ "version": "2.0.0",
1968
+ "source": {
1969
+ "type": "git",
1970
+ "url": "https://github.com/sebastianbergmann/recursion-context.git",
1971
+ "reference": "2c3ba150cbec723aa057506e73a8d33bdb286c9a"
1972
+ },
1973
+ "dist": {
1974
+ "type": "zip",
1975
+ "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/2c3ba150cbec723aa057506e73a8d33bdb286c9a",
1976
+ "reference": "2c3ba150cbec723aa057506e73a8d33bdb286c9a",
1977
+ "shasum": ""
1978
+ },
1979
+ "require": {
1980
+ "php": ">=5.3.3"
1981
+ },
1982
+ "require-dev": {
1983
+ "phpunit/phpunit": "~4.4"
1984
+ },
1985
+ "type": "library",
1986
+ "extra": {
1987
+ "branch-alias": {
1988
+ "dev-master": "2.0.x-dev"
1989
+ }
1990
+ },
1991
+ "autoload": {
1992
+ "classmap": [
1993
+ "src/"
1994
+ ]
1995
+ },
1996
+ "notification-url": "https://packagist.org/downloads/",
1997
+ "license": [
1998
+ "BSD-3-Clause"
1999
+ ],
2000
+ "authors": [
2001
+ {
2002
+ "name": "Jeff Welch",
2003
+ "email": "whatthejeff@gmail.com"
2004
+ },
2005
+ {
2006
+ "name": "Sebastian Bergmann",
2007
+ "email": "sebastian@phpunit.de"
2008
+ },
2009
+ {
2010
+ "name": "Adam Harvey",
2011
+ "email": "aharvey@php.net"
2012
+ }
2013
+ ],
2014
+ "description": "Provides functionality to recursively process PHP variables",
2015
+ "homepage": "http://www.github.com/sebastianbergmann/recursion-context",
2016
+ "time": "2016-11-19T07:33:16+00:00"
2017
+ },
2018
+ {
2019
+ "name": "sebastian/resource-operations",
2020
+ "version": "1.0.0",
2021
+ "source": {
2022
+ "type": "git",
2023
+ "url": "https://github.com/sebastianbergmann/resource-operations.git",
2024
+ "reference": "ce990bb21759f94aeafd30209e8cfcdfa8bc3f52"
2025
+ },
2026
+ "dist": {
2027
+ "type": "zip",
2028
+ "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/ce990bb21759f94aeafd30209e8cfcdfa8bc3f52",
2029
+ "reference": "ce990bb21759f94aeafd30209e8cfcdfa8bc3f52",
2030
+ "shasum": ""
2031
+ },
2032
+ "require": {
2033
+ "php": ">=5.6.0"
2034
+ },
2035
+ "type": "library",
2036
+ "extra": {
2037
+ "branch-alias": {
2038
+ "dev-master": "1.0.x-dev"
2039
+ }
2040
+ },
2041
+ "autoload": {
2042
+ "classmap": [
2043
+ "src/"
2044
+ ]
2045
+ },
2046
+ "notification-url": "https://packagist.org/downloads/",
2047
+ "license": [
2048
+ "BSD-3-Clause"
2049
+ ],
2050
+ "authors": [
2051
+ {
2052
+ "name": "Sebastian Bergmann",
2053
+ "email": "sebastian@phpunit.de"
2054
+ }
2055
+ ],
2056
+ "description": "Provides a list of PHP built-in functions that operate on resources",
2057
+ "homepage": "https://www.github.com/sebastianbergmann/resource-operations",
2058
+ "time": "2015-07-28T20:34:47+00:00"
2059
+ },
2060
+ {
2061
+ "name": "sebastian/version",
2062
+ "version": "2.0.1",
2063
+ "source": {
2064
+ "type": "git",
2065
+ "url": "https://github.com/sebastianbergmann/version.git",
2066
+ "reference": "99732be0ddb3361e16ad77b68ba41efc8e979019"
2067
+ },
2068
+ "dist": {
2069
+ "type": "zip",
2070
+ "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/99732be0ddb3361e16ad77b68ba41efc8e979019",
2071
+ "reference": "99732be0ddb3361e16ad77b68ba41efc8e979019",
2072
+ "shasum": ""
2073
+ },
2074
+ "require": {
2075
+ "php": ">=5.6"
2076
+ },
2077
+ "type": "library",
2078
+ "extra": {
2079
+ "branch-alias": {
2080
+ "dev-master": "2.0.x-dev"
2081
+ }
2082
+ },
2083
+ "autoload": {
2084
+ "classmap": [
2085
+ "src/"
2086
+ ]
2087
+ },
2088
+ "notification-url": "https://packagist.org/downloads/",
2089
+ "license": [
2090
+ "BSD-3-Clause"
2091
+ ],
2092
+ "authors": [
2093
+ {
2094
+ "name": "Sebastian Bergmann",
2095
+ "email": "sebastian@phpunit.de",
2096
+ "role": "lead"
2097
+ }
2098
+ ],
2099
+ "description": "Library that helps with managing the version number of Git-hosted PHP projects",
2100
+ "homepage": "https://github.com/sebastianbergmann/version",
2101
+ "time": "2016-10-03T07:35:21+00:00"
2102
+ },
2103
+ {
2104
+ "name": "seld/jsonlint",
2105
+ "version": "1.7.2",
2106
+ "source": {
2107
+ "type": "git",
2108
+ "url": "https://github.com/Seldaek/jsonlint.git",
2109
+ "reference": "e2e5d290e4d2a4f0eb449f510071392e00e10d19"
2110
+ },
2111
+ "dist": {
2112
+ "type": "zip",
2113
+ "url": "https://api.github.com/repos/Seldaek/jsonlint/zipball/e2e5d290e4d2a4f0eb449f510071392e00e10d19",
2114
+ "reference": "e2e5d290e4d2a4f0eb449f510071392e00e10d19",
2115
+ "shasum": ""
2116
+ },
2117
+ "require": {
2118
+ "php": "^5.3 || ^7.0"
2119
+ },
2120
+ "require-dev": {
2121
+ "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.0"
2122
  },
2123
  "bin": [
2124
  "bin/jsonlint"
2147
  "parser",
2148
  "validator"
2149
  ],
2150
+ "time": "2019-10-24T14:27:39+00:00"
2151
  },
2152
  {
2153
  "name": "seld/phar-utils",
2154
+ "version": "1.0.1",
2155
  "source": {
2156
  "type": "git",
2157
  "url": "https://github.com/Seldaek/phar-utils.git",
2191
  "keywords": [
2192
  "phra"
2193
  ],
2194
+ "time": "2015-10-13T18:44:15+00:00"
2195
+ },
2196
+ {
2197
+ "name": "squizlabs/php_codesniffer",
2198
+ "version": "3.5.1",
2199
+ "source": {
2200
+ "type": "git",
2201
+ "url": "https://github.com/squizlabs/PHP_CodeSniffer.git",
2202
+ "reference": "82cd0f854ceca17731d6d019c7098e3755c45060"
2203
+ },
2204
+ "dist": {
2205
+ "type": "zip",
2206
+ "url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/82cd0f854ceca17731d6d019c7098e3755c45060",
2207
+ "reference": "82cd0f854ceca17731d6d019c7098e3755c45060",
2208
+ "shasum": ""
2209
+ },
2210
+ "require": {
2211
+ "ext-simplexml": "*",
2212
+ "ext-tokenizer": "*",
2213
+ "ext-xmlwriter": "*",
2214
+ "php": ">=5.4.0"
2215
+ },
2216
+ "require-dev": {
2217
+ "phpunit/phpunit": "^4.0 || ^5.0 || ^6.0 || ^7.0"
2218
+ },
2219
+ "bin": [
2220
+ "bin/phpcs",
2221
+ "bin/phpcbf"
2222
+ ],
2223
+ "type": "library",
2224
+ "extra": {
2225
+ "branch-alias": {
2226
+ "dev-master": "3.x-dev"
2227
+ }
2228
+ },
2229
+ "notification-url": "https://packagist.org/downloads/",
2230
+ "license": [
2231
+ "BSD-3-Clause"
2232
+ ],
2233
+ "authors": [
2234
+ {
2235
+ "name": "Greg Sherwood",
2236
+ "role": "lead"
2237
+ }
2238
+ ],
2239
+ "description": "PHP_CodeSniffer tokenizes PHP, JavaScript and CSS files and detects violations of a defined set of coding standards.",
2240
+ "homepage": "https://github.com/squizlabs/PHP_CodeSniffer",
2241
+ "keywords": [
2242
+ "phpcs",
2243
+ "standards"
2244
+ ],
2245
+ "time": "2019-10-16T21:14:26+00:00"
2246
  },
2247
  {
2248
  "name": "symfony/config",
2249
+ "version": "v3.4.32",
2250
  "source": {
2251
  "type": "git",
2252
  "url": "https://github.com/symfony/config.git",
2253
+ "reference": "717ad66b5257e9752ae3c5722b5810bb4c40b236"
2254
  },
2255
  "dist": {
2256
  "type": "zip",
2257
+ "url": "https://api.github.com/repos/symfony/config/zipball/717ad66b5257e9752ae3c5722b5810bb4c40b236",
2258
+ "reference": "717ad66b5257e9752ae3c5722b5810bb4c40b236",
2259
  "shasum": ""
2260
  },
2261
  "require": {
2262
  "php": "^5.5.9|>=7.0.8",
2263
+ "symfony/filesystem": "~2.8|~3.0|~4.0",
2264
+ "symfony/polyfill-ctype": "~1.8"
2265
  },
2266
  "conflict": {
2267
  "symfony/dependency-injection": "<3.3",
2269
  },
2270
  "require-dev": {
2271
  "symfony/dependency-injection": "~3.3|~4.0",
2272
+ "symfony/event-dispatcher": "~3.3|~4.0",
2273
  "symfony/finder": "~3.3|~4.0",
2274
  "symfony/yaml": "~3.0|~4.0"
2275
  },
2306
  ],
2307
  "description": "Symfony Config Component",
2308
  "homepage": "https://symfony.com",
2309
+ "time": "2019-09-19T15:32:51+00:00"
2310
  },
2311
  {
2312
  "name": "symfony/console",
2313
+ "version": "v3.4.32",
2314
  "source": {
2315
  "type": "git",
2316
  "url": "https://github.com/symfony/console.git",
2317
+ "reference": "4727d7f3c99b9dea0ae70ed4f34645728aa90453"
2318
  },
2319
  "dist": {
2320
  "type": "zip",
2321
+ "url": "https://api.github.com/repos/symfony/console/zipball/4727d7f3c99b9dea0ae70ed4f34645728aa90453",
2322
+ "reference": "4727d7f3c99b9dea0ae70ed4f34645728aa90453",
2323
  "shasum": ""
2324
  },
2325
  "require": {
2328
  "symfony/polyfill-mbstring": "~1.0"
2329
  },
2330
  "conflict": {
2331
+ "symfony/dependency-injection": "<3.4",
2332
  "symfony/process": "<3.3"
2333
  },
2334
+ "provide": {
2335
+ "psr/log-implementation": "1.0"
2336
+ },
2337
  "require-dev": {
2338
  "psr/log": "~1.0",
2339
  "symfony/config": "~3.3|~4.0",
2340
+ "symfony/dependency-injection": "~3.4|~4.0",
2341
  "symfony/event-dispatcher": "~2.8|~3.0|~4.0",
 
2342
  "symfony/lock": "~3.4|~4.0",
2343
  "symfony/process": "~3.3|~4.0"
2344
  },
2378
  ],
2379
  "description": "Symfony Console Component",
2380
  "homepage": "https://symfony.com",
2381
+ "time": "2019-10-06T19:52:09+00:00"
2382
  },
2383
  {
2384
  "name": "symfony/debug",
2385
+ "version": "v3.4.32",
2386
  "source": {
2387
  "type": "git",
2388
  "url": "https://github.com/symfony/debug.git",
2389
+ "reference": "b3e7ce815d82196435d16dc458023f8fb6b36ceb"
2390
  },
2391
  "dist": {
2392
  "type": "zip",
2393
+ "url": "https://api.github.com/repos/symfony/debug/zipball/b3e7ce815d82196435d16dc458023f8fb6b36ceb",
2394
+ "reference": "b3e7ce815d82196435d16dc458023f8fb6b36ceb",
2395
  "shasum": ""
2396
  },
2397
  "require": {
2434
  ],
2435
  "description": "Symfony Debug Component",
2436
  "homepage": "https://symfony.com",
2437
+ "time": "2019-09-19T15:32:51+00:00"
2438
  },
2439
  {
2440
  "name": "symfony/dependency-injection",
2441
+ "version": "v3.4.32",
2442
  "source": {
2443
  "type": "git",
2444
  "url": "https://github.com/symfony/dependency-injection.git",
2445
+ "reference": "9cf81798f857205c5bbb4c8c7895f838d40b0c4b"
2446
  },
2447
  "dist": {
2448
  "type": "zip",
2449
+ "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/9cf81798f857205c5bbb4c8c7895f838d40b0c4b",
2450
+ "reference": "9cf81798f857205c5bbb4c8c7895f838d40b0c4b",
2451
  "shasum": ""
2452
  },
2453
  "require": {
2455
  "psr/container": "^1.0"
2456
  },
2457
  "conflict": {
2458
+ "symfony/config": "<3.3.7",
2459
  "symfony/finder": "<3.3",
2460
  "symfony/proxy-manager-bridge": "<3.4",
2461
  "symfony/yaml": "<3.4"
2505
  ],
2506
  "description": "Symfony DependencyInjection Component",
2507
  "homepage": "https://symfony.com",
2508
+ "time": "2019-09-27T15:47:48+00:00"
2509
  },
2510
  {
2511
  "name": "symfony/event-dispatcher",
2512
+ "version": "v3.4.32",
2513
  "source": {
2514
  "type": "git",
2515
  "url": "https://github.com/symfony/event-dispatcher.git",
2516
+ "reference": "3e922c4c3430b9de624e8a285dada5e61e230959"
2517
  },
2518
  "dist": {
2519
  "type": "zip",
2520
+ "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/3e922c4c3430b9de624e8a285dada5e61e230959",
2521
+ "reference": "3e922c4c3430b9de624e8a285dada5e61e230959",
2522
  "shasum": ""
2523
  },
2524
  "require": {
2568
  ],
2569
  "description": "Symfony EventDispatcher Component",
2570
  "homepage": "https://symfony.com",
2571
+ "time": "2019-08-23T08:05:57+00:00"
2572
  },
2573
  {
2574
  "name": "symfony/filesystem",
2575
+ "version": "v3.4.32",
2576
  "source": {
2577
  "type": "git",
2578
  "url": "https://github.com/symfony/filesystem.git",
2579
+ "reference": "00e3a6ddd723b8bcfe4f2a1b6f82b98eeeb51516"
2580
  },
2581
  "dist": {
2582
  "type": "zip",
2583
+ "url": "https://api.github.com/repos/symfony/filesystem/zipball/00e3a6ddd723b8bcfe4f2a1b6f82b98eeeb51516",
2584
+ "reference": "00e3a6ddd723b8bcfe4f2a1b6f82b98eeeb51516",
2585
  "shasum": ""
2586
  },
2587
  "require": {
2588
+ "php": "^5.5.9|>=7.0.8",
2589
+ "symfony/polyfill-ctype": "~1.8"
2590
  },
2591
  "type": "library",
2592
  "extra": {
2618
  ],
2619
  "description": "Symfony Filesystem Component",
2620
  "homepage": "https://symfony.com",
2621
+ "time": "2019-08-20T13:31:17+00:00"
2622
  },
2623
  {
2624
  "name": "symfony/finder",
2625
+ "version": "v3.4.32",
2626
  "source": {
2627
  "type": "git",
2628
  "url": "https://github.com/symfony/finder.git",
2629
+ "reference": "2b6a666d6ff7fb65d10b97d817c8e7930944afb9"
2630
  },
2631
  "dist": {
2632
  "type": "zip",
2633
+ "url": "https://api.github.com/repos/symfony/finder/zipball/2b6a666d6ff7fb65d10b97d817c8e7930944afb9",
2634
+ "reference": "2b6a666d6ff7fb65d10b97d817c8e7930944afb9",
2635
  "shasum": ""
2636
  },
2637
  "require": {
2667
  ],
2668
  "description": "Symfony Finder Component",
2669
  "homepage": "https://symfony.com",
2670
+ "time": "2019-09-01T21:32:23+00:00"
2671
+ },
2672
+ {
2673
+ "name": "symfony/polyfill-ctype",
2674
+ "version": "v1.12.0",
2675
+ "source": {
2676
+ "type": "git",
2677
+ "url": "https://github.com/symfony/polyfill-ctype.git",
2678
+ "reference": "550ebaac289296ce228a706d0867afc34687e3f4"
2679
+ },
2680
+ "dist": {
2681
+ "type": "zip",
2682
+ "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/550ebaac289296ce228a706d0867afc34687e3f4",
2683
+ "reference": "550ebaac289296ce228a706d0867afc34687e3f4",
2684
+ "shasum": ""
2685
+ },
2686
+ "require": {
2687
+ "php": ">=5.3.3"
2688
+ },
2689
+ "suggest": {
2690
+ "ext-ctype": "For best performance"
2691
+ },
2692
+ "type": "library",
2693
+ "extra": {
2694
+ "branch-alias": {
2695
+ "dev-master": "1.12-dev"
2696
+ }
2697
+ },
2698
+ "autoload": {
2699
+ "psr-4": {
2700
+ "Symfony\\Polyfill\\Ctype\\": ""
2701
+ },
2702
+ "files": [
2703
+ "bootstrap.php"
2704
+ ]
2705
+ },
2706
+ "notification-url": "https://packagist.org/downloads/",
2707
+ "license": [
2708
+ "MIT"
2709
+ ],
2710
+ "authors": [
2711
+ {
2712
+ "name": "Gert de Pagter",
2713
+ "email": "BackEndTea@gmail.com"
2714
+ },
2715
+ {
2716
+ "name": "Symfony Community",
2717
+ "homepage": "https://symfony.com/contributors"
2718
+ }
2719
+ ],
2720
+ "description": "Symfony polyfill for ctype functions",
2721
+ "homepage": "https://symfony.com",
2722
+ "keywords": [
2723
+ "compatibility",
2724
+ "ctype",
2725
+ "polyfill",
2726
+ "portable"
2727
+ ],
2728
+ "time": "2019-08-06T08:03:45+00:00"
2729
  },
2730
  {
2731
  "name": "symfony/polyfill-mbstring",
2732
+ "version": "v1.12.0",
2733
  "source": {
2734
  "type": "git",
2735
  "url": "https://github.com/symfony/polyfill-mbstring.git",
2736
+ "reference": "b42a2f66e8f1b15ccf25652c3424265923eb4f17"
2737
  },
2738
  "dist": {
2739
  "type": "zip",
2740
+ "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/b42a2f66e8f1b15ccf25652c3424265923eb4f17",
2741
+ "reference": "b42a2f66e8f1b15ccf25652c3424265923eb4f17",
2742
  "shasum": ""
2743
  },
2744
  "require": {
2750
  "type": "library",
2751
  "extra": {
2752
  "branch-alias": {
2753
+ "dev-master": "1.12-dev"
2754
  }
2755
  },
2756
  "autoload": {
2784
  "portable",
2785
  "shim"
2786
  ],
2787
+ "time": "2019-08-06T08:03:45+00:00"
2788
  },
2789
  {
2790
  "name": "symfony/process",
2791
+ "version": "v3.4.32",
2792
  "source": {
2793
  "type": "git",
2794
  "url": "https://github.com/symfony/process.git",
2795
+ "reference": "344dc588b163ff58274f1769b90b75237f32ed16"
2796
  },
2797
  "dist": {
2798
  "type": "zip",
2799
+ "url": "https://api.github.com/repos/symfony/process/zipball/344dc588b163ff58274f1769b90b75237f32ed16",
2800
+ "reference": "344dc588b163ff58274f1769b90b75237f32ed16",
2801
  "shasum": ""
2802
  },
2803
  "require": {
2833
  ],
2834
  "description": "Symfony Process Component",
2835
  "homepage": "https://symfony.com",
2836
+ "time": "2019-09-25T14:09:38+00:00"
2837
  },
2838
  {
2839
  "name": "symfony/translation",
2840
+ "version": "v3.4.32",
2841
  "source": {
2842
  "type": "git",
2843
  "url": "https://github.com/symfony/translation.git",
2844
+ "reference": "dd313664be0588560acacb252543b585f5408547"
2845
  },
2846
  "dist": {
2847
  "type": "zip",
2848
+ "url": "https://api.github.com/repos/symfony/translation/zipball/dd313664be0588560acacb252543b585f5408547",
2849
+ "reference": "dd313664be0588560acacb252543b585f5408547",
2850
  "shasum": ""
2851
  },
2852
  "require": {
2856
  "conflict": {
2857
  "symfony/config": "<2.8",
2858
  "symfony/dependency-injection": "<3.4",
2859
+ "symfony/yaml": "<3.4"
2860
  },
2861
  "require-dev": {
2862
  "psr/log": "~1.0",
2863
  "symfony/config": "~2.8|~3.0|~4.0",
2864
  "symfony/dependency-injection": "~3.4|~4.0",
2865
+ "symfony/finder": "~2.8|~3.0|~4.0",
2866
+ "symfony/http-kernel": "~3.4|~4.0",
2867
  "symfony/intl": "^2.8.18|^3.2.5|~4.0",
2868
+ "symfony/var-dumper": "~3.4|~4.0",
2869
+ "symfony/yaml": "~3.4|~4.0"
2870
  },
2871
  "suggest": {
2872
+ "psr/log-implementation": "To use logging capability in translator",
2873
  "symfony/config": "",
2874
  "symfony/yaml": ""
2875
  },
2903
  ],
2904
  "description": "Symfony Translation Component",
2905
  "homepage": "https://symfony.com",
2906
+ "time": "2019-09-27T05:57:25+00:00"
2907
  },
2908
  {
2909
  "name": "symfony/yaml",
2910
+ "version": "v3.4.32",
2911
  "source": {
2912
  "type": "git",
2913
  "url": "https://github.com/symfony/yaml.git",
2914
+ "reference": "768f817446da74a776a31eea335540f9dcb53942"
2915
  },
2916
  "dist": {
2917
  "type": "zip",
2918
+ "url": "https://api.github.com/repos/symfony/yaml/zipball/768f817446da74a776a31eea335540f9dcb53942",
2919
+ "reference": "768f817446da74a776a31eea335540f9dcb53942",
2920
  "shasum": ""
2921
  },
2922
  "require": {
2923
+ "php": "^5.5.9|>=7.0.8",
2924
+ "symfony/polyfill-ctype": "~1.8"
2925
+ },
2926
+ "conflict": {
2927
+ "symfony/console": "<3.4"
2928
  },
2929
  "require-dev": {
2930
+ "symfony/console": "~3.4|~4.0"
2931
  },
2932
  "suggest": {
2933
  "symfony/console": "For validating YAML files using the lint command"
2962
  ],
2963
  "description": "Symfony Yaml Component",
2964
  "homepage": "https://symfony.com",
2965
+ "time": "2019-09-10T10:38:46+00:00"
2966
+ },
2967
+ {
2968
+ "name": "webmozart/assert",
2969
+ "version": "1.5.0",
2970
+ "source": {
2971
+ "type": "git",
2972
+ "url": "https://github.com/webmozart/assert.git",
2973
+ "reference": "88e6d84706d09a236046d686bbea96f07b3a34f4"
2974
+ },
2975
+ "dist": {
2976
+ "type": "zip",
2977
+ "url": "https://api.github.com/repos/webmozart/assert/zipball/88e6d84706d09a236046d686bbea96f07b3a34f4",
2978
+ "reference": "88e6d84706d09a236046d686bbea96f07b3a34f4",
2979
+ "shasum": ""
2980
+ },
2981
+ "require": {
2982
+ "php": "^5.3.3 || ^7.0",
2983
+ "symfony/polyfill-ctype": "^1.8"
2984
+ },
2985
+ "require-dev": {
2986
+ "phpunit/phpunit": "^4.8.36 || ^7.5.13"
2987
+ },
2988
+ "type": "library",
2989
+ "extra": {
2990
+ "branch-alias": {
2991
+ "dev-master": "1.3-dev"
2992
+ }
2993
+ },
2994
+ "autoload": {
2995
+ "psr-4": {
2996
+ "Webmozart\\Assert\\": "src/"
2997
+ }
2998
+ },
2999
+ "notification-url": "https://packagist.org/downloads/",
3000
+ "license": [
3001
+ "MIT"
3002
+ ],
3003
+ "authors": [
3004
+ {
3005
+ "name": "Bernhard Schussek",
3006
+ "email": "bschussek@gmail.com"
3007
+ }
3008
+ ],
3009
+ "description": "Assertions to validate method input/output with nice error messages.",
3010
+ "keywords": [
3011
+ "assert",
3012
+ "check",
3013
+ "validate"
3014
+ ],
3015
+ "time": "2019-08-24T08:43:50+00:00"
3016
+ },
3017
+ {
3018
+ "name": "woocommerce/woocommerce-sniffs",
3019
+ "version": "0.0.8",
3020
+ "source": {
3021
+ "type": "git",
3022
+ "url": "https://github.com/woocommerce/woocommerce-sniffs.git",
3023
+ "reference": "ccdae93ba678d59cd9741bec077d0c63c0a82958"
3024
+ },
3025
+ "dist": {
3026
+ "type": "zip",
3027
+ "url": "https://api.github.com/repos/woocommerce/woocommerce-sniffs/zipball/ccdae93ba678d59cd9741bec077d0c63c0a82958",
3028
+ "reference": "ccdae93ba678d59cd9741bec077d0c63c0a82958",
3029
+ "shasum": ""
3030
+ },
3031
+ "require": {
3032
+ "dealerdirect/phpcodesniffer-composer-installer": "0.5.0",
3033
+ "php": ">=7.0",
3034
+ "phpcompatibility/phpcompatibility-wp": "2.1.0",
3035
+ "wp-coding-standards/wpcs": "2.1.1"
3036
+ },
3037
+ "type": "phpcodesniffer-standard",
3038
+ "notification-url": "https://packagist.org/downloads/",
3039
+ "license": [
3040
+ "MIT"
3041
+ ],
3042
+ "authors": [
3043
+ {
3044
+ "name": "Claudio Sanches",
3045
+ "email": "claudio@automattic.com"
3046
+ }
3047
+ ],
3048
+ "description": "WooCommerce sniffs",
3049
+ "keywords": [
3050
+ "phpcs",
3051
+ "standards",
3052
+ "woocommerce",
3053
+ "wordpress"
3054
+ ],
3055
+ "time": "2019-10-16T18:25:21+00:00"
3056
  },
3057
  {
3058
  "name": "wp-cli/autoload-splitter",
3097
  },
3098
  {
3099
  "name": "wp-cli/cache-command",
3100
+ "version": "v1.0.6",
3101
  "source": {
3102
  "type": "git",
3103
  "url": "https://github.com/wp-cli/cache-command.git",
3104
+ "reference": "d82cba9effa198f17847dce5771c8fb20c443ffa"
3105
  },
3106
  "dist": {
3107
  "type": "zip",
3108
+ "url": "https://api.github.com/repos/wp-cli/cache-command/zipball/d82cba9effa198f17847dce5771c8fb20c443ffa",
3109
+ "reference": "d82cba9effa198f17847dce5771c8fb20c443ffa",
3110
  "shasum": ""
3111
  },
3112
  "require-dev": {
3121
  "bundled": true,
3122
  "commands": [
3123
  "cache",
3124
+ "cache add",
3125
+ "cache decr",
3126
+ "cache delete",
3127
+ "cache flush",
3128
+ "cache get",
3129
+ "cache incr",
3130
+ "cache replace",
3131
+ "cache set",
3132
+ "cache type",
3133
+ "transient",
3134
+ "transient delete",
3135
+ "transient get",
3136
+ "transient set",
3137
+ "transient type"
3138
  ]
3139
  },
3140
  "autoload": {
3156
  "homepage": "https://runcommand.io"
3157
  }
3158
  ],
3159
+ "description": "Manages object and transient caches.",
3160
  "homepage": "https://github.com/wp-cli/cache-command",
3161
+ "time": "2017-12-14T19:21:19+00:00"
3162
  },
3163
  {
3164
  "name": "wp-cli/checksum-command",
3165
+ "version": "v1.0.9",
3166
  "source": {
3167
  "type": "git",
3168
  "url": "https://github.com/wp-cli/checksum-command.git",
3169
+ "reference": "89a319440651f2867f282339c2223cfe5e9cc3fb"
3170
  },
3171
  "dist": {
3172
  "type": "zip",
3173
+ "url": "https://api.github.com/repos/wp-cli/checksum-command/zipball/89a319440651f2867f282339c2223cfe5e9cc3fb",
3174
+ "reference": "89a319440651f2867f282339c2223cfe5e9cc3fb",
3175
  "shasum": ""
3176
  },
3177
  "require-dev": {
3178
  "behat/behat": "~2.5",
3179
+ "wp-cli/wp-cli": "^1.5"
3180
  },
3181
  "type": "wp-cli-package",
3182
  "extra": {
3185
  },
3186
  "bundled": true,
3187
  "commands": [
3188
+ "core verify-checksums",
3189
+ "plugin verify-checksums"
3190
  ]
3191
  },
3192
  "autoload": {
3208
  "homepage": "https://runcommand.io"
3209
  }
3210
  ],
3211
+ "description": "Verifies file integrity by comparing to published checksums.",
3212
  "homepage": "https://github.com/wp-cli/checksum-command",
3213
+ "time": "2018-04-20T07:47:27+00:00"
3214
  },
3215
  {
3216
  "name": "wp-cli/config-command",
3217
+ "version": "v1.2.0",
3218
  "source": {
3219
  "type": "git",
3220
  "url": "https://github.com/wp-cli/config-command.git",
3221
+ "reference": "7bec9b4685b4022ab511630422dd6acccadfca9b"
3222
  },
3223
  "dist": {
3224
  "type": "zip",
3225
+ "url": "https://api.github.com/repos/wp-cli/config-command/zipball/7bec9b4685b4022ab511630422dd6acccadfca9b",
3226
+ "reference": "7bec9b4685b4022ab511630422dd6acccadfca9b",
3227
  "shasum": ""
3228
  },
3229
+ "require": {
3230
+ "wp-cli/wp-config-transformer": "^1.2.1"
3231
+ },
3232
  "require-dev": {
3233
  "behat/behat": "~2.5",
3234
  "wp-cli/wp-cli": "*"
3241
  "bundled": true,
3242
  "commands": [
3243
  "config",
3244
+ "config edit",
3245
+ "config delete",
3246
  "config create",
3247
  "config get",
3248
+ "config has",
3249
+ "config list",
3250
+ "config path",
3251
+ "config set"
3252
  ]
3253
  },
3254
  "autoload": {
3268
  "name": "Daniel Bachhuber",
3269
  "email": "daniel@runcommand.io",
3270
  "homepage": "https://runcommand.io"
3271
+ },
3272
+ {
3273
+ "name": "Alain Schlesser",
3274
+ "email": "alain.schlesser@gmail.com",
3275
+ "homepage": "https://www.alainschlesser.com"
3276
  }
3277
  ],
3278
+ "description": "Generates and reads the wp-config.php file.",
3279
  "homepage": "https://github.com/wp-cli/config-command",
3280
+ "time": "2018-04-20T08:03:51+00:00"
3281
  },
3282
  {
3283
  "name": "wp-cli/core-command",
3284
+ "version": "v1.0.12",
3285
  "source": {
3286
  "type": "git",
3287
  "url": "https://github.com/wp-cli/core-command.git",
3288
+ "reference": "b41913707029c5147b38810700e424ed5f5fe8e0"
3289
  },
3290
  "dist": {
3291
  "type": "zip",
3292
+ "url": "https://api.github.com/repos/wp-cli/core-command/zipball/b41913707029c5147b38810700e424ed5f5fe8e0",
3293
+ "reference": "b41913707029c5147b38810700e424ed5f5fe8e0",
3294
  "shasum": ""
3295
  },
3296
  "require-dev": {
3304
  },
3305
  "bundled": true,
3306
  "commands": [
3307
+ "core",
3308
  "core check-update",
3309
  "core download",
3310
  "core install",
3335
  "homepage": "https://runcommand.io"
3336
  }
3337
  ],
3338
+ "description": "Downloads, installs, updates, and manages a WordPress installation.",
3339
  "homepage": "https://github.com/wp-cli/core-command",
3340
+ "time": "2018-07-25T15:55:02+00:00"
3341
  },
3342
  {
3343
  "name": "wp-cli/cron-command",
3344
+ "version": "v1.0.5",
3345
  "source": {
3346
  "type": "git",
3347
  "url": "https://github.com/wp-cli/cron-command.git",
3348
+ "reference": "9da7e36e8f9c14cb171a3c5204cba2865e0ed7ef"
3349
  },
3350
  "dist": {
3351
  "type": "zip",
3352
+ "url": "https://api.github.com/repos/wp-cli/cron-command/zipball/9da7e36e8f9c14cb171a3c5204cba2865e0ed7ef",
3353
+ "reference": "9da7e36e8f9c14cb171a3c5204cba2865e0ed7ef",
3354
  "shasum": ""
3355
  },
3356
  "require-dev": {
3364
  },
3365
  "bundled": true,
3366
  "commands": [
3367
+ "cron",
3368
  "cron test",
3369
+ "cron event",
3370
  "cron event delete",
3371
  "cron event list",
3372
  "cron event run",
3373
  "cron event schedule",
3374
+ "cron schedule",
3375
  "cron schedule list"
3376
  ]
3377
  },
3394
  "homepage": "https://runcommand.io"
3395
  }
3396
  ],
3397
+ "description": "Tests, runs, and deletes WP-Cron events; manages WP-Cron schedules.",
3398
  "homepage": "https://github.com/wp-cli/cron-command",
3399
+ "time": "2017-12-08T15:09:54+00:00"
3400
  },
3401
  {
3402
  "name": "wp-cli/db-command",
3403
+ "version": "v1.3.5",
3404
  "source": {
3405
  "type": "git",
3406
  "url": "https://github.com/wp-cli/db-command.git",
3407
+ "reference": "c260be59d9ac4c0012b016405e17d0251137fb89"
3408
  },
3409
  "dist": {
3410
  "type": "zip",
3411
+ "url": "https://api.github.com/repos/wp-cli/db-command/zipball/c260be59d9ac4c0012b016405e17d0251137fb89",
3412
+ "reference": "c260be59d9ac4c0012b016405e17d0251137fb89",
3413
  "shasum": ""
3414
  },
 
 
 
3415
  "require-dev": {
3416
+ "behat/behat": "~2.5",
3417
+ "wp-cli/wp-cli": "^1.5"
3418
  },
3419
  "type": "wp-cli-package",
3420
  "extra": {
3423
  },
3424
  "bundled": true,
3425
  "commands": [
3426
+ "db",
3427
  "db create",
3428
  "db drop",
3429
  "db reset",
3437
  "db import",
3438
  "db search",
3439
  "db tables",
3440
+ "db size",
3441
+ "db columns"
3442
  ]
3443
  },
3444
  "autoload": {
3460
  "homepage": "https://runcommand.io"
3461
  }
3462
  ],
3463
+ "description": "Performs basic database operations using credentials stored in wp-config.php.",
3464
  "homepage": "https://github.com/wp-cli/db-command",
3465
+ "time": "2018-07-31T02:06:59+00:00"
3466
+ },
3467
+ {
3468
+ "name": "wp-cli/embed-command",
3469
+ "version": "v1.0.0",
3470
+ "source": {
3471
+ "type": "git",
3472
+ "url": "https://github.com/wp-cli/embed-command.git",
3473
+ "reference": "81319d4243a8dfe096389bf54cdc4fc3dec53497"
3474
+ },
3475
+ "dist": {
3476
+ "type": "zip",
3477
+ "url": "https://api.github.com/repos/wp-cli/embed-command/zipball/81319d4243a8dfe096389bf54cdc4fc3dec53497",
3478
+ "reference": "81319d4243a8dfe096389bf54cdc4fc3dec53497",
3479
+ "shasum": ""
3480
+ },
3481
+ "require-dev": {
3482
+ "behat/behat": "~2.5",
3483
+ "wp-cli/wp-cli": "^1.5"
3484
+ },
3485
+ "type": "wp-cli-package",
3486
+ "extra": {
3487
+ "branch-alias": {
3488
+ "dev-master": "1.x-dev"
3489
+ },
3490
+ "bundled": true,
3491
+ "commands": [
3492
+ "embed",
3493
+ "embed fetch",
3494
+ "embed provider list",
3495
+ "embed provider match",
3496
+ "embed handler list",
3497
+ "embed cache clear",
3498
+ "embed cache find",
3499
+ "embed cache trigger"
3500
+ ]
3501
+ },
3502
+ "autoload": {
3503
+ "psr-4": {
3504
+ "WP_CLI\\Embeds\\": "src/"
3505
+ },
3506
+ "files": [
3507
+ "embed-command.php"
3508
+ ]
3509
+ },
3510
+ "notification-url": "https://packagist.org/downloads/",
3511
+ "license": [
3512
+ "MIT"
3513
+ ],
3514
+ "authors": [
3515
+ {
3516
+ "name": "Pascal Birchler",
3517
+ "homepage": "https://pascalbirchler.com/"
3518
+ }
3519
+ ],
3520
+ "description": "Inspects oEmbed providers, clears embed cache, and more.",
3521
+ "homepage": "https://github.com/wp-cli/embed-command",
3522
+ "time": "2018-01-22T21:26:48+00:00"
3523
  },
3524
  {
3525
  "name": "wp-cli/entity-command",
3526
+ "version": "v1.3.1",
3527
  "source": {
3528
  "type": "git",
3529
  "url": "https://github.com/wp-cli/entity-command.git",
3530
+ "reference": "7b000645684b6acbb1d55ab47b77eb08f35cd229"
3531
  },
3532
  "dist": {
3533
  "type": "zip",
3534
+ "url": "https://api.github.com/repos/wp-cli/entity-command/zipball/7b000645684b6acbb1d55ab47b77eb08f35cd229",
3535
+ "reference": "7b000645684b6acbb1d55ab47b77eb08f35cd229",
3536
  "shasum": ""
3537
  },
3538
  "require-dev": {
3539
  "behat/behat": "~2.5",
3540
  "phpunit/phpunit": "^4.8",
3541
+ "wp-cli/wp-cli": "^1.5"
3542
  },
3543
  "type": "wp-cli-package",
3544
  "extra": {
3548
  "bundled": true,
3549
  "commands": [
3550
  "comment",
3551
+ "comment approve",
3552
+ "comment count",
3553
+ "comment create",
3554
+ "comment delete",
3555
+ "comment exists",
3556
+ "comment generate",
3557
+ "comment get",
3558
+ "comment list",
3559
  "comment meta",
3560
+ "comment meta add",
3561
+ "comment meta delete",
3562
+ "comment meta get",
3563
+ "comment meta list",
3564
+ "comment meta patch",
3565
+ "comment meta pluck",
3566
+ "comment meta update",
3567
+ "comment recount",
3568
+ "comment spam",
3569
+ "comment status",
3570
+ "comment trash",
3571
+ "comment unapprove",
3572
+ "comment unspam",
3573
+ "comment untrash",
3574
+ "comment update",
3575
  "menu",
3576
+ "menu create",
3577
+ "menu delete",
3578
  "menu item",
3579
+ "menu item add-custom",
3580
+ "menu item add-post",
3581
+ "menu item add-term",
3582
+ "menu item delete",
3583
+ "menu item list",
3584
+ "menu item update",
3585
+ "menu list",
3586
  "menu location",
3587
+ "menu location assign",
3588
+ "menu location list",
3589
+ "menu location remove",
3590
  "network meta",
3591
+ "network meta add",
3592
+ "network meta delete",
3593
+ "network meta get",
3594
+ "network meta list",
3595
+ "network meta patch",
3596
+ "network meta pluck",
3597
+ "network meta update",
3598
  "option",
3599
  "option add",
3600
  "option delete",
3601
  "option get",
3602
  "option list",
3603
+ "option patch",
3604
+ "option pluck",
3605
  "option update",
3606
  "post",
3607
+ "post create",
3608
+ "post delete",
3609
+ "post edit",
3610
+ "post generate",
3611
+ "post get",
3612
+ "post list",
3613
  "post meta",
3614
+ "post meta add",
3615
+ "post meta delete",
3616
+ "post meta get",
3617
+ "post meta list",
3618
+ "post meta patch",
3619
+ "post meta pluck",
3620
+ "post meta update",
3621
  "post term",
3622
+ "post term add",
3623
+ "post term list",
3624
+ "post term remove",
3625
+ "post term set",
3626
+ "post update",
3627
  "post-type",
3628
+ "post-type get",
3629
+ "post-type list",
3630
  "site",
3631
+ "site activate",
3632
+ "site archive",
3633
+ "site create",
3634
+ "site deactivate",
3635
+ "site delete",
3636
+ "site empty",
3637
+ "site list",
3638
+ "site mature",
3639
+ "site option",
3640
+ "site private",
3641
+ "site public",
3642
+ "site spam",
3643
+ "site unarchive",
3644
+ "site unmature",
3645
+ "site unspam",
3646
  "taxonomy",
3647
+ "taxonomy get",
3648
+ "taxonomy list",
3649
  "term",
3650
+ "term create",
3651
+ "term delete",
3652
+ "term generate",
3653
+ "term get",
3654
+ "term list",
3655
  "term meta",
3656
+ "term meta add",
3657
+ "term meta delete",
3658
+ "term meta get",
3659
+ "term meta list",
3660
+ "term meta patch",
3661
+ "term meta pluck",
3662
+ "term meta update",
3663
+ "term recount",
3664
+ "term update",
3665
  "user",
3666
+ "user add-cap",
3667
+ "user add-role",
3668
+ "user create",
3669
+ "user delete",
3670
+ "user generate",
3671
+ "user get",
3672
+ "user import-csv",
3673
+ "user list",
3674
+ "user list-caps",
3675
  "user meta",
3676
+ "user meta add",
3677
+ "user meta delete",
3678
+ "user meta get",
3679
+ "user meta list",
3680
+ "user meta patch",
3681
+ "user meta pluck",
3682
+ "user meta update",
3683
+ "user remove-cap",
3684
+ "user remove-role",
3685
+ "user reset-password",
3686
+ "user session",
3687
+ "user session destroy",
3688
+ "user session list",
3689
+ "user set-role",
3690
+ "user spam",
3691
+ "user term",
3692
+ "user term add",
3693
+ "user term list",
3694
+ "user term remove",
3695
+ "user term set",
3696
+ "user unspam",
3697
+ "user update"
3698
  ]
3699
  },
3700
  "autoload": {
3719
  ],
3720
  "description": "Manage WordPress core entities.",
3721
  "homepage": "https://github.com/wp-cli/entity-command",
3722
+ "time": "2018-07-13T12:21:06+00:00"
3723
  },
3724
  {
3725
  "name": "wp-cli/eval-command",
3726
+ "version": "v1.0.5",
3727
  "source": {
3728
  "type": "git",
3729
  "url": "https://github.com/wp-cli/eval-command.git",
3730
+ "reference": "9640d40ab28cd86590396f08f8c382e659f57321"
3731
  },
3732
  "dist": {
3733
  "type": "zip",
3734
+ "url": "https://api.github.com/repos/wp-cli/eval-command/zipball/9640d40ab28cd86590396f08f8c382e659f57321",
3735
+ "reference": "9640d40ab28cd86590396f08f8c382e659f57321",
3736
  "shasum": ""
3737
  },
3738
  "require": {
3771
  "homepage": "https://runcommand.io"
3772
  }
3773
  ],
3774
+ "description": "Executes arbitrary PHP code or files.",
3775
  "homepage": "https://github.com/wp-cli/eval-command",
3776
+ "time": "2017-12-08T14:33:34+00:00"
3777
  },
3778
  {
3779
  "name": "wp-cli/export-command",
3780
+ "version": "v1.0.7",
3781
  "source": {
3782
  "type": "git",
3783
  "url": "https://github.com/wp-cli/export-command.git",
3784
+ "reference": "776d33ad6b2ac93c00fded27402ca8e188e7bff0"
3785
  },
3786
  "dist": {
3787
  "type": "zip",
3788
+ "url": "https://api.github.com/repos/wp-cli/export-command/zipball/776d33ad6b2ac93c00fded27402ca8e188e7bff0",
3789
+ "reference": "776d33ad6b2ac93c00fded27402ca8e188e7bff0",
3790
  "shasum": ""
3791
  },
3792
  "require": {
3793
+ "nb/oxymel": "~0.1.0"
 
3794
  },
3795
  "require-dev": {
3796
+ "behat/behat": "~2.5",
3797
+ "wp-cli/wp-cli": "^1.5"
3798
  },
3799
  "type": "wp-cli-package",
3800
  "extra": {
3825
  "homepage": "https://runcommand.io"
3826
  }
3827
  ],
3828
+ "description": "Exports WordPress content to a WXR file.",
3829
  "homepage": "https://github.com/wp-cli/export-command",
3830
+ "time": "2018-04-20T08:10:47+00:00"
3831
  },
3832
  {
3833
  "name": "wp-cli/extension-command",
3834
+ "version": "v1.2.2",
3835
  "source": {
3836
  "type": "git",
3837
  "url": "https://github.com/wp-cli/extension-command.git",
3838
+ "reference": "18f1036bad42f481f178c2f4139039e9424b6e14"
3839
  },
3840
  "dist": {
3841
  "type": "zip",
3842
+ "url": "https://api.github.com/repos/wp-cli/extension-command/zipball/18f1036bad42f481f178c2f4139039e9424b6e14",
3843
+ "reference": "18f1036bad42f481f178c2f4139039e9424b6e14",
3844
  "shasum": ""
3845
  },
3846
  "require-dev": {
3854
  },
3855
  "bundled": true,
3856
  "commands": [
3857
+ "plugin",
3858
  "plugin activate",
3859
  "plugin deactivate",
3860
  "plugin delete",
3868
  "plugin toggle",
3869
  "plugin uninstall",
3870
  "plugin update",
3871
+ "theme",
3872
  "theme activate",
3873
  "theme delete",
3874
  "theme disable",
3877
  "theme install",
3878
  "theme is-installed",
3879
  "theme list",
3880
+ "theme mod",
3881
  "theme mod get",
3882
  "theme mod set",
3883
  "theme mod remove",
3884
  "theme path",
3885
  "theme search",
3886
  "theme status",
3887
+ "theme update",
3888
+ "theme mod list"
3889
  ]
3890
  },
3891
  "autoload": {
3892
  "psr-4": {
3893
+ "": "src/"
 
3894
  },
3895
  "files": [
3896
  "extension-command.php"
3907
  "homepage": "https://runcommand.io"
3908
  }
3909
  ],
3910
+ "description": "Manages plugins and themes, including installs, activations, and updates.",
3911
  "homepage": "https://github.com/wp-cli/extension-command",
3912
+ "time": "2018-07-31T17:46:49+00:00"
3913
  },
3914
  {
3915
  "name": "wp-cli/import-command",
3916
+ "version": "v1.0.7",
3917
  "source": {
3918
  "type": "git",
3919
  "url": "https://github.com/wp-cli/import-command.git",
3920
+ "reference": "421fec5bd96671931f2119a89d28bae2f9edeb6b"
3921
  },
3922
  "dist": {
3923
  "type": "zip",
3924
+ "url": "https://api.github.com/repos/wp-cli/import-command/zipball/421fec5bd96671931f2119a89d28bae2f9edeb6b",
3925
+ "reference": "421fec5bd96671931f2119a89d28bae2f9edeb6b",
3926
  "shasum": ""
3927
  },
3928
  "require": {
3960
  "homepage": "https://runcommand.io"
3961
  }
3962
  ],
3963
+ "description": "Imports content from a given WXR file.",
3964
  "homepage": "https://github.com/wp-cli/import-command",
3965
+ "time": "2018-04-20T08:07:05+00:00"
3966
  },
3967
  {
3968
  "name": "wp-cli/language-command",
3969
+ "version": "v1.0.6",
3970
  "source": {
3971
  "type": "git",
3972
  "url": "https://github.com/wp-cli/language-command.git",
3973
+ "reference": "2a3d1ce5a722a4d70809619a065087aa933f6209"
3974
  },
3975
  "dist": {
3976
  "type": "zip",
3977
+ "url": "https://api.github.com/repos/wp-cli/language-command/zipball/2a3d1ce5a722a4d70809619a065087aa933f6209",
3978
+ "reference": "2a3d1ce5a722a4d70809619a065087aa933f6209",
3979
  "shasum": ""
3980
  },
3981
  "require-dev": {
3988
  "dev-master": "1.x-dev"
3989
  },
3990
  "commands": [
3991
+ "language",
3992
+ "language core",
3993
  "language core activate",
3994
  "language core install",
3995
  "language core list",
4017
  "homepage": "https://runcommand.io"
4018
  }
4019
  ],
4020
+ "description": "Installs, activates, and manages language packs.",
4021
  "homepage": "https://github.com/wp-cli/language-command",
4022
+ "time": "2017-12-08T17:50:26+00:00"
4023
  },
4024
  {
4025
  "name": "wp-cli/media-command",
4026
+ "version": "v1.1.4",
4027
  "source": {
4028
  "type": "git",
4029
  "url": "https://github.com/wp-cli/media-command.git",
4030
+ "reference": "7f8664ba722505446b3ef3dbc6717e8e7f20265c"
4031
  },
4032
  "dist": {
4033
  "type": "zip",
4034
+ "url": "https://api.github.com/repos/wp-cli/media-command/zipball/7f8664ba722505446b3ef3dbc6717e8e7f20265c",
4035
+ "reference": "7f8664ba722505446b3ef3dbc6717e8e7f20265c",
4036
  "shasum": ""
4037
  },
 
 
 
4038
  "require-dev": {
4039
+ "behat/behat": "~2.5",
4040
+ "wp-cli/wp-cli": "^1.5"
4041
  },
4042
  "type": "wp-cli-package",
4043
  "extra": {
4044
  "branch-alias": {
4045
  "dev-master": "1.x-dev"
4046
  },
4047
+ "bundled": true,
4048
  "commands": [
4049
+ "media",
4050
  "media import",
4051
+ "media regenerate",
4052
+ "media image-size"
4053
+ ]
4054
  },
4055
  "autoload": {
4056
  "psr-4": {
4071
  "homepage": "https://runcommand.io"
4072
  }
4073
  ],
4074
+ "description": "Imports files as attachments, regenerates thumbnails, or lists registered image sizes.",
4075
  "homepage": "https://github.com/wp-cli/media-command",
4076
+ "time": "2018-01-29T02:17:56+00:00"
4077
  },
4078
  {
4079
  "name": "wp-cli/mustangostang-spyc",
4125
  },
4126
  {
4127
  "name": "wp-cli/package-command",
4128
+ "version": "v1.0.14",
4129
  "source": {
4130
  "type": "git",
4131
  "url": "https://github.com/wp-cli/package-command.git",
4132
+ "reference": "a7ce916de5e1d0c3d910d4fc8ca31928ee3775d3"
4133
  },
4134
  "dist": {
4135
  "type": "zip",
4136
+ "url": "https://api.github.com/repos/wp-cli/package-command/zipball/a7ce916de5e1d0c3d910d4fc8ca31928ee3775d3",
4137
+ "reference": "a7ce916de5e1d0c3d910d4fc8ca31928ee3775d3",
4138
  "shasum": ""
4139
  },
4140
  "require": {
4141
+ "composer/composer": "^1.2.0"
 
4142
  },
4143
  "require-dev": {
4144
+ "behat/behat": "~2.5",
4145
+ "wp-cli/wp-cli": "^1.5"
4146
  },
4147
  "type": "wp-cli-package",
4148
  "extra": {
4149
  "branch-alias": {
4150
  "dev-master": "1.x-dev"
4151
  },
4152
+ "bundled": true,
4153
  "commands": [
4154
+ "package",
4155
  "package browse",
4156
  "package install",
4157
  "package list",
4158
  "package update",
4159
  "package uninstall"
4160
+ ]
 
4161
  },
4162
  "autoload": {
4163
  "psr-4": {
4178
  "homepage": "https://runcommand.io"
4179
  }
4180
  ],
4181
+ "description": "Lists, installs, and removes WP-CLI packages.",
4182
  "homepage": "https://github.com/wp-cli/package-command",
4183
+ "time": "2018-05-28T11:40:24+00:00"
4184
  },
4185
  {
4186
  "name": "wp-cli/php-cli-tools",
4187
+ "version": "v0.11.11",
4188
  "source": {
4189
  "type": "git",
4190
  "url": "https://github.com/wp-cli/php-cli-tools.git",
4191
+ "reference": "fe9c7c44a9e1bf2196ec51dc38da0593dbf2993f"
4192
  },
4193
  "dist": {
4194
  "type": "zip",
4195
+ "url": "https://api.github.com/repos/wp-cli/php-cli-tools/zipball/fe9c7c44a9e1bf2196ec51dc38da0593dbf2993f",
4196
+ "reference": "fe9c7c44a9e1bf2196ec51dc38da0593dbf2993f",
4197
  "shasum": ""
4198
  },
4199
  "require": {
4230
  "cli",
4231
  "console"
4232
  ],
4233
+ "time": "2018-09-04T13:28:00+00:00"
4234
  },
4235
  {
4236
  "name": "wp-cli/rewrite-command",
4237
+ "version": "v1.0.5",
4238
  "source": {
4239
  "type": "git",
4240
  "url": "https://github.com/wp-cli/rewrite-command.git",
4241
+ "reference": "6b1695887e289ffad14c8f4ea86b5f1d92757408"
4242
  },
4243
  "dist": {
4244
  "type": "zip",
4245
+ "url": "https://api.github.com/repos/wp-cli/rewrite-command/zipball/6b1695887e289ffad14c8f4ea86b5f1d92757408",
4246
+ "reference": "6b1695887e289ffad14c8f4ea86b5f1d92757408",
4247
  "shasum": ""
4248
  },
4249
  "require-dev": {
4256
  "dev-master": "1.x-dev"
4257
  },
4258
  "commands": [
4259
+ "rewrite",
4260
  "rewrite flush",
4261
  "rewrite list",
4262
  "rewrite structure"
4282
  "homepage": "https://runcommand.io"
4283
  }
4284
  ],
4285
+ "description": "Lists or flushes the site's rewrite rules, updates the permalink structure.",
4286
  "homepage": "https://github.com/wp-cli/rewrite-command",
4287
+ "time": "2017-12-08T17:51:04+00:00"
4288
  },
4289
  {
4290
  "name": "wp-cli/role-command",
4291
+ "version": "v1.1.0",
4292
  "source": {
4293
  "type": "git",
4294
  "url": "https://github.com/wp-cli/role-command.git",
4295
+ "reference": "f50134ea9c27c108b1069cf044f7395c8f9bf716"
4296
  },
4297
  "dist": {
4298
  "type": "zip",
4299
+ "url": "https://api.github.com/repos/wp-cli/role-command/zipball/f50134ea9c27c108b1069cf044f7395c8f9bf716",
4300
+ "reference": "f50134ea9c27c108b1069cf044f7395c8f9bf716",
4301
  "shasum": ""
4302
  },
4303
  "require-dev": {
4310
  "dev-master": "1.x-dev"
4311
  },
4312
  "commands": [
4313
+ "role",
4314
  "role create",
4315
  "role delete",
4316
  "role exists",
4317
  "role list",
4318
  "role reset",
4319
+ "cap",
4320
  "cap add",
4321
  "cap list",
4322
  "cap remove"
4342
  "homepage": "https://runcommand.io"
4343
  }
4344
  ],
4345
+ "description": "Adds, removes, lists, and resets roles and capabilities.",
4346
  "homepage": "https://github.com/wp-cli/role-command",
4347
+ "time": "2018-04-20T08:05:51+00:00"
4348
  },
4349
  {
4350
  "name": "wp-cli/scaffold-command",
4351
+ "version": "v1.2.0",
4352
  "source": {
4353
  "type": "git",
4354
  "url": "https://github.com/wp-cli/scaffold-command.git",
4355
+ "reference": "a897a54ba0a8199743d90204ff773b302fc77572"
4356
  },
4357
  "dist": {
4358
  "type": "zip",
4359
+ "url": "https://api.github.com/repos/wp-cli/scaffold-command/zipball/a897a54ba0a8199743d90204ff773b302fc77572",
4360
+ "reference": "a897a54ba0a8199743d90204ff773b302fc77572",
4361
  "shasum": ""
4362
  },
4363
  "require-dev": {
4364
  "behat/behat": "~2.5",
4365
+ "wp-cli/wp-cli": "^1.5"
4366
  },
4367
  "type": "wp-cli-package",
4368
  "extra": {
4369
  "branch-alias": {
4370
  "dev-master": "1.x-dev"
4371
  },
4372
+ "bundled": true,
4373
  "commands": [
4374
  "scaffold",
4375
  "scaffold _s",
4376
+ "scaffold block",
4377
  "scaffold child-theme",
4378
  "scaffold plugin",
4379
  "scaffold plugin-tests",
4380
  "scaffold post-type",
4381
  "scaffold taxonomy",
4382
  "scaffold theme-tests"
4383
+ ]
 
4384
  },
4385
  "autoload": {
4386
  "psr-4": {
4401
  "homepage": "https://runcommand.io"
4402
  }
4403
  ],
4404
+ "description": "Generates code for post types, taxonomies, blocks, plugins, child themes, etc.",
4405
  "homepage": "https://github.com/wp-cli/scaffold-command",
4406
+ "time": "2018-07-29T15:02:24+00:00"
4407
  },
4408
  {
4409
  "name": "wp-cli/search-replace-command",
4410
+ "version": "v1.3.1",
4411
  "source": {
4412
  "type": "git",
4413
  "url": "https://github.com/wp-cli/search-replace-command.git",
4414
+ "reference": "be21639dc530ad6506664baa813862d39b6d78ba"
4415
  },
4416
  "dist": {
4417
  "type": "zip",
4418
+ "url": "https://api.github.com/repos/wp-cli/search-replace-command/zipball/be21639dc530ad6506664baa813862d39b6d78ba",
4419
+ "reference": "be21639dc530ad6506664baa813862d39b6d78ba",
4420
  "shasum": ""
4421
  },
 
 
 
4422
  "require-dev": {
4423
+ "behat/behat": "~2.5",
4424
+ "wp-cli/wp-cli": "^1.5"
4425
  },
4426
  "type": "wp-cli-package",
4427
  "extra": {
4428
  "branch-alias": {
4429
  "dev-master": "1.x-dev"
4430
  },
4431
+ "bundled": true,
4432
  "commands": [
4433
  "search-replace"
4434
+ ]
 
4435
  },
4436
  "autoload": {
4437
  "psr-4": {
4438
+ "": "src/"
 
4439
  },
4440
  "files": [
4441
  "search-replace-command.php"
4452
  "homepage": "https://runcommand.io"
4453
  }
4454
  ],
4455
+ "description": "Searches/replaces strings in the database.",
4456
  "homepage": "https://github.com/wp-cli/search-replace-command",
4457
+ "time": "2018-05-29T10:21:19+00:00"
4458
  },
4459
  {
4460
  "name": "wp-cli/server-command",
4461
+ "version": "v1.0.9",
4462
  "source": {
4463
  "type": "git",
4464
  "url": "https://github.com/wp-cli/server-command.git",
4465
+ "reference": "6192e6d7becd07e4c11a8f1560655c73a3b3526a"
4466
  },
4467
  "dist": {
4468
  "type": "zip",
4469
+ "url": "https://api.github.com/repos/wp-cli/server-command/zipball/6192e6d7becd07e4c11a8f1560655c73a3b3526a",
4470
+ "reference": "6192e6d7becd07e4c11a8f1560655c73a3b3526a",
4471
  "shasum": ""
4472
  },
4473
  "require": {
4505
  "homepage": "https://runcommand.io"
4506
  }
4507
  ],
4508
+ "description": "Launches PHP's built-in web server for a specific WordPress installation.",
4509
  "homepage": "https://github.com/wp-cli/server-command",
4510
+ "time": "2017-12-14T20:06:24+00:00"
4511
  },
4512
  {
4513
  "name": "wp-cli/shell-command",
4514
+ "version": "v1.0.5",
4515
  "source": {
4516
  "type": "git",
4517
  "url": "https://github.com/wp-cli/shell-command.git",
4518
+ "reference": "507603a8994d984b6c4d5bd26e31ede6d9cce37e"
4519
  },
4520
  "dist": {
4521
  "type": "zip",
4522
+ "url": "https://api.github.com/repos/wp-cli/shell-command/zipball/507603a8994d984b6c4d5bd26e31ede6d9cce37e",
4523
+ "reference": "507603a8994d984b6c4d5bd26e31ede6d9cce37e",
4524
  "shasum": ""
4525
  },
4526
  "require": {
4559
  "homepage": "https://runcommand.io"
4560
  }
4561
  ],
4562
+ "description": "Opens an interactive PHP console for running and testing PHP code.",
4563
  "homepage": "https://github.com/wp-cli/shell-command",
4564
+ "time": "2017-12-08T16:03:53+00:00"
4565
  },
4566
  {
4567
  "name": "wp-cli/super-admin-command",
4568
+ "version": "v1.0.6",
4569
  "source": {
4570
  "type": "git",
4571
  "url": "https://github.com/wp-cli/super-admin-command.git",
4572
+ "reference": "2982d2e6514dbb318561d72d0577746a3a37181e"
4573
  },
4574
  "dist": {
4575
  "type": "zip",
4576
+ "url": "https://api.github.com/repos/wp-cli/super-admin-command/zipball/2982d2e6514dbb318561d72d0577746a3a37181e",
4577
+ "reference": "2982d2e6514dbb318561d72d0577746a3a37181e",
4578
  "shasum": ""
4579
  },
4580
  "require-dev": {
4587
  "dev-master": "1.x-dev"
4588
  },
4589
  "commands": [
4590
+ "super-admin",
4591
  "super-admin add",
4592
  "super-admin list",
4593
  "super-admin remove"
4613
  "homepage": "https://runcommand.io"
4614
  }
4615
  ],
4616
+ "description": "Lists, adds, or removes super admin users on a multisite installation.",
4617
  "homepage": "https://github.com/wp-cli/super-admin-command",
4618
+ "time": "2017-12-08T17:43:53+00:00"
4619
  },
4620
  {
4621
  "name": "wp-cli/widget-command",
4622
+ "version": "v1.0.5",
4623
  "source": {
4624
  "type": "git",
4625
  "url": "https://github.com/wp-cli/widget-command.git",
4626
+ "reference": "657e0f77d80c892f8f72f90a3a25112c254386df"
4627
  },
4628
  "dist": {
4629
  "type": "zip",
4630
+ "url": "https://api.github.com/repos/wp-cli/widget-command/zipball/657e0f77d80c892f8f72f90a3a25112c254386df",
4631
+ "reference": "657e0f77d80c892f8f72f90a3a25112c254386df",
4632
  "shasum": ""
4633
  },
4634
  "require-dev": {
4641
  "dev-master": "1.x-dev"
4642
  },
4643
  "commands": [
4644
+ "widget",
4645
  "widget add",
4646
  "widget deactivate",
4647
  "widget delete",
4649
  "widget move",
4650
  "widget reset",
4651
  "widget update",
4652
+ "sidebar",
4653
  "sidebar list"
4654
  ],
4655
  "bundled": true
4673
  "homepage": "https://runcommand.io"
4674
  }
4675
  ],
4676
+ "description": "Adds, moves, and removes widgets; lists sidebars.",
4677
  "homepage": "https://github.com/wp-cli/widget-command",
4678
+ "time": "2017-12-08T17:45:57+00:00"
4679
  },
4680
  {
4681
  "name": "wp-cli/wp-cli",
4682
+ "version": "v1.5.1",
4683
  "source": {
4684
  "type": "git",
4685
  "url": "https://github.com/wp-cli/wp-cli.git",
4686
+ "reference": "3aac73bc4d629372531f3e15bbb67945d19b5d5a"
4687
  },
4688
  "dist": {
4689
  "type": "zip",
4690
+ "url": "https://api.github.com/repos/wp-cli/wp-cli/zipball/3aac73bc4d629372531f3e15bbb67945d19b5d5a",
4691
+ "reference": "3aac73bc4d629372531f3e15bbb67945d19b5d5a",
4692
  "shasum": ""
4693
  },
4694
  "require": {
4695
  "composer/composer": "^1.2.0",
4696
  "composer/semver": "~1.0",
4697
+ "justinrainbow/json-schema": "~5.2.5",
4698
  "mustache/mustache": "~2.4",
4699
  "php": ">=5.3.29",
4700
  "ramsey/array_column": "~1.1",
4716
  "wp-cli/core-command": "^1.0",
4717
  "wp-cli/cron-command": "^1.0",
4718
  "wp-cli/db-command": "^1.0",
4719
+ "wp-cli/embed-command": "^1.0",
4720
  "wp-cli/entity-command": "^1.0",
4721
  "wp-cli/eval-command": "^1.0",
4722
  "wp-cli/export-command": "^1.0",
4738
  },
4739
  "require-dev": {
4740
  "behat/behat": "2.5.*",
4741
+ "dealerdirect/phpcodesniffer-composer-installer": "^0.4.3",
4742
  "phpunit/phpunit": "3.7.*",
4743
+ "roave/security-advisories": "dev-master",
4744
+ "wimg/php-compatibility": "^8.0",
4745
+ "wp-coding-standards/wpcs": "^0.13.1"
4746
  },
4747
  "suggest": {
4748
  "psy/psysh": "Enhanced `wp shell` functionality"
4753
  ],
4754
  "type": "library",
4755
  "extra": {
4756
+ "branch-alias": {
4757
+ "dev-master": "1.5.x-dev"
4758
+ },
4759
  "autoload-splitter": {
4760
  "splitter-logic": "WP_CLI\\AutoloadSplitter",
4761
  "splitter-location": "php/WP_CLI/AutoloadSplitter.php",
4775
  "license": [
4776
  "MIT"
4777
  ],
4778
+ "description": "The command line interface for WordPress",
4779
+ "homepage": "https://wp-cli.org",
4780
  "keywords": [
4781
  "cli",
4782
  "wordpress"
4783
  ],
4784
+ "time": "2018-05-31T11:04:05+00:00"
4785
+ },
4786
+ {
4787
+ "name": "wp-cli/wp-config-transformer",
4788
+ "version": "v1.2.6",
4789
+ "source": {
4790
+ "type": "git",
4791
+ "url": "https://github.com/wp-cli/wp-config-transformer.git",
4792
+ "reference": "1ca98343443a8e4585865db5f50e8e6121fee70b"
4793
+ },
4794
+ "dist": {
4795
+ "type": "zip",
4796
+ "url": "https://api.github.com/repos/wp-cli/wp-config-transformer/zipball/1ca98343443a8e4585865db5f50e8e6121fee70b",
4797
+ "reference": "1ca98343443a8e4585865db5f50e8e6121fee70b",
4798
+ "shasum": ""
4799
+ },
4800
+ "require": {
4801
+ "php": ">=5.3.29"
4802
+ },
4803
+ "require-dev": {
4804
+ "composer/composer": "^1.5.6",
4805
+ "phpunit/phpunit": "^6.5.5",
4806
+ "wp-coding-standards/wpcs": "^0.14.0 || ^1.0.0 || ^2.0.0"
4807
+ },
4808
+ "type": "library",
4809
+ "autoload": {
4810
+ "files": [
4811
+ "src/WPConfigTransformer.php"
4812
+ ]
4813
+ },
4814
+ "notification-url": "https://packagist.org/downloads/",
4815
+ "license": [
4816
+ "MIT"
4817
+ ],
4818
+ "authors": [
4819
+ {
4820
+ "name": "Frankie Jarrett",
4821
+ "email": "fjarrett@gmail.com"
4822
+ }
4823
+ ],
4824
+ "description": "Programmatically edit a wp-config.php file.",
4825
+ "time": "2019-07-23T17:24:43+00:00"
4826
+ },
4827
+ {
4828
+ "name": "wp-coding-standards/wpcs",
4829
+ "version": "2.1.1",
4830
+ "source": {
4831
+ "type": "git",
4832
+ "url": "https://github.com/WordPress/WordPress-Coding-Standards.git",
4833
+ "reference": "bd9c33152115e6741e3510ff7189605b35167908"
4834
+ },
4835
+ "dist": {
4836
+ "type": "zip",
4837
+ "url": "https://api.github.com/repos/WordPress/WordPress-Coding-Standards/zipball/bd9c33152115e6741e3510ff7189605b35167908",
4838
+ "reference": "bd9c33152115e6741e3510ff7189605b35167908",
4839
+ "shasum": ""
4840
+ },
4841
+ "require": {
4842
+ "php": ">=5.4",
4843
+ "squizlabs/php_codesniffer": "^3.3.1"
4844
+ },
4845
+ "require-dev": {
4846
+ "dealerdirect/phpcodesniffer-composer-installer": "^0.5.0",
4847
+ "phpcompatibility/php-compatibility": "^9.0",
4848
+ "phpunit/phpunit": "^4.0 || ^5.0 || ^6.0 || ^7.0"
4849
+ },
4850
+ "suggest": {
4851
+ "dealerdirect/phpcodesniffer-composer-installer": "^0.5.0 || This Composer plugin will sort out the PHPCS 'installed_paths' automatically."
4852
+ },
4853
+ "type": "phpcodesniffer-standard",
4854
+ "notification-url": "https://packagist.org/downloads/",
4855
+ "license": [
4856
+ "MIT"
4857
+ ],
4858
+ "authors": [
4859
+ {
4860
+ "name": "Contributors",
4861
+ "homepage": "https://github.com/WordPress-Coding-Standards/WordPress-Coding-Standards/graphs/contributors"
4862
+ }
4863
+ ],
4864
+ "description": "PHP_CodeSniffer rules (sniffs) to enforce WordPress coding conventions",
4865
+ "keywords": [
4866
+ "phpcs",
4867
+ "standards",
4868
+ "wordpress"
4869
+ ],
4870
+ "time": "2019-05-21T02:50:00+00:00"
4871
  }
4872
  ],
4873
  "aliases": [],
4874
  "minimum-stability": "dev",
4875
  "stability-flags": [],
4876
+ "prefer-stable": true,
4877
  "prefer-lowest": false,
4878
  "platform": [],
4879
  "platform-dev": []
includes/vendor/action-scheduler/deprecated/ActionScheduler_Schedule_Deprecated.php ADDED
@@ -0,0 +1,29 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Class ActionScheduler_Abstract_Schedule
5
+ */
6
+ abstract class ActionScheduler_Schedule_Deprecated implements ActionScheduler_Schedule {
7
+
8
+ /**
9
+ * Get the date & time this schedule was created to run, or calculate when it should be run
10
+ * after a given date & time.
11
+ *
12
+ * @param DateTime $after
13
+ *
14
+ * @return DateTime|null
15
+ */
16
+ public function next( DateTime $after = NULL ) {
17
+ if ( empty( $after ) ) {
18
+ $return_value = $this->get_date();
19
+ $replacement_method = 'get_date()';
20
+ } else {
21
+ $return_value = $this->get_next( $after );
22
+ $replacement_method = 'get_next( $after )';
23
+ }
24
+
25
+ _deprecated_function( __METHOD__, '3.0.0', __CLASS__ . '::' . $replacement_method );
26
+
27
+ return $return_value;
28
+ }
29
+ }
includes/vendor/action-scheduler/deprecated/ActionScheduler_Store_Deprecated.php ADDED
@@ -0,0 +1,49 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Class ActionScheduler_Store_Deprecated
5
+ * @codeCoverageIgnore
6
+ */
7
+ abstract class ActionScheduler_Store_Deprecated {
8
+
9
+ /**
10
+ * Mark an action that failed to fetch correctly as failed.
11
+ *
12
+ * @since 2.2.6
13
+ *
14
+ * @param int $action_id The ID of the action.
15
+ */
16
+ public function mark_failed_fetch_action( $action_id ) {
17
+ _deprecated_function( __METHOD__, '3.0.0', 'ActionScheduler_Store::mark_failure()' );
18
+ self::$store->mark_failure( $action_id );
19
+ }
20
+
21
+ /**
22
+ * Add base hooks
23
+ *
24
+ * @since 2.2.6
25
+ */
26
+ protected static function hook() {
27
+ _deprecated_function( __METHOD__, '3.0.0' );
28
+ }
29
+
30
+ /**
31
+ * Remove base hooks
32
+ *
33
+ * @since 2.2.6
34
+ */
35
+ protected static function unhook() {
36
+ _deprecated_function( __METHOD__, '3.0.0' );
37
+ }
38
+
39
+ /**
40
+ * Get the site's local time.
41
+ *
42
+ * @deprecated 2.1.0
43
+ * @return DateTimeZone
44
+ */
45
+ protected function get_local_timezone() {
46
+ _deprecated_function( __FUNCTION__, '2.1.0', 'ActionScheduler_TimezoneHelper::set_local_timezone()' );
47
+ return ActionScheduler_TimezoneHelper::get_local_timezone();
48
+ }
49
+ }
includes/vendor/action-scheduler/docs/_layouts/default.html CHANGED
@@ -21,7 +21,7 @@
21
  <body>
22
 
23
  <header>
24
- <a class="github-corner" href="https://github.com/Prospress/action-scheduler/" aria-label="View on GitHub">
25
  <svg width="80" height="80" viewBox="0 0 250 250" style="fill:#b5e853; color:#151513; position: fixed; top: 0; border: 0; right: 0;" aria-hidden="true">
26
  <path d="M0,0 L115,115 L130,115 L142,142 L250,250 L250,0 Z"></path><path d="M128.3,109.0 C113.8,99.7 119.0,89.6 119.0,89.6 C122.0,82.7 120.5,78.6 120.5,78.6 C119.2,72.0 123.4,76.3 123.4,76.3 C127.3,80.9 125.5,87.3 125.5,87.3 C122.9,97.6 130.6,101.9 134.4,103.2" fill="currentColor" style="transform-origin: 130px 106px;" class="octo-arm"></path><path d="M115.0,115.0 C114.9,115.1 118.7,116.5 119.8,115.4 L133.7,101.6 C136.9,99.2 139.9,98.4 142.2,98.6 C133.8,88.0 127.5,74.4 143.8,58.0 C148.5,53.4 154.0,51.2 159.7,51.0 C160.3,49.4 163.2,43.6 171.4,40.1 C171.4,40.1 176.1,42.5 178.8,56.2 C183.1,58.6 187.2,61.8 190.9,65.4 C194.5,69.0 197.7,73.2 200.1,77.6 C213.8,80.2 216.3,84.9 216.3,84.9 C212.7,93.1 206.9,96.0 205.4,96.6 C205.1,102.4 203.0,107.8 198.3,112.5 C181.9,128.9 168.3,122.5 157.7,114.1 C157.9,116.9 156.7,120.9 152.7,124.9 L141.0,136.5 C139.8,137.7 141.6,141.9 141.8,141.8 Z" fill="currentColor" class="octo-body"></path>
27
  </svg>
@@ -42,9 +42,6 @@
42
  <footer>
43
  <div class="container">
44
  <p><a href="/usage/">Usage</a> | <a href="/admin/">Admin</a> | <a href="/wp-cli/">WP-CLI</a> | <a href="/perf/">Background Processing at Scale</a> | <a href="/api/">API</a> | <a href="/faq/">FAQ</a>
45
- <p class="footer-image">
46
- <a href="https://prospress.com"><img src="http://pic.pros.pr/eb8dcec9bd54/prospress-hacker-green-logo.png" width="120"></a>
47
- </p>
48
  </div>
49
  </footer>
50
 
21
  <body>
22
 
23
  <header>
24
+ <a class="github-corner" href="https://github.com/woocommerce/action-scheduler/" aria-label="View on GitHub">
25
  <svg width="80" height="80" viewBox="0 0 250 250" style="fill:#b5e853; color:#151513; position: fixed; top: 0; border: 0; right: 0;" aria-hidden="true">
26
  <path d="M0,0 L115,115 L130,115 L142,142 L250,250 L250,0 Z"></path><path d="M128.3,109.0 C113.8,99.7 119.0,89.6 119.0,89.6 C122.0,82.7 120.5,78.6 120.5,78.6 C119.2,72.0 123.4,76.3 123.4,76.3 C127.3,80.9 125.5,87.3 125.5,87.3 C122.9,97.6 130.6,101.9 134.4,103.2" fill="currentColor" style="transform-origin: 130px 106px;" class="octo-arm"></path><path d="M115.0,115.0 C114.9,115.1 118.7,116.5 119.8,115.4 L133.7,101.6 C136.9,99.2 139.9,98.4 142.2,98.6 C133.8,88.0 127.5,74.4 143.8,58.0 C148.5,53.4 154.0,51.2 159.7,51.0 C160.3,49.4 163.2,43.6 171.4,40.1 C171.4,40.1 176.1,42.5 178.8,56.2 C183.1,58.6 187.2,61.8 190.9,65.4 C194.5,69.0 197.7,73.2 200.1,77.6 C213.8,80.2 216.3,84.9 216.3,84.9 C212.7,93.1 206.9,96.0 205.4,96.6 C205.1,102.4 203.0,107.8 198.3,112.5 C181.9,128.9 168.3,122.5 157.7,114.1 C157.9,116.9 156.7,120.9 152.7,124.9 L141.0,136.5 C139.8,137.7 141.6,141.9 141.8,141.8 Z" fill="currentColor" class="octo-body"></path>
27
  </svg>
42
  <footer>
43
  <div class="container">
44
  <p><a href="/usage/">Usage</a> | <a href="/admin/">Admin</a> | <a href="/wp-cli/">WP-CLI</a> | <a href="/perf/">Background Processing at Scale</a> | <a href="/api/">API</a> | <a href="/faq/">FAQ</a>
 
 
 
45
  </div>
46
  </footer>
47
 
includes/vendor/action-scheduler/docs/android-chrome-192x192.png CHANGED
Binary file
includes/vendor/action-scheduler/docs/android-chrome-256x256.png CHANGED
Binary file
includes/vendor/action-scheduler/docs/api.md CHANGED
@@ -5,7 +5,7 @@ description: Reference guide for background processing functions provided by the
5
 
6
  Action Scheduler provides a range of functions for scheduling hooks to run at some time in the future on one or more occassions.
7
 
8
- To understand the scheduling functoins, it can help to think of them as extensions to WordPress' `do_action()` function that add the ability to delay and repeat when the hook will be triggered.
9
 
10
  ## WP-Cron APIs vs. Action Scheduler APIs
11
 
@@ -13,7 +13,7 @@ The Action Scheduler API functions are designed to mirror the WordPress [WP-Cron
13
 
14
  Functions return similar values and accept similar arguments to their WP-Cron counterparts. The notable differences are:
15
 
16
- * `as_schedule_single_action()` & `as_schedule_recurring_action()` will return the post ID of the scheduled action rather than boolean indicating whether the event was scheduled
17
  * `as_schedule_recurring_action()` takes an interval in seconds as the recurring interval rather than an arbitrary string
18
  * `as_schedule_single_action()` & `as_schedule_recurring_action()` can accept a `$group` parameter to group different actions for the one plugin together.
19
  * the `wp_` prefix is substituted with `as_` and the term `event` is replaced with `action`
@@ -24,11 +24,34 @@ As mentioned in the [Usage - Load Order](/usage/#load-order) section, Action Sch
24
 
25
  Do not use Action Scheduler API functions prior to `'init'` hook with priority `1`. Doing so could lead to unexpected results, like data being stored in the incorrect location.
26
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
27
  ## Function Reference / `as_schedule_single_action()`
28
 
29
  ### Description
30
 
31
- Schedule an action to run one time.
32
 
33
  ### Usage
34
 
@@ -45,7 +68,7 @@ as_schedule_single_action( $timestamp, $hook, $args, $group )
45
 
46
  ### Return value
47
 
48
- (integer) the action's ID in the [posts](http://codex.wordpress.org/Database_Description#Table_Overview) table.
49
 
50
 
51
  ## Function Reference / `as_schedule_recurring_action()`
@@ -70,7 +93,7 @@ as_schedule_recurring_action( $timestamp, $interval_in_seconds, $hook, $args, $g
70
 
71
  ### Return value
72
 
73
- (integer) the action's ID in the [posts](http://codex.wordpress.org/Database_Description#Table_Overview) table.
74
 
75
 
76
  ## Function Reference / `as_schedule_cron_action()`
@@ -95,14 +118,14 @@ as_schedule_cron_action( $timestamp, $schedule, $hook, $args, $group )
95
 
96
  ### Return value
97
 
98
- (integer) the action's ID in the [posts](http://codex.wordpress.org/Database_Description#Table_Overview) table.
99
 
100
 
101
  ## Function Reference / `as_unschedule_action()`
102
 
103
  ### Description
104
 
105
- Cancel the next occurrence of a job.
106
 
107
  ### Usage
108
 
@@ -113,6 +136,28 @@ as_unschedule_action( $hook, $args, $group )
113
  ### Parameters
114
 
115
  - **$hook** (string)(required) Name of the action hook. Default: _none_.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
116
  - **$args** (array) Arguments to pass to callbacks when the hook triggers. Default: _`array()`_.
117
  - **$group** (array) The group to assign this job to. Default: _''_.
118
 
5
 
6
  Action Scheduler provides a range of functions for scheduling hooks to run at some time in the future on one or more occassions.
7
 
8
+ To understand the scheduling functions, it can help to think of them as extensions to WordPress' `do_action()` function that add the ability to delay and repeat when the hook will be triggered.
9
 
10
  ## WP-Cron APIs vs. Action Scheduler APIs
11
 
13
 
14
  Functions return similar values and accept similar arguments to their WP-Cron counterparts. The notable differences are:
15
 
16
+ * `as_schedule_single_action()` & `as_schedule_recurring_action()` will return the ID of the scheduled action rather than boolean indicating whether the event was scheduled
17
  * `as_schedule_recurring_action()` takes an interval in seconds as the recurring interval rather than an arbitrary string
18
  * `as_schedule_single_action()` & `as_schedule_recurring_action()` can accept a `$group` parameter to group different actions for the one plugin together.
19
  * the `wp_` prefix is substituted with `as_` and the term `event` is replaced with `action`
24
 
25
  Do not use Action Scheduler API functions prior to `'init'` hook with priority `1`. Doing so could lead to unexpected results, like data being stored in the incorrect location.
26
 
27
+ ## Function Reference / `as_enqueue_async_action()`
28
+
29
+ ### Description
30
+
31
+ Enqueue an action to run one time, as soon as possible.
32
+
33
+ ### Usage
34
+
35
+ ```php
36
+ as_enqueue_async_action( $hook, $args, $group )
37
+ ````
38
+
39
+ ### Parameters
40
+
41
+ - **$hook** (string)(required) Name of the action hook. Default: _none_.
42
+ - **$args** (array) Arguments to pass to callbacks when the hook triggers. Default: _`array()`_.
43
+ - **$group** (array) The group to assign this job to. Default: _''_.
44
+
45
+ ### Return value
46
+
47
+ (integer) the action's ID.
48
+
49
+
50
  ## Function Reference / `as_schedule_single_action()`
51
 
52
  ### Description
53
 
54
+ Schedule an action to run one time at some defined point in the future.
55
 
56
  ### Usage
57
 
68
 
69
  ### Return value
70
 
71
+ (integer) the action's ID.
72
 
73
 
74
  ## Function Reference / `as_schedule_recurring_action()`
93
 
94
  ### Return value
95
 
96
+ (integer) the action's ID.
97
 
98
 
99
  ## Function Reference / `as_schedule_cron_action()`
118
 
119
  ### Return value
120
 
121
+ (integer) the action's ID.
122
 
123
 
124
  ## Function Reference / `as_unschedule_action()`
125
 
126
  ### Description
127
 
128
+ Cancel the next occurrence of a scheduled action.
129
 
130
  ### Usage
131
 
136
  ### Parameters
137
 
138
  - **$hook** (string)(required) Name of the action hook. Default: _none_.
139
+ - **$args** (array) Arguments passed to callbacks when the hook triggers. Default: _`array()`_.
140
+ - **$group** (array) The group job was assigned to. Default: _''_.
141
+
142
+ ### Return value
143
+
144
+ (null)
145
+
146
+ ## Function Reference / `as_unschedule_all_actions()`
147
+
148
+ ### Description
149
+
150
+ Cancel all occurrences of a scheduled action.
151
+
152
+ ### Usage
153
+
154
+ ```php
155
+ as_unschedule_action( $hook, $args, $group )
156
+ ````
157
+
158
+ ### Parameters
159
+
160
+ - **$hook** (string)(required) Name of the action hook.
161
  - **$args** (array) Arguments to pass to callbacks when the hook triggers. Default: _`array()`_.
162
  - **$group** (array) The group to assign this job to. Default: _''_.
163
 
includes/vendor/action-scheduler/docs/apple-touch-icon.png CHANGED
Binary file
includes/vendor/action-scheduler/docs/assets/css/style.scss CHANGED
@@ -35,7 +35,7 @@ footer {
35
  animation:octocat-wave 560ms ease-in-out
36
  }
37
 
38
- @keyframes octocat-wave{
39
  0%,100%{
40
  transform:rotate(0)
41
  }
@@ -51,7 +51,7 @@ footer {
51
  .github-corner:hover .octo-arm {
52
  animation:none
53
  }
54
- .github-corner .octo-arm{
55
  animation:octocat-wave 560ms ease-in-out
56
  }
57
  }
35
  animation:octocat-wave 560ms ease-in-out
36
  }
37
 
38
+ @keyframes octocat-wave {
39
  0%,100%{
40
  transform:rotate(0)
41
  }
51
  .github-corner:hover .octo-arm {
52
  animation:none
53
  }
54
+ .github-corner .octo-arm {
55
  animation:octocat-wave 560ms ease-in-out
56
  }
57
  }
includes/vendor/action-scheduler/docs/faq.md CHANGED
@@ -4,11 +4,11 @@
4
 
5
  Action Scheduler is designed to be used and released in plugins. It avoids redeclaring public API functions when more than one copy of the library is being loaded by different plugins. It will also load only the most recent version of itself (by checking registered versions after all plugins are loaded on the `'plugins_loaded'` hook).
6
 
7
- To use it in your plugin, simply require the `action-scheduler/action-scheduler.php` file. Action Scheduler will take care of the rest.
8
 
9
  ### I don't want to use WP-Cron. Does Action Scheduler depend on WP-Cron?
10
 
11
- By default, Action Scheduler is initiated by WP-Cron. However, it has no dependency on the WP-Cron system. You can initiate the Action Scheduler queue in other ways with just one or two lines of code.
12
 
13
  For example, you can start a queue directly by calling:
14
 
@@ -19,30 +19,38 @@ ActionScheduler::runner()->run();
19
  Or trigger the `'action_scheduler_run_queue'` hook and let Action Scheduler do it for you:
20
 
21
  ```php
22
- do_action( 'action_scheduler_run_queue' );
23
  ```
24
 
25
- Further customization can be done by extending the `ActionScheduler_Abstract_QueueRunner` class to create a custom Queue Runner. For an example of a customized queue runner, see the [`ActionScheduler_WPCLI_QueueRunner`](https://github.com/Prospress/action-scheduler/blob/master/classes/ActionScheduler_WPCLI_QueueRunner.php), which is used when running WP CLI.
26
 
27
- Want to create some other method for initiating Action Scheduler? [Open a new issue](https://github.com/Prospress/action-scheduler/issues/new), we'd love to help you with it.
28
 
29
  ### I don't want to use WP-Cron, ever. Does Action Scheduler replace WP-Cron?
30
 
31
  By default, Action Scheduler is designed to work alongside WP-Cron and not change any of its behaviour. This helps avoid unexpectedly overriding WP-Cron on sites installing your plugin, which may have nothing to do with WP-Cron.
32
 
33
- However, we can understand why you might want to replace WP-Cron completely in environments within you control, especially as it gets you the advantages of Action Scheduler. This should be possible without too much code.
34
 
35
  You could use the `'schedule_event'` hook in WordPress to use Action Scheduler for only newly scheduled WP-Cron jobs and map the `$event` param to Action Scheduler API functions.
36
 
37
  Alternatively, you can use a combination of the `'pre_update_option_cron'` and `'pre_option_cron'` hooks to override all new and previously scheduled WP-Cron jobs (similar to the way [Cavalcade](https://github.com/humanmade/Cavalcade) does it).
38
 
39
- If you'd like to create a plugin to do this automatically and want to share your work with others, [open a new issue to let us know](https://github.com/Prospress/action-scheduler/issues/new), we'd love to help you with it.
40
 
41
- ### Eww gross, Custom Post Types! That's _so_ 2010. Can I use a different storage scheme?
 
 
 
 
 
 
 
 
42
 
43
  Of course! Action Scheduler data storage is completely swappable, and always has been.
44
 
45
- You can store scheduled actions in custom tables in the WordPress site's database. Some sites using it already are. You can actually store them anywhere for that matter, like in a remote storage service from Amazon Web Services.
46
 
47
  To implement a custom store:
48
 
@@ -56,11 +64,9 @@ function eg_define_custom_store( $existing_storage_class ) {
56
  add_filter( 'action_scheduler_store_class', 'eg_define_custom_store', 10, 1 );
57
  ```
58
 
59
- Take a look at the `ActionScheduler_wpPostStore` class for an example implementation of `ActionScheduler_Store`.
60
-
61
- If you'd like to create a plugin to do this automatically and release it publicly to help others, [open a new issue to let us know](https://github.com/Prospress/action-scheduler/issues/new), we'd love to help you with it.
62
 
63
- > Note: we're also moving Action Scheduler itself to use [custom tables for better scalability](https://github.com/Prospress/action-scheduler/issues/77).
64
 
65
  ### Can I use a different storage scheme just for logging?
66
 
@@ -78,7 +84,7 @@ function eg_define_custom_logger( $existing_storage_class ) {
78
  add_filter( 'action_scheduler_logger_class', 'eg_define_custom_logger', 10, 1 );
79
  ```
80
 
81
- Take a look at the `ActionScheduler_wpCommentLogger` class for an example implementation of `ActionScheduler_Logger`.
82
 
83
  ### I want to run Action Scheduler only on a dedicated application server in my cluster. Can I do that?
84
 
@@ -96,6 +102,6 @@ It requires no setup, and won't override any WordPress APIs (unless you want it
96
 
97
  ### How does Action Scheduler work on WordPress Multisite?
98
 
99
- Action Scheduler is designed to manage the scheduled actions on a single site. It has no special handling for running queues across multiple sites in a multisite network. That said, because it's storage and Queue Runner are completely swappable, it would be possible to write multisite handling classes to use with it.
100
 
101
- If you'd like to create a multisite plugin to do this and release it publicly to help others, [open a new issue to let us know](https://github.com/Prospress/action-scheduler/issues/new), we'd love to help you with it.
4
 
5
  Action Scheduler is designed to be used and released in plugins. It avoids redeclaring public API functions when more than one copy of the library is being loaded by different plugins. It will also load only the most recent version of itself (by checking registered versions after all plugins are loaded on the `'plugins_loaded'` hook).
6
 
7
+ To use it in your plugin (or theme), simply require the `action-scheduler/action-scheduler.php` file. Action Scheduler will take care of the rest. __Note:__ Action Scheduler is only loaded from a theme if it is not included in any active plugins.
8
 
9
  ### I don't want to use WP-Cron. Does Action Scheduler depend on WP-Cron?
10
 
11
+ By default, Action Scheduler is initiated by WP-Cron (and the `'shutdown'` hook on admin requests). However, it has no dependency on the WP-Cron system. You can initiate the Action Scheduler queue in other ways with just one or two lines of code.
12
 
13
  For example, you can start a queue directly by calling:
14
 
19
  Or trigger the `'action_scheduler_run_queue'` hook and let Action Scheduler do it for you:
20
 
21
  ```php
22
+ do_action( 'action_scheduler_run_queue', $context_identifier );
23
  ```
24
 
25
+ Further customization can be done by extending the `ActionScheduler_Abstract_QueueRunner` class to create a custom Queue Runner. For an example of a customized queue runner, see the [`ActionScheduler_WPCLI_QueueRunner`](https://github.com/woocommerce/action-scheduler/blob/master/classes/ActionScheduler_WPCLI_QueueRunner.php), which is used when running WP CLI.
26
 
27
+ Want to create some other method for initiating Action Scheduler? [Open a new issue](https://github.com/woocommerce/action-scheduler/issues/new), we'd love to help you with it.
28
 
29
  ### I don't want to use WP-Cron, ever. Does Action Scheduler replace WP-Cron?
30
 
31
  By default, Action Scheduler is designed to work alongside WP-Cron and not change any of its behaviour. This helps avoid unexpectedly overriding WP-Cron on sites installing your plugin, which may have nothing to do with WP-Cron.
32
 
33
+ However, we can understand why you might want to replace WP-Cron completely in environments within your control, especially as it gets you the advantages of Action Scheduler. This should be possible without too much code.
34
 
35
  You could use the `'schedule_event'` hook in WordPress to use Action Scheduler for only newly scheduled WP-Cron jobs and map the `$event` param to Action Scheduler API functions.
36
 
37
  Alternatively, you can use a combination of the `'pre_update_option_cron'` and `'pre_option_cron'` hooks to override all new and previously scheduled WP-Cron jobs (similar to the way [Cavalcade](https://github.com/humanmade/Cavalcade) does it).
38
 
39
+ If you'd like to create a plugin to do this automatically and want to share your work with others, [open a new issue to let us know](https://github.com/woocommerce/action-scheduler/issues/new), we'd love to help you with it.
40
 
41
+ ### How does Action Scheduler store its data?
42
+
43
+ Action Scheduler 3.0 and newer stores data in custom tables prefixed with `actionscheduler_`. For the list of all tables and their schemas, refer to the `ActionScheduler_StoreSchema` class.
44
+
45
+ Prior to Action 3.0, actions were a custom post type, and data was stored in `wp_posts`, `wp_postmeta` and related tables.
46
+
47
+ Action Scheduler 3+ migrates data from the custom post type to custom tables.
48
+
49
+ ### Can I use a different storage scheme?
50
 
51
  Of course! Action Scheduler data storage is completely swappable, and always has been.
52
 
53
+ If you choose to, you can actually store them anywhere, like in a remote storage service from Amazon Web Services.
54
 
55
  To implement a custom store:
56
 
64
  add_filter( 'action_scheduler_store_class', 'eg_define_custom_store', 10, 1 );
65
  ```
66
 
67
+ Take a look at the `classes/data-stores/ActionScheduler_DBStore.php` class for an example implementation of `ActionScheduler_Store`.
 
 
68
 
69
+ If you'd like to create a plugin to do this automatically and release it publicly to help others, [open a new issue to let us know](https://github.com/woocommerce/action-scheduler/issues/new), we'd love to help you with it.
70
 
71
  ### Can I use a different storage scheme just for logging?
72
 
84
  add_filter( 'action_scheduler_logger_class', 'eg_define_custom_logger', 10, 1 );
85
  ```
86
 
87
+ Take a look at the `classes/data-stores/ActionScheduler_DBLogger.php` class for an example implementation of `ActionScheduler_Logger`.
88
 
89
  ### I want to run Action Scheduler only on a dedicated application server in my cluster. Can I do that?
90
 
102
 
103
  ### How does Action Scheduler work on WordPress Multisite?
104
 
105
+ Action Scheduler is designed to manage the scheduled actions on a single site. It has no special handling for running queues across multiple sites in a multisite network. That said, because its storage and Queue Runner are completely swappable, it would be possible to write multisite handling classes to use with it.
106
 
107
+ If you'd like to create a multisite plugin to do this and release it publicly to help others, [open a new issue to let us know](https://github.com/woocommerce/action-scheduler/issues/new), we'd love to help you with it.
includes/vendor/action-scheduler/docs/favicon-16x16.png CHANGED
Binary file
includes/vendor/action-scheduler/docs/favicon-32x32.png CHANGED
Binary file
includes/vendor/action-scheduler/docs/favicon.ico CHANGED
Binary file
includes/vendor/action-scheduler/docs/index.md CHANGED
@@ -3,7 +3,7 @@ title: Action Scheduler - Background Processing Job Queue for WordPress
3
  ---
4
  ## WordPress Job Queue with Background Processing
5
 
6
- Action Scheduler is a library for triggering a WordPress hook to run at some time in the future. Each hook can be scheduled with unique data, to allow callbacks to perform operations on that data. The hook can also be scheduled to run on one or more occassions.
7
 
8
  Think of it like an extension to `do_action()` which adds the ability to delay and repeat a hook.
9
 
@@ -21,25 +21,25 @@ Action Scheduler is specifically designed for distribution in WordPress plugins
21
 
22
  ### How it Works
23
 
24
- Action Scheduler uses a WordPress [custom post type](http://codex.wordpress.org/Post_Types), creatively named `scheduled-action`, to store the hook name, arguments and scheduled date for an action that should be triggered at some time in the future.
25
 
26
- The scheduler will attempt to run every minute by attaching itself as a callback to the `'action_scheduler_run_schedule'` hook, which is scheduled using WordPress's built-in [WP-Cron](http://codex.wordpress.org/Function_Reference/wp_cron) system.
27
 
28
- When triggered, Action Scheduler will check for posts of the `scheduled-action` type that have a `post_date` at or before this point in time i.e. actions scheduled to run now or at sometime in the past.
29
 
30
  ### Batch Processing Background Jobs
31
 
32
- If there are actions to be processed, Action Scheduler will stake a unique claim for a batch of 20 actions and begin processing that batch. The PHP process spawned to run the batch will then continue processing batches of 20 actions until it times out or exhausts available memory.
33
 
34
- If your site has a large number of actions scheduled to run at the same time, Action Scheduler will process more than one batch at a time. Specifically, when the `'action_scheduler_run_schedule'` hook is triggered approximately one minute after the first batch began processing, a new PHP process will stake a new claim to a batch of actions which were not claimed by the previous process. It will then begin to process that batch.
35
 
36
- This will continue until all actions are processed using a maximum of 5 concurrent queues.
37
 
38
  ### Housekeeping
39
 
40
- Before processing a batch, the scheduler will remove any existing claims on actions which have been sitting in a queue for more than five minutes.
41
 
42
- Action Scheduler will also trash any actions which were completed more than a month ago.
43
 
44
  If an action runs for more than 5 minutes, Action Scheduler will assume the action has timed out and will mark it as failed. However, if all callbacks attached to the action were to successfully complete sometime after that 5 minute timeout, its status would later be updated to completed.
45
 
@@ -49,11 +49,11 @@ Did your background job run?
49
 
50
  Never be left wondering with Action Scheduler's built-in record keeping.
51
 
52
- All events for each action are logged in the [comments table](http://codex.wordpress.org/Database_Description#Table_Overview) and displayed in the [administration interface](/admin/).
53
 
54
  The events logged by default include when an action:
55
  * is created
56
- * starts
57
  * completes
58
  * fails
59
 
@@ -63,6 +63,6 @@ Actions can also be grouped together using a custom taxonomy named `action-group
63
 
64
  ## Credits
65
 
66
- Developed and maintained by [Prospress](http://prospress.com/) in collaboration with [Flightless](https://flightless.us/).
67
 
68
- Collaboration is cool. We'd love to work with you to improve Action Scheduler. [Pull Requests](https://github.com/prospress/action-scheduler/pulls) welcome.
3
  ---
4
  ## WordPress Job Queue with Background Processing
5
 
6
+ Action Scheduler is a library for triggering a WordPress hook to run at some time in the future (or as soon as possible, in the case of an async action). Each hook can be scheduled with unique data, to allow callbacks to perform operations on that data. The hook can also be scheduled to run on one or more occassions.
7
 
8
  Think of it like an extension to `do_action()` which adds the ability to delay and repeat a hook.
9
 
21
 
22
  ### How it Works
23
 
24
+ Action Scheduler stores the hook name, arguments and scheduled date for an action that should be triggered at some time in the future.
25
 
26
+ The scheduler will attempt to run every minute by attaching itself as a callback to the `'action_scheduler_run_schedule'` hook, which is scheduled using WordPress's built-in [WP-Cron](http://codex.wordpress.org/Function_Reference/wp_cron) system. Once per minute on, it will also check on the `'shutdown'` hook of WP Admin requests whether there are pending actions, and if there are, it will initiate a queue via an async loopback request.
27
 
28
+ When triggered, Action Scheduler will check for scheduled actions that have a due date at or before this point in time i.e. actions scheduled to run now or at sometime in the past. Action scheduled to run asynchronously, i.e. not scheduled, have a zero date, meaning they will always be due no matter when the check occurs.
29
 
30
  ### Batch Processing Background Jobs
31
 
32
+ If there are actions to be processed, Action Scheduler will stake a unique claim for a batch of 25 actions and begin processing that batch. The PHP process spawned to run the batch will then continue processing batches of 25 actions until it uses 90% of available memory or has been processing for 30 seconds.
33
 
34
+ At that point, if there are additional actions to process, an asynchronous loopback request will be made to the site to continue processing actions in a new request.
35
 
36
+ This process and the loopback requests will continue until all actions are processed.
37
 
38
  ### Housekeeping
39
 
40
+ Before processing a batch, the scheduler will remove any existing claims on actions which have been sitting in a queue for more than five minutes (or more specifically, 10 times the allowed time limit, which defaults to 30 seconds).
41
 
42
+ Action Scheduler will also trash any actions which were completed or canceled more than a month ago.
43
 
44
  If an action runs for more than 5 minutes, Action Scheduler will assume the action has timed out and will mark it as failed. However, if all callbacks attached to the action were to successfully complete sometime after that 5 minute timeout, its status would later be updated to completed.
45
 
49
 
50
  Never be left wondering with Action Scheduler's built-in record keeping.
51
 
52
+ All events for each action are logged in the `actionscheduler_logs` table and displayed in the [administration interface](/admin/).
53
 
54
  The events logged by default include when an action:
55
  * is created
56
+ * starts (including details of how it was run, e.g. via [WP CLI](/wp-cli/) or WP Cron)
57
  * completes
58
  * fails
59
 
63
 
64
  ## Credits
65
 
66
+ Action Scheduler is developed and maintained by folks at [Automattic](http://automattic.com/) with significant early development completed by [Flightless](https://flightless.us/).
67
 
68
+ Collaboration is cool. We'd love to work with you to improve Action Scheduler. [Pull Requests](https://github.com/woocommerce/action-scheduler/pulls) welcome.
includes/vendor/action-scheduler/docs/perf.md CHANGED
@@ -4,24 +4,25 @@ description: Learn how to do WordPress background processing at scale by tuning
4
  ---
5
  # Background Processing at Scale
6
 
7
- Action Scheduler's default processing is designed to work reliably across all different hosting environments. In order to achieve that, the default processing thresholds are very conservative.
8
 
9
- Specifically, Action Scheduler will only process actions until:
10
 
11
  * 90% of available memory is used
12
  * processing another 3 actions would exceed 30 seconds of total request time, based on the average processing time for the current batch
 
13
 
14
- On sites with large queues, this can result in very slow processing time.
15
 
16
- While using [WP CLI to process queues](/wp-cli/) is the best approach to increasing processing speed, on occasion, that is not a viable option. In these cases, it's also possible to increase the processing thresholds in Action Scheduler to increase the rate at which actions are processed by the default WP Cron queue runner.
17
 
18
  ## Increasing Time Limit
19
 
20
- By default, Action Scheduler will only process actions for a maximum of 30 seconds. This time limit minimises the risk of a script timeout on unknown hosting environments, some of which enforce 30 second timeouts.
21
 
22
- If you know your host supports longer than this time limit for web requests, you can increase this time limit. This allows more actions to be processed in each request and reduces the lag between processing each queue, greating speeding up the processing rate of scheduled actions.
23
 
24
- For example, the following snippet will increase the timelimit to 2 minutes (120 seconds):
25
 
26
  ```php
27
  function eg_increase_time_limit( $time_limit ) {
@@ -38,7 +39,7 @@ Some of the known host time limits are:
38
 
39
  ## Increasing Batch Size
40
 
41
- By default, Action Scheduler will claim a batch of 25 actions. This small batch size is because the default time limit is only 30 seconds; however, if you know your actions are processing very quickly, e.g. taking microseconds not seconds, or that you have more than 30 second available to process each batch, increasing the batch size can improve performance.
42
 
43
  This is because claiming a batch has some overhead, so the less often a batch needs to be claimed, the faster actions can be processed.
44
 
@@ -53,11 +54,11 @@ add_filter( 'action_scheduler_queue_runner_batch_size', 'eg_increase_action_sche
53
 
54
  ## Increasing Concurrent Batches
55
 
56
- By default, Action Scheduler will run up to 5 concurrent batches of actions. This is to prevent consuming all the available connections or processes on your webserver.
57
 
58
- However, your server may allow a large number of connection, for example, because it has a high value for Apache's `MaxClients` setting or PHP-FPM's `pm.max_children` setting.
59
 
60
- If this is the case, you can use the `'action_scheduler_queue_runner_concurrent_batches'` filter to increase the number of conncurrent batches allowed, and therefore speed up processing large numbers of actions scheduled to be processed simultaneously.
61
 
62
  For example, to increase the allowed number of concurrent queues to 10, we can use the following code:
63
 
@@ -68,17 +69,19 @@ function eg_increase_action_scheduler_concurrent_batches( $concurrent_batches )
68
  add_filter( 'action_scheduler_queue_runner_concurrent_batches', 'eg_increase_action_scheduler_concurrent_batches' );
69
  ```
70
 
 
 
71
  ## Increasing Initialisation Rate of Runners
72
 
73
- By default, Action scheduler initiates at most, one queue runner every time the `'action_scheduler_run_queue'` action is triggered by WP Cron.
74
 
75
- Because this action is only triggered at most once every minute, if a queue is only allowed to process for one minute, then there will never be more than one queue processing actions, greatly reducing the processing rate.
76
 
77
- To handle larger queues on more powerful servers, it's a good idea to initiate additional queue runners whenever the `'action_scheduler_run_queue'` action is run.
78
 
79
  That can be done by initiated additional secure requests to our server via loopback requests.
80
 
81
- The code below demonstrates how to create 5 loopback requests each time a queue begins
82
 
83
  ```php
84
  /**
@@ -122,6 +125,8 @@ function eg_create_additional_runners() {
122
  add_action( 'wp_ajax_nopriv_eg_create_additional_runners', 'eg_create_additional_runners', 0 );
123
  ```
124
 
 
 
125
  ## High Volume Plugin
126
 
127
- It's not necessary to add all of this code yourself, the folks at [Prospress](https://prospress.com) have created a handy plugin to get access to each of these increases - the [Action Scheduler - High Volume](https://github.com/prospress/action-scheduler-high-volume) plugin.
4
  ---
5
  # Background Processing at Scale
6
 
7
+ Action Scheduler's default processing is designed to work reliably across all different hosting environments. In order to achieve that, the default processing thresholds are more conservative than many servers could support.
8
 
9
+ Specifically, Action Scheduler will only process actions in a request until:
10
 
11
  * 90% of available memory is used
12
  * processing another 3 actions would exceed 30 seconds of total request time, based on the average processing time for the current batch
13
+ * in a single concurrent queue
14
 
15
+ While Action Scheduler will initiate an asychronous loopback request to process additional actions, on sites with very large queues, this can result in slow processing times.
16
 
17
+ While using [WP CLI to process queues](/wp-cli/) is the best approach to increasing processing speed, on occasion, that is not a viable option. In these cases, it's also possible to increase the processing thresholds in Action Scheduler to increase the rate at which actions are processed by the default queue runner.
18
 
19
  ## Increasing Time Limit
20
 
21
+ By default, Action Scheduler will only process actions for a maximum of 30 seconds in each request. This time limit minimises the risk of a script timeout on unknown hosting environments, some of which enforce 30 second timeouts.
22
 
23
+ If you know your host supports longer than this time limit for web requests, you can increase this time limit. This allows more actions to be processed in each request and reduces the lag between processing each queue, greatly speeding up the processing rate of scheduled actions.
24
 
25
+ For example, the following snippet will increase the time limit to 2 minutes (120 seconds):
26
 
27
  ```php
28
  function eg_increase_time_limit( $time_limit ) {
39
 
40
  ## Increasing Batch Size
41
 
42
+ By default, Action Scheduler will claim a batch of 25 actions. This small batch size is because the default time limit is only 30 seconds; however, if you know your actions are processing very quickly, e.g. taking microseconds not seconds, or that you have more than 30 second available to process each batch, increasing the batch size can slightly improve performance.
43
 
44
  This is because claiming a batch has some overhead, so the less often a batch needs to be claimed, the faster actions can be processed.
45
 
54
 
55
  ## Increasing Concurrent Batches
56
 
57
+ By default, Action Scheduler will run only one concurrent batches of actions. This is to prevent consuming a lot of available connections or processes on your webserver.
58
 
59
+ However, your server may allow a large number of connections, for example, because it has a high value for Apache's `MaxClients` setting or PHP-FPM's `pm.max_children` setting.
60
 
61
+ If this is the case, you can use the `'action_scheduler_queue_runner_concurrent_batches'` filter to increase the number of concurrent batches allowed, and therefore speed up processing large numbers of actions scheduled to be processed simultaneously.
62
 
63
  For example, to increase the allowed number of concurrent queues to 10, we can use the following code:
64
 
69
  add_filter( 'action_scheduler_queue_runner_concurrent_batches', 'eg_increase_action_scheduler_concurrent_batches' );
70
  ```
71
 
72
+ > WARNING: because of the async queue runner introduced in Action Scheduler 3.0 will continue asynchronous loopback requests to process actions, increasing the number of concurrent batches can substantially increase server load and take down a site. [WP CLI](/wp-cli/) is a better method to achieve higher throughput.
73
+
74
  ## Increasing Initialisation Rate of Runners
75
 
76
+ By default, Action scheduler initiates at most one queue runner every time the `'action_scheduler_run_queue'` action is triggered by WP Cron.
77
 
78
+ Because this action is only triggered at most once every minute, then there will rarely be more than one queue processing actions even if the concurrent runners is increased.
79
 
80
+ To handle larger queues on more powerful servers, it's possible to initiate additional queue runners whenever the `'action_scheduler_run_queue'` action is run.
81
 
82
  That can be done by initiated additional secure requests to our server via loopback requests.
83
 
84
+ The code below demonstrates how to create 5 loopback requests each time a queue begins:
85
 
86
  ```php
87
  /**
125
  add_action( 'wp_ajax_nopriv_eg_create_additional_runners', 'eg_create_additional_runners', 0 );
126
  ```
127
 
128
+ > WARNING: because of the processing rate of scheduled actions, this kind of increase can very easily take down a site. Use only on high powered servers and be sure to test before attempting to use it in production.
129
+
130
  ## High Volume Plugin
131
 
132
+ It's not necessary to add all of this code yourself, there is a handy plugin to get access to each of these increases - the [Action Scheduler - High Volume](https://github.com/woocommerce/action-scheduler-high-volume) plugin.
includes/vendor/action-scheduler/docs/usage.md CHANGED
@@ -53,7 +53,7 @@ Action Scheduler includes the necessary file headers to be used as a standard Wo
53
 
54
  To install it as a plugin:
55
 
56
- 1. Download the .zip archive of the latest [stable release](https://github.com/Prospress/action-scheduler/releases)
57
  1. Go to the **Plugins > Add New > Upload** administration screen on your WordPress site
58
  1. Select the archive file you just downloaded
59
  1. Click **Install Now**
@@ -77,7 +77,7 @@ To include Action Scheduler as a git subtree:
77
  #### Step 1. Add the Repository as a Remote
78
 
79
  ```
80
- git remote add -f subtree-action-scheduler https://github.com/Prospress/action-scheduler.git
81
  ```
82
 
83
  Adding the subtree as a remote allows us to refer to it in short from via the name `subtree-action-scheduler`, instead of the full GitHub URL.
@@ -112,7 +112,7 @@ require_once( plugin_dir_path( __FILE__ ) . '/libraries/action-scheduler/action-
112
 
113
  There is no need to call any functions or do else to initialize Action Scheduler.
114
 
115
- When the `action-scheduler.php` file is included, Action Scheduler will register the version in that file and then load the most recent version of itself on the site. It will also load the most recent version of [all API functions](https://github.com/prospress/action-scheduler#api-functions).
116
 
117
  ### Load Order
118
 
@@ -121,3 +121,7 @@ Action Scheduler will register its version on `'plugins_loaded'` with priority `
121
  It is recommended to load it _when the file including it is included_. However, if you need to load it on a hook, then the hook must occur before `'plugins_loaded'`, or you can use `'plugins_loaded'` with negative priority, like `-10`.
122
 
123
  Action Scheduler will later initialize itself on `'init'` with priority `1`. Action Scheduler APIs should not be used until after `'init'` with priority `1`.
 
 
 
 
53
 
54
  To install it as a plugin:
55
 
56
+ 1. Download the .zip archive of the latest [stable release](https://github.com/woocommerce/action-scheduler/releases)
57
  1. Go to the **Plugins > Add New > Upload** administration screen on your WordPress site
58
  1. Select the archive file you just downloaded
59
  1. Click **Install Now**
77
  #### Step 1. Add the Repository as a Remote
78
 
79
  ```
80
+ git remote add -f subtree-action-scheduler https://github.com/woocommerce/action-scheduler.git
81
  ```
82
 
83
  Adding the subtree as a remote allows us to refer to it in short from via the name `subtree-action-scheduler`, instead of the full GitHub URL.
112
 
113
  There is no need to call any functions or do else to initialize Action Scheduler.
114
 
115
+ When the `action-scheduler.php` file is included, Action Scheduler will register the version in that file and then load the most recent version of itself on the site. It will also load the most recent version of [all API functions](https://actionscheduler.org/api/).
116
 
117
  ### Load Order
118
 
121
  It is recommended to load it _when the file including it is included_. However, if you need to load it on a hook, then the hook must occur before `'plugins_loaded'`, or you can use `'plugins_loaded'` with negative priority, like `-10`.
122
 
123
  Action Scheduler will later initialize itself on `'init'` with priority `1`. Action Scheduler APIs should not be used until after `'init'` with priority `1`.
124
+
125
+ ### Usage in Themes
126
+
127
+ When using Action Scheduler in themes, it's important to note that if Action Scheduler has been registered by a plugin, then the latest version registered by a plugin will be used, rather than the version included in the theme. This is because of the version dependency handling code using `'plugins_loaded'` since version 1.0.
includes/vendor/action-scheduler/docs/wp-cli.md CHANGED
@@ -13,7 +13,7 @@ For large sites, WP CLI is a much better choice for running queues of actions th
13
 
14
  With a regular web request, you may have to deal with script timeouts enforced by hosts, or other restraints that make it more challenging to run Action Scheduler tasks. Utilizing WP CLI to run commands directly on the server give you more freedom. This means that you typically don't have the same constraints of a normal web request.
15
 
16
- If you choose to utilize WP CLI exclusively, you can disable the normal WP CLI queue runner by installing the [Action Scheduler - Disable Default Queue Runner](https://github.com/Prospress/action-scheduler-disable-default-runner) plugin. Note that if you do this, you **must** run Action Scheduler via WP CLI or another method, otherwise no scheduled actions will be processed.
17
 
18
  ## Commands
19
 
13
 
14
  With a regular web request, you may have to deal with script timeouts enforced by hosts, or other restraints that make it more challenging to run Action Scheduler tasks. Utilizing WP CLI to run commands directly on the server give you more freedom. This means that you typically don't have the same constraints of a normal web request.
15
 
16
+ If you choose to utilize WP CLI exclusively, you can disable the normal WP CLI queue runner by installing the [Action Scheduler - Disable Default Queue Runner](https://github.com/woocommerce/action-scheduler-disable-default-runner) plugin. Note that if you do this, you **must** run Action Scheduler via WP CLI or another method, otherwise no scheduled actions will be processed.
17
 
18
  ## Commands
19
 
includes/vendor/action-scheduler/functions.php CHANGED
@@ -4,6 +4,18 @@
4
  * General API functions for scheduling actions
5
  */
6
 
 
 
 
 
 
 
 
 
 
 
 
 
7
  /**
8
  * Schedule an action to run one time
9
  *
@@ -36,7 +48,9 @@ function as_schedule_recurring_action( $timestamp, $interval_in_seconds, $hook,
36
  /**
37
  * Schedule an action that recurs on a cron-like schedule.
38
  *
39
- * @param int $timestamp The schedule will start on or after this time
 
 
40
  * @param string $schedule A cron-link schedule string
41
  * @see http://en.wikipedia.org/wiki/Cron
42
  * * * * * * *
@@ -99,17 +113,35 @@ function as_unschedule_action( $hook, $args = array(), $group = '' ) {
99
  * @param string $group
100
  */
101
  function as_unschedule_all_actions( $hook, $args = array(), $group = '' ) {
 
 
 
 
 
 
 
 
 
 
102
  do {
103
  $unscheduled_action = as_unschedule_action( $hook, $args, $group );
104
  } while ( ! empty( $unscheduled_action ) );
105
  }
106
 
107
  /**
 
 
 
 
 
 
 
 
108
  * @param string $hook
109
  * @param array $args
110
  * @param string $group
111
  *
112
- * @return int|bool The timestamp for the next occurrence, or false if nothing was found
113
  */
114
  function as_next_scheduled_action( $hook, $args = NULL, $group = '' ) {
115
  $params = array();
@@ -119,14 +151,24 @@ function as_next_scheduled_action( $hook, $args = NULL, $group = '' ) {
119
  if ( !empty($group) ) {
120
  $params['group'] = $group;
121
  }
 
 
 
 
 
 
 
 
122
  $job_id = ActionScheduler::store()->find_action( $hook, $params );
123
  if ( empty($job_id) ) {
124
  return false;
125
  }
126
  $job = ActionScheduler::store()->fetch_action( $job_id );
127
- $next = $job->get_schedule()->next();
128
- if ( $next ) {
129
- return (int)($next->format('U'));
 
 
130
  }
131
  return false;
132
  }
4
  * General API functions for scheduling actions
5
  */
6
 
7
+ /**
8
+ * Enqueue an action to run one time, as soon as possible
9
+ *
10
+ * @param string $hook The hook to trigger.
11
+ * @param array $args Arguments to pass when the hook triggers.
12
+ * @param string $group The group to assign this job to.
13
+ * @return string The action ID.
14
+ */
15
+ function as_enqueue_async_action( $hook, $args = array(), $group = '' ) {
16
+ return ActionScheduler::factory()->async( $hook, $args, $group );
17
+ }
18
+
19
  /**
20
  * Schedule an action to run one time
21
  *
48
  /**
49
  * Schedule an action that recurs on a cron-like schedule.
50
  *
51
+ * @param int $base_timestamp The first instance of the action will be scheduled
52
+ * to run at a time calculated after this timestamp matching the cron
53
+ * expression. This can be used to delay the first instance of the action.
54
  * @param string $schedule A cron-link schedule string
55
  * @see http://en.wikipedia.org/wiki/Cron
56
  * * * * * * *
113
  * @param string $group
114
  */
115
  function as_unschedule_all_actions( $hook, $args = array(), $group = '' ) {
116
+ if ( empty( $args ) ) {
117
+ if ( ! empty( $hook ) && empty( $group ) ) {
118
+ ActionScheduler_Store::instance()->cancel_actions_by_hook( $hook );
119
+ return;
120
+ }
121
+ if ( ! empty( $group ) && empty( $hook ) ) {
122
+ ActionScheduler_Store::instance()->cancel_actions_by_group( $group );
123
+ return;
124
+ }
125
+ }
126
  do {
127
  $unscheduled_action = as_unschedule_action( $hook, $args, $group );
128
  } while ( ! empty( $unscheduled_action ) );
129
  }
130
 
131
  /**
132
+ * Check if there is an existing action in the queue with a given hook, args and group combination.
133
+ *
134
+ * An action in the queue could be pending, in-progress or aysnc. If the is pending for a time in
135
+ * future, its scheduled date will be returned as a timestamp. If it is currently being run, or an
136
+ * async action sitting in the queue waiting to be processed, in which case boolean true will be
137
+ * returned. Or there may be no async, in-progress or pending action for this hook, in which case,
138
+ * boolean false will be the return value.
139
+ *
140
  * @param string $hook
141
  * @param array $args
142
  * @param string $group
143
  *
144
+ * @return int|bool The timestamp for the next occurrence of a pending scheduled action, true for an async or in-progress action or false if there is no matching action.
145
  */
146
  function as_next_scheduled_action( $hook, $args = NULL, $group = '' ) {
147
  $params = array();
151
  if ( !empty($group) ) {
152
  $params['group'] = $group;
153
  }
154
+
155
+ $params['status'] = ActionScheduler_Store::STATUS_RUNNING;
156
+ $job_id = ActionScheduler::store()->find_action( $hook, $params );
157
+ if ( ! empty( $job_id ) ) {
158
+ return true;
159
+ }
160
+
161
+ $params['status'] = ActionScheduler_Store::STATUS_PENDING;
162
  $job_id = ActionScheduler::store()->find_action( $hook, $params );
163
  if ( empty($job_id) ) {
164
  return false;
165
  }
166
  $job = ActionScheduler::store()->fetch_action( $job_id );
167
+ $scheduled_date = $job->get_schedule()->get_date();
168
+ if ( $scheduled_date ) {
169
+ return (int) $scheduled_date->format( 'U' );
170
+ } elseif ( NULL === $scheduled_date ) { // pending async action with NullSchedule
171
+ return true;
172
  }
173
  return false;
174
  }
includes/vendor/action-scheduler/lib/WP_Async_Request.php ADDED
@@ -0,0 +1,170 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * WP Async Request
4
+ *
5
+ * @package WP-Background-Processing
6
+ */
7
+ /*
8
+ Library URI: https://github.com/deliciousbrains/wp-background-processing/blob/fbbc56f2480910d7959972ec9ec0819a13c6150a/classes/wp-async-request.php
9
+ Author: Delicious Brains Inc.
10
+ Author URI: https://deliciousbrains.com/
11
+ License: GNU General Public License v2.0
12
+ License URI: https://github.com/deliciousbrains/wp-background-processing/commit/126d7945dd3d39f39cb6488ca08fe1fb66cb351a
13
+ */
14
+
15
+ if ( ! class_exists( 'WP_Async_Request' ) ) {
16
+
17
+ /**
18
+ * Abstract WP_Async_Request class.
19
+ *
20
+ * @abstract
21
+ */
22
+ abstract class WP_Async_Request {
23
+
24
+ /**
25
+ * Prefix
26
+ *
27
+ * (default value: 'wp')
28
+ *
29
+ * @var string
30
+ * @access protected
31
+ */
32
+ protected $prefix = 'wp';
33
+
34
+ /**
35
+ * Action
36
+ *
37
+ * (default value: 'async_request')
38
+ *
39
+ * @var string
40
+ * @access protected
41
+ */
42
+ protected $action = 'async_request';
43
+
44
+ /**
45
+ * Identifier
46
+ *
47
+ * @var mixed
48
+ * @access protected
49
+ */
50
+ protected $identifier;
51
+
52
+ /**
53
+ * Data
54
+ *
55
+ * (default value: array())
56
+ *
57
+ * @var array
58
+ * @access protected
59
+ */
60
+ protected $data = array();
61
+
62
+ /**
63
+ * Initiate new async request
64
+ */
65
+ public function __construct() {
66
+ $this->identifier = $this->prefix . '_' . $this->action;
67
+
68
+ add_action( 'wp_ajax_' . $this->identifier, array( $this, 'maybe_handle' ) );
69
+ add_action( 'wp_ajax_nopriv_' . $this->identifier, array( $this, 'maybe_handle' ) );
70
+ }
71
+
72
+ /**
73
+ * Set data used during the request
74
+ *
75
+ * @param array $data Data.
76
+ *
77
+ * @return $this
78
+ */
79
+ public function data( $data ) {
80
+ $this->data = $data;
81
+
82
+ return $this;
83
+ }
84
+
85
+ /**
86
+ * Dispatch the async request
87
+ *
88
+ * @return array|WP_Error
89
+ */
90
+ public function dispatch() {
91
+ $url = add_query_arg( $this->get_query_args(), $this->get_query_url() );
92
+ $args = $this->get_post_args();
93
+
94
+ return wp_remote_post( esc_url_raw( $url ), $args );
95
+ }
96
+
97
+ /**
98
+ * Get query args
99
+ *
100
+ * @return array
101
+ */
102
+ protected function get_query_args() {
103
+ if ( property_exists( $this, 'query_args' ) ) {
104
+ return $this->query_args;
105
+ }
106
+
107
+ return array(
108
+ 'action' => $this->identifier,
109
+ 'nonce' => wp_create_nonce( $this->identifier ),
110
+ );
111
+ }
112
+
113
+ /**
114
+ * Get query URL
115
+ *
116
+ * @return string
117
+ */
118
+ protected function get_query_url() {
119
+ if ( property_exists( $this, 'query_url' ) ) {
120
+ return $this->query_url;
121
+ }
122
+
123
+ return admin_url( 'admin-ajax.php' );
124
+ }
125
+
126
+ /**
127
+ * Get post args
128
+ *
129
+ * @return array
130
+ */
131
+ protected function get_post_args() {
132
+ if ( property_exists( $this, 'post_args' ) ) {
133
+ return $this->post_args;
134
+ }
135
+
136
+ return array(
137
+ 'timeout' => 0.01,
138
+ 'blocking' => false,
139
+ 'body' => $this->data,
140
+ 'cookies' => $_COOKIE,
141
+ 'sslverify' => apply_filters( 'https_local_ssl_verify', false ),
142
+ );
143
+ }
144
+
145
+ /**
146
+ * Maybe handle
147
+ *
148
+ * Check for correct nonce and pass to handler.
149
+ */
150
+ public function maybe_handle() {
151
+ // Don't lock up other requests while processing
152
+ session_write_close();
153
+
154
+ check_ajax_referer( $this->identifier, 'nonce' );
155
+
156
+ $this->handle();
157
+
158
+ wp_die();
159
+ }
160
+
161
+ /**
162
+ * Handle
163
+ *
164
+ * Override this method to perform any actions required
165
+ * during the async request.
166
+ */
167
+ abstract protected function handle();
168
+
169
+ }
170
+ }
includes/vendor/action-scheduler/package-lock.json ADDED
@@ -0,0 +1,2138 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "action-scheduler",
3
+ "version": "3.0.0",
4
+ "lockfileVersion": 1,
5
+ "requires": true,
6
+ "dependencies": {
7
+ "@babel/code-frame": {
8
+ "version": "7.5.5",
9
+ "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.5.5.tgz",
10
+ "integrity": "sha512-27d4lZoomVyo51VegxI20xZPuSHusqbQag/ztrBC7wegWoQ1nLREPVSKSW8byhTlzTKyNE4ifaTA6lCp7JjpFw==",
11
+ "dev": true,
12
+ "requires": {
13
+ "@babel/highlight": "^7.0.0"
14
+ }
15
+ },
16
+ "@babel/highlight": {
17
+ "version": "7.5.0",
18
+ "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.5.0.tgz",
19
+ "integrity": "sha512-7dV4eu9gBxoM0dAnj/BCFDW9LFU0zvTrkq0ugM7pnHEgguOEeOz1so2ZghEdzviYzQEED0r4EAgpsBChKy1TRQ==",
20
+ "dev": true,
21
+ "requires": {
22
+ "chalk": "^2.0.0",
23
+ "esutils": "^2.0.2",
24
+ "js-tokens": "^4.0.0"
25
+ }
26
+ },
27
+ "@nodelib/fs.scandir": {
28
+ "version": "2.1.3",
29
+ "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.3.tgz",
30
+ "integrity": "sha512-eGmwYQn3gxo4r7jdQnkrrN6bY478C3P+a/y72IJukF8LjB6ZHeB3c+Ehacj3sYeSmUXGlnA67/PmbM9CVwL7Dw==",
31
+ "dev": true,
32
+ "requires": {
33
+ "@nodelib/fs.stat": "2.0.3",
34
+ "run-parallel": "^1.1.9"
35
+ }
36
+ },
37
+ "@nodelib/fs.stat": {
38
+ "version": "2.0.3",
39
+ "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.3.tgz",
40
+ "integrity": "sha512-bQBFruR2TAwoevBEd/NWMoAAtNGzTRgdrqnYCc7dhzfoNvqPzLyqlEQnzZ3kVnNrSp25iyxE00/3h2fqGAGArA==",
41
+ "dev": true
42
+ },
43
+ "@nodelib/fs.walk": {
44
+ "version": "1.2.4",
45
+ "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.4.tgz",
46
+ "integrity": "sha512-1V9XOY4rDW0rehzbrcqAmHnz8e7SKvX27gh8Gt2WgB0+pdzdiLV83p72kZPU+jvMbS1qU5mauP2iOvO8rhmurQ==",
47
+ "dev": true,
48
+ "requires": {
49
+ "@nodelib/fs.scandir": "2.1.3",
50
+ "fastq": "^1.6.0"
51
+ }
52
+ },
53
+ "@samverschueren/stream-to-observable": {
54
+ "version": "0.3.0",
55
+ "resolved": "https://registry.npmjs.org/@samverschueren/stream-to-observable/-/stream-to-observable-0.3.0.tgz",
56
+ "integrity": "sha512-MI4Xx6LHs4Webyvi6EbspgyAb4D2Q2VtnCQ1blOJcoLS6mVa8lNN2rkIy1CVxfTUpoyIbCTkXES1rLXztFD1lg==",
57
+ "dev": true,
58
+ "requires": {
59
+ "any-observable": "^0.3.0"
60
+ }
61
+ },
62
+ "@types/events": {
63
+ "version": "3.0.0",
64
+ "resolved": "https://registry.npmjs.org/@types/events/-/events-3.0.0.tgz",
65
+ "integrity": "sha512-EaObqwIvayI5a8dCzhFrjKzVwKLxjoG9T6Ppd5CEo07LRKfQ8Yokw54r5+Wq7FaBQ+yXRvQAYPrHwya1/UFt9g==",
66
+ "dev": true
67
+ },
68
+ "@types/glob": {
69
+ "version": "7.1.1",
70
+ "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.1.1.tgz",
71
+ "integrity": "sha512-1Bh06cbWJUHMC97acuD6UMG29nMt0Aqz1vF3guLfG+kHHJhy3AyohZFFxYk2f7Q1SQIrNwvncxAE0N/9s70F2w==",
72
+ "dev": true,
73
+ "requires": {
74
+ "@types/events": "*",
75
+ "@types/minimatch": "*",
76
+ "@types/node": "*"
77
+ }
78
+ },
79
+ "@types/minimatch": {
80
+ "version": "3.0.3",
81
+ "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.3.tgz",
82
+ "integrity": "sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA==",
83
+ "dev": true
84
+ },
85
+ "@types/node": {
86
+ "version": "12.11.7",
87
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-12.11.7.tgz",
88
+ "integrity": "sha512-JNbGaHFCLwgHn/iCckiGSOZ1XYHsKFwREtzPwSGCVld1SGhOlmZw2D4ZI94HQCrBHbADzW9m4LER/8olJTRGHA==",
89
+ "dev": true
90
+ },
91
+ "@types/normalize-package-data": {
92
+ "version": "2.4.0",
93
+ "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.0.tgz",
94
+ "integrity": "sha512-f5j5b/Gf71L+dbqxIpQ4Z2WlmI/mPJ0fOkGGmFgtb6sAu97EPczzbS3/tJKxmcYDj55OX6ssqwDAWOHIYDRDGA==",
95
+ "dev": true
96
+ },
97
+ "abbrev": {
98
+ "version": "1.1.1",
99
+ "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz",
100
+ "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==",
101
+ "dev": true
102
+ },
103
+ "aggregate-error": {
104
+ "version": "3.0.1",
105
+ "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.0.1.tgz",
106
+ "integrity": "sha512-quoaXsZ9/BLNae5yiNoUz+Nhkwz83GhWwtYFglcjEQB2NDHCIpApbqXxIFnm4Pq/Nvhrsq5sYJFyohrrxnTGAA==",
107
+ "dev": true,
108
+ "requires": {
109
+ "clean-stack": "^2.0.0",
110
+ "indent-string": "^4.0.0"
111
+ },
112
+ "dependencies": {
113
+ "indent-string": {
114
+ "version": "4.0.0",
115
+ "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz",
116
+ "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==",
117
+ "dev": true
118
+ }
119
+ }
120
+ },
121
+ "ansi-escapes": {
122
+ "version": "3.2.0",
123
+ "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz",
124
+ "integrity": "sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==",
125
+ "dev": true
126
+ },
127
+ "ansi-regex": {
128
+ "version": "2.1.1",
129
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
130
+ "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=",
131
+ "dev": true
132
+ },
133
+ "ansi-styles": {
134
+ "version": "3.2.1",
135
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
136
+ "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
137
+ "dev": true,
138
+ "requires": {
139
+ "color-convert": "^1.9.0"
140
+ }
141
+ },
142
+ "any-observable": {
143
+ "version": "0.3.0",
144
+ "resolved": "https://registry.npmjs.org/any-observable/-/any-observable-0.3.0.tgz",
145
+ "integrity": "sha512-/FQM1EDkTsf63Ub2C6O7GuYFDsSXUwsaZDurV0np41ocwq0jthUAYCmhBX9f+KwlaCgIuWyr/4WlUQUBfKfZog==",
146
+ "dev": true
147
+ },
148
+ "argparse": {
149
+ "version": "1.0.10",
150
+ "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
151
+ "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
152
+ "dev": true,
153
+ "requires": {
154
+ "sprintf-js": "~1.0.2"
155
+ },
156
+ "dependencies": {
157
+ "sprintf-js": {
158
+ "version": "1.0.3",
159
+ "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
160
+ "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=",
161
+ "dev": true
162
+ }
163
+ }
164
+ },
165
+ "array-find-index": {
166
+ "version": "1.0.2",
167
+ "resolved": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz",
168
+ "integrity": "sha1-3wEKoSh+Fku9pvlyOwqWoexBh6E=",
169
+ "dev": true
170
+ },
171
+ "array-union": {
172
+ "version": "2.1.0",
173
+ "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz",
174
+ "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==",
175
+ "dev": true
176
+ },
177
+ "async": {
178
+ "version": "1.5.2",
179
+ "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz",
180
+ "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=",
181
+ "dev": true
182
+ },
183
+ "balanced-match": {
184
+ "version": "1.0.0",
185
+ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
186
+ "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=",
187
+ "dev": true
188
+ },
189
+ "brace-expansion": {
190
+ "version": "1.1.11",
191
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
192
+ "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
193
+ "dev": true,
194
+ "requires": {
195
+ "balanced-match": "^1.0.0",
196
+ "concat-map": "0.0.1"
197
+ }
198
+ },
199
+ "braces": {
200
+ "version": "3.0.2",
201
+ "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
202
+ "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
203
+ "dev": true,
204
+ "requires": {
205
+ "fill-range": "^7.0.1"
206
+ }
207
+ },
208
+ "caller-callsite": {
209
+ "version": "2.0.0",
210
+ "resolved": "https://registry.npmjs.org/caller-callsite/-/caller-callsite-2.0.0.tgz",
211
+ "integrity": "sha1-hH4PzgoiN1CpoCfFSzNzGtMVQTQ=",
212
+ "dev": true,
213
+ "requires": {
214
+ "callsites": "^2.0.0"
215
+ }
216
+ },
217
+ "caller-path": {
218
+ "version": "2.0.0",
219
+ "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-2.0.0.tgz",
220
+ "integrity": "sha1-Ro+DBE42mrIBD6xfBs7uFbsssfQ=",
221
+ "dev": true,
222
+ "requires": {
223
+ "caller-callsite": "^2.0.0"
224
+ }
225
+ },
226
+ "callsites": {
227
+ "version": "2.0.0",
228
+ "resolved": "https://registry.npmjs.org/callsites/-/callsites-2.0.0.tgz",
229
+ "integrity": "sha1-BuuE8A7qQT2oav/vrL/7Ngk7PFA=",
230
+ "dev": true
231
+ },
232
+ "camelcase": {
233
+ "version": "2.1.1",
234
+ "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-2.1.1.tgz",
235
+ "integrity": "sha1-fB0W1nmhu+WcoCys7PsBHiAfWh8=",
236
+ "dev": true
237
+ },
238
+ "camelcase-keys": {
239
+ "version": "2.1.0",
240
+ "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-2.1.0.tgz",
241
+ "integrity": "sha1-MIvur/3ygRkFHvodkyITyRuPkuc=",
242
+ "dev": true,
243
+ "requires": {
244
+ "camelcase": "^2.0.0",
245
+ "map-obj": "^1.0.0"
246
+ }
247
+ },
248
+ "chalk": {
249
+ "version": "2.4.2",
250
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
251
+ "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
252
+ "dev": true,
253
+ "requires": {
254
+ "ansi-styles": "^3.2.1",
255
+ "escape-string-regexp": "^1.0.5",
256
+ "supports-color": "^5.3.0"
257
+ }
258
+ },
259
+ "ci-info": {
260
+ "version": "2.0.0",
261
+ "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz",
262
+ "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==",
263
+ "dev": true
264
+ },
265
+ "clean-stack": {
266
+ "version": "2.2.0",
267
+ "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz",
268
+ "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==",
269
+ "dev": true
270
+ },
271
+ "cli-cursor": {
272
+ "version": "2.1.0",
273
+ "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz",
274
+ "integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=",
275
+ "dev": true,
276
+ "requires": {
277
+ "restore-cursor": "^2.0.0"
278
+ }
279
+ },
280
+ "cli-truncate": {
281
+ "version": "0.2.1",
282
+ "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-0.2.1.tgz",
283
+ "integrity": "sha1-nxXPuwcFAFNpIWxiasfQWrkN1XQ=",
284
+ "dev": true,
285
+ "requires": {
286
+ "slice-ansi": "0.0.4",
287
+ "string-width": "^1.0.1"
288
+ }
289
+ },
290
+ "code-point-at": {
291
+ "version": "1.1.0",
292
+ "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz",
293
+ "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=",
294
+ "dev": true
295
+ },
296
+ "coffeescript": {
297
+ "version": "1.10.0",
298
+ "resolved": "https://registry.npmjs.org/coffeescript/-/coffeescript-1.10.0.tgz",
299
+ "integrity": "sha1-56qDAZF+9iGzXYo580jc3R234z4=",
300
+ "dev": true
301
+ },
302
+ "color-convert": {
303
+ "version": "1.9.3",
304
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
305
+ "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
306
+ "dev": true,
307
+ "requires": {
308
+ "color-name": "1.1.3"
309
+ }
310
+ },
311
+ "color-name": {
312
+ "version": "1.1.3",
313
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
314
+ "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
315
+ "dev": true
316
+ },
317
+ "colors": {
318
+ "version": "1.1.2",
319
+ "resolved": "https://registry.npmjs.org/colors/-/colors-1.1.2.tgz",
320
+ "integrity": "sha1-FopHAXVran9RoSzgyXv6KMCE7WM=",
321
+ "dev": true
322
+ },
323
+ "commander": {
324
+ "version": "2.20.3",
325
+ "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
326
+ "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
327
+ "dev": true
328
+ },
329
+ "concat-map": {
330
+ "version": "0.0.1",
331
+ "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
332
+ "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=",
333
+ "dev": true
334
+ },
335
+ "cosmiconfig": {
336
+ "version": "5.2.1",
337
+ "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-5.2.1.tgz",
338
+ "integrity": "sha512-H65gsXo1SKjf8zmrJ67eJk8aIRKV5ff2D4uKZIBZShbhGSpEmsQOPW/SKMKYhSTrqR7ufy6RP69rPogdaPh/kA==",
339
+ "dev": true,
340
+ "requires": {
341
+ "import-fresh": "^2.0.0",
342
+ "is-directory": "^0.3.1",
343
+ "js-yaml": "^3.13.1",
344
+ "parse-json": "^4.0.0"
345
+ },
346
+ "dependencies": {
347
+ "parse-json": {
348
+ "version": "4.0.0",
349
+ "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz",
350
+ "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=",
351
+ "dev": true,
352
+ "requires": {
353
+ "error-ex": "^1.3.1",
354
+ "json-parse-better-errors": "^1.0.1"
355
+ }
356
+ }
357
+ }
358
+ },
359
+ "cross-spawn": {
360
+ "version": "6.0.5",
361
+ "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz",
362
+ "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==",
363
+ "dev": true,
364
+ "requires": {
365
+ "nice-try": "^1.0.4",
366
+ "path-key": "^2.0.1",
367
+ "semver": "^5.5.0",
368
+ "shebang-command": "^1.2.0",
369
+ "which": "^1.2.9"
370
+ }
371
+ },
372
+ "currently-unhandled": {
373
+ "version": "0.4.1",
374
+ "resolved": "https://registry.npmjs.org/currently-unhandled/-/currently-unhandled-0.4.1.tgz",
375
+ "integrity": "sha1-mI3zP+qxke95mmE2nddsF635V+o=",
376
+ "dev": true,
377
+ "requires": {
378
+ "array-find-index": "^1.0.1"
379
+ }
380
+ },
381
+ "date-fns": {
382
+ "version": "1.30.1",
383
+ "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-1.30.1.tgz",
384
+ "integrity": "sha512-hBSVCvSmWC+QypYObzwGOd9wqdDpOt+0wl0KbU+R+uuZBS1jN8VsD1ss3irQDknRj5NvxiTF6oj/nDRnN/UQNw==",
385
+ "dev": true
386
+ },
387
+ "dateformat": {
388
+ "version": "1.0.12",
389
+ "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-1.0.12.tgz",
390
+ "integrity": "sha1-nxJLZ1lMk3/3BpMuSmQsyo27/uk=",
391
+ "dev": true,
392
+ "requires": {
393
+ "get-stdin": "^4.0.1",
394
+ "meow": "^3.3.0"
395
+ }
396
+ },
397
+ "debug": {
398
+ "version": "4.1.1",
399
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz",
400
+ "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==",
401
+ "dev": true,
402
+ "requires": {
403
+ "ms": "^2.1.1"
404
+ }
405
+ },
406
+ "decamelize": {
407
+ "version": "1.2.0",
408
+ "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz",
409
+ "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=",
410
+ "dev": true
411
+ },
412
+ "dedent": {
413
+ "version": "0.7.0",
414
+ "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz",
415
+ "integrity": "sha1-JJXduvbrh0q7Dhvp3yLS5aVEMmw=",
416
+ "dev": true
417
+ },
418
+ "del": {
419
+ "version": "5.1.0",
420
+ "resolved": "https://registry.npmjs.org/del/-/del-5.1.0.tgz",
421
+ "integrity": "sha512-wH9xOVHnczo9jN2IW68BabcecVPxacIA3g/7z6vhSU/4stOKQzeCRK0yD0A24WiAAUJmmVpWqrERcTxnLo3AnA==",
422
+ "dev": true,
423
+ "requires": {
424
+ "globby": "^10.0.1",
425
+ "graceful-fs": "^4.2.2",
426
+ "is-glob": "^4.0.1",
427
+ "is-path-cwd": "^2.2.0",
428
+ "is-path-inside": "^3.0.1",
429
+ "p-map": "^3.0.0",
430
+ "rimraf": "^3.0.0",
431
+ "slash": "^3.0.0"
432
+ },
433
+ "dependencies": {
434
+ "glob": {
435
+ "version": "7.1.5",
436
+ "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.5.tgz",
437
+ "integrity": "sha512-J9dlskqUXK1OeTOYBEn5s8aMukWMwWfs+rPTn/jn50Ux4MNXVhubL1wu/j2t+H4NVI+cXEcCaYellqaPVGXNqQ==",
438
+ "dev": true,
439
+ "requires": {
440
+ "fs.realpath": "^1.0.0",
441
+ "inflight": "^1.0.4",
442
+ "inherits": "2",
443
+ "minimatch": "^3.0.4",
444
+ "once": "^1.3.0",
445
+ "path-is-absolute": "^1.0.0"
446
+ }
447
+ },
448
+ "rimraf": {
449
+ "version": "3.0.0",
450
+ "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.0.tgz",
451
+ "integrity": "sha512-NDGVxTsjqfunkds7CqsOiEnxln4Bo7Nddl3XhS4pXg5OzwkLqJ971ZVAAnB+DDLnF76N+VnDEiBHaVV8I06SUg==",
452
+ "dev": true,
453
+ "requires": {
454
+ "glob": "^7.1.3"
455
+ }
456
+ }
457
+ }
458
+ },
459
+ "dir-glob": {
460
+ "version": "3.0.1",
461
+ "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz",
462
+ "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==",
463
+ "dev": true,
464
+ "requires": {
465
+ "path-type": "^4.0.0"
466
+ },
467
+ "dependencies": {
468
+ "path-type": {
469
+ "version": "4.0.0",
470
+ "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz",
471
+ "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==",
472
+ "dev": true
473
+ }
474
+ }
475
+ },
476
+ "elegant-spinner": {
477
+ "version": "1.0.1",
478
+ "resolved": "https://registry.npmjs.org/elegant-spinner/-/elegant-spinner-1.0.1.tgz",
479
+ "integrity": "sha1-2wQ1IcldfjA/2PNFvtwzSc+wcp4=",
480
+ "dev": true
481
+ },
482
+ "end-of-stream": {
483
+ "version": "1.4.4",
484
+ "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz",
485
+ "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==",
486
+ "dev": true,
487
+ "requires": {
488
+ "once": "^1.4.0"
489
+ }
490
+ },
491
+ "error-ex": {
492
+ "version": "1.3.2",
493
+ "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz",
494
+ "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==",
495
+ "dev": true,
496
+ "requires": {
497
+ "is-arrayish": "^0.2.1"
498
+ }
499
+ },
500
+ "escape-string-regexp": {
501
+ "version": "1.0.5",
502
+ "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
503
+ "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=",
504
+ "dev": true
505
+ },
506
+ "esprima": {
507
+ "version": "4.0.1",
508
+ "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
509
+ "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==",
510
+ "dev": true
511
+ },
512
+ "esutils": {
513
+ "version": "2.0.3",
514
+ "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz",
515
+ "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==",
516
+ "dev": true
517
+ },
518
+ "eventemitter2": {
519
+ "version": "0.4.14",
520
+ "resolved": "https://registry.npmjs.org/eventemitter2/-/eventemitter2-0.4.14.tgz",
521
+ "integrity": "sha1-j2G3XN4BKy6esoTUVFWDtWQ7Yas=",
522
+ "dev": true
523
+ },
524
+ "execa": {
525
+ "version": "1.0.0",
526
+ "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz",
527
+ "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==",
528
+ "dev": true,
529
+ "requires": {
530
+ "cross-spawn": "^6.0.0",
531
+ "get-stream": "^4.0.0",
532
+ "is-stream": "^1.1.0",
533
+ "npm-run-path": "^2.0.0",
534
+ "p-finally": "^1.0.0",
535
+ "signal-exit": "^3.0.0",
536
+ "strip-eof": "^1.0.0"
537
+ }
538
+ },
539
+ "exit": {
540
+ "version": "0.1.2",
541
+ "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz",
542
+ "integrity": "sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=",
543
+ "dev": true
544
+ },
545
+ "fast-glob": {
546
+ "version": "3.1.0",
547
+ "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.1.0.tgz",
548
+ "integrity": "sha512-TrUz3THiq2Vy3bjfQUB2wNyPdGBeGmdjbzzBLhfHN4YFurYptCKwGq/TfiRavbGywFRzY6U2CdmQ1zmsY5yYaw==",
549
+ "dev": true,
550
+ "requires": {
551
+ "@nodelib/fs.stat": "^2.0.2",
552
+ "@nodelib/fs.walk": "^1.2.3",
553
+ "glob-parent": "^5.1.0",
554
+ "merge2": "^1.3.0",
555
+ "micromatch": "^4.0.2"
556
+ }
557
+ },
558
+ "fastq": {
559
+ "version": "1.6.0",
560
+ "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.6.0.tgz",
561
+ "integrity": "sha512-jmxqQ3Z/nXoeyDmWAzF9kH1aGZSis6e/SbfPmJpUnyZ0ogr6iscHQaml4wsEepEWSdtmpy+eVXmCRIMpxaXqOA==",
562
+ "dev": true,
563
+ "requires": {
564
+ "reusify": "^1.0.0"
565
+ }
566
+ },
567
+ "figures": {
568
+ "version": "1.7.0",
569
+ "resolved": "https://registry.npmjs.org/figures/-/figures-1.7.0.tgz",
570
+ "integrity": "sha1-y+Hjr/zxzUS4DK3+0o3Hk6lwHS4=",
571
+ "dev": true,
572
+ "requires": {
573
+ "escape-string-regexp": "^1.0.5",
574
+ "object-assign": "^4.1.0"
575
+ }
576
+ },
577
+ "fill-range": {
578
+ "version": "7.0.1",
579
+ "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
580
+ "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
581
+ "dev": true,
582
+ "requires": {
583
+ "to-regex-range": "^5.0.1"
584
+ }
585
+ },
586
+ "find-up": {
587
+ "version": "1.1.2",
588
+ "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz",
589
+ "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=",
590
+ "dev": true,
591
+ "requires": {
592
+ "path-exists": "^2.0.0",
593
+ "pinkie-promise": "^2.0.0"
594
+ }
595
+ },
596
+ "findup-sync": {
597
+ "version": "0.3.0",
598
+ "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-0.3.0.tgz",
599
+ "integrity": "sha1-N5MKpdgWt3fANEXhlmzGeQpMCxY=",
600
+ "dev": true,
601
+ "requires": {
602
+ "glob": "~5.0.0"
603
+ },
604
+ "dependencies": {
605
+ "glob": {
606
+ "version": "5.0.15",
607
+ "resolved": "https://registry.npmjs.org/glob/-/glob-5.0.15.tgz",
608
+ "integrity": "sha1-G8k2ueAvSmA/zCIuz3Yz0wuLk7E=",
609
+ "dev": true,
610
+ "requires": {
611
+ "inflight": "^1.0.4",
612
+ "inherits": "2",
613
+ "minimatch": "2 || 3",
614
+ "once": "^1.3.0",
615
+ "path-is-absolute": "^1.0.0"
616
+ }
617
+ }
618
+ }
619
+ },
620
+ "fs.realpath": {
621
+ "version": "1.0.0",
622
+ "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
623
+ "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=",
624
+ "dev": true
625
+ },
626
+ "get-own-enumerable-property-symbols": {
627
+ "version": "3.0.1",
628
+ "resolved": "https://registry.npmjs.org/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-3.0.1.tgz",
629
+ "integrity": "sha512-09/VS4iek66Dh2bctjRkowueRJbY1JDGR1L/zRxO1Qk8Uxs6PnqaNSqalpizPT+CDjre3hnEsuzvhgomz9qYrA==",
630
+ "dev": true
631
+ },
632
+ "get-stdin": {
633
+ "version": "4.0.1",
634
+ "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz",
635
+ "integrity": "sha1-uWjGsKBDhDJJAui/Gl3zJXmkUP4=",
636
+ "dev": true
637
+ },
638
+ "get-stream": {
639
+ "version": "4.1.0",
640
+ "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz",
641
+ "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==",
642
+ "dev": true,
643
+ "requires": {
644
+ "pump": "^3.0.0"
645
+ }
646
+ },
647
+ "getobject": {
648
+ "version": "0.1.0",
649
+ "resolved": "https://registry.npmjs.org/getobject/-/getobject-0.1.0.tgz",
650
+ "integrity": "sha1-BHpEl4n6Fg0Bj1SG7ZEyC27HiFw=",
651
+ "dev": true
652
+ },
653
+ "glob": {
654
+ "version": "7.0.6",
655
+ "resolved": "https://registry.npmjs.org/glob/-/glob-7.0.6.tgz",
656
+ "integrity": "sha1-IRuvr0nlJbjNkyYNFKsTYVKz9Xo=",
657
+ "dev": true,
658
+ "requires": {
659
+ "fs.realpath": "^1.0.0",
660
+ "inflight": "^1.0.4",
661
+ "inherits": "2",
662
+ "minimatch": "^3.0.2",
663
+ "once": "^1.3.0",
664
+ "path-is-absolute": "^1.0.0"
665
+ }
666
+ },
667
+ "glob-parent": {
668
+ "version": "5.1.0",
669
+ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.0.tgz",
670
+ "integrity": "sha512-qjtRgnIVmOfnKUE3NJAQEdk+lKrxfw8t5ke7SXtfMTHcjsBfOfWXCQfdb30zfDoZQ2IRSIiidmjtbHZPZ++Ihw==",
671
+ "dev": true,
672
+ "requires": {
673
+ "is-glob": "^4.0.1"
674
+ }
675
+ },
676
+ "globby": {
677
+ "version": "10.0.1",
678
+ "resolved": "https://registry.npmjs.org/globby/-/globby-10.0.1.tgz",
679
+ "integrity": "sha512-sSs4inE1FB2YQiymcmTv6NWENryABjUNPeWhOvmn4SjtKybglsyPZxFB3U1/+L1bYi0rNZDqCLlHyLYDl1Pq5A==",
680
+ "dev": true,
681
+ "requires": {
682
+ "@types/glob": "^7.1.1",
683
+ "array-union": "^2.1.0",
684
+ "dir-glob": "^3.0.1",
685
+ "fast-glob": "^3.0.3",
686
+ "glob": "^7.1.3",
687
+ "ignore": "^5.1.1",
688
+ "merge2": "^1.2.3",
689
+ "slash": "^3.0.0"
690
+ },
691
+ "dependencies": {
692
+ "glob": {
693
+ "version": "7.1.5",
694
+ "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.5.tgz",
695
+ "integrity": "sha512-J9dlskqUXK1OeTOYBEn5s8aMukWMwWfs+rPTn/jn50Ux4MNXVhubL1wu/j2t+H4NVI+cXEcCaYellqaPVGXNqQ==",
696
+ "dev": true,
697
+ "requires": {
698
+ "fs.realpath": "^1.0.0",
699
+ "inflight": "^1.0.4",
700
+ "inherits": "2",
701
+ "minimatch": "^3.0.4",
702
+ "once": "^1.3.0",
703
+ "path-is-absolute": "^1.0.0"
704
+ }
705
+ }
706
+ }
707
+ },
708
+ "graceful-fs": {
709
+ "version": "4.2.3",
710
+ "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.3.tgz",
711
+ "integrity": "sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ==",
712
+ "dev": true
713
+ },
714
+ "grunt": {
715
+ "version": "1.0.4",
716
+ "resolved": "https://registry.npmjs.org/grunt/-/grunt-1.0.4.tgz",
717
+ "integrity": "sha512-PYsMOrOC+MsdGEkFVwMaMyc6Ob7pKmq+deg1Sjr+vvMWp35sztfwKE7qoN51V+UEtHsyNuMcGdgMLFkBHvMxHQ==",
718
+ "dev": true,
719
+ "requires": {
720
+ "coffeescript": "~1.10.0",
721
+ "dateformat": "~1.0.12",
722
+ "eventemitter2": "~0.4.13",
723
+ "exit": "~0.1.1",
724
+ "findup-sync": "~0.3.0",
725
+ "glob": "~7.0.0",
726
+ "grunt-cli": "~1.2.0",
727
+ "grunt-known-options": "~1.1.0",
728
+ "grunt-legacy-log": "~2.0.0",
729
+ "grunt-legacy-util": "~1.1.1",
730
+ "iconv-lite": "~0.4.13",
731
+ "js-yaml": "~3.13.0",
732
+ "minimatch": "~3.0.2",
733
+ "mkdirp": "~0.5.1",
734
+ "nopt": "~3.0.6",
735
+ "path-is-absolute": "~1.0.0",
736
+ "rimraf": "~2.6.2"
737
+ },
738
+ "dependencies": {
739
+ "grunt-cli": {
740
+ "version": "1.2.0",
741
+ "resolved": "https://registry.npmjs.org/grunt-cli/-/grunt-cli-1.2.0.tgz",
742
+ "integrity": "sha1-VisRnrsGndtGSs4oRVAb6Xs1tqg=",
743
+ "dev": true,
744
+ "requires": {
745
+ "findup-sync": "~0.3.0",
746
+ "grunt-known-options": "~1.1.0",
747
+ "nopt": "~3.0.6",
748
+ "resolve": "~1.1.0"
749
+ }
750
+ },
751
+ "resolve": {
752
+ "version": "1.1.7",
753
+ "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz",
754
+ "integrity": "sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs=",
755
+ "dev": true
756
+ }
757
+ }
758
+ },
759
+ "grunt-checktextdomain": {
760
+ "version": "1.0.1",
761
+ "resolved": "https://registry.npmjs.org/grunt-checktextdomain/-/grunt-checktextdomain-1.0.1.tgz",
762
+ "integrity": "sha1-slTQHh3pEwBdTbHFMD2QI7mD4Zs=",
763
+ "dev": true,
764
+ "requires": {
765
+ "chalk": "~0.2.1",
766
+ "text-table": "~0.2.0"
767
+ },
768
+ "dependencies": {
769
+ "ansi-styles": {
770
+ "version": "0.2.0",
771
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-0.2.0.tgz",
772
+ "integrity": "sha1-NZq0sV3NZLptdHNLcsNjYKmvLBk=",
773
+ "dev": true
774
+ },
775
+ "chalk": {
776
+ "version": "0.2.1",
777
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-0.2.1.tgz",
778
+ "integrity": "sha1-dhPhV1FFshOGSD9/SFql/6jL0Qw=",
779
+ "dev": true,
780
+ "requires": {
781
+ "ansi-styles": "~0.2.0",
782
+ "has-color": "~0.1.0"
783
+ }
784
+ }
785
+ }
786
+ },
787
+ "grunt-known-options": {
788
+ "version": "1.1.1",
789
+ "resolved": "https://registry.npmjs.org/grunt-known-options/-/grunt-known-options-1.1.1.tgz",
790
+ "integrity": "sha512-cHwsLqoighpu7TuYj5RonnEuxGVFnztcUqTqp5rXFGYL4OuPFofwC4Ycg7n9fYwvK6F5WbYgeVOwph9Crs2fsQ==",
791
+ "dev": true
792
+ },
793
+ "grunt-legacy-log": {
794
+ "version": "2.0.0",
795
+ "resolved": "https://registry.npmjs.org/grunt-legacy-log/-/grunt-legacy-log-2.0.0.tgz",
796
+ "integrity": "sha512-1m3+5QvDYfR1ltr8hjiaiNjddxGdQWcH0rw1iKKiQnF0+xtgTazirSTGu68RchPyh1OBng1bBUjLmX8q9NpoCw==",
797
+ "dev": true,
798
+ "requires": {
799
+ "colors": "~1.1.2",
800
+ "grunt-legacy-log-utils": "~2.0.0",
801
+ "hooker": "~0.2.3",
802
+ "lodash": "~4.17.5"
803
+ }
804
+ },
805
+ "grunt-legacy-log-utils": {
806
+ "version": "2.0.1",
807
+ "resolved": "https://registry.npmjs.org/grunt-legacy-log-utils/-/grunt-legacy-log-utils-2.0.1.tgz",
808
+ "integrity": "sha512-o7uHyO/J+i2tXG8r2bZNlVk20vlIFJ9IEYyHMCQGfWYru8Jv3wTqKZzvV30YW9rWEjq0eP3cflQ1qWojIe9VFA==",
809
+ "dev": true,
810
+ "requires": {
811
+ "chalk": "~2.4.1",
812
+ "lodash": "~4.17.10"
813
+ }
814
+ },
815
+ "grunt-legacy-util": {
816
+ "version": "1.1.1",
817
+ "resolved": "https://registry.npmjs.org/grunt-legacy-util/-/grunt-legacy-util-1.1.1.tgz",
818
+ "integrity": "sha512-9zyA29w/fBe6BIfjGENndwoe1Uy31BIXxTH3s8mga0Z5Bz2Sp4UCjkeyv2tI449ymkx3x26B+46FV4fXEddl5A==",
819
+ "dev": true,
820
+ "requires": {
821
+ "async": "~1.5.2",
822
+ "exit": "~0.1.1",
823
+ "getobject": "~0.1.0",
824
+ "hooker": "~0.2.3",
825
+ "lodash": "~4.17.10",
826
+ "underscore.string": "~3.3.4",
827
+ "which": "~1.3.0"
828
+ }
829
+ },
830
+ "grunt-phpcs": {
831
+ "version": "0.4.0",
832
+ "resolved": "https://registry.npmjs.org/grunt-phpcs/-/grunt-phpcs-0.4.0.tgz",
833
+ "integrity": "sha1-oI1iX8ZEZeRTsr2T+BCyqB6Uvao=",
834
+ "dev": true
835
+ },
836
+ "has-ansi": {
837
+ "version": "2.0.0",
838
+ "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz",
839
+ "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=",
840
+ "dev": true,
841
+ "requires": {
842
+ "ansi-regex": "^2.0.0"
843
+ }
844
+ },
845
+ "has-color": {
846
+ "version": "0.1.7",
847
+ "resolved": "https://registry.npmjs.org/has-color/-/has-color-0.1.7.tgz",
848
+ "integrity": "sha1-ZxRKUmDDT8PMpnfQQdr1L+e3iy8=",
849
+ "dev": true
850
+ },
851
+ "has-flag": {
852
+ "version": "3.0.0",
853
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
854
+ "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
855
+ "dev": true
856
+ },
857
+ "hooker": {
858
+ "version": "0.2.3",
859
+ "resolved": "https://registry.npmjs.org/hooker/-/hooker-0.2.3.tgz",
860
+ "integrity": "sha1-uDT3I8xKJCqmWWNFnfbZhMXT2Vk=",
861
+ "dev": true
862
+ },
863
+ "hosted-git-info": {
864
+ "version": "2.8.5",
865
+ "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.5.tgz",
866
+ "integrity": "sha512-kssjab8CvdXfcXMXVcvsXum4Hwdq9XGtRD3TteMEvEbq0LXyiNQr6AprqKqfeaDXze7SxWvRxdpwE6ku7ikLkg==",
867
+ "dev": true
868
+ },
869
+ "husky": {
870
+ "version": "3.0.9",
871
+ "resolved": "https://registry.npmjs.org/husky/-/husky-3.0.9.tgz",
872
+ "integrity": "sha512-Yolhupm7le2/MqC1VYLk/cNmYxsSsqKkTyBhzQHhPK1jFnC89mmmNVuGtLNabjDI6Aj8UNIr0KpRNuBkiC4+sg==",
873
+ "dev": true,
874
+ "requires": {
875
+ "chalk": "^2.4.2",
876
+ "ci-info": "^2.0.0",
877
+ "cosmiconfig": "^5.2.1",
878
+ "execa": "^1.0.0",
879
+ "get-stdin": "^7.0.0",
880
+ "opencollective-postinstall": "^2.0.2",
881
+ "pkg-dir": "^4.2.0",
882
+ "please-upgrade-node": "^3.2.0",
883
+ "read-pkg": "^5.2.0",
884
+ "run-node": "^1.0.0",
885
+ "slash": "^3.0.0"
886
+ },
887
+ "dependencies": {
888
+ "get-stdin": {
889
+ "version": "7.0.0",
890
+ "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-7.0.0.tgz",
891
+ "integrity": "sha512-zRKcywvrXlXsA0v0i9Io4KDRaAw7+a1ZpjRwl9Wox8PFlVCCHra7E9c4kqXCoCM9nR5tBkaTTZRBoCm60bFqTQ==",
892
+ "dev": true
893
+ },
894
+ "parse-json": {
895
+ "version": "5.0.0",
896
+ "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.0.0.tgz",
897
+ "integrity": "sha512-OOY5b7PAEFV0E2Fir1KOkxchnZNCdowAJgQ5NuxjpBKTRP3pQhwkrkxqQjeoKJ+fO7bCpmIZaogI4eZGDMEGOw==",
898
+ "dev": true,
899
+ "requires": {
900
+ "@babel/code-frame": "^7.0.0",
901
+ "error-ex": "^1.3.1",
902
+ "json-parse-better-errors": "^1.0.1",
903
+ "lines-and-columns": "^1.1.6"
904
+ }
905
+ },
906
+ "read-pkg": {
907
+ "version": "5.2.0",
908
+ "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz",
909
+ "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==",
910
+ "dev": true,
911
+ "requires": {
912
+ "@types/normalize-package-data": "^2.4.0",
913
+ "normalize-package-data": "^2.5.0",
914
+ "parse-json": "^5.0.0",
915
+ "type-fest": "^0.6.0"
916
+ }
917
+ }
918
+ }
919
+ },
920
+ "iconv-lite": {
921
+ "version": "0.4.24",
922
+ "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
923
+ "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
924
+ "dev": true,
925
+ "requires": {
926
+ "safer-buffer": ">= 2.1.2 < 3"
927
+ }
928
+ },
929
+ "ignore": {
930
+ "version": "5.1.4",
931
+ "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.4.tgz",
932
+ "integrity": "sha512-MzbUSahkTW1u7JpKKjY7LCARd1fU5W2rLdxlM4kdkayuCwZImjkpluF9CM1aLewYJguPDqewLam18Y6AU69A8A==",
933
+ "dev": true
934
+ },
935
+ "import-fresh": {
936
+ "version": "2.0.0",
937
+ "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-2.0.0.tgz",
938
+ "integrity": "sha1-2BNVwVYS04bGH53dOSLUMEgipUY=",
939
+ "dev": true,
940
+ "requires": {
941
+ "caller-path": "^2.0.0",
942
+ "resolve-from": "^3.0.0"
943
+ }
944
+ },
945
+ "indent-string": {
946
+ "version": "2.1.0",
947
+ "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-2.1.0.tgz",
948
+ "integrity": "sha1-ji1INIdCEhtKghi3oTfppSBJ3IA=",
949
+ "dev": true,
950
+ "requires": {
951
+ "repeating": "^2.0.0"
952
+ }
953
+ },
954
+ "inflight": {
955
+ "version": "1.0.6",
956
+ "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
957
+ "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
958
+ "dev": true,
959
+ "requires": {
960
+ "once": "^1.3.0",
961
+ "wrappy": "1"
962
+ }
963
+ },
964
+ "inherits": {
965
+ "version": "2.0.4",
966
+ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
967
+ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
968
+ "dev": true
969
+ },
970
+ "is-arrayish": {
971
+ "version": "0.2.1",
972
+ "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz",
973
+ "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=",
974
+ "dev": true
975
+ },
976
+ "is-directory": {
977
+ "version": "0.3.1",
978
+ "resolved": "https://registry.npmjs.org/is-directory/-/is-directory-0.3.1.tgz",
979
+ "integrity": "sha1-YTObbyR1/Hcv2cnYP1yFddwVSuE=",
980
+ "dev": true
981
+ },
982
+ "is-extglob": {
983
+ "version": "2.1.1",
984
+ "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
985
+ "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=",
986
+ "dev": true
987
+ },
988
+ "is-finite": {
989
+ "version": "1.0.2",
990
+ "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.0.2.tgz",
991
+ "integrity": "sha1-zGZ3aVYCvlUO8R6LSqYwU0K20Ko=",
992
+ "dev": true,
993
+ "requires": {
994
+ "number-is-nan": "^1.0.0"
995
+ }
996
+ },
997
+ "is-fullwidth-code-point": {
998
+ "version": "1.0.0",
999
+ "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz",
1000
+ "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=",
1001
+ "dev": true,
1002
+ "requires": {
1003
+ "number-is-nan": "^1.0.0"
1004
+ }
1005
+ },
1006
+ "is-glob": {
1007
+ "version": "4.0.1",
1008
+ "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz",
1009
+ "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==",
1010
+ "dev": true,
1011
+ "requires": {
1012
+ "is-extglob": "^2.1.1"
1013
+ }
1014
+ },
1015
+ "is-number": {
1016
+ "version": "7.0.0",
1017
+ "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
1018
+ "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
1019
+ "dev": true
1020
+ },
1021
+ "is-obj": {
1022
+ "version": "1.0.1",
1023
+ "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz",
1024
+ "integrity": "sha1-PkcprB9f3gJc19g6iW2rn09n2w8=",
1025
+ "dev": true
1026
+ },
1027
+ "is-observable": {
1028
+ "version": "1.1.0",
1029
+ "resolved": "https://registry.npmjs.org/is-observable/-/is-observable-1.1.0.tgz",
1030
+ "integrity": "sha512-NqCa4Sa2d+u7BWc6CukaObG3Fh+CU9bvixbpcXYhy2VvYS7vVGIdAgnIS5Ks3A/cqk4rebLJ9s8zBstT2aKnIA==",
1031
+ "dev": true,
1032
+ "requires": {
1033
+ "symbol-observable": "^1.1.0"
1034
+ }
1035
+ },
1036
+ "is-path-cwd": {
1037
+ "version": "2.2.0",
1038
+ "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-2.2.0.tgz",
1039
+ "integrity": "sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ==",
1040
+ "dev": true
1041
+ },
1042
+ "is-path-inside": {
1043
+ "version": "3.0.2",
1044
+ "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.2.tgz",
1045
+ "integrity": "sha512-/2UGPSgmtqwo1ktx8NDHjuPwZWmHhO+gj0f93EkhLB5RgW9RZevWYYlIkS6zePc6U2WpOdQYIwHe9YC4DWEBVg==",
1046
+ "dev": true
1047
+ },
1048
+ "is-promise": {
1049
+ "version": "2.1.0",
1050
+ "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz",
1051
+ "integrity": "sha1-eaKp7OfwlugPNtKy87wWwf9L8/o=",
1052
+ "dev": true
1053
+ },
1054
+ "is-regexp": {
1055
+ "version": "1.0.0",
1056
+ "resolved": "https://registry.npmjs.org/is-regexp/-/is-regexp-1.0.0.tgz",
1057
+ "integrity": "sha1-/S2INUXEa6xaYz57mgnof6LLUGk=",
1058
+ "dev": true
1059
+ },
1060
+ "is-stream": {
1061
+ "version": "1.1.0",
1062
+ "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz",
1063
+ "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=",
1064
+ "dev": true
1065
+ },
1066
+ "is-utf8": {
1067
+ "version": "0.2.1",
1068
+ "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz",
1069
+ "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=",
1070
+ "dev": true
1071
+ },
1072
+ "isexe": {
1073
+ "version": "2.0.0",
1074
+ "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
1075
+ "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=",
1076
+ "dev": true
1077
+ },
1078
+ "js-tokens": {
1079
+ "version": "4.0.0",
1080
+ "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
1081
+ "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
1082
+ "dev": true
1083
+ },
1084
+ "js-yaml": {
1085
+ "version": "3.13.1",
1086
+ "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz",
1087
+ "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==",
1088
+ "dev": true,
1089
+ "requires": {
1090
+ "argparse": "^1.0.7",
1091
+ "esprima": "^4.0.0"
1092
+ }
1093
+ },
1094
+ "json-parse-better-errors": {
1095
+ "version": "1.0.2",
1096
+ "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz",
1097
+ "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==",
1098
+ "dev": true
1099
+ },
1100
+ "lines-and-columns": {
1101
+ "version": "1.1.6",
1102
+ "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.1.6.tgz",
1103
+ "integrity": "sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA=",
1104
+ "dev": true
1105
+ },
1106
+ "lint-staged": {
1107
+ "version": "9.4.2",
1108
+ "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-9.4.2.tgz",
1109
+ "integrity": "sha512-OFyGokJSWTn2M6vngnlLXjaHhi8n83VIZZ5/1Z26SULRUWgR3ITWpAEQC9Pnm3MC/EpCxlwts/mQWDHNji2+zA==",
1110
+ "dev": true,
1111
+ "requires": {
1112
+ "chalk": "^2.4.2",
1113
+ "commander": "^2.20.0",
1114
+ "cosmiconfig": "^5.2.1",
1115
+ "debug": "^4.1.1",
1116
+ "dedent": "^0.7.0",
1117
+ "del": "^5.0.0",
1118
+ "execa": "^2.0.3",
1119
+ "listr": "^0.14.3",
1120
+ "log-symbols": "^3.0.0",
1121
+ "micromatch": "^4.0.2",
1122
+ "normalize-path": "^3.0.0",
1123
+ "please-upgrade-node": "^3.1.1",
1124
+ "string-argv": "^0.3.0",
1125
+ "stringify-object": "^3.3.0"
1126
+ },
1127
+ "dependencies": {
1128
+ "cross-spawn": {
1129
+ "version": "7.0.1",
1130
+ "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.1.tgz",
1131
+ "integrity": "sha512-u7v4o84SwFpD32Z8IIcPZ6z1/ie24O6RU3RbtL5Y316l3KuHVPx9ItBgWQ6VlfAFnRnTtMUrsQ9MUUTuEZjogg==",
1132
+ "dev": true,
1133
+ "requires": {
1134
+ "path-key": "^3.1.0",
1135
+ "shebang-command": "^2.0.0",
1136
+ "which": "^2.0.1"
1137
+ }
1138
+ },
1139
+ "execa": {
1140
+ "version": "2.1.0",
1141
+ "resolved": "https://registry.npmjs.org/execa/-/execa-2.1.0.tgz",
1142
+ "integrity": "sha512-Y/URAVapfbYy2Xp/gb6A0E7iR8xeqOCXsuuaoMn7A5PzrXUK84E1gyiEfq0wQd/GHA6GsoHWwhNq8anb0mleIw==",
1143
+ "dev": true,
1144
+ "requires": {
1145
+ "cross-spawn": "^7.0.0",
1146
+ "get-stream": "^5.0.0",
1147
+ "is-stream": "^2.0.0",
1148
+ "merge-stream": "^2.0.0",
1149
+ "npm-run-path": "^3.0.0",
1150
+ "onetime": "^5.1.0",
1151
+ "p-finally": "^2.0.0",
1152
+ "signal-exit": "^3.0.2",
1153
+ "strip-final-newline": "^2.0.0"
1154
+ }
1155
+ },
1156
+ "get-stream": {
1157
+ "version": "5.1.0",
1158
+ "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.1.0.tgz",
1159
+ "integrity": "sha512-EXr1FOzrzTfGeL0gQdeFEvOMm2mzMOglyiOXSTpPC+iAjAKftbr3jpCMWynogwYnM+eSj9sHGc6wjIcDvYiygw==",
1160
+ "dev": true,
1161
+ "requires": {
1162
+ "pump": "^3.0.0"
1163
+ }
1164
+ },
1165
+ "is-stream": {
1166
+ "version": "2.0.0",
1167
+ "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.0.tgz",
1168
+ "integrity": "sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw==",
1169
+ "dev": true
1170
+ },
1171
+ "npm-run-path": {
1172
+ "version": "3.1.0",
1173
+ "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-3.1.0.tgz",
1174
+ "integrity": "sha512-Dbl4A/VfiVGLgQv29URL9xshU8XDY1GeLy+fsaZ1AA8JDSfjvr5P5+pzRbWqRSBxk6/DW7MIh8lTM/PaGnP2kg==",
1175
+ "dev": true,
1176
+ "requires": {
1177
+ "path-key": "^3.0.0"
1178
+ }
1179
+ },
1180
+ "p-finally": {
1181
+ "version": "2.0.1",
1182
+ "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-2.0.1.tgz",
1183
+ "integrity": "sha512-vpm09aKwq6H9phqRQzecoDpD8TmVyGw70qmWlyq5onxY7tqyTTFVvxMykxQSQKILBSFlbXpypIw2T1Ml7+DDtw==",
1184
+ "dev": true
1185
+ },
1186
+ "path-key": {
1187
+ "version": "3.1.0",
1188
+ "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.0.tgz",
1189
+ "integrity": "sha512-8cChqz0RP6SHJkMt48FW0A7+qUOn+OsnOsVtzI59tZ8m+5bCSk7hzwET0pulwOM2YMn9J1efb07KB9l9f30SGg==",
1190
+ "dev": true
1191
+ },
1192
+ "shebang-command": {
1193
+ "version": "2.0.0",
1194
+ "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
1195
+ "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
1196
+ "dev": true,
1197
+ "requires": {
1198
+ "shebang-regex": "^3.0.0"
1199
+ }
1200
+ },
1201
+ "shebang-regex": {
1202
+ "version": "3.0.0",
1203
+ "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
1204
+ "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
1205
+ "dev": true
1206
+ },
1207
+ "which": {
1208
+ "version": "2.0.1",
1209
+ "resolved": "https://registry.npmjs.org/which/-/which-2.0.1.tgz",
1210
+ "integrity": "sha512-N7GBZOTswtB9lkQBZA4+zAXrjEIWAUOB93AvzUiudRzRxhUdLURQ7D/gAIMY1gatT/LTbmbcv8SiYazy3eYB7w==",
1211
+ "dev": true,
1212
+ "requires": {
1213
+ "isexe": "^2.0.0"
1214
+ }
1215
+ }
1216
+ }
1217
+ },
1218
+ "listr": {
1219
+ "version": "0.14.3",
1220
+ "resolved": "https://registry.npmjs.org/listr/-/listr-0.14.3.tgz",
1221
+ "integrity": "sha512-RmAl7su35BFd/xoMamRjpIE4j3v+L28o8CT5YhAXQJm1fD+1l9ngXY8JAQRJ+tFK2i5njvi0iRUKV09vPwA0iA==",
1222
+ "dev": true,
1223
+ "requires": {
1224
+ "@samverschueren/stream-to-observable": "^0.3.0",
1225
+ "is-observable": "^1.1.0",
1226
+ "is-promise": "^2.1.0",
1227
+ "is-stream": "^1.1.0",
1228
+ "listr-silent-renderer": "^1.1.1",
1229
+ "listr-update-renderer": "^0.5.0",
1230
+ "listr-verbose-renderer": "^0.5.0",
1231
+ "p-map": "^2.0.0",
1232
+ "rxjs": "^6.3.3"
1233
+ },
1234
+ "dependencies": {
1235
+ "p-map": {
1236
+ "version": "2.1.0",
1237
+ "resolved": "https://registry.npmjs.org/p-map/-/p-map-2.1.0.tgz",
1238
+ "integrity": "sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw==",
1239
+ "dev": true
1240
+ }
1241
+ }
1242
+ },
1243
+ "listr-silent-renderer": {
1244
+ "version": "1.1.1",
1245
+ "resolved": "https://registry.npmjs.org/listr-silent-renderer/-/listr-silent-renderer-1.1.1.tgz",
1246
+ "integrity": "sha1-kktaN1cVN3C/Go4/v3S4u/P5JC4=",
1247
+ "dev": true
1248
+ },
1249
+ "listr-update-renderer": {
1250
+ "version": "0.5.0",
1251
+ "resolved": "https://registry.npmjs.org/listr-update-renderer/-/listr-update-renderer-0.5.0.tgz",
1252
+ "integrity": "sha512-tKRsZpKz8GSGqoI/+caPmfrypiaq+OQCbd+CovEC24uk1h952lVj5sC7SqyFUm+OaJ5HN/a1YLt5cit2FMNsFA==",
1253
+ "dev": true,
1254
+ "requires": {
1255
+ "chalk": "^1.1.3",
1256
+ "cli-truncate": "^0.2.1",
1257
+ "elegant-spinner": "^1.0.1",
1258
+ "figures": "^1.7.0",
1259
+ "indent-string": "^3.0.0",
1260
+ "log-symbols": "^1.0.2",
1261
+ "log-update": "^2.3.0",
1262
+ "strip-ansi": "^3.0.1"
1263
+ },
1264
+ "dependencies": {
1265
+ "ansi-styles": {
1266
+ "version": "2.2.1",
1267
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
1268
+ "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=",
1269
+ "dev": true
1270
+ },
1271
+ "chalk": {
1272
+ "version": "1.1.3",
1273
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
1274
+ "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
1275
+ "dev": true,
1276
+ "requires": {
1277
+ "ansi-styles": "^2.2.1",
1278
+ "escape-string-regexp": "^1.0.2",
1279
+ "has-ansi": "^2.0.0",
1280
+ "strip-ansi": "^3.0.0",
1281
+ "supports-color": "^2.0.0"
1282
+ }
1283
+ },
1284
+ "indent-string": {
1285
+ "version": "3.2.0",
1286
+ "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-3.2.0.tgz",
1287
+ "integrity": "sha1-Sl/W0nzDMvN+VBmlBNu4NxBckok=",
1288
+ "dev": true
1289
+ },
1290
+ "log-symbols": {
1291
+ "version": "1.0.2",
1292
+ "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-1.0.2.tgz",
1293
+ "integrity": "sha1-N2/3tY6jCGoPCfrMdGF+ylAeGhg=",
1294
+ "dev": true,
1295
+ "requires": {
1296
+ "chalk": "^1.0.0"
1297
+ }
1298
+ },
1299
+ "supports-color": {
1300
+ "version": "2.0.0",
1301
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
1302
+ "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
1303
+ "dev": true
1304
+ }
1305
+ }
1306
+ },
1307
+ "listr-verbose-renderer": {
1308
+ "version": "0.5.0",
1309
+ "resolved": "https://registry.npmjs.org/listr-verbose-renderer/-/listr-verbose-renderer-0.5.0.tgz",
1310
+ "integrity": "sha512-04PDPqSlsqIOaaaGZ+41vq5FejI9auqTInicFRndCBgE3bXG8D6W1I+mWhk+1nqbHmyhla/6BUrd5OSiHwKRXw==",
1311
+ "dev": true,
1312
+ "requires": {
1313
+ "chalk": "^2.4.1",
1314
+ "cli-cursor": "^2.1.0",
1315
+ "date-fns": "^1.27.2",
1316
+ "figures": "^2.0.0"
1317
+ },
1318
+ "dependencies": {
1319
+ "figures": {
1320
+ "version": "2.0.0",
1321
+ "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz",
1322
+ "integrity": "sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=",
1323
+ "dev": true,
1324
+ "requires": {
1325
+ "escape-string-regexp": "^1.0.5"
1326
+ }
1327
+ }
1328
+ }
1329
+ },
1330
+ "load-json-file": {
1331
+ "version": "1.1.0",
1332
+ "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz",
1333
+ "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=",
1334
+ "dev": true,
1335
+ "requires": {
1336
+ "graceful-fs": "^4.1.2",
1337
+ "parse-json": "^2.2.0",
1338
+ "pify": "^2.0.0",
1339
+ "pinkie-promise": "^2.0.0",
1340
+ "strip-bom": "^2.0.0"
1341
+ }
1342
+ },
1343
+ "locate-path": {
1344
+ "version": "5.0.0",
1345
+ "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
1346
+ "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
1347
+ "dev": true,
1348
+ "requires": {
1349
+ "p-locate": "^4.1.0"
1350
+ }
1351
+ },
1352
+ "lodash": {
1353
+ "version": "4.17.15",
1354
+ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz",
1355
+ "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==",
1356
+ "dev": true
1357
+ },
1358
+ "log-symbols": {
1359
+ "version": "3.0.0",
1360
+ "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-3.0.0.tgz",
1361
+ "integrity": "sha512-dSkNGuI7iG3mfvDzUuYZyvk5dD9ocYCYzNU6CYDE6+Xqd+gwme6Z00NS3dUh8mq/73HaEtT7m6W+yUPtU6BZnQ==",
1362
+ "dev": true,
1363
+ "requires": {
1364
+ "chalk": "^2.4.2"
1365
+ }
1366
+ },
1367
+ "log-update": {
1368
+ "version": "2.3.0",
1369
+ "resolved": "https://registry.npmjs.org/log-update/-/log-update-2.3.0.tgz",
1370
+ "integrity": "sha1-iDKP19HOeTiykoN0bwsbwSayRwg=",
1371
+ "dev": true,
1372
+ "requires": {
1373
+ "ansi-escapes": "^3.0.0",
1374
+ "cli-cursor": "^2.0.0",
1375
+ "wrap-ansi": "^3.0.1"
1376
+ }
1377
+ },
1378
+ "loud-rejection": {
1379
+ "version": "1.6.0",
1380
+ "resolved": "https://registry.npmjs.org/loud-rejection/-/loud-rejection-1.6.0.tgz",
1381
+ "integrity": "sha1-W0b4AUft7leIcPCG0Eghz5mOVR8=",
1382
+ "dev": true,
1383
+ "requires": {
1384
+ "currently-unhandled": "^0.4.1",
1385
+ "signal-exit": "^3.0.0"
1386
+ }
1387
+ },
1388
+ "map-obj": {
1389
+ "version": "1.0.1",
1390
+ "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz",
1391
+ "integrity": "sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0=",
1392
+ "dev": true
1393
+ },
1394
+ "meow": {
1395
+ "version": "3.7.0",
1396
+ "resolved": "https://registry.npmjs.org/meow/-/meow-3.7.0.tgz",
1397
+ "integrity": "sha1-cstmi0JSKCkKu/qFaJJYcwioAfs=",
1398
+ "dev": true,
1399
+ "requires": {
1400
+ "camelcase-keys": "^2.0.0",
1401
+ "decamelize": "^1.1.2",
1402
+ "loud-rejection": "^1.0.0",
1403
+ "map-obj": "^1.0.1",
1404
+ "minimist": "^1.1.3",
1405
+ "normalize-package-data": "^2.3.4",
1406
+ "object-assign": "^4.0.1",
1407
+ "read-pkg-up": "^1.0.1",
1408
+ "redent": "^1.0.0",
1409
+ "trim-newlines": "^1.0.0"
1410
+ }
1411
+ },
1412
+ "merge-stream": {
1413
+ "version": "2.0.0",
1414
+ "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz",
1415
+ "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==",
1416
+ "dev": true
1417
+ },
1418
+ "merge2": {
1419
+ "version": "1.3.0",
1420
+ "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.3.0.tgz",
1421
+ "integrity": "sha512-2j4DAdlBOkiSZIsaXk4mTE3sRS02yBHAtfy127xRV3bQUFqXkjHCHLW6Scv7DwNRbIWNHH8zpnz9zMaKXIdvYw==",
1422
+ "dev": true
1423
+ },
1424
+ "micromatch": {
1425
+ "version": "4.0.2",
1426
+ "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.2.tgz",
1427
+ "integrity": "sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==",
1428
+ "dev": true,
1429
+ "requires": {
1430
+ "braces": "^3.0.1",
1431
+ "picomatch": "^2.0.5"
1432
+ }
1433
+ },
1434
+ "mimic-fn": {
1435
+ "version": "2.1.0",
1436
+ "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz",
1437
+ "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==",
1438
+ "dev": true
1439
+ },
1440
+ "minimatch": {
1441
+ "version": "3.0.4",
1442
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
1443
+ "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
1444
+ "dev": true,
1445
+ "requires": {
1446
+ "brace-expansion": "^1.1.7"
1447
+ }
1448
+ },
1449
+ "minimist": {
1450
+ "version": "1.2.0",
1451
+ "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
1452
+ "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=",
1453
+ "dev": true
1454
+ },
1455
+ "mkdirp": {
1456
+ "version": "0.5.1",
1457
+ "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
1458
+ "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=",
1459
+ "dev": true,
1460
+ "requires": {
1461
+ "minimist": "0.0.8"
1462
+ },
1463
+ "dependencies": {
1464
+ "minimist": {
1465
+ "version": "0.0.8",
1466
+ "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz",
1467
+ "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=",
1468
+ "dev": true
1469
+ }
1470
+ }
1471
+ },
1472
+ "ms": {
1473
+ "version": "2.1.2",
1474
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
1475
+ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
1476
+ "dev": true
1477
+ },
1478
+ "nice-try": {
1479
+ "version": "1.0.5",
1480
+ "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz",
1481
+ "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==",
1482
+ "dev": true
1483
+ },
1484
+ "nopt": {
1485
+ "version": "3.0.6",
1486
+ "resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz",
1487
+ "integrity": "sha1-xkZdvwirzU2zWTF/eaxopkayj/k=",
1488
+ "dev": true,
1489
+ "requires": {
1490
+ "abbrev": "1"
1491
+ }
1492
+ },
1493
+ "normalize-package-data": {
1494
+ "version": "2.5.0",
1495
+ "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz",
1496
+ "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==",
1497
+ "dev": true,
1498
+ "requires": {
1499
+ "hosted-git-info": "^2.1.4",
1500
+ "resolve": "^1.10.0",
1501
+ "semver": "2 || 3 || 4 || 5",
1502
+ "validate-npm-package-license": "^3.0.1"
1503
+ }
1504
+ },
1505
+ "normalize-path": {
1506
+ "version": "3.0.0",
1507
+ "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
1508
+ "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
1509
+ "dev": true
1510
+ },
1511
+ "npm-run-path": {
1512
+ "version": "2.0.2",
1513
+ "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz",
1514
+ "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=",
1515
+ "dev": true,
1516
+ "requires": {
1517
+ "path-key": "^2.0.0"
1518
+ }
1519
+ },
1520
+ "number-is-nan": {
1521
+ "version": "1.0.1",
1522
+ "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz",
1523
+ "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=",
1524
+ "dev": true
1525
+ },
1526
+ "object-assign": {
1527
+ "version": "4.1.1",
1528
+ "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
1529
+ "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=",
1530
+ "dev": true
1531
+ },
1532
+ "once": {
1533
+ "version": "1.4.0",
1534
+ "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
1535
+ "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
1536
+ "dev": true,
1537
+ "requires": {
1538
+ "wrappy": "1"
1539
+ }
1540
+ },
1541
+ "onetime": {
1542
+ "version": "5.1.0",
1543
+ "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.0.tgz",
1544
+ "integrity": "sha512-5NcSkPHhwTVFIQN+TUqXoS5+dlElHXdpAWu9I0HP20YOtIi+aZ0Ct82jdlILDxjLEAWwvm+qj1m6aEtsDVmm6Q==",
1545
+ "dev": true,
1546
+ "requires": {
1547
+ "mimic-fn": "^2.1.0"
1548
+ }
1549
+ },
1550
+ "opencollective-postinstall": {
1551
+ "version": "2.0.2",
1552
+ "resolved": "https://registry.npmjs.org/opencollective-postinstall/-/opencollective-postinstall-2.0.2.tgz",
1553
+ "integrity": "sha512-pVOEP16TrAO2/fjej1IdOyupJY8KDUM1CvsaScRbw6oddvpQoOfGk4ywha0HKKVAD6RkW4x6Q+tNBwhf3Bgpuw==",
1554
+ "dev": true
1555
+ },
1556
+ "p-finally": {
1557
+ "version": "1.0.0",
1558
+ "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz",
1559
+ "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=",
1560
+ "dev": true
1561
+ },
1562
+ "p-limit": {
1563
+ "version": "2.2.1",
1564
+ "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.1.tgz",
1565
+ "integrity": "sha512-85Tk+90UCVWvbDavCLKPOLC9vvY8OwEX/RtKF+/1OADJMVlFfEHOiMTPVyxg7mk/dKa+ipdHm0OUkTvCpMTuwg==",
1566
+ "dev": true,
1567
+ "requires": {
1568
+ "p-try": "^2.0.0"
1569
+ }
1570
+ },
1571
+ "p-locate": {
1572
+ "version": "4.1.0",
1573
+ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
1574
+ "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
1575
+ "dev": true,
1576
+ "requires": {
1577
+ "p-limit": "^2.2.0"
1578
+ }
1579
+ },
1580
+ "p-map": {
1581
+ "version": "3.0.0",
1582
+ "resolved": "https://registry.npmjs.org/p-map/-/p-map-3.0.0.tgz",
1583
+ "integrity": "sha512-d3qXVTF/s+W+CdJ5A29wywV2n8CQQYahlgz2bFiA+4eVNJbHJodPZ+/gXwPGh0bOqA+j8S+6+ckmvLGPk1QpxQ==",
1584
+ "dev": true,
1585
+ "requires": {
1586
+ "aggregate-error": "^3.0.0"
1587
+ }
1588
+ },
1589
+ "p-try": {
1590
+ "version": "2.2.0",
1591
+ "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz",
1592
+ "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==",
1593
+ "dev": true
1594
+ },
1595
+ "parse-json": {
1596
+ "version": "2.2.0",
1597
+ "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz",
1598
+ "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=",
1599
+ "dev": true,
1600
+ "requires": {
1601
+ "error-ex": "^1.2.0"
1602
+ }
1603
+ },
1604
+ "path-exists": {
1605
+ "version": "2.1.0",
1606
+ "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz",
1607
+ "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=",
1608
+ "dev": true,
1609
+ "requires": {
1610
+ "pinkie-promise": "^2.0.0"
1611
+ }
1612
+ },
1613
+ "path-is-absolute": {
1614
+ "version": "1.0.1",
1615
+ "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
1616
+ "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=",
1617
+ "dev": true
1618
+ },
1619
+ "path-key": {
1620
+ "version": "2.0.1",
1621
+ "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz",
1622
+ "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=",
1623
+ "dev": true
1624
+ },
1625
+ "path-parse": {
1626
+ "version": "1.0.6",
1627
+ "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz",
1628
+ "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==",
1629
+ "dev": true
1630
+ },
1631
+ "path-type": {
1632
+ "version": "1.1.0",
1633
+ "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz",
1634
+ "integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=",
1635
+ "dev": true,
1636
+ "requires": {
1637
+ "graceful-fs": "^4.1.2",
1638
+ "pify": "^2.0.0",
1639
+ "pinkie-promise": "^2.0.0"
1640
+ }
1641
+ },
1642
+ "picomatch": {
1643
+ "version": "2.0.7",
1644
+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.0.7.tgz",
1645
+ "integrity": "sha512-oLHIdio3tZ0qH76NybpeneBhYVj0QFTfXEFTc/B3zKQspYfYYkWYgFsmzo+4kvId/bQRcNkVeguI3y+CD22BtA==",
1646
+ "dev": true
1647
+ },
1648
+ "pify": {
1649
+ "version": "2.3.0",
1650
+ "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
1651
+ "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=",
1652
+ "dev": true
1653
+ },
1654
+ "pinkie": {
1655
+ "version": "2.0.4",
1656
+ "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz",
1657
+ "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=",
1658
+ "dev": true
1659
+ },
1660
+ "pinkie-promise": {
1661
+ "version": "2.0.1",
1662
+ "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz",
1663
+ "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=",
1664
+ "dev": true,
1665
+ "requires": {
1666
+ "pinkie": "^2.0.0"
1667
+ }
1668
+ },
1669
+ "pkg-dir": {
1670
+ "version": "4.2.0",
1671
+ "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz",
1672
+ "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==",
1673
+ "dev": true,
1674
+ "requires": {
1675
+ "find-up": "^4.0.0"
1676
+ },
1677
+ "dependencies": {
1678
+ "find-up": {
1679
+ "version": "4.1.0",
1680
+ "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
1681
+ "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
1682
+ "dev": true,
1683
+ "requires": {
1684
+ "locate-path": "^5.0.0",
1685
+ "path-exists": "^4.0.0"
1686
+ }
1687
+ },
1688
+ "path-exists": {
1689
+ "version": "4.0.0",
1690
+ "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
1691
+ "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
1692
+ "dev": true
1693
+ }
1694
+ }
1695
+ },
1696
+ "please-upgrade-node": {
1697
+ "version": "3.2.0",
1698
+ "resolved": "https://registry.npmjs.org/please-upgrade-node/-/please-upgrade-node-3.2.0.tgz",
1699
+ "integrity": "sha512-gQR3WpIgNIKwBMVLkpMUeR3e1/E1y42bqDQZfql+kDeXd8COYfM8PQA4X6y7a8u9Ua9FHmsrrmirW2vHs45hWg==",
1700
+ "dev": true,
1701
+ "requires": {
1702
+ "semver-compare": "^1.0.0"
1703
+ }
1704
+ },
1705
+ "pump": {
1706
+ "version": "3.0.0",
1707
+ "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz",
1708
+ "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==",
1709
+ "dev": true,
1710
+ "requires": {
1711
+ "end-of-stream": "^1.1.0",
1712
+ "once": "^1.3.1"
1713
+ }
1714
+ },
1715
+ "read-pkg": {
1716
+ "version": "1.1.0",
1717
+ "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz",
1718
+ "integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=",
1719
+ "dev": true,
1720
+ "requires": {
1721
+ "load-json-file": "^1.0.0",
1722
+ "normalize-package-data": "^2.3.2",
1723
+ "path-type": "^1.0.0"
1724
+ }
1725
+ },
1726
+ "read-pkg-up": {
1727
+ "version": "1.0.1",
1728
+ "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz",
1729
+ "integrity": "sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=",
1730
+ "dev": true,
1731
+ "requires": {
1732
+ "find-up": "^1.0.0",
1733
+ "read-pkg": "^1.0.0"
1734
+ }
1735
+ },
1736
+ "redent": {
1737
+ "version": "1.0.0",
1738
+ "resolved": "https://registry.npmjs.org/redent/-/redent-1.0.0.tgz",
1739
+ "integrity": "sha1-z5Fqsf1fHxbfsggi3W7H9zDCr94=",
1740
+ "dev": true,
1741
+ "requires": {
1742
+ "indent-string": "^2.1.0",
1743
+ "strip-indent": "^1.0.1"
1744
+ }
1745
+ },
1746
+ "repeating": {
1747
+ "version": "2.0.1",
1748
+ "resolved": "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz",
1749
+ "integrity": "sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo=",
1750
+ "dev": true,
1751
+ "requires": {
1752
+ "is-finite": "^1.0.0"
1753
+ }
1754
+ },
1755
+ "resolve": {
1756
+ "version": "1.12.0",
1757
+ "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.12.0.tgz",
1758
+ "integrity": "sha512-B/dOmuoAik5bKcD6s6nXDCjzUKnaDvdkRyAk6rsmsKLipWj4797iothd7jmmUhWTfinVMU+wc56rYKsit2Qy4w==",
1759
+ "dev": true,
1760
+ "requires": {
1761
+ "path-parse": "^1.0.6"
1762
+ }
1763
+ },
1764
+ "resolve-from": {
1765
+ "version": "3.0.0",
1766
+ "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz",
1767
+ "integrity": "sha1-six699nWiBvItuZTM17rywoYh0g=",
1768
+ "dev": true
1769
+ },
1770
+ "restore-cursor": {
1771
+ "version": "2.0.0",
1772
+ "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz",
1773
+ "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=",
1774
+ "dev": true,
1775
+ "requires": {
1776
+ "onetime": "^2.0.0",
1777
+ "signal-exit": "^3.0.2"
1778
+ },
1779
+ "dependencies": {
1780
+ "mimic-fn": {
1781
+ "version": "1.2.0",
1782
+ "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz",
1783
+ "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==",
1784
+ "dev": true
1785
+ },
1786
+ "onetime": {
1787
+ "version": "2.0.1",
1788
+ "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz",
1789
+ "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=",
1790
+ "dev": true,
1791
+ "requires": {
1792
+ "mimic-fn": "^1.0.0"
1793
+ }
1794
+ }
1795
+ }
1796
+ },
1797
+ "reusify": {
1798
+ "version": "1.0.4",
1799
+ "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz",
1800
+ "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==",
1801
+ "dev": true
1802
+ },
1803
+ "rimraf": {
1804
+ "version": "2.6.3",
1805
+ "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz",
1806
+ "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==",
1807
+ "dev": true,
1808
+ "requires": {
1809
+ "glob": "^7.1.3"
1810
+ },
1811
+ "dependencies": {
1812
+ "glob": {
1813
+ "version": "7.1.5",
1814
+ "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.5.tgz",
1815
+ "integrity": "sha512-J9dlskqUXK1OeTOYBEn5s8aMukWMwWfs+rPTn/jn50Ux4MNXVhubL1wu/j2t+H4NVI+cXEcCaYellqaPVGXNqQ==",
1816
+ "dev": true,
1817
+ "requires": {
1818
+ "fs.realpath": "^1.0.0",
1819
+ "inflight": "^1.0.4",
1820
+ "inherits": "2",
1821
+ "minimatch": "^3.0.4",
1822
+ "once": "^1.3.0",
1823
+ "path-is-absolute": "^1.0.0"
1824
+ }
1825
+ }
1826
+ }
1827
+ },
1828
+ "run-node": {
1829
+ "version": "1.0.0",
1830
+ "resolved": "https://registry.npmjs.org/run-node/-/run-node-1.0.0.tgz",
1831
+ "integrity": "sha512-kc120TBlQ3mih1LSzdAJXo4xn/GWS2ec0l3S+syHDXP9uRr0JAT8Qd3mdMuyjqCzeZktgP3try92cEgf9Nks8A==",
1832
+ "dev": true
1833
+ },
1834
+ "run-parallel": {
1835
+ "version": "1.1.9",
1836
+ "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.1.9.tgz",
1837
+ "integrity": "sha512-DEqnSRTDw/Tc3FXf49zedI638Z9onwUotBMiUFKmrO2sdFKIbXamXGQ3Axd4qgphxKB4kw/qP1w5kTxnfU1B9Q==",
1838
+ "dev": true
1839
+ },
1840
+ "rxjs": {
1841
+ "version": "6.5.3",
1842
+ "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.5.3.tgz",
1843
+ "integrity": "sha512-wuYsAYYFdWTAnAaPoKGNhfpWwKZbJW+HgAJ+mImp+Epl7BG8oNWBCTyRM8gba9k4lk8BgWdoYm21Mo/RYhhbgA==",
1844
+ "dev": true,
1845
+ "requires": {
1846
+ "tslib": "^1.9.0"
1847
+ }
1848
+ },
1849
+ "safer-buffer": {
1850
+ "version": "2.1.2",
1851
+ "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
1852
+ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
1853
+ "dev": true
1854
+ },
1855
+ "semver": {
1856
+ "version": "5.7.1",
1857
+ "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
1858
+ "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
1859
+ "dev": true
1860
+ },
1861
+ "semver-compare": {
1862
+ "version": "1.0.0",
1863
+ "resolved": "https://registry.npmjs.org/semver-compare/-/semver-compare-1.0.0.tgz",
1864
+ "integrity": "sha1-De4hahyUGrN+nvsXiPavxf9VN/w=",
1865
+ "dev": true
1866
+ },
1867
+ "shebang-command": {
1868
+ "version": "1.2.0",
1869
+ "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz",
1870
+ "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=",
1871
+ "dev": true,
1872
+ "requires": {
1873
+ "shebang-regex": "^1.0.0"
1874
+ }
1875
+ },
1876
+ "shebang-regex": {
1877
+ "version": "1.0.0",
1878
+ "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz",
1879
+ "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=",
1880
+ "dev": true
1881
+ },
1882
+ "signal-exit": {
1883
+ "version": "3.0.2",
1884
+ "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz",
1885
+ "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=",
1886
+ "dev": true
1887
+ },
1888
+ "slash": {
1889
+ "version": "3.0.0",
1890
+ "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
1891
+ "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==",
1892
+ "dev": true
1893
+ },
1894
+ "slice-ansi": {
1895
+ "version": "0.0.4",
1896
+ "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-0.0.4.tgz",
1897
+ "integrity": "sha1-7b+JA/ZvfOL46v1s7tZeJkyDGzU=",
1898
+ "dev": true
1899
+ },
1900
+ "spdx-correct": {
1901
+ "version": "3.1.0",
1902
+ "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.0.tgz",
1903
+ "integrity": "sha512-lr2EZCctC2BNR7j7WzJ2FpDznxky1sjfxvvYEyzxNyb6lZXHODmEoJeFu4JupYlkfha1KZpJyoqiJ7pgA1qq8Q==",
1904
+ "dev": true,
1905
+ "requires": {
1906
+ "spdx-expression-parse": "^3.0.0",
1907
+ "spdx-license-ids": "^3.0.0"
1908
+ }
1909
+ },
1910
+ "spdx-exceptions": {
1911
+ "version": "2.2.0",
1912
+ "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.2.0.tgz",
1913
+ "integrity": "sha512-2XQACfElKi9SlVb1CYadKDXvoajPgBVPn/gOQLrTvHdElaVhr7ZEbqJaRnJLVNeaI4cMEAgVCeBMKF6MWRDCRA==",
1914
+ "dev": true
1915
+ },
1916
+ "spdx-expression-parse": {
1917
+ "version": "3.0.0",
1918
+ "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz",
1919
+ "integrity": "sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg==",
1920
+ "dev": true,
1921
+ "requires": {
1922
+ "spdx-exceptions": "^2.1.0",
1923
+ "spdx-license-ids": "^3.0.0"
1924
+ }
1925
+ },
1926
+ "spdx-license-ids": {
1927
+ "version": "3.0.5",
1928
+ "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.5.tgz",
1929
+ "integrity": "sha512-J+FWzZoynJEXGphVIS+XEh3kFSjZX/1i9gFBaWQcB+/tmpe2qUsSBABpcxqxnAxFdiUFEgAX1bjYGQvIZmoz9Q==",
1930
+ "dev": true
1931
+ },
1932
+ "sprintf-js": {
1933
+ "version": "1.1.2",
1934
+ "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.2.tgz",
1935
+ "integrity": "sha512-VE0SOVEHCk7Qc8ulkWw3ntAzXuqf7S2lvwQaDLRnUeIEaKNQJzV6BwmLKhOqT61aGhfUMrXeaBk+oDGCzvhcug==",
1936
+ "dev": true
1937
+ },
1938
+ "string-argv": {
1939
+ "version": "0.3.1",
1940
+ "resolved": "https://registry.npmjs.org/string-argv/-/string-argv-0.3.1.tgz",
1941
+ "integrity": "sha512-a1uQGz7IyVy9YwhqjZIZu1c8JO8dNIe20xBmSS6qu9kv++k3JGzCVmprbNN5Kn+BgzD5E7YYwg1CcjuJMRNsvg==",
1942
+ "dev": true
1943
+ },
1944
+ "string-width": {
1945
+ "version": "1.0.2",
1946
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz",
1947
+ "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=",
1948
+ "dev": true,
1949
+ "requires": {
1950
+ "code-point-at": "^1.0.0",
1951
+ "is-fullwidth-code-point": "^1.0.0",
1952
+ "strip-ansi": "^3.0.0"
1953
+ }
1954
+ },
1955
+ "stringify-object": {
1956
+ "version": "3.3.0",
1957
+ "resolved": "https://registry.npmjs.org/stringify-object/-/stringify-object-3.3.0.tgz",
1958
+ "integrity": "sha512-rHqiFh1elqCQ9WPLIC8I0Q/g/wj5J1eMkyoiD6eoQApWHP0FtlK7rqnhmabL5VUY9JQCcqwwvlOaSuutekgyrw==",
1959
+ "dev": true,
1960
+ "requires": {
1961
+ "get-own-enumerable-property-symbols": "^3.0.0",
1962
+ "is-obj": "^1.0.1",
1963
+ "is-regexp": "^1.0.0"
1964
+ }
1965
+ },
1966
+ "strip-ansi": {
1967
+ "version": "3.0.1",
1968
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
1969
+ "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
1970
+ "dev": true,
1971
+ "requires": {
1972
+ "ansi-regex": "^2.0.0"
1973
+ }
1974
+ },
1975
+ "strip-bom": {
1976
+ "version": "2.0.0",
1977
+ "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz",
1978
+ "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=",
1979
+ "dev": true,
1980
+ "requires": {
1981
+ "is-utf8": "^0.2.0"
1982
+ }
1983
+ },
1984
+ "strip-eof": {
1985
+ "version": "1.0.0",
1986
+ "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz",
1987
+ "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=",
1988
+ "dev": true
1989
+ },
1990
+ "strip-final-newline": {
1991
+ "version": "2.0.0",
1992
+ "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz",
1993
+ "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==",
1994
+ "dev": true
1995
+ },
1996
+ "strip-indent": {
1997
+ "version": "1.0.1",
1998
+ "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-1.0.1.tgz",
1999
+ "integrity": "sha1-DHlipq3vp7vUrDZkYKY4VSrhoKI=",
2000
+ "dev": true,
2001
+ "requires": {
2002
+ "get-stdin": "^4.0.1"
2003
+ }
2004
+ },
2005
+ "supports-color": {
2006
+ "version": "5.5.0",
2007
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
2008
+ "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
2009
+ "dev": true,
2010
+ "requires": {
2011
+ "has-flag": "^3.0.0"
2012
+ }
2013
+ },
2014
+ "symbol-observable": {
2015
+ "version": "1.2.0",
2016
+ "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.2.0.tgz",
2017
+ "integrity": "sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ==",
2018
+ "dev": true
2019
+ },
2020
+ "text-table": {
2021
+ "version": "0.2.0",
2022
+ "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
2023
+ "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=",
2024
+ "dev": true
2025
+ },
2026
+ "to-regex-range": {
2027
+ "version": "5.0.1",
2028
+ "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
2029
+ "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
2030
+ "dev": true,
2031
+ "requires": {
2032
+ "is-number": "^7.0.0"
2033
+ }
2034
+ },
2035
+ "trim-newlines": {
2036
+ "version": "1.0.0",
2037
+ "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-1.0.0.tgz",
2038
+ "integrity": "sha1-WIeWa7WCpFA6QetST301ARgVphM=",
2039
+ "dev": true
2040
+ },
2041
+ "tslib": {
2042
+ "version": "1.10.0",
2043
+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.10.0.tgz",
2044
+ "integrity": "sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ==",
2045
+ "dev": true
2046
+ },
2047
+ "type-fest": {
2048
+ "version": "0.6.0",
2049
+ "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz",
2050
+ "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==",
2051
+ "dev": true
2052
+ },
2053
+ "underscore.string": {
2054
+ "version": "3.3.5",
2055
+ "resolved": "https://registry.npmjs.org/underscore.string/-/underscore.string-3.3.5.tgz",
2056
+ "integrity": "sha512-g+dpmgn+XBneLmXXo+sGlW5xQEt4ErkS3mgeN2GFbremYeMBSJKr9Wf2KJplQVaiPY/f7FN6atosWYNm9ovrYg==",
2057
+ "dev": true,
2058
+ "requires": {
2059
+ "sprintf-js": "^1.0.3",
2060
+ "util-deprecate": "^1.0.2"
2061
+ }
2062
+ },
2063
+ "util-deprecate": {
2064
+ "version": "1.0.2",
2065
+ "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
2066
+ "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=",
2067
+ "dev": true
2068
+ },
2069
+ "validate-npm-package-license": {
2070
+ "version": "3.0.4",
2071
+ "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz",
2072
+ "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==",
2073
+ "dev": true,
2074
+ "requires": {
2075
+ "spdx-correct": "^3.0.0",
2076
+ "spdx-expression-parse": "^3.0.0"
2077
+ }
2078
+ },
2079
+ "which": {
2080
+ "version": "1.3.1",
2081
+ "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz",
2082
+ "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==",
2083
+ "dev": true,
2084
+ "requires": {
2085
+ "isexe": "^2.0.0"
2086
+ }
2087
+ },
2088
+ "wrap-ansi": {
2089
+ "version": "3.0.1",
2090
+ "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-3.0.1.tgz",
2091
+ "integrity": "sha1-KIoE2H7aXChuBg3+jxNc6NAH+Lo=",
2092
+ "dev": true,
2093
+ "requires": {
2094
+ "string-width": "^2.1.1",
2095
+ "strip-ansi": "^4.0.0"
2096
+ },
2097
+ "dependencies": {
2098
+ "ansi-regex": {
2099
+ "version": "3.0.0",
2100
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz",
2101
+ "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=",
2102
+ "dev": true
2103
+ },
2104
+ "is-fullwidth-code-point": {
2105
+ "version": "2.0.0",
2106
+ "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz",
2107
+ "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=",
2108
+ "dev": true
2109
+ },
2110
+ "string-width": {
2111
+ "version": "2.1.1",
2112
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz",
2113
+ "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==",
2114
+ "dev": true,
2115
+ "requires": {
2116
+ "is-fullwidth-code-point": "^2.0.0",
2117
+ "strip-ansi": "^4.0.0"
2118
+ }
2119
+ },
2120
+ "strip-ansi": {
2121
+ "version": "4.0.0",
2122
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz",
2123
+ "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=",
2124
+ "dev": true,
2125
+ "requires": {
2126
+ "ansi-regex": "^3.0.0"
2127
+ }
2128
+ }
2129
+ }
2130
+ },
2131
+ "wrappy": {
2132
+ "version": "1.0.2",
2133
+ "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
2134
+ "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
2135
+ "dev": true
2136
+ }
2137
+ }
2138
+ }
includes/vendor/action-scheduler/package.json ADDED
@@ -0,0 +1,39 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "action-scheduler",
3
+ "title": "Action Scheduler",
4
+ "version": "3.0.0",
5
+ "homepage": "https://actionscheduler.org/",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "https://github.com/woocommerce/action-scheduler.git"
9
+ },
10
+ "license": "GPL-3.0+",
11
+ "main": "Gruntfile.js",
12
+ "scripts": {
13
+ "build": "grunt",
14
+ "check-textdomain": "grunt checktextdomain",
15
+ "phpcs": "grunt phpcs"
16
+ },
17
+ "devDependencies": {
18
+ "grunt": "1.0.4",
19
+ "grunt-checktextdomain": "1.0.1",
20
+ "grunt-phpcs": "0.4.0",
21
+ "husky": "3.0.9",
22
+ "lint-staged": "9.4.2"
23
+ },
24
+ "engines": {
25
+ "node": ">=10.15.0",
26
+ "npm": ">=6.4.1"
27
+ },
28
+ "husky": {
29
+ "hooks": {
30
+ "pre-commit": "lint-staged"
31
+ }
32
+ },
33
+ "lint-staged": {
34
+ "*.php": [
35
+ "php -d display_errors=1 -l",
36
+ "composer run-script phpcs-pre-commit"
37
+ ]
38
+ }
39
+ }
includes/vendor/action-scheduler/phpcs.xml ADDED
@@ -0,0 +1,39 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0"?>
2
+ <ruleset name="WordPress Coding Standards">
3
+ <description>WooCommerce dev PHP_CodeSniffer ruleset.</description>
4
+
5
+ <!-- Exclude paths -->
6
+ <exclude-pattern>docs/</exclude-pattern>
7
+ <exclude-pattern>*/node_modules/*</exclude-pattern>
8
+ <exclude-pattern>*/vendor/*</exclude-pattern>
9
+
10
+ <!-- Configs -->
11
+ <config name="minimum_supported_wp_version" value="4.7" />
12
+ <config name="testVersion" value="5.6-" />
13
+
14
+ <!-- Rules -->
15
+ <rule ref="WooCommerce-Core" />
16
+
17
+ <rule ref="WordPress.WP.I18n">
18
+ <properties>
19
+ <property name="text_domain" type="array" value="action-scheduler" />
20
+ </properties>
21
+ </rule>
22
+
23
+ <rule ref="WordPress.Files.FileName.InvalidClassFileName">
24
+ <exclude-pattern>classes/*</exclude-pattern>
25
+ <exclude-pattern>deprecated/*</exclude-pattern>
26
+ <exclude-pattern>lib/*</exclude-pattern>
27
+ <exclude-pattern>tests/*</exclude-pattern>
28
+ </rule>
29
+ <rule ref="WordPress.Files.FileName.NotHyphenatedLowercase">
30
+ <exclude-pattern>classes/*</exclude-pattern>
31
+ <exclude-pattern>deprecated/*</exclude-pattern>
32
+ <exclude-pattern>lib/*</exclude-pattern>
33
+ <exclude-pattern>tests/*</exclude-pattern>
34
+ </rule>
35
+
36
+ <rule ref="Generic.Commenting">
37
+ <exclude-pattern>tests/</exclude-pattern>
38
+ </rule>
39
+ </ruleset>
includes/vendor/action-scheduler/tests/bootstrap.php CHANGED
@@ -29,3 +29,6 @@ if ( class_exists( 'PHPUnit\Framework\TestResult' ) ) { // PHPUnit 6.0 or newer
29
  } else {
30
  include_once('phpunit/deprecated/ActionScheduler_UnitTestCase.php');
31
  }
 
 
 
29
  } else {
30
  include_once('phpunit/deprecated/ActionScheduler_UnitTestCase.php');
31
  }
32
+
33
+ include_once('phpunit/ActionScheduler_Mocker.php');
34
+ include_once('phpunit/ActionScheduler_Mock_Async_Request_QueueRunner.php');
includes/vendor/action-scheduler/tests/phpunit.xml.dist CHANGED
@@ -12,8 +12,24 @@
12
  bootstrap="bootstrap.php"
13
  >
14
  <testsuites>
 
 
 
 
 
 
 
 
 
15
  <testsuite name="Action Scheduler">
16
- <directory>./phpunit</directory>
 
 
 
 
 
 
 
17
  </testsuite>
18
  </testsuites>
19
  <groups>
12
  bootstrap="bootstrap.php"
13
  >
14
  <testsuites>
15
+ <testsuite name="Migration">
16
+ <directory phpVersion="5.6">./phpunit/migration</directory>
17
+ </testsuite>
18
+ <testsuite name="Tables">
19
+ <file phpVersion="5.6">./phpunit/jobstore/ActionScheduler_DBStoreMigrator_Test.php</file>
20
+ <file phpVersion="5.6">./phpunit/jobstore/ActionScheduler_DBStore_Test.php</file>
21
+ <file phpVersion="5.6">./phpunit/jobstore/ActionScheduler_HybridStore_Test.php</file>
22
+ <file phpVersion="5.6">./phpunit/logging/ActionScheduler_DBLogger_Test.php</file>
23
+ </testsuite>
24
  <testsuite name="Action Scheduler">
25
+ <directory>./phpunit/helpers</directory>
26
+ <directory>./phpunit/jobs</directory>
27
+ <directory>./phpunit/procedural_api</directory>
28
+ <directory>./phpunit/runner</directory>
29
+ <directory>./phpunit/schedules</directory>
30
+ <directory>./phpunit/versioning</directory>
31
+ <file>./phpunit/logging/ActionScheduler_wpCommentLogger_Test.php</file>
32
+ <file>./phpunit/jobstore/ActionScheduler_wpPostStore_Test.php</file>
33
  </testsuite>
34
  </testsuites>
35
  <groups>
includes/vendor/action-scheduler/tests/phpunit/ActionScheduler_Mock_Async_Request_QueueRunner.php ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * ActionScheduler_Mock_AsyncRequest_QueueRunner
4
+ */
5
+
6
+ defined( 'ABSPATH' ) || exit;
7
+
8
+ /**
9
+ * ActionScheduler_Mock_AsyncRequest_QueueRunner class.
10
+ */
11
+ class ActionScheduler_Mock_AsyncRequest_QueueRunner extends ActionScheduler_AsyncRequest_QueueRunner {
12
+
13
+ /**
14
+ * Do not run queues via async requests.
15
+ */
16
+ protected function allow() {
17
+ return false;
18
+ }
19
+ }
includes/vendor/action-scheduler/tests/phpunit/ActionScheduler_Mocker.php ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * ActionScheduler_Mocker
4
+ */
5
+
6
+ defined( 'ABSPATH' ) || exit;
7
+
8
+ /**
9
+ * ActionScheduler_Mocker class.
10
+ */
11
+ class ActionScheduler_Mocker {
12
+
13
+ /**
14
+ * Do not run queues via async requests.
15
+ *
16
+ * @param ActionScheduler_Store $store
17
+ */
18
+ public static function get_queue_runner( ActionScheduler_Store $store = null ) {
19
+
20
+ if ( ! $store ) {
21
+ $store = ActionScheduler_Store::instance();
22
+ }
23
+
24
+ return new ActionScheduler_QueueRunner( $store, null, null, self::get_async_request_queue_runner( $store ) );
25
+ }
26
+
27
+ /**
28
+ * Get an instance of the mock queue runner
29
+ *
30
+ * @param ActionScheduler_Store $store
31
+ */
32
+ protected static function get_async_request_queue_runner( ActionScheduler_Store $store ) {
33
+ return new ActionScheduler_Mock_AsyncRequest_QueueRunner( $store );
34
+ }
35
+ }
includes/vendor/action-scheduler/tests/phpunit/jobs/ActionScheduler_NullAction_Test.php CHANGED
@@ -10,7 +10,7 @@ class ActionScheduler_NullAction_Test extends ActionScheduler_UnitTestCase {
10
 
11
  $this->assertEmpty($action->get_hook());
12
  $this->assertEmpty($action->get_args());
13
- $this->assertNull($action->get_schedule()->next());
14
  }
15
  }
16
 
10
 
11
  $this->assertEmpty($action->get_hook());
12
  $this->assertEmpty($action->get_args());
13
+ $this->assertNull( $action->get_schedule()->get_date() );
14
  }
15
  }
16
 
includes/vendor/action-scheduler/tests/phpunit/jobstore/ActionScheduler_DBStoreMigrator_Test.php ADDED
@@ -0,0 +1,26 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Class ActionScheduler_DBStoreMigrator_Test
5
+ * @group tables
6
+ */
7
+ class ActionScheduler_DBStoreMigrator_Test extends ActionScheduler_UnitTestCase {
8
+
9
+ public function test_create_action_with_last_attempt_date() {
10
+ $scheduled_date = as_get_datetime_object( strtotime( '-24 hours' ) );
11
+ $last_attempt_date = as_get_datetime_object( strtotime( '-23 hours' ) );
12
+
13
+ $action = new ActionScheduler_FinishedAction( 'my_hook', [], new ActionScheduler_SimpleSchedule( $scheduled_date ) );
14
+ $store = new ActionScheduler_DBStoreMigrator();
15
+
16
+ $action_id = $store->save_action( $action, null, $last_attempt_date );
17
+ $action_date = $store->get_date( $action_id );
18
+
19
+ $this->assertEquals( $last_attempt_date->format( 'U' ), $action_date->format( 'U' ) );
20
+
21
+ $action_id = $store->save_action( $action, $scheduled_date, $last_attempt_date );
22
+ $action_date = $store->get_date( $action_id );
23
+
24
+ $this->assertEquals( $last_attempt_date->format( 'U' ), $action_date->format( 'U' ) );
25
+ }
26
+ }
includes/vendor/action-scheduler/tests/phpunit/jobstore/ActionScheduler_DBStore_Test.php ADDED
@@ -0,0 +1,396 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Class ActionScheduler_DBStore_Test
5
+ * @group tables
6
+ */
7
+ class ActionScheduler_DBStore_Test extends ActionScheduler_UnitTestCase {
8
+
9
+ public function test_create_action() {
10
+ $time = as_get_datetime_object();
11
+ $schedule = new ActionScheduler_SimpleSchedule( $time );
12
+ $action = new ActionScheduler_Action( 'my_hook', [], $schedule );
13
+ $store = new ActionScheduler_DBStore();
14
+ $action_id = $store->save_action( $action );
15
+
16
+ $this->assertNotEmpty( $action_id );
17
+ }
18
+
19
+ public function test_create_action_with_scheduled_date() {
20
+ $time = as_get_datetime_object( strtotime( '-1 week' ) );
21
+ $action = new ActionScheduler_Action( 'my_hook', [], new ActionScheduler_SimpleSchedule( $time ) );
22
+ $store = new ActionScheduler_DBStore();
23
+ $action_id = $store->save_action( $action, $time );
24
+ $action_date = $store->get_date( $action_id );
25
+
26
+ $this->assertEquals( $time->format( 'U' ), $action_date->format( 'U' ) );
27
+ }
28
+
29
+ public function test_retrieve_action() {
30
+ $time = as_get_datetime_object();
31
+ $schedule = new ActionScheduler_SimpleSchedule( $time );
32
+ $action = new ActionScheduler_Action( 'my_hook', [], $schedule, 'my_group' );
33
+ $store = new ActionScheduler_DBStore();
34
+ $action_id = $store->save_action( $action );
35
+
36
+ $retrieved = $store->fetch_action( $action_id );
37
+ $this->assertEquals( $action->get_hook(), $retrieved->get_hook() );
38
+ $this->assertEqualSets( $action->get_args(), $retrieved->get_args() );
39
+ $this->assertEquals( $action->get_schedule()->get_date()->format( 'U' ), $retrieved->get_schedule()->get_date()->format( 'U' ) );
40
+ $this->assertEquals( $action->get_group(), $retrieved->get_group() );
41
+ }
42
+
43
+ public function test_cancel_action() {
44
+ $time = as_get_datetime_object();
45
+ $schedule = new ActionScheduler_SimpleSchedule( $time );
46
+ $action = new ActionScheduler_Action( 'my_hook', [], $schedule, 'my_group' );
47
+ $store = new ActionScheduler_DBStore();
48
+ $action_id = $store->save_action( $action );
49
+ $store->cancel_action( $action_id );
50
+
51
+ $fetched = $store->fetch_action( $action_id );
52
+ $this->assertInstanceOf( 'ActionScheduler_CanceledAction', $fetched );
53
+ }
54
+
55
+ public function test_cancel_actions_by_hook() {
56
+ $store = new ActionScheduler_DBStore();
57
+ $actions = [];
58
+ $hook = 'by_hook_test';
59
+ for ( $day = 1; $day <= 3; $day++ ) {
60
+ $delta = sprintf( '+%d day', $day );
61
+ $time = as_get_datetime_object( $delta );
62
+ $schedule = new ActionScheduler_SimpleSchedule( $time );
63
+ $action = new ActionScheduler_Action( $hook, [], $schedule, 'my_group' );
64
+ $actions[] = $store->save_action( $action );
65
+ }
66
+ $store->cancel_actions_by_hook( $hook );
67
+
68
+ foreach ( $actions as $action_id ) {
69
+ $fetched = $store->fetch_action( $action_id );
70
+ $this->assertInstanceOf( 'ActionScheduler_CanceledAction', $fetched );
71
+ }
72
+ }
73
+
74
+ public function test_cancel_actions_by_group() {
75
+ $store = new ActionScheduler_DBStore();
76
+ $actions = [];
77
+ $group = 'by_group_test';
78
+ for ( $day = 1; $day <= 3; $day++ ) {
79
+ $delta = sprintf( '+%d day', $day );
80
+ $time = as_get_datetime_object( $delta );
81
+ $schedule = new ActionScheduler_SimpleSchedule( $time );
82
+ $action = new ActionScheduler_Action( 'my_hook', [], $schedule, $group );
83
+ $actions[] = $store->save_action( $action );
84
+ }
85
+ $store->cancel_actions_by_group( $group );
86
+
87
+ foreach ( $actions as $action_id ) {
88
+ $fetched = $store->fetch_action( $action_id );
89
+ $this->assertInstanceOf( 'ActionScheduler_CanceledAction', $fetched );
90
+ }
91
+ }
92
+
93
+ public function test_claim_actions() {
94
+ $created_actions = [];
95
+ $store = new ActionScheduler_DBStore();
96
+ for ( $i = 3; $i > - 3; $i -- ) {
97
+ $time = as_get_datetime_object( $i . ' hours' );
98
+ $schedule = new ActionScheduler_SimpleSchedule( $time );
99
+ $action = new ActionScheduler_Action( 'my_hook', [ $i ], $schedule, 'my_group' );
100
+
101
+ $created_actions[] = $store->save_action( $action );
102
+ }
103
+
104
+ $claim = $store->stake_claim();
105
+ $this->assertInstanceof( 'ActionScheduler_ActionClaim', $claim );
106
+
107
+ $this->assertCount( 3, $claim->get_actions() );
108
+ $this->assertEqualSets( array_slice( $created_actions, 3, 3 ), $claim->get_actions() );
109
+ }
110
+
111
+ public function test_claim_actions_order() {
112
+
113
+ $store = new ActionScheduler_DBStore();
114
+ $schedule = new ActionScheduler_SimpleSchedule( as_get_datetime_object( '-1 hour' ) );
115
+ $created_actions = array(
116
+ $store->save_action( new ActionScheduler_Action( 'my_hook', array( 1 ), $schedule, 'my_group' ) ),
117
+ $store->save_action( new ActionScheduler_Action( 'my_hook', array( 1 ), $schedule, 'my_group' ) ),
118
+ );
119
+
120
+ $claim = $store->stake_claim();
121
+ $this->assertInstanceof( 'ActionScheduler_ActionClaim', $claim );
122
+
123
+ // Verify uniqueness of action IDs.
124
+ $this->assertEquals( 2, count( array_unique( $created_actions ) ) );
125
+
126
+ // Verify the count and order of the actions.
127
+ $claimed_actions = $claim->get_actions();
128
+ $this->assertCount( 2, $claimed_actions );
129
+ $this->assertEquals( $created_actions, $claimed_actions );
130
+
131
+ // Verify the reversed order doesn't pass.
132
+ $reversed_actions = array_reverse( $created_actions );
133
+ $this->assertNotEquals( $reversed_actions, $claimed_actions );
134
+ }
135
+
136
+ public function test_claim_actions_by_hooks() {
137
+ $created_actions = $created_actions_by_hook = [];
138
+ $store = new ActionScheduler_DBStore();
139
+ $unique_hook_one = 'my_unique_hook_one';
140
+ $unique_hook_two = 'my_unique_hook_two';
141
+ $unique_hooks = array(
142
+ $unique_hook_one,
143
+ $unique_hook_two,
144
+ );
145
+
146
+ for ( $i = 3; $i > - 3; $i -- ) {
147
+ foreach ( $unique_hooks as $unique_hook ) {
148
+ $time = as_get_datetime_object( $i . ' hours' );
149
+ $schedule = new ActionScheduler_SimpleSchedule( $time );
150
+ $action = new ActionScheduler_Action( $unique_hook, [ $i ], $schedule, 'my_group' );
151
+
152
+ $action_id = $store->save_action( $action );
153
+ $created_actions[] = $created_actions_by_hook[ $unique_hook ][] = $action_id;
154
+ }
155
+ }
156
+
157
+ $claim = $store->stake_claim( 10, null, $unique_hooks );
158
+ $this->assertInstanceof( 'ActionScheduler_ActionClaim', $claim );
159
+ $this->assertCount( 6, $claim->get_actions() );
160
+ $this->assertEqualSets( array_slice( $created_actions, 6, 6 ), $claim->get_actions() );
161
+
162
+ $store->release_claim( $claim );
163
+
164
+ $claim = $store->stake_claim( 10, null, array( $unique_hook_one ) );
165
+ $this->assertInstanceof( 'ActionScheduler_ActionClaim', $claim );
166
+ $this->assertCount( 3, $claim->get_actions() );
167
+ $this->assertEqualSets( array_slice( $created_actions_by_hook[ $unique_hook_one ], 3, 3 ), $claim->get_actions() );
168
+
169
+ $store->release_claim( $claim );
170
+
171
+ $claim = $store->stake_claim( 10, null, array( $unique_hook_two ) );
172
+ $this->assertInstanceof( 'ActionScheduler_ActionClaim', $claim );
173
+ $this->assertCount( 3, $claim->get_actions() );
174
+ $this->assertEqualSets( array_slice( $created_actions_by_hook[ $unique_hook_two ], 3, 3 ), $claim->get_actions() );
175
+ }
176
+
177
+ public function test_claim_actions_by_group() {
178
+ $created_actions = [];
179
+ $store = new ActionScheduler_DBStore();
180
+ $unique_group_one = 'my_unique_group_one';
181
+ $unique_group_two = 'my_unique_group_two';
182
+ $unique_groups = array(
183
+ $unique_group_one,
184
+ $unique_group_two,
185
+ );
186
+
187
+ for ( $i = 3; $i > - 3; $i -- ) {
188
+ foreach ( $unique_groups as $unique_group ) {
189
+ $time = as_get_datetime_object( $i . ' hours' );
190
+ $schedule = new ActionScheduler_SimpleSchedule( $time );
191
+ $action = new ActionScheduler_Action( 'my_hook', [ $i ], $schedule, $unique_group );
192
+
193
+ $created_actions[ $unique_group ][] = $store->save_action( $action );
194
+ }
195
+ }
196
+
197
+ $claim = $store->stake_claim( 10, null, array(), $unique_group_one );
198
+ $this->assertInstanceof( 'ActionScheduler_ActionClaim', $claim );
199
+ $this->assertCount( 3, $claim->get_actions() );
200
+ $this->assertEqualSets( array_slice( $created_actions[ $unique_group_one ], 3, 3 ), $claim->get_actions() );
201
+
202
+ $store->release_claim( $claim );
203
+
204
+ $claim = $store->stake_claim( 10, null, array(), $unique_group_two );
205
+ $this->assertInstanceof( 'ActionScheduler_ActionClaim', $claim );
206
+ $this->assertCount( 3, $claim->get_actions() );
207
+ $this->assertEqualSets( array_slice( $created_actions[ $unique_group_two ], 3, 3 ), $claim->get_actions() );
208
+ }
209
+
210
+ public function test_claim_actions_by_hook_and_group() {
211
+ $created_actions = $created_actions_by_hook = [];
212
+ $store = new ActionScheduler_DBStore();
213
+
214
+ $unique_hook_one = 'my_other_unique_hook_one';
215
+ $unique_hook_two = 'my_other_unique_hook_two';
216
+ $unique_hooks = array(
217
+ $unique_hook_one,
218
+ $unique_hook_two,
219
+ );
220
+
221
+ $unique_group_one = 'my_other_other_unique_group_one';
222
+ $unique_group_two = 'my_other_unique_group_two';
223
+ $unique_groups = array(
224
+ $unique_group_one,
225
+ $unique_group_two,
226
+ );
227
+
228
+ for ( $i = 3; $i > - 3; $i -- ) {
229
+ foreach ( $unique_hooks as $unique_hook ) {
230
+ foreach ( $unique_groups as $unique_group ) {
231
+ $time = as_get_datetime_object( $i . ' hours' );
232
+ $schedule = new ActionScheduler_SimpleSchedule( $time );
233
+ $action = new ActionScheduler_Action( $unique_hook, [ $i ], $schedule, $unique_group );
234
+
235
+ $action_id = $store->save_action( $action );
236
+ $created_actions[ $unique_group ][] = $action_id;
237
+ $created_actions_by_hook[ $unique_hook ][ $unique_group ][] = $action_id;
238
+ }
239
+ }
240
+ }
241
+
242
+ /** Test Both Hooks with Each Group */
243
+
244
+ $claim = $store->stake_claim( 10, null, $unique_hooks, $unique_group_one );
245
+ $this->assertInstanceof( 'ActionScheduler_ActionClaim', $claim );
246
+ $this->assertCount( 6, $claim->get_actions() );
247
+ $this->assertEqualSets( array_slice( $created_actions[ $unique_group_one ], 6, 6 ), $claim->get_actions() );
248
+
249
+ $store->release_claim( $claim );
250
+
251
+ $claim = $store->stake_claim( 10, null, $unique_hooks, $unique_group_two );
252
+ $this->assertInstanceof( 'ActionScheduler_ActionClaim', $claim );
253
+ $this->assertCount( 6, $claim->get_actions() );
254
+ $this->assertEqualSets( array_slice( $created_actions[ $unique_group_two ], 6, 6 ), $claim->get_actions() );
255
+
256
+ $store->release_claim( $claim );
257
+
258
+ /** Test Just One Hook with Group One */
259
+
260
+ $claim = $store->stake_claim( 10, null, array( $unique_hook_one ), $unique_group_one );
261
+ $this->assertInstanceof( 'ActionScheduler_ActionClaim', $claim );
262
+ $this->assertCount( 3, $claim->get_actions() );
263
+ $this->assertEqualSets( array_slice( $created_actions_by_hook[ $unique_hook_one ][ $unique_group_one ], 3, 3 ), $claim->get_actions() );
264
+
265
+ $store->release_claim( $claim );
266
+
267
+ $claim = $store->stake_claim( 24, null, array( $unique_hook_two ), $unique_group_one );
268
+ $this->assertInstanceof( 'ActionScheduler_ActionClaim', $claim );
269
+ $this->assertCount( 3, $claim->get_actions() );
270
+ $this->assertEqualSets( array_slice( $created_actions_by_hook[ $unique_hook_two ][ $unique_group_one ], 3, 3 ), $claim->get_actions() );
271
+
272
+ $store->release_claim( $claim );
273
+
274
+ /** Test Just One Hook with Group Two */
275
+
276
+ $claim = $store->stake_claim( 10, null, array( $unique_hook_one ), $unique_group_two );
277
+ $this->assertInstanceof( 'ActionScheduler_ActionClaim', $claim );
278
+ $this->assertCount( 3, $claim->get_actions() );
279
+ $this->assertEqualSets( array_slice( $created_actions_by_hook[ $unique_hook_one ][ $unique_group_two ], 3, 3 ), $claim->get_actions() );
280
+
281
+ $store->release_claim( $claim );
282
+
283
+ $claim = $store->stake_claim( 24, null, array( $unique_hook_two ), $unique_group_two );
284
+ $this->assertInstanceof( 'ActionScheduler_ActionClaim', $claim );
285
+ $this->assertCount( 3, $claim->get_actions() );
286
+ $this->assertEqualSets( array_slice( $created_actions_by_hook[ $unique_hook_two ][ $unique_group_two ], 3, 3 ), $claim->get_actions() );
287
+ }
288
+
289
+ public function test_duplicate_claim() {
290
+ $created_actions = [];
291
+ $store = new ActionScheduler_DBStore();
292
+ for ( $i = 0; $i > - 3; $i -- ) {
293
+ $time = as_get_datetime_object( $i . ' hours' );
294
+ $schedule = new ActionScheduler_SimpleSchedule( $time );
295
+ $action = new ActionScheduler_Action( 'my_hook', [ $i ], $schedule, 'my_group' );
296
+
297
+ $created_actions[] = $store->save_action( $action );
298
+ }
299
+
300
+ $claim1 = $store->stake_claim();
301
+ $claim2 = $store->stake_claim();
302
+ $this->assertCount( 3, $claim1->get_actions() );
303
+ $this->assertCount( 0, $claim2->get_actions() );
304
+ }
305
+
306
+ public function test_release_claim() {
307
+ $created_actions = [];
308
+ $store = new ActionScheduler_DBStore();
309
+ for ( $i = 0; $i > - 3; $i -- ) {
310
+ $time = as_get_datetime_object( $i . ' hours' );
311
+ $schedule = new ActionScheduler_SimpleSchedule( $time );
312
+ $action = new ActionScheduler_Action( 'my_hook', [ $i ], $schedule, 'my_group' );
313
+
314
+ $created_actions[] = $store->save_action( $action );
315
+ }
316
+
317
+ $claim1 = $store->stake_claim();
318
+
319
+ $store->release_claim( $claim1 );
320
+
321
+ $claim2 = $store->stake_claim();
322
+ $this->assertCount( 3, $claim2->get_actions() );
323
+ }
324
+
325
+ public function test_search() {
326
+ $created_actions = [];
327
+ $store = new ActionScheduler_DBStore();
328
+ for ( $i = - 3; $i <= 3; $i ++ ) {
329
+ $time = as_get_datetime_object( $i . ' hours' );
330
+ $schedule = new ActionScheduler_SimpleSchedule( $time );
331
+ $action = new ActionScheduler_Action( 'my_hook', [ $i ], $schedule, 'my_group' );
332
+
333
+ $created_actions[] = $store->save_action( $action );
334
+ }
335
+
336
+ $next_no_args = $store->find_action( 'my_hook' );
337
+ $this->assertEquals( $created_actions[ 0 ], $next_no_args );
338
+
339
+ $next_with_args = $store->find_action( 'my_hook', [ 'args' => [ 1 ] ] );
340
+ $this->assertEquals( $created_actions[ 4 ], $next_with_args );
341
+
342
+ $non_existent = $store->find_action( 'my_hook', [ 'args' => [ 17 ] ] );
343
+ $this->assertNull( $non_existent );
344
+ }
345
+
346
+ public function test_search_by_group() {
347
+ $store = new ActionScheduler_DBStore();
348
+ $schedule = new ActionScheduler_SimpleSchedule( as_get_datetime_object( 'tomorrow' ) );
349
+
350
+ $abc = $store->save_action( new ActionScheduler_Action( 'my_hook', [ 1 ], $schedule, 'abc' ) );
351
+ $def = $store->save_action( new ActionScheduler_Action( 'my_hook', [ 1 ], $schedule, 'def' ) );
352
+ $ghi = $store->save_action( new ActionScheduler_Action( 'my_hook', [ 1 ], $schedule, 'ghi' ) );
353
+
354
+ $this->assertEquals( $abc, $store->find_action( 'my_hook', [ 'group' => 'abc' ] ) );
355
+ $this->assertEquals( $def, $store->find_action( 'my_hook', [ 'group' => 'def' ] ) );
356
+ $this->assertEquals( $ghi, $store->find_action( 'my_hook', [ 'group' => 'ghi' ] ) );
357
+ }
358
+
359
+ public function test_get_run_date() {
360
+ $time = as_get_datetime_object( '-10 minutes' );
361
+ $schedule = new ActionScheduler_IntervalSchedule( $time, HOUR_IN_SECONDS );
362
+ $action = new ActionScheduler_Action( 'my_hook', [], $schedule );
363
+ $store = new ActionScheduler_DBStore();
364
+ $action_id = $store->save_action( $action );
365
+
366
+ $this->assertEquals( $time->format( 'U' ), $store->get_date( $action_id )->format( 'U' ) );
367
+
368
+ $action = $store->fetch_action( $action_id );
369
+ $action->execute();
370
+ $now = as_get_datetime_object();
371
+ $store->mark_complete( $action_id );
372
+
373
+ $this->assertEquals( $now->format( 'U' ), $store->get_date( $action_id )->format( 'U' ) );
374
+
375
+ $next = $action->get_schedule()->get_next( $now );
376
+ $new_action_id = $store->save_action( $action, $next );
377
+
378
+ $this->assertEquals( (int) ( $now->format( 'U' ) ) + HOUR_IN_SECONDS, $store->get_date( $new_action_id )->format( 'U' ) );
379
+ }
380
+
381
+ public function test_get_status() {
382
+ $time = as_get_datetime_object('-10 minutes');
383
+ $schedule = new ActionScheduler_IntervalSchedule($time, HOUR_IN_SECONDS);
384
+ $action = new ActionScheduler_Action('my_hook', array(), $schedule);
385
+ $store = new ActionScheduler_DBStore();
386
+ $action_id = $store->save_action($action);
387
+
388
+ $this->assertEquals( ActionScheduler_Store::STATUS_PENDING, $store->get_status( $action_id ) );
389
+
390
+ $store->mark_complete( $action_id );
391
+ $this->assertEquals( ActionScheduler_Store::STATUS_COMPLETE, $store->get_status( $action_id ) );
392
+
393
+ $store->mark_failure( $action_id );
394
+ $this->assertEquals( ActionScheduler_Store::STATUS_FAILED, $store->get_status( $action_id ) );
395
+ }
396
+ }
includes/vendor/action-scheduler/tests/phpunit/jobstore/ActionScheduler_HybridStore_Test.php ADDED
@@ -0,0 +1,272 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+
4
+ use Action_Scheduler\Migration\Config;
5
+ use ActionScheduler_NullAction as NullAction;
6
+ use ActionScheduler_wpCommentLogger as CommentLogger;
7
+ use ActionScheduler_wpPostStore as PostStore;
8
+
9
+ /**
10
+ * Class ActionScheduler_HybridStore_Test
11
+ * @group tables
12
+ */
13
+
14
+ class ActionScheduler_HybridStore_Test extends ActionScheduler_UnitTestCase {
15
+ private $demarkation_id = 1000;
16
+
17
+ public function setUp() {
18
+ parent::setUp();
19
+ if ( ! taxonomy_exists( PostStore::GROUP_TAXONOMY ) ) {
20
+ // register the post type and taxonomy necessary for the store to work
21
+ $store = new PostStore();
22
+ $store->init();
23
+ }
24
+ update_option( ActionScheduler_HybridStore::DEMARKATION_OPTION, $this->demarkation_id );
25
+ $hybrid = new ActionScheduler_HybridStore();
26
+ $hybrid->set_autoincrement( '', ActionScheduler_StoreSchema::ACTIONS_TABLE );
27
+ }
28
+
29
+ public function tearDown() {
30
+ parent::tearDown();
31
+
32
+ // reset the autoincrement index
33
+ /** @var \wpdb $wpdb */
34
+ global $wpdb;
35
+ $wpdb->query( "TRUNCATE TABLE {$wpdb->actionscheduler_actions}" );
36
+ delete_option( ActionScheduler_HybridStore::DEMARKATION_OPTION );
37
+ }
38
+
39
+ public function test_actions_are_migrated_on_find() {
40
+ $source_store = new PostStore();
41
+ $destination_store = new ActionScheduler_DBStore();
42
+ $source_logger = new CommentLogger();
43
+ $destination_logger = new ActionScheduler_DBLogger();
44
+
45
+ $config = new Config();
46
+ $config->set_source_store( $source_store );
47
+ $config->set_source_logger( $source_logger );
48
+ $config->set_destination_store( $destination_store );
49
+ $config->set_destination_logger( $destination_logger );
50
+
51
+ $hybrid_store = new ActionScheduler_HybridStore( $config );
52
+
53
+ $time = as_get_datetime_object( '10 minutes ago' );
54
+ $schedule = new ActionScheduler_SimpleSchedule( $time );
55
+ $action = new ActionScheduler_Action( __FUNCTION__, [], $schedule );
56
+ $source_id = $source_store->save_action( $action );
57
+
58
+ $found = $hybrid_store->find_action( __FUNCTION__, [] );
59
+
60
+ $this->assertNotEquals( $source_id, $found );
61
+ $this->assertGreaterThanOrEqual( $this->demarkation_id, $found );
62
+
63
+ $found_in_source = $source_store->fetch_action( $source_id );
64
+ $this->assertInstanceOf( NullAction::class, $found_in_source );
65
+ }
66
+
67
+
68
+ public function test_actions_are_migrated_on_query() {
69
+ $source_store = new PostStore();
70
+ $destination_store = new ActionScheduler_DBStore();
71
+ $source_logger = new CommentLogger();
72
+ $destination_logger = new ActionScheduler_DBLogger();
73
+
74
+ $config = new Config();
75
+ $config->set_source_store( $source_store );
76
+ $config->set_source_logger( $source_logger );
77
+ $config->set_destination_store( $destination_store );
78
+ $config->set_destination_logger( $destination_logger );
79
+
80
+ $hybrid_store = new ActionScheduler_HybridStore( $config );
81
+
82
+ $source_actions = [];
83
+ $destination_actions = [];
84
+
85
+ for ( $i = 0; $i < 10; $i++ ) {
86
+ // create in instance in the source store
87
+ $time = as_get_datetime_object( ( $i * 10 + 1 ) . ' minutes' );
88
+ $schedule = new ActionScheduler_SimpleSchedule( $time );
89
+ $action = new ActionScheduler_Action( __FUNCTION__, [], $schedule );
90
+
91
+ $source_actions[] = $source_store->save_action( $action );
92
+
93
+ // create an instance in the destination store
94
+ $time = as_get_datetime_object( ( $i * 10 + 5 ) . ' minutes' );
95
+ $schedule = new ActionScheduler_SimpleSchedule( $time );
96
+ $action = new ActionScheduler_Action( __FUNCTION__, [], $schedule );
97
+
98
+ $destination_actions[] = $destination_store->save_action( $action );
99
+ }
100
+
101
+ $found = $hybrid_store->query_actions([
102
+ 'hook' => __FUNCTION__,
103
+ 'per_page' => 6,
104
+ ] );
105
+
106
+ $this->assertCount( 6, $found );
107
+ foreach ( $found as $key => $action_id ) {
108
+ $this->assertNotContains( $action_id, $source_actions );
109
+ $this->assertGreaterThanOrEqual( $this->demarkation_id, $action_id );
110
+ if ( $key % 2 == 0 ) { // it should have been in the source store
111
+ $this->assertNotContains( $action_id, $destination_actions );
112
+ } else { // it should have already been in the destination store
113
+ $this->assertContains( $action_id, $destination_actions );
114
+ }
115
+ }
116
+
117
+ // six of the original 10 should have migrated to the new store
118
+ // even though only three were retrieve in the final query
119
+ $found_in_source = $source_store->query_actions( [
120
+ 'hook' => __FUNCTION__,
121
+ 'per_page' => 10,
122
+ ] );
123
+ $this->assertCount( 4, $found_in_source );
124
+ }
125
+
126
+
127
+ public function test_actions_are_migrated_on_claim() {
128
+ $source_store = new PostStore();
129
+ $destination_store = new ActionScheduler_DBStore();
130
+ $source_logger = new CommentLogger();
131
+ $destination_logger = new ActionScheduler_DBLogger();
132
+
133
+ $config = new Config();
134
+ $config->set_source_store( $source_store );
135
+ $config->set_source_logger( $source_logger );
136
+ $config->set_destination_store( $destination_store );
137
+ $config->set_destination_logger( $destination_logger );
138
+
139
+ $hybrid_store = new ActionScheduler_HybridStore( $config );
140
+
141
+ $source_actions = [];
142
+ $destination_actions = [];
143
+
144
+ for ( $i = 0; $i < 10; $i++ ) {
145
+ // create in instance in the source store
146
+ $time = as_get_datetime_object( ( $i * 10 + 1 ) . ' minutes ago' );
147
+ $schedule = new ActionScheduler_SimpleSchedule( $time );
148
+ $action = new ActionScheduler_Action( __FUNCTION__, [], $schedule );
149
+
150
+ $source_actions[] = $source_store->save_action( $action );
151
+
152
+ // create an instance in the destination store
153
+ $time = as_get_datetime_object( ( $i * 10 + 5 ) . ' minutes ago' );
154
+ $schedule = new ActionScheduler_SimpleSchedule( $time );
155
+ $action = new ActionScheduler_Action( __FUNCTION__, [], $schedule );
156
+
157
+ $destination_actions[] = $destination_store->save_action( $action );
158
+ }
159
+
160
+ $claim = $hybrid_store->stake_claim( 6 );
161
+
162
+ $claimed_actions = $claim->get_actions();
163
+ $this->assertCount( 6, $claimed_actions );
164
+ $this->assertCount( 3, array_intersect( $destination_actions, $claimed_actions ) );
165
+
166
+
167
+ // six of the original 10 should have migrated to the new store
168
+ // even though only three were retrieve in the final claim
169
+ $found_in_source = $source_store->query_actions( [
170
+ 'hook' => __FUNCTION__,
171
+ 'per_page' => 10,
172
+ ] );
173
+ $this->assertCount( 4, $found_in_source );
174
+
175
+ $this->assertEquals( 0, $source_store->get_claim_count() );
176
+ $this->assertEquals( 1, $destination_store->get_claim_count() );
177
+ $this->assertEquals( 1, $hybrid_store->get_claim_count() );
178
+
179
+ }
180
+
181
+ public function test_fetch_respects_demarkation() {
182
+ $source_store = new PostStore();
183
+ $destination_store = new ActionScheduler_DBStore();
184
+ $source_logger = new CommentLogger();
185
+ $destination_logger = new ActionScheduler_DBLogger();
186
+
187
+ $config = new Config();
188
+ $config->set_source_store( $source_store );
189
+ $config->set_source_logger( $source_logger );
190
+ $config->set_destination_store( $destination_store );
191
+ $config->set_destination_logger( $destination_logger );
192
+
193
+ $hybrid_store = new ActionScheduler_HybridStore( $config );
194
+
195
+ $source_actions = [];
196
+ $destination_actions = [];
197
+
198
+ for ( $i = 0; $i < 2; $i++ ) {
199
+ // create in instance in the source store
200
+ $time = as_get_datetime_object( ( $i * 10 + 1 ) . ' minutes ago' );
201
+ $schedule = new ActionScheduler_SimpleSchedule( $time );
202
+ $action = new ActionScheduler_Action( __FUNCTION__, [], $schedule );
203
+
204
+ $source_actions[] = $source_store->save_action( $action );
205
+
206
+ // create an instance in the destination store
207
+ $time = as_get_datetime_object( ( $i * 10 + 5 ) . ' minutes ago' );
208
+ $schedule = new ActionScheduler_SimpleSchedule( $time );
209
+ $action = new ActionScheduler_Action( __FUNCTION__, [], $schedule );
210
+
211
+ $destination_actions[] = $destination_store->save_action( $action );
212
+ }
213
+
214
+ foreach ( $source_actions as $action_id ) {
215
+ $action = $hybrid_store->fetch_action( $action_id );
216
+ $this->assertInstanceOf( ActionScheduler_Action::class, $action );
217
+ $this->assertNotInstanceOf( NullAction::class, $action );
218
+ }
219
+
220
+ foreach ( $destination_actions as $action_id ) {
221
+ $action = $hybrid_store->fetch_action( $action_id );
222
+ $this->assertInstanceOf( ActionScheduler_Action::class, $action );
223
+ $this->assertNotInstanceOf( NullAction::class, $action );
224
+ }
225
+ }
226
+
227
+ public function test_mark_complete_respects_demarkation() {
228
+ $source_store = new PostStore();
229
+ $destination_store = new ActionScheduler_DBStore();
230
+ $source_logger = new CommentLogger();
231
+ $destination_logger = new ActionScheduler_DBLogger();
232
+
233
+ $config = new Config();
234
+ $config->set_source_store( $source_store );
235
+ $config->set_source_logger( $source_logger );
236
+ $config->set_destination_store( $destination_store );
237
+ $config->set_destination_logger( $destination_logger );
238
+
239
+ $hybrid_store = new ActionScheduler_HybridStore( $config );
240
+
241
+ $source_actions = [];
242
+ $destination_actions = [];
243
+
244
+ for ( $i = 0; $i < 2; $i++ ) {
245
+ // create in instance in the source store
246
+ $time = as_get_datetime_object( ( $i * 10 + 1 ) . ' minutes ago' );
247
+ $schedule = new ActionScheduler_SimpleSchedule( $time );
248
+ $action = new ActionScheduler_Action( __FUNCTION__, [], $schedule );
249
+
250
+ $source_actions[] = $source_store->save_action( $action );
251
+
252
+ // create an instance in the destination store
253
+ $time = as_get_datetime_object( ( $i * 10 + 5 ) . ' minutes ago' );
254
+ $schedule = new ActionScheduler_SimpleSchedule( $time );
255
+ $action = new ActionScheduler_Action( __FUNCTION__, [], $schedule );
256
+
257
+ $destination_actions[] = $destination_store->save_action( $action );
258
+ }
259
+
260
+ foreach ( $source_actions as $action_id ) {
261
+ $hybrid_store->mark_complete( $action_id );
262
+ $action = $hybrid_store->fetch_action( $action_id );
263
+ $this->assertInstanceOf( ActionScheduler_FinishedAction::class, $action );
264
+ }
265
+
266
+ foreach ( $destination_actions as $action_id ) {
267
+ $hybrid_store->mark_complete( $action_id );
268
+ $action = $hybrid_store->fetch_action( $action_id );
269
+ $this->assertInstanceOf( ActionScheduler_FinishedAction::class, $action );
270
+ }
271
+ }
272
+ }
includes/vendor/action-scheduler/tests/phpunit/jobstore/ActionScheduler_wpPostStore_Test.php CHANGED
@@ -37,7 +37,7 @@ class ActionScheduler_wpPostStore_Test extends ActionScheduler_UnitTestCase {
37
  $retrieved = $store->fetch_action($action_id);
38
  $this->assertEquals($action->get_hook(), $retrieved->get_hook());
39
  $this->assertEqualSets($action->get_args(), $retrieved->get_args());
40
- $this->assertEquals($action->get_schedule()->next()->getTimestamp(), $retrieved->get_schedule()->next()->getTimestamp());
41
  $this->assertEquals($action->get_group(), $retrieved->get_group());
42
  }
43
 
@@ -76,6 +76,45 @@ class ActionScheduler_wpPostStore_Test extends ActionScheduler_UnitTestCase {
76
  $this->assertInstanceOf( 'ActionScheduler_CanceledAction', $fetched );
77
  }
78
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
79
  public function test_claim_actions() {
80
  $created_actions = array();
81
  $store = new ActionScheduler_wpPostStore();
@@ -225,7 +264,7 @@ class ActionScheduler_wpPostStore_Test extends ActionScheduler_UnitTestCase {
225
  $action->execute();
226
  $store->mark_complete( $action_id );
227
 
228
- $next = $action->get_schedule()->next( as_get_datetime_object() );
229
  $new_action_id = $store->save_action( $action, $next );
230
 
231
  $this->assertEquals('publish', get_post_status($action_id));
@@ -246,9 +285,9 @@ class ActionScheduler_wpPostStore_Test extends ActionScheduler_UnitTestCase {
246
  $now = as_get_datetime_object();
247
  $store->mark_complete( $action_id );
248
 
249
- $this->assertEquals( $store->get_date($action_id)->getTimestamp(), $now->getTimestamp() );
250
 
251
- $next = $action->get_schedule()->next( $now );
252
  $new_action_id = $store->save_action( $action, $next );
253
 
254
  $this->assertEquals( (int)($now->getTimestamp()) + HOUR_IN_SECONDS, $store->get_date($new_action_id)->getTimestamp() );
37
  $retrieved = $store->fetch_action($action_id);
38
  $this->assertEquals($action->get_hook(), $retrieved->get_hook());
39
  $this->assertEqualSets($action->get_args(), $retrieved->get_args());
40
+ $this->assertEquals( $action->get_schedule()->get_date()->getTimestamp(), $retrieved->get_schedule()->get_date()->getTimestamp() );
41
  $this->assertEquals($action->get_group(), $retrieved->get_group());
42
  }
43
 
76
  $this->assertInstanceOf( 'ActionScheduler_CanceledAction', $fetched );
77
  }
78
 
79
+ public function test_cancel_actions_by_hook() {
80
+ $store = new ActionScheduler_wpPostStore();
81
+ $actions = array();
82
+ $hook = 'by_hook_test';
83
+ for ( $day = 1; $day <= 3; $day++ ) {
84
+ $delta = sprintf( '+%d day', $day );
85
+ $time = as_get_datetime_object( $delta );
86
+ $schedule = new ActionScheduler_SimpleSchedule( $time );
87
+ $action = new ActionScheduler_Action( $hook, array(), $schedule, 'my_group' );
88
+ $actions[] = $store->save_action( $action );
89
+ }
90
+ $store->cancel_actions_by_hook( $hook );
91
+
92
+ foreach ( $actions as $action_id ) {
93
+ $fetched = $store->fetch_action( $action_id );
94
+ $this->assertInstanceOf( 'ActionScheduler_CanceledAction', $fetched );
95
+ }
96
+ }
97
+
98
+ public function test_cancel_actions_by_group() {
99
+ $store = new ActionScheduler_wpPostStore();
100
+ $actions = array();
101
+ $group = 'by_group_test';
102
+
103
+ for ( $day = 1; $day <= 3; $day++ ) {
104
+ $delta = sprintf( '+%d day', $day );
105
+ $time = as_get_datetime_object( $delta );
106
+ $schedule = new ActionScheduler_SimpleSchedule( $time );
107
+ $action = new ActionScheduler_Action( 'my_hook', array(), $schedule, $group );
108
+ $actions[] = $store->save_action( $action );
109
+ }
110
+ $store->cancel_actions_by_group( $group );
111
+
112
+ foreach ( $actions as $action_id ) {
113
+ $fetched = $store->fetch_action( $action_id );
114
+ $this->assertInstanceOf( 'ActionScheduler_CanceledAction', $fetched );
115
+ }
116
+ }
117
+
118
  public function test_claim_actions() {
119
  $created_actions = array();
120
  $store = new ActionScheduler_wpPostStore();
264
  $action->execute();
265
  $store->mark_complete( $action_id );
266
 
267
+ $next = $action->get_schedule()->get_next( as_get_datetime_object() );
268
  $new_action_id = $store->save_action( $action, $next );
269
 
270
  $this->assertEquals('publish', get_post_status($action_id));
285
  $now = as_get_datetime_object();
286
  $store->mark_complete( $action_id );
287
 
288
+ $this->assertEquals( $store->get_date( $action_id )->getTimestamp(), $now->getTimestamp(), '', 1 ); // allow timestamp to be 1 second off for older versions of PHP
289
 
290
+ $next = $action->get_schedule()->get_next( $now );
291
  $new_action_id = $store->save_action( $action, $next );
292
 
293
  $this->assertEquals( (int)($now->getTimestamp()) + HOUR_IN_SECONDS, $store->get_date($new_action_id)->getTimestamp() );
includes/vendor/action-scheduler/tests/phpunit/lock/ActionScheduler_OptionLock_Test.php ADDED
@@ -0,0 +1,45 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Class ActionScheduler_Lock_Test
5
+ * @package test_cases\lock
6
+ */
7
+ class ActionScheduler_OptionLock_Test extends ActionScheduler_UnitTestCase {
8
+ public function test_instance() {
9
+ $lock = ActionScheduler::lock();
10
+ $this->assertInstanceOf( 'ActionScheduler_Lock', $lock );
11
+ $this->assertInstanceOf( 'ActionScheduler_OptionLock', $lock );
12
+ }
13
+
14
+ public function test_is_locked() {
15
+ $lock = ActionScheduler::lock();
16
+ $lock_type = md5( rand() );
17
+
18
+ $this->assertFalse( $lock->is_locked( $lock_type ) );
19
+
20
+ $lock->set( $lock_type );
21
+ $this->assertTrue( $lock->is_locked( $lock_type ) );
22
+ }
23
+
24
+ public function test_set() {
25
+ $lock = ActionScheduler::lock();
26
+ $lock_type = md5( rand() );
27
+
28
+ $lock->set( $lock_type );
29
+ $this->assertTrue( $lock->is_locked( $lock_type ) );
30
+ }
31
+
32
+ public function test_get_expiration() {
33
+ $lock = ActionScheduler::lock();
34
+ $lock_type = md5( rand() );
35
+
36
+ $lock->set( $lock_type );
37
+
38
+ $expiration = $lock->get_expiration( $lock_type );
39
+ $current_time = time();
40
+
41
+ $this->assertGreaterThanOrEqual( 0, $expiration );
42
+ $this->assertGreaterThan( $current_time, $expiration );
43
+ $this->assertLessThan( $current_time + MINUTE_IN_SECONDS + 1, $expiration );
44
+ }
45
+ }
includes/vendor/action-scheduler/tests/phpunit/logging/ActionScheduler_DBLogger_Test.php ADDED
@@ -0,0 +1,139 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Class ActionScheduler_DBLogger_Test
5
+ * @package test_cases\logging
6
+ * @group tables
7
+ */
8
+ class ActionScheduler_DBLogger_Test extends ActionScheduler_UnitTestCase {
9
+ public function test_default_logger() {
10
+ $logger = ActionScheduler::logger();
11
+ $this->assertInstanceOf( 'ActionScheduler_Logger', $logger );
12
+ $this->assertInstanceOf( ActionScheduler_DBLogger::class, $logger );
13
+ }
14
+
15
+ public function test_add_log_entry() {
16
+ $action_id = as_schedule_single_action( time(), __METHOD__ );
17
+ $logger = ActionScheduler::logger();
18
+ $message = 'Logging that something happened';
19
+ $log_id = $logger->log( $action_id, $message );
20
+ $entry = $logger->get_entry( $log_id );
21
+
22
+ $this->assertEquals( $action_id, $entry->get_action_id() );
23
+ $this->assertEquals( $message, $entry->get_message() );
24
+ }
25
+
26
+ public function test_null_log_entry() {
27
+ $logger = ActionScheduler::logger();
28
+ $entry = $logger->get_entry( 1 );
29
+ $this->assertEquals( '', $entry->get_action_id() );
30
+ $this->assertEquals( '', $entry->get_message() );
31
+ }
32
+
33
+ public function test_storage_logs() {
34
+ $action_id = as_schedule_single_action( time(), __METHOD__ );
35
+ $logger = ActionScheduler::logger();
36
+ $logs = $logger->get_logs( $action_id );
37
+ $expected = new ActionScheduler_LogEntry( $action_id, 'action created' );
38
+ $this->assertCount( 1, $logs );
39
+ $this->assertEquals( $expected->get_action_id(), $logs[0]->get_action_id() );
40
+ $this->assertEquals( $expected->get_message(), $logs[0]->get_message() );
41
+ }
42
+
43
+ public function test_execution_logs() {
44
+ $action_id = as_schedule_single_action( time(), __METHOD__ );
45
+ $logger = ActionScheduler::logger();
46
+ $started = new ActionScheduler_LogEntry( $action_id, 'action started via Unit Tests' );
47
+ $finished = new ActionScheduler_LogEntry( $action_id, 'action complete via Unit Tests' );
48
+
49
+ $runner = ActionScheduler_Mocker::get_queue_runner();
50
+ $runner->run( 'Unit Tests' );
51
+
52
+ // Expect 3 logs with the correct action ID.
53
+ $logs = $logger->get_logs( $action_id );
54
+ $this->assertCount( 3, $logs );
55
+ foreach ( $logs as $log ) {
56
+ $this->assertEquals( $action_id, $log->get_action_id() );
57
+ }
58
+
59
+ // Expect created, then started, then completed.
60
+ $this->assertEquals( 'action created', $logs[0]->get_message() );
61
+ $this->assertEquals( $started->get_message(), $logs[1]->get_message() );
62
+ $this->assertEquals( $finished->get_message(), $logs[2]->get_message() );
63
+ }
64
+
65
+ public function test_failed_execution_logs() {
66
+ $hook = __METHOD__;
67
+ add_action( $hook, array( $this, '_a_hook_callback_that_throws_an_exception' ) );
68
+ $action_id = as_schedule_single_action( time(), $hook );
69
+ $logger = ActionScheduler::logger();
70
+ $started = new ActionScheduler_LogEntry( $action_id, 'action started via Unit Tests' );
71
+ $finished = new ActionScheduler_LogEntry( $action_id, 'action complete via Unit Tests' );
72
+ $failed = new ActionScheduler_LogEntry( $action_id, 'action failed via Unit Tests: Execution failed' );
73
+
74
+ $runner = ActionScheduler_Mocker::get_queue_runner();
75
+ $runner->run( 'Unit Tests' );
76
+
77
+ // Expect 3 logs with the correct action ID.
78
+ $logs = $logger->get_logs( $action_id );
79
+ $this->assertCount( 3, $logs );
80
+ foreach ( $logs as $log ) {
81
+ $this->assertEquals( $action_id, $log->get_action_id() );
82
+ $this->assertNotEquals( $finished->get_message(), $log->get_message() );
83
+ }
84
+
85
+ // Expect created, then started, then failed.
86
+ $this->assertEquals( 'action created', $logs[0]->get_message() );
87
+ $this->assertEquals( $started->get_message(), $logs[1]->get_message() );
88
+ $this->assertEquals( $failed->get_message(), $logs[2]->get_message() );
89
+ }
90
+
91
+ public function test_fatal_error_log() {
92
+ $action_id = as_schedule_single_action( time(), __METHOD__ );
93
+ $logger = ActionScheduler::logger();
94
+ do_action( 'action_scheduler_unexpected_shutdown', $action_id, array(
95
+ 'type' => E_ERROR,
96
+ 'message' => 'Test error',
97
+ 'file' => __FILE__,
98
+ 'line' => __LINE__,
99
+ ));
100
+
101
+ $logs = $logger->get_logs( $action_id );
102
+ $found_log = FALSE;
103
+ foreach ( $logs as $l ) {
104
+ if ( strpos( $l->get_message(), 'unexpected shutdown' ) === 0 ) {
105
+ $found_log = TRUE;
106
+ }
107
+ }
108
+ $this->assertTrue( $found_log, 'Unexpected shutdown log not found' );
109
+ }
110
+
111
+ public function test_canceled_action_log() {
112
+ $action_id = as_schedule_single_action( time(), __METHOD__ );
113
+ as_unschedule_action( __METHOD__ );
114
+ $logger = ActionScheduler::logger();
115
+ $logs = $logger->get_logs( $action_id );
116
+ $expected = new ActionScheduler_LogEntry( $action_id, 'action canceled' );
117
+ $this->assertEquals( $expected->get_message(), end( $logs )->get_message() );
118
+ }
119
+
120
+ public function test_deleted_action_cleanup() {
121
+ $time = as_get_datetime_object('-10 minutes');
122
+ $schedule = new \ActionScheduler_SimpleSchedule($time);
123
+ $action = new \ActionScheduler_Action('my_hook', array(), $schedule);
124
+ $store = new ActionScheduler_DBStore();
125
+ $action_id = $store->save_action($action);
126
+
127
+ $logger = new ActionScheduler_DBLogger();
128
+ $logs = $logger->get_logs( $action_id );
129
+ $this->assertNotEmpty( $logs );
130
+
131
+ $store->delete_action( $action_id );
132
+ $logs = $logger->get_logs( $action_id );
133
+ $this->assertEmpty( $logs );
134
+ }
135
+
136
+ public function _a_hook_callback_that_throws_an_exception() {
137
+ throw new \RuntimeException('Execution failed');
138
+ }
139
+ }
includes/vendor/action-scheduler/tests/phpunit/logging/ActionScheduler_wpCommentLogger_Test.php CHANGED
@@ -5,10 +5,16 @@
5
  * @package test_cases\logging
6
  */
7
  class ActionScheduler_wpCommentLogger_Test extends ActionScheduler_UnitTestCase {
 
 
8
  public function test_default_logger() {
9
  $logger = ActionScheduler::logger();
10
  $this->assertInstanceOf( 'ActionScheduler_Logger', $logger );
11
- $this->assertInstanceOf( 'ActionScheduler_wpCommentLogger', $logger );
 
 
 
 
12
  }
13
 
14
  public function test_add_log_entry() {
@@ -83,11 +89,11 @@ class ActionScheduler_wpCommentLogger_Test extends ActionScheduler_UnitTestCase
83
  public function test_execution_comments() {
84
  $action_id = as_schedule_single_action( time(), 'a hook' );
85
  $logger = ActionScheduler::logger();
86
- $started = new ActionScheduler_LogEntry( $action_id, 'action started' );
87
- $finished = new ActionScheduler_LogEntry( $action_id, 'action complete' );
88
 
89
- $runner = new ActionScheduler_QueueRunner();
90
- $runner->run();
91
 
92
  $logs = $logger->get_logs( $action_id );
93
  $this->assertTrue( in_array( $this->log_entry_to_array( $started ), $this->log_entry_to_array( $logs ) ) );
@@ -99,12 +105,12 @@ class ActionScheduler_wpCommentLogger_Test extends ActionScheduler_UnitTestCase
99
  add_action( $hook, array( $this, '_a_hook_callback_that_throws_an_exception' ) );
100
  $action_id = as_schedule_single_action( time(), $hook );
101
  $logger = ActionScheduler::logger();
102
- $started = new ActionScheduler_LogEntry( $action_id, 'action started' );
103
- $finished = new ActionScheduler_LogEntry( $action_id, 'action complete' );
104
- $failed = new ActionScheduler_LogEntry( $action_id, 'action failed: Execution failed' );
105
 
106
- $runner = new ActionScheduler_QueueRunner();
107
- $runner->run();
108
 
109
  $logs = $logger->get_logs( $action_id );
110
  $this->assertTrue( in_array( $this->log_entry_to_array( $started ), $this->log_entry_to_array( $logs ) ) );
@@ -112,6 +118,21 @@ class ActionScheduler_wpCommentLogger_Test extends ActionScheduler_UnitTestCase
112
  $this->assertTrue( in_array( $this->log_entry_to_array( $failed ), $this->log_entry_to_array( $logs ) ) );
113
  }
114
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
115
  public function test_fatal_error_comments() {
116
  $hook = md5(rand());
117
  $action_id = as_schedule_single_action( time(), $hook );
@@ -147,6 +168,10 @@ class ActionScheduler_wpCommentLogger_Test extends ActionScheduler_UnitTestCase
147
  }
148
 
149
  public function test_filtering_of_get_comments() {
 
 
 
 
150
  $post_id = $this->factory->post->create_object(array(
151
  'post_title' => __FUNCTION__,
152
  ));
@@ -181,5 +206,13 @@ class ActionScheduler_wpCommentLogger_Test extends ActionScheduler_UnitTestCase
181
  $this->assertCount( 2, $comments );
182
  $this->assertContains( $log_id, wp_list_pluck($comments, 'comment_ID'));
183
  }
 
 
 
 
 
 
 
 
184
  }
185
 
5
  * @package test_cases\logging
6
  */
7
  class ActionScheduler_wpCommentLogger_Test extends ActionScheduler_UnitTestCase {
8
+ private $use_comment_logger;
9
+
10
  public function test_default_logger() {
11
  $logger = ActionScheduler::logger();
12
  $this->assertInstanceOf( 'ActionScheduler_Logger', $logger );
13
+ if ( $this->using_comment_logger() ) {
14
+ $this->assertInstanceOf( 'ActionScheduler_wpCommentLogger', $logger );
15
+ } else {
16
+ $this->assertNotInstanceOf( 'ActionScheduler_wpCommentLogger', $logger );
17
+ }
18
  }
19
 
20
  public function test_add_log_entry() {
89
  public function test_execution_comments() {
90
  $action_id = as_schedule_single_action( time(), 'a hook' );
91
  $logger = ActionScheduler::logger();
92
+ $started = new ActionScheduler_LogEntry( $action_id, 'action started via Unit Tests' );
93
+ $finished = new ActionScheduler_LogEntry( $action_id, 'action complete via Unit Tests' );
94
 
95
+ $runner = ActionScheduler_Mocker::get_queue_runner();
96
+ $runner->run( 'Unit Tests' );
97
 
98
  $logs = $logger->get_logs( $action_id );
99
  $this->assertTrue( in_array( $this->log_entry_to_array( $started ), $this->log_entry_to_array( $logs ) ) );
105
  add_action( $hook, array( $this, '_a_hook_callback_that_throws_an_exception' ) );
106
  $action_id = as_schedule_single_action( time(), $hook );
107
  $logger = ActionScheduler::logger();
108
+ $started = new ActionScheduler_LogEntry( $action_id, 'action started via Unit Tests' );
109
+ $finished = new ActionScheduler_LogEntry( $action_id, 'action complete via Unit Tests' );
110
+ $failed = new ActionScheduler_LogEntry( $action_id, 'action failed via Unit Tests: Execution failed' );
111
 
112
+ $runner = ActionScheduler_Mocker::get_queue_runner();
113
+ $runner->run( 'Unit Tests' );
114
 
115
  $logs = $logger->get_logs( $action_id );
116
  $this->assertTrue( in_array( $this->log_entry_to_array( $started ), $this->log_entry_to_array( $logs ) ) );
118
  $this->assertTrue( in_array( $this->log_entry_to_array( $failed ), $this->log_entry_to_array( $logs ) ) );
119
  }
120
 
121
+ public function test_failed_schedule_next_instance_comments() {
122
+ $action_id = rand();
123
+ $logger = ActionScheduler::logger();
124
+ $log_entry = new ActionScheduler_LogEntry( $action_id, 'There was a failure scheduling the next instance of this action: Execution failed' );
125
+
126
+ try {
127
+ $this->_a_hook_callback_that_throws_an_exception();
128
+ } catch ( Exception $e ) {
129
+ do_action( 'action_scheduler_failed_to_schedule_next_instance', $action_id, $e, new ActionScheduler_Action('my_hook') );
130
+ }
131
+
132
+ $logs = $logger->get_logs( $action_id );
133
+ $this->assertTrue( in_array( $this->log_entry_to_array( $log_entry ), $this->log_entry_to_array( $logs ) ) );
134
+ }
135
+
136
  public function test_fatal_error_comments() {
137
  $hook = md5(rand());
138
  $action_id = as_schedule_single_action( time(), $hook );
168
  }
169
 
170
  public function test_filtering_of_get_comments() {
171
+ if ( ! $this->using_comment_logger() ) {
172
+ return;
173
+ }
174
+
175
  $post_id = $this->factory->post->create_object(array(
176
  'post_title' => __FUNCTION__,
177
  ));
206
  $this->assertCount( 2, $comments );
207
  $this->assertContains( $log_id, wp_list_pluck($comments, 'comment_ID'));
208
  }
209
+
210
+ private function using_comment_logger() {
211
+ if ( null === $this->use_comment_logger ) {
212
+ $this->use_comment_logger = ! ActionScheduler_DataController::dependencies_met();
213
+ }
214
+
215
+ return $this->use_comment_logger;
216
+ }
217
  }
218
 
includes/vendor/action-scheduler/tests/phpunit/migration/ActionMigrator_Test.php ADDED
@@ -0,0 +1,145 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ use Action_Scheduler\Migration\ActionMigrator;
4
+ use Action_Scheduler\Migration\LogMigrator;
5
+
6
+ /**
7
+ * Class ActionMigrator_Test
8
+ * @group migration
9
+ */
10
+ class ActionMigrator_Test extends ActionScheduler_UnitTestCase {
11
+ public function setUp() {
12
+ parent::setUp();
13
+ if ( ! taxonomy_exists( ActionScheduler_wpPostStore::GROUP_TAXONOMY ) ) {
14
+ // register the post type and taxonomy necessary for the store to work
15
+ $store = new ActionScheduler_wpPostStore();
16
+ $store->init();
17
+ }
18
+ }
19
+
20
+ public function test_migrate_from_wpPost_to_db() {
21
+ $source = new ActionScheduler_wpPostStore();
22
+ $destination = new ActionScheduler_DBStore();
23
+ $migrator = new ActionMigrator( $source, $destination, $this->get_log_migrator() );
24
+
25
+ $time = as_get_datetime_object();
26
+ $schedule = new ActionScheduler_SimpleSchedule( $time );
27
+ $action = new ActionScheduler_Action( 'my_hook', [], $schedule, 'my_group' );
28
+ $action_id = $source->save_action( $action );
29
+
30
+ $new_id = $migrator->migrate( $action_id );
31
+
32
+ // ensure we get the same record out of the new store as we stored in the old
33
+ $retrieved = $destination->fetch_action( $new_id );
34
+ $this->assertEquals( $action->get_hook(), $retrieved->get_hook() );
35
+ $this->assertEqualSets( $action->get_args(), $retrieved->get_args() );
36
+ $this->assertEquals( $action->get_schedule()->get_date()->format( 'U' ), $retrieved->get_schedule()->get_date()->format( 'U' ) );
37
+ $this->assertEquals( $action->get_group(), $retrieved->get_group() );
38
+ $this->assertEquals( \ActionScheduler_Store::STATUS_PENDING, $destination->get_status( $new_id ) );
39
+
40
+
41
+ // ensure that the record in the old store does not exist
42
+ $old_action = $source->fetch_action( $action_id );
43
+ $this->assertInstanceOf( 'ActionScheduler_NullAction', $old_action );
44
+ }
45
+
46
+ public function test_does_not_migrate_missing_action_from_wpPost_to_db() {
47
+ $source = new ActionScheduler_wpPostStore();
48
+ $destination = new ActionScheduler_DBStore();
49
+ $migrator = new ActionMigrator( $source, $destination, $this->get_log_migrator() );
50
+
51
+ $action_id = rand( 100, 100000 );
52
+
53
+ $new_id = $migrator->migrate( $action_id );
54
+ $this->assertEquals( 0, $new_id );
55
+
56
+ // ensure we get the same record out of the new store as we stored in the old
57
+ $retrieved = $destination->fetch_action( $new_id );
58
+ $this->assertInstanceOf( 'ActionScheduler_NullAction', $retrieved );
59
+ }
60
+
61
+ public function test_migrate_completed_action_from_wpPost_to_db() {
62
+ $source = new ActionScheduler_wpPostStore();
63
+ $destination = new ActionScheduler_DBStore();
64
+ $migrator = new ActionMigrator( $source, $destination, $this->get_log_migrator() );
65
+
66
+ $time = as_get_datetime_object();
67
+ $schedule = new ActionScheduler_SimpleSchedule( $time );
68
+ $action = new ActionScheduler_Action( 'my_hook', [], $schedule, 'my_group' );
69
+ $action_id = $source->save_action( $action );
70
+ $source->mark_complete( $action_id );
71
+
72
+ $new_id = $migrator->migrate( $action_id );
73
+
74
+ // ensure we get the same record out of the new store as we stored in the old
75
+ $retrieved = $destination->fetch_action( $new_id );
76
+ $this->assertEquals( $action->get_hook(), $retrieved->get_hook() );
77
+ $this->assertEqualSets( $action->get_args(), $retrieved->get_args() );
78
+ $this->assertEquals( $action->get_schedule()->get_date()->format( 'U' ), $retrieved->get_schedule()->get_date()->format( 'U' ) );
79
+ $this->assertEquals( $action->get_group(), $retrieved->get_group() );
80
+ $this->assertTrue( $retrieved->is_finished() );
81
+ $this->assertEquals( \ActionScheduler_Store::STATUS_COMPLETE, $destination->get_status( $new_id ) );
82
+
83
+ // ensure that the record in the old store does not exist
84
+ $old_action = $source->fetch_action( $action_id );
85
+ $this->assertInstanceOf( 'ActionScheduler_NullAction', $old_action );
86
+ }
87
+
88
+ public function test_migrate_failed_action_from_wpPost_to_db() {
89
+ $source = new ActionScheduler_wpPostStore();
90
+ $destination = new ActionScheduler_DBStore();
91
+ $migrator = new ActionMigrator( $source, $destination, $this->get_log_migrator() );
92
+
93
+ $time = as_get_datetime_object();
94
+ $schedule = new ActionScheduler_SimpleSchedule( $time );
95
+ $action = new ActionScheduler_Action( 'my_hook', [], $schedule, 'my_group' );
96
+ $action_id = $source->save_action( $action );
97
+ $source->mark_failure( $action_id );
98
+
99
+ $new_id = $migrator->migrate( $action_id );
100
+
101
+ // ensure we get the same record out of the new store as we stored in the old
102
+ $retrieved = $destination->fetch_action( $new_id );
103
+ $this->assertEquals( $action->get_hook(), $retrieved->get_hook() );
104
+ $this->assertEqualSets( $action->get_args(), $retrieved->get_args() );
105
+ $this->assertEquals( $action->get_schedule()->get_date()->format( 'U' ), $retrieved->get_schedule()->get_date()->format( 'U' ) );
106
+ $this->assertEquals( $action->get_group(), $retrieved->get_group() );
107
+ $this->assertTrue( $retrieved->is_finished() );
108
+ $this->assertEquals( \ActionScheduler_Store::STATUS_FAILED, $destination->get_status( $new_id ) );
109
+
110
+ // ensure that the record in the old store does not exist
111
+ $old_action = $source->fetch_action( $action_id );
112
+ $this->assertInstanceOf( 'ActionScheduler_NullAction', $old_action );
113
+ }
114
+
115
+ public function test_migrate_canceled_action_from_wpPost_to_db() {
116
+ $source = new ActionScheduler_wpPostStore();
117
+ $destination = new ActionScheduler_DBStore();
118
+ $migrator = new ActionMigrator( $source, $destination, $this->get_log_migrator() );
119
+
120
+ $time = as_get_datetime_object();
121
+ $schedule = new ActionScheduler_SimpleSchedule( $time );
122
+ $action = new ActionScheduler_Action( 'my_hook', [], $schedule, 'my_group' );
123
+ $action_id = $source->save_action( $action );
124
+ $source->cancel_action( $action_id );
125
+
126
+ $new_id = $migrator->migrate( $action_id );
127
+
128
+ // ensure we get the same record out of the new store as we stored in the old
129
+ $retrieved = $destination->fetch_action( $new_id );
130
+ $this->assertEquals( $action->get_hook(), $retrieved->get_hook() );
131
+ $this->assertEqualSets( $action->get_args(), $retrieved->get_args() );
132
+ $this->assertEquals( $action->get_schedule()->get_date()->format( 'U' ), $retrieved->get_schedule()->get_date()->format( 'U' ) );
133
+ $this->assertEquals( $action->get_group(), $retrieved->get_group() );
134
+ $this->assertTrue( $retrieved->is_finished() );
135
+ $this->assertEquals( \ActionScheduler_Store::STATUS_CANCELED, $destination->get_status( $new_id ) );
136
+
137
+ // ensure that the record in the old store does not exist
138
+ $old_action = $source->fetch_action( $action_id );
139
+ $this->assertInstanceOf( 'ActionScheduler_NullAction', $old_action );
140
+ }
141
+
142
+ private function get_log_migrator() {
143
+ return new LogMigrator( \ActionScheduler::logger(), new ActionScheduler_DBLogger() );
144
+ }
145
+ }
includes/vendor/action-scheduler/tests/phpunit/migration/BatchFetcher_Test.php ADDED
@@ -0,0 +1,76 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ use Action_Scheduler\Migration\BatchFetcher;
4
+ use ActionScheduler_wpPostStore as PostStore;
5
+
6
+ /**
7
+ * Class BatchFetcher_Test
8
+ * @group migration
9
+ */
10
+ class BatchFetcher_Test extends ActionScheduler_UnitTestCase {
11
+ public function setUp() {
12
+ parent::setUp();
13
+ if ( ! taxonomy_exists( PostStore::GROUP_TAXONOMY ) ) {
14
+ // register the post type and taxonomy necessary for the store to work
15
+ $store = new PostStore();
16
+ $store->init();
17
+ }
18
+ }
19
+
20
+ public function test_nothing_to_migrate() {
21
+ $store = new PostStore();
22
+ $batch_fetcher = new BatchFetcher( $store );
23
+
24
+ $actions = $batch_fetcher->fetch();
25
+ $this->assertEmpty( $actions );
26
+ }
27
+
28
+ public function test_get_due_before_future() {
29
+ $store = new PostStore();
30
+ $due = [];
31
+ $future = [];
32
+
33
+ for ( $i = 0; $i < 5; $i ++ ) {
34
+ $time = as_get_datetime_object( $i + 1 . ' minutes' );
35
+ $schedule = new ActionScheduler_SimpleSchedule( $time );
36
+ $action = new ActionScheduler_Action( 'my_hook', [], $schedule );
37
+ $future[] = $store->save_action( $action );
38
+
39
+ $time = as_get_datetime_object( $i + 1 . ' minutes ago' );
40
+ $schedule = new ActionScheduler_SimpleSchedule( $time );
41
+ $action = new ActionScheduler_Action( 'my_hook', [], $schedule );
42
+ $due[] = $store->save_action( $action );
43
+ }
44
+
45
+ $batch_fetcher = new BatchFetcher( $store );
46
+
47
+ $actions = $batch_fetcher->fetch();
48
+
49
+ $this->assertEqualSets( $due, $actions );
50
+ }
51
+
52
+
53
+ public function test_get_future_before_complete() {
54
+ $store = new PostStore();
55
+ $future = [];
56
+ $complete = [];
57
+
58
+ for ( $i = 0; $i < 5; $i ++ ) {
59
+ $time = as_get_datetime_object( $i + 1 . ' minutes' );
60
+ $schedule = new ActionScheduler_SimpleSchedule( $time );
61
+ $action = new ActionScheduler_Action( 'my_hook', [], $schedule );
62
+ $future[] = $store->save_action( $action );
63
+
64
+ $time = as_get_datetime_object( $i + 1 . ' minutes ago' );
65
+ $schedule = new ActionScheduler_SimpleSchedule( $time );
66
+ $action = new ActionScheduler_FinishedAction( 'my_hook', [], $schedule );
67
+ $complete[] = $store->save_action( $action );
68
+ }
69
+
70
+ $batch_fetcher = new BatchFetcher( $store );
71
+
72
+ $actions = $batch_fetcher->fetch();
73
+
74
+ $this->assertEqualSets( $future, $actions );
75
+ }
76
+ }
includes/vendor/action-scheduler/tests/phpunit/migration/Config_Test.php ADDED
@@ -0,0 +1,33 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ use Action_Scheduler\Migration\Config;
4
+
5
+ /**
6
+ * Class Config_Test
7
+ * @group migration
8
+ */
9
+ class Config_Test extends ActionScheduler_UnitTestCase {
10
+ public function test_source_store_required() {
11
+ $config = new Config();
12
+ $this->expectException( \RuntimeException::class );
13
+ $config->get_source_store();
14
+ }
15
+
16
+ public function test_source_logger_required() {
17
+ $config = new Config();
18
+ $this->expectException( \RuntimeException::class );
19
+ $config->get_source_logger();
20
+ }
21
+
22
+ public function test_destination_store_required() {
23
+ $config = new Config();
24
+ $this->expectException( \RuntimeException::class );
25
+ $config->get_destination_store();
26
+ }
27
+
28
+ public function test_destination_logger_required() {
29
+ $config = new Config();
30
+ $this->expectException( \RuntimeException::class );
31
+ $config->get_destination_logger();
32
+ }
33
+ }
includes/vendor/action-scheduler/tests/phpunit/migration/LogMigrator_Test.php ADDED
@@ -0,0 +1,44 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ use Action_Scheduler\Migration\LogMigrator;
4
+
5
+ /**
6
+ * Class LogMigrator_Test
7
+ * @group migration
8
+ */
9
+ class LogMigrator_Test extends ActionScheduler_UnitTestCase {
10
+ function setUp() {
11
+ parent::setUp();
12
+ if ( ! taxonomy_exists( ActionScheduler_wpPostStore::GROUP_TAXONOMY ) ) {
13
+ // register the post type and taxonomy necessary for the store to work
14
+ $store = new ActionScheduler_wpPostStore();
15
+ $store->init();
16
+ }
17
+ }
18
+
19
+ public function test_migrate_from_wpComment_to_db() {
20
+ $source = new ActionScheduler_wpCommentLogger();
21
+ $destination = new ActionScheduler_DBLogger();
22
+ $migrator = new LogMigrator( $source, $destination );
23
+ $source_action_id = rand( 10, 10000 );
24
+ $destination_action_id = rand( 10, 10000 );
25
+
26
+ $logs = [];
27
+ for ( $i = 0 ; $i < 3 ; $i++ ) {
28
+ for ( $j = 0 ; $j < 5 ; $j++ ) {
29
+ $logs[ $i ][ $j ] = md5(rand());
30
+ if ( $i == 1 ) {
31
+ $source->log( $source_action_id, $logs[ $i ][ $j ] );
32
+ }
33
+ }
34
+ }
35
+
36
+ $migrator->migrate( $source_action_id, $destination_action_id );
37
+
38
+ $migrated = $destination->get_logs( $destination_action_id );
39
+ $this->assertEqualSets( $logs[ 1 ], array_map( function( $log ) { return $log->get_message(); }, $migrated ) );
40
+
41
+ // no API for deleting logs, so we leave them for manual cleanup later
42
+ $this->assertCount( 5, $source->get_logs( $source_action_id ) );
43
+ }
44
+ }
includes/vendor/action-scheduler/tests/phpunit/migration/Runner_Test.php ADDED
@@ -0,0 +1,92 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+
4
+ use Action_Scheduler\Migration\Config;
5
+ use Action_Scheduler\Migration\Runner;
6
+ use ActionScheduler_wpCommentLogger as CommentLogger;
7
+ use ActionScheduler_wpPostStore as PostStore;
8
+
9
+ /**
10
+ * Class Runner_Test
11
+ * @group migration
12
+ */
13
+ class Runner_Test extends ActionScheduler_UnitTestCase {
14
+ public function setUp() {
15
+ parent::setUp();
16
+ if ( ! taxonomy_exists( PostStore::GROUP_TAXONOMY ) ) {
17
+ // register the post type and taxonomy necessary for the store to work
18
+ $store = new PostStore();
19
+ $store->init();
20
+ }
21
+ }
22
+
23
+ public function test_migrate_batches() {
24
+ $source_store = new PostStore();
25
+ $destination_store = new ActionScheduler_DBStore();
26
+ $source_logger = new CommentLogger();
27
+ $destination_logger = new ActionScheduler_DBLogger();
28
+
29
+ $config = new Config();
30
+ $config->set_source_store( $source_store );
31
+ $config->set_source_logger( $source_logger );
32
+ $config->set_destination_store( $destination_store );
33
+ $config->set_destination_logger( $destination_logger );
34
+
35
+ $runner = new Runner( $config );
36
+
37
+ $due = [];
38
+ $future = [];
39
+ $complete = [];
40
+
41
+ for ( $i = 0; $i < 5; $i ++ ) {
42
+ $time = as_get_datetime_object( $i + 1 . ' minutes' );
43
+ $schedule = new ActionScheduler_SimpleSchedule( $time );
44
+ $action = new ActionScheduler_Action( 'my_hook', [], $schedule );
45
+ $future[] = $source_store->save_action( $action );
46
+
47
+ $time = as_get_datetime_object( $i + 1 . ' minutes ago' );
48
+ $schedule = new ActionScheduler_SimpleSchedule( $time );
49
+ $action = new ActionScheduler_Action( 'my_hook', [], $schedule );
50
+ $due[] = $source_store->save_action( $action );
51
+
52
+ $time = as_get_datetime_object( $i + 1 . ' minutes ago' );
53
+ $schedule = new ActionScheduler_SimpleSchedule( $time );
54
+ $action = new ActionScheduler_FinishedAction( 'my_hook', [], $schedule );
55
+ $complete[] = $source_store->save_action( $action );
56
+ }
57
+
58
+ $created = $source_store->query_actions( [ 'per_page' => 0 ] );
59
+ $this->assertCount( 15, $created );
60
+
61
+ $runner->run( 10 );
62
+
63
+ // due actions should migrate in the first batch
64
+ $migrated = $destination_store->query_actions( [ 'per_page' => 0 ] );
65
+ $this->assertCount( 5, $migrated );
66
+
67
+ $remaining = $source_store->query_actions( [ 'per_page' => 0 ] );
68
+ $this->assertCount( 10, $remaining );
69
+
70
+
71
+ $runner->run( 10 );
72
+
73
+ // pending actions should migrate in the second batch
74
+ $migrated = $destination_store->query_actions( [ 'per_page' => 0 ] );
75
+ $this->assertCount( 10, $migrated );
76
+
77
+ $remaining = $source_store->query_actions( [ 'per_page' => 0 ] );
78
+ $this->assertCount( 5, $remaining );
79
+
80
+
81
+ $runner->run( 10 );
82
+
83
+ // completed actions should migrate in the third batch
84
+ $migrated = $destination_store->query_actions( [ 'per_page' => 0 ] );
85
+ $this->assertCount( 15, $migrated );
86
+
87
+ $remaining = $source_store->query_actions( [ 'per_page' => 0 ] );
88
+ $this->assertCount( 0, $remaining );
89
+
90
+ }
91
+
92
+ }
includes/vendor/action-scheduler/tests/phpunit/migration/Scheduler_Test.php ADDED
@@ -0,0 +1,122 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ use Action_Scheduler\Migration\Scheduler;
4
+ use ActionScheduler_wpPostStore as PostStore;
5
+
6
+ /**
7
+ * Class Scheduler_Test
8
+ * @group migration
9
+ */
10
+ class Scheduler_Test extends ActionScheduler_UnitTestCase {
11
+ public function setUp() {
12
+ parent::setUp();
13
+ if ( ! taxonomy_exists( PostStore::GROUP_TAXONOMY ) ) {
14
+ // register the post type and taxonomy necessary for the store to work
15
+ $store = new PostStore();
16
+ $store->init();
17
+ }
18
+ }
19
+
20
+ public function test_migration_is_complete() {
21
+ ActionScheduler_DataController::mark_migration_complete();
22
+ $this->assertTrue( ActionScheduler_DataController::is_migration_complete() );
23
+ }
24
+
25
+ public function test_migration_is_not_complete() {
26
+ $this->assertFalse( ActionScheduler_DataController::is_migration_complete() );
27
+ update_option( ActionScheduler_DataController::STATUS_FLAG, 'something_random' );
28
+ $this->assertFalse( ActionScheduler_DataController::is_migration_complete() );
29
+ }
30
+
31
+ public function test_migration_is_scheduled() {
32
+ $scheduler = new Scheduler();
33
+ $scheduler->schedule_migration();
34
+ $this->assertTrue( $scheduler->is_migration_scheduled() );
35
+ }
36
+
37
+ public function test_migration_is_not_scheduled() {
38
+ $scheduler = new Scheduler();
39
+ $this->assertFalse( $scheduler->is_migration_scheduled() );
40
+ }
41
+
42
+ public function test_scheduler_runs_migration() {
43
+ $source_store = new PostStore();
44
+ $destination_store = new ActionScheduler_DBStore();
45
+
46
+ $return_5 = function () {
47
+ return 5;
48
+ };
49
+ add_filter( 'action_scheduler/migration_batch_size', $return_5 );
50
+
51
+ // Make sure successive migration actions are delayed so all actions aren't migrated at once on separate hooks
52
+ $return_60 = function () {
53
+ return 60;
54
+ };
55
+ add_filter( 'action_scheduler/migration_interval', $return_60 );
56
+
57
+ for ( $i = 0; $i < 10; $i ++ ) {
58
+ $time = as_get_datetime_object( $i + 1 . ' minutes' );
59
+ $schedule = new ActionScheduler_SimpleSchedule( $time );
60
+ $action = new ActionScheduler_Action( 'my_hook', [], $schedule );
61
+ $future[] = $source_store->save_action( $action );
62
+
63
+ $time = as_get_datetime_object( $i + 1 . ' minutes ago' );
64
+ $schedule = new ActionScheduler_SimpleSchedule( $time );
65
+ $action = new ActionScheduler_Action( 'my_hook', [], $schedule );
66
+ $due[] = $source_store->save_action( $action );
67
+ }
68
+
69
+ $this->assertCount( 20, $source_store->query_actions( [ 'per_page' => 0 ] ) );
70
+
71
+ $scheduler = new Scheduler();
72
+ $scheduler->schedule_migration();
73
+
74
+ $queue_runner = ActionScheduler_Mocker::get_queue_runner( $destination_store );
75
+ $queue_runner->run();
76
+
77
+ // 5 actions should have moved from the source store when the queue runner triggered the migration action
78
+ $this->assertCount( 15, $source_store->query_actions( [ 'per_page' => 0 ] ) );
79
+
80
+ remove_filter( 'action_scheduler/migration_batch_size', $return_5 );
81
+ remove_filter( 'action_scheduler/migration_interval', $return_60 );
82
+ }
83
+
84
+ public function test_scheduler_marks_itself_complete() {
85
+ $source_store = new PostStore();
86
+ $destination_store = new ActionScheduler_DBStore();
87
+
88
+ for ( $i = 0; $i < 5; $i ++ ) {
89
+ $time = as_get_datetime_object( $i + 1 . ' minutes ago' );
90
+ $schedule = new ActionScheduler_SimpleSchedule( $time );
91
+ $action = new ActionScheduler_Action( 'my_hook', [], $schedule );
92
+ $due[] = $source_store->save_action( $action );
93
+ }
94
+
95
+ $this->assertCount( 5, $source_store->query_actions( [ 'per_page' => 0 ] ) );
96
+
97
+ $scheduler = new Scheduler();
98
+ $scheduler->schedule_migration();
99
+
100
+ $queue_runner = ActionScheduler_Mocker::get_queue_runner( $destination_store );
101
+ $queue_runner->run();
102
+
103
+ // All actions should have moved from the source store when the queue runner triggered the migration action
104
+ $this->assertCount( 0, $source_store->query_actions( [ 'per_page' => 0 ] ) );
105
+
106
+ // schedule another so we can get it to run immediately
107
+ $scheduler->unschedule_migration();
108
+ $scheduler->schedule_migration();
109
+
110
+ // run again so it knows that there's nothing left to process
111
+ $queue_runner->run();
112
+
113
+ $scheduler->unhook();
114
+
115
+ // ensure the flag is set marking migration as complete
116
+ $this->assertTrue( ActionScheduler_DataController::is_migration_complete() );
117
+
118
+ // ensure that another instance has not been scheduled
119
+ $this->assertFalse( $scheduler->is_migration_scheduled() );
120
+
121
+ }
122
+ }
includes/vendor/action-scheduler/tests/phpunit/procedural_api/procedural_api_Test.php CHANGED
@@ -12,7 +12,7 @@ class procedural_api_Test extends ActionScheduler_UnitTestCase {
12
 
13
  $store = ActionScheduler::store();
14
  $action = $store->fetch_action($action_id);
15
- $this->assertEquals( $time, $action->get_schedule()->next()->getTimestamp() );
16
  $this->assertEquals( $hook, $action->get_hook() );
17
  }
18
 
@@ -23,8 +23,8 @@ class procedural_api_Test extends ActionScheduler_UnitTestCase {
23
 
24
  $store = ActionScheduler::store();
25
  $action = $store->fetch_action($action_id);
26
- $this->assertEquals( $time, $action->get_schedule()->next()->getTimestamp() );
27
- $this->assertEquals( $time + HOUR_IN_SECONDS + 2, $action->get_schedule()->next(as_get_datetime_object($time + 2))->getTimestamp());
28
  $this->assertEquals( $hook, $action->get_hook() );
29
  }
30
 
@@ -36,8 +36,11 @@ class procedural_api_Test extends ActionScheduler_UnitTestCase {
36
  $store = ActionScheduler::store();
37
  $action = $store->fetch_action($action_id);
38
  $expected_date = as_get_datetime_object('2014-10-10');
39
- $this->assertEquals( $expected_date->getTimestamp(), $action->get_schedule()->next()->getTimestamp() );
40
  $this->assertEquals( $hook, $action->get_hook() );
 
 
 
41
  }
42
 
43
  public function test_get_next() {
@@ -50,6 +53,32 @@ class procedural_api_Test extends ActionScheduler_UnitTestCase {
50
  $this->assertEquals( $time->getTimestamp(), $next );
51
  }
52
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
53
  public function provider_time_hook_args_group() {
54
  $time = time() + 60 * 2;
55
  $hook = md5( rand() );
@@ -111,13 +140,16 @@ class procedural_api_Test extends ActionScheduler_UnitTestCase {
111
 
112
  // Make sure the next scheduled action is unscheduled
113
  $this->assertEquals( $hook, $unscheduled_action->get_hook() );
114
- $this->assertNull( $unscheduled_action->get_schedule()->next() );
 
 
115
 
116
  // Make sure other scheduled actions are not unscheduled
 
117
  $scheduled_action = $store->fetch_action( $action_id_scheduled );
118
 
119
  $this->assertEquals( $hook, $scheduled_action->get_hook() );
120
- $this->assertEquals( $action_scheduled_time, $scheduled_action->get_schedule()->next()->getTimestamp() );
121
  }
122
 
123
  /**
@@ -137,13 +169,18 @@ class procedural_api_Test extends ActionScheduler_UnitTestCase {
137
  $next = as_next_scheduled_action( $hook );
138
  $this->assertFalse($next);
139
 
 
 
 
140
  $store = ActionScheduler::store();
141
 
142
  foreach ( $action_ids as $action_id ) {
143
  $action = $store->fetch_action($action_id);
144
 
145
- $this->assertNull($action->get_schedule()->next());
146
- $this->assertEquals($hook, $action->get_hook() );
 
 
147
  }
148
  }
149
 
@@ -201,7 +238,7 @@ class procedural_api_Test extends ActionScheduler_UnitTestCase {
201
  $au_now = new ActionScheduler_DateTime(null);
202
  $as_au_now = as_get_datetime_object();
203
 
204
- $this->assertEquals($au_now->getTimestamp(),$as_now->getTimestamp());
205
 
206
  // But not in the same timezone, as $as_now should be using UTC
207
  $this->assertNotEquals($au_now->format('Y-m-d H:i:s'),$as_now->format('Y-m-d H:i:s'));
12
 
13
  $store = ActionScheduler::store();
14
  $action = $store->fetch_action($action_id);
15
+ $this->assertEquals( $time, $action->get_schedule()->get_date()->getTimestamp() );
16
  $this->assertEquals( $hook, $action->get_hook() );
17
  }
18
 
23
 
24
  $store = ActionScheduler::store();
25
  $action = $store->fetch_action($action_id);
26
+ $this->assertEquals( $time, $action->get_schedule()->get_date()->getTimestamp() );
27
+ $this->assertEquals( $time + HOUR_IN_SECONDS + 2, $action->get_schedule()->get_next(as_get_datetime_object($time + 2))->getTimestamp());
28
  $this->assertEquals( $hook, $action->get_hook() );
29
  }
30
 
36
  $store = ActionScheduler::store();
37
  $action = $store->fetch_action($action_id);
38
  $expected_date = as_get_datetime_object('2014-10-10');
39
+ $this->assertEquals( $expected_date->getTimestamp(), $action->get_schedule()->get_date()->getTimestamp() );
40
  $this->assertEquals( $hook, $action->get_hook() );
41
+
42
+ $expected_date = as_get_datetime_object( '2015-10-10' );
43
+ $this->assertEquals( $expected_date->getTimestamp(), $action->get_schedule()->get_next( as_get_datetime_object( '2015-01-02' ) )->getTimestamp() );
44
  }
45
 
46
  public function test_get_next() {
53
  $this->assertEquals( $time->getTimestamp(), $next );
54
  }
55
 
56
+ public function test_get_next_async() {
57
+ $hook = md5(rand());
58
+ $action_id = as_enqueue_async_action( $hook );
59
+
60
+ $next = as_next_scheduled_action( $hook );
61
+
62
+ $this->assertTrue( $next );
63
+
64
+ $store = ActionScheduler::store();
65
+
66
+ // Completed async actions should still return false
67
+ $store->mark_complete( $action_id );
68
+ $next = as_next_scheduled_action( $hook );
69
+ $this->assertFalse( $next );
70
+
71
+ // Failed async actions should still return false
72
+ $store->mark_failure( $action_id );
73
+ $next = as_next_scheduled_action( $hook );
74
+ $this->assertFalse( $next );
75
+
76
+ // Cancelled async actions should still return false
77
+ $store->cancel_action( $action_id );
78
+ $next = as_next_scheduled_action( $hook );
79
+ $this->assertFalse( $next );
80
+ }
81
+
82
  public function provider_time_hook_args_group() {
83
  $time = time() + 60 * 2;
84
  $hook = md5( rand() );
140
 
141
  // Make sure the next scheduled action is unscheduled
142
  $this->assertEquals( $hook, $unscheduled_action->get_hook() );
143
+ $this->assertEquals( as_get_datetime_object($time), $unscheduled_action->get_schedule()->get_date() );
144
+ $this->assertEquals( ActionScheduler_Store::STATUS_CANCELED, $store->get_status( $action_id_unscheduled ) );
145
+ $this->assertNull( $unscheduled_action->get_schedule()->get_next( as_get_datetime_object() ) );
146
 
147
  // Make sure other scheduled actions are not unscheduled
148
+ $this->assertEquals( ActionScheduler_Store::STATUS_PENDING, $store->get_status( $action_id_scheduled ) );
149
  $scheduled_action = $store->fetch_action( $action_id_scheduled );
150
 
151
  $this->assertEquals( $hook, $scheduled_action->get_hook() );
152
+ $this->assertEquals( $action_scheduled_time, $scheduled_action->get_schedule()->get_date()->getTimestamp() );
153
  }
154
 
155
  /**
169
  $next = as_next_scheduled_action( $hook );
170
  $this->assertFalse($next);
171
 
172
+ $after = as_get_datetime_object( $time );
173
+ $after->modify( '+1 minute' );
174
+
175
  $store = ActionScheduler::store();
176
 
177
  foreach ( $action_ids as $action_id ) {
178
  $action = $store->fetch_action($action_id);
179
 
180
+ $this->assertEquals( $hook, $action->get_hook() );
181
+ $this->assertEquals( as_get_datetime_object( $time ), $action->get_schedule()->get_date() );
182
+ $this->assertEquals( ActionScheduler_Store::STATUS_CANCELED, $store->get_status( $action_id ) );
183
+ $this->assertNull( $action->get_schedule()->get_next( $after ) );
184
  }
185
  }
186
 
238
  $au_now = new ActionScheduler_DateTime(null);
239
  $as_au_now = as_get_datetime_object();
240
 
241
+ $this->assertEquals( $au_now->getTimestamp(), $as_now->getTimestamp(), '', 2 );
242
 
243
  // But not in the same timezone, as $as_now should be using UTC
244
  $this->assertNotEquals($au_now->format('Y-m-d H:i:s'),$as_now->format('Y-m-d H:i:s'));
includes/vendor/action-scheduler/tests/phpunit/runner/ActionScheduler_QueueCleaner_Test.php CHANGED
@@ -7,7 +7,7 @@ class ActionScheduler_QueueCleaner_Test extends ActionScheduler_UnitTestCase {
7
 
8
  public function test_delete_old_actions() {
9
  $store = ActionScheduler::store();
10
- $runner = new ActionScheduler_QueueRunner( $store );
11
 
12
  $random = md5(rand());
13
  $schedule = new ActionScheduler_SimpleSchedule(as_get_datetime_object('1 day ago'));
@@ -62,7 +62,7 @@ class ActionScheduler_QueueCleaner_Test extends ActionScheduler_UnitTestCase {
62
 
63
  public function test_do_not_delete_recent_actions() {
64
  $store = ActionScheduler::store();
65
- $runner = new ActionScheduler_QueueRunner( $store );
66
 
67
  $random = md5(rand());
68
  $schedule = new ActionScheduler_SimpleSchedule(as_get_datetime_object('1 day ago'));
7
 
8
  public function test_delete_old_actions() {
9
  $store = ActionScheduler::store();
10
+ $runner = ActionScheduler_Mocker::get_queue_runner( $store );
11
 
12
  $random = md5(rand());
13
  $schedule = new ActionScheduler_SimpleSchedule(as_get_datetime_object('1 day ago'));
62
 
63
  public function test_do_not_delete_recent_actions() {
64
  $store = ActionScheduler::store();
65
+ $runner = ActionScheduler_Mocker::get_queue_runner( $store );
66
 
67
  $random = md5(rand());
68
  $schedule = new ActionScheduler_SimpleSchedule(as_get_datetime_object('1 day ago'));
includes/vendor/action-scheduler/tests/phpunit/runner/ActionScheduler_QueueRunner_Test.php CHANGED
@@ -7,7 +7,7 @@
7
  class ActionScheduler_QueueRunner_Test extends ActionScheduler_UnitTestCase {
8
  public function test_create_runner() {
9
  $store = ActionScheduler::store();
10
- $runner = new ActionScheduler_QueueRunner( $store );
11
  $actions_run = $runner->run();
12
 
13
  $this->assertEquals( 0, $actions_run );
@@ -15,7 +15,7 @@ class ActionScheduler_QueueRunner_Test extends ActionScheduler_UnitTestCase {
15
 
16
  public function test_run() {
17
  $store = ActionScheduler::store();
18
- $runner = new ActionScheduler_QueueRunner( $store );
19
 
20
  $mock = new MockAction();
21
  $random = md5(rand());
@@ -37,7 +37,7 @@ class ActionScheduler_QueueRunner_Test extends ActionScheduler_UnitTestCase {
37
 
38
  public function test_run_with_future_actions() {
39
  $store = ActionScheduler::store();
40
- $runner = new ActionScheduler_QueueRunner( $store );
41
 
42
  $mock = new MockAction();
43
  $random = md5(rand());
@@ -65,7 +65,7 @@ class ActionScheduler_QueueRunner_Test extends ActionScheduler_UnitTestCase {
65
 
66
  public function test_completed_action_status() {
67
  $store = ActionScheduler::store();
68
- $runner = new ActionScheduler_QueueRunner( $store );
69
 
70
  $random = md5(rand());
71
  $schedule = new ActionScheduler_SimpleSchedule(as_get_datetime_object('12 hours ago'));
@@ -80,77 +80,145 @@ class ActionScheduler_QueueRunner_Test extends ActionScheduler_UnitTestCase {
80
  $this->assertTrue( $finished_action->is_finished() );
81
  }
82
 
83
- public function test_next_instance_of_action() {
84
- $store = ActionScheduler::store();
85
- $runner = new ActionScheduler_QueueRunner( $store );
 
 
 
86
 
87
- $random = md5(rand());
88
- $schedule = new ActionScheduler_IntervalSchedule(as_get_datetime_object('12 hours ago'), DAY_IN_SECONDS);
 
 
 
89
 
90
- $action = new ActionScheduler_Action( $random, array(), $schedule );
91
- $store->save_action( $action );
92
 
93
- $runner->run();
 
 
 
 
 
 
 
 
 
 
 
 
 
94
 
95
- $claim = $store->stake_claim(10, as_get_datetime_object((DAY_IN_SECONDS - 60).' seconds'));
96
- $this->assertCount(0, $claim->get_actions());
97
 
98
- $claim = $store->stake_claim(10, as_get_datetime_object(DAY_IN_SECONDS.' seconds'));
99
  $actions = $claim->get_actions();
100
- $this->assertCount(1, $actions);
101
 
102
- $action_id = reset($actions);
103
- $new_action = $store->fetch_action($action_id);
104
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
105
 
106
- $this->assertEquals( $random, $new_action->get_hook() );
107
- $this->assertEquals( $schedule->next(as_get_datetime_object())->getTimestamp(), $new_action->get_schedule()->next(as_get_datetime_object())->getTimestamp() );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
108
  }
109
 
110
  public function test_hooked_into_wp_cron() {
111
- $next = wp_next_scheduled( ActionScheduler_QueueRunner::WP_CRON_HOOK );
112
  $this->assertNotEmpty($next);
113
  }
114
 
115
  public function test_batch_count_limit() {
116
  $store = ActionScheduler::store();
117
- $runner = new ActionScheduler_QueueRunner( $store );
118
 
119
  $mock = new MockAction();
120
  $random = md5(rand());
121
  add_action( $random, array( $mock, 'action' ) );
122
  $schedule = new ActionScheduler_SimpleSchedule(new ActionScheduler_DateTime('1 day ago'));
123
 
124
- for ( $i = 0 ; $i < 30 ; $i++ ) {
125
  $action = new ActionScheduler_Action( $random, array($random), $schedule );
126
  $store->save_action( $action );
127
  }
128
 
129
- $claims = array();
130
-
131
- for ( $i = 0 ; $i < 5 ; $i++ ) {
132
- $claims[] = $store->stake_claim( 5 );
133
- }
134
 
135
  $actions_run = $runner->run();
136
 
137
-
138
  $this->assertEquals( 0, $mock->get_call_count() );
139
  $this->assertEquals( 0, $actions_run );
140
 
141
- $first = reset($claims);
142
- $store->release_claim( $first );
143
 
144
  $actions_run = $runner->run();
145
- $this->assertEquals( 10, $mock->get_call_count() );
146
- $this->assertEquals( 10, $actions_run );
 
147
 
148
  remove_action( $random, array( $mock, 'action' ) );
149
  }
150
 
151
  public function test_changing_batch_count_limit() {
152
  $store = ActionScheduler::store();
153
- $runner = new ActionScheduler_QueueRunner( $store );
154
 
155
  $random = md5(rand());
156
  $schedule = new ActionScheduler_SimpleSchedule(new ActionScheduler_DateTime('1 day ago'));
7
  class ActionScheduler_QueueRunner_Test extends ActionScheduler_UnitTestCase {
8
  public function test_create_runner() {
9
  $store = ActionScheduler::store();
10
+ $runner = ActionScheduler_Mocker::get_queue_runner( $store );
11
  $actions_run = $runner->run();
12
 
13
  $this->assertEquals( 0, $actions_run );
15
 
16
  public function test_run() {
17
  $store = ActionScheduler::store();
18
+ $runner = ActionScheduler_Mocker::get_queue_runner( $store );
19
 
20
  $mock = new MockAction();
21
  $random = md5(rand());
37
 
38
  public function test_run_with_future_actions() {
39
  $store = ActionScheduler::store();
40
+ $runner = ActionScheduler_Mocker::get_queue_runner( $store );
41
 
42
  $mock = new MockAction();
43
  $random = md5(rand());
65
 
66
  public function test_completed_action_status() {
67
  $store = ActionScheduler::store();
68
+ $runner = ActionScheduler_Mocker::get_queue_runner( $store );
69
 
70
  $random = md5(rand());
71
  $schedule = new ActionScheduler_SimpleSchedule(as_get_datetime_object('12 hours ago'));
80
  $this->assertTrue( $finished_action->is_finished() );
81
  }
82
 
83
+ public function test_next_instance_of_cron_action() {
84
+ // Create an action with daily Cron expression (i.e. midnight each day)
85
+ $random = md5( rand() );
86
+ $action_id = ActionScheduler::factory()->cron( $random, array(), null, '0 0 * * *' );
87
+ $store = ActionScheduler::store();
88
+ $runner = ActionScheduler_Mocker::get_queue_runner( $store );
89
 
90
+ // Make sure the 1st instance of the action is scheduled to occur tomorrow
91
+ $date = as_get_datetime_object( 'tomorrow' );
92
+ $date->modify( '-1 minute' );
93
+ $claim = $store->stake_claim( 10, $date );
94
+ $this->assertCount( 0, $claim->get_actions() );
95
 
96
+ $store->release_claim( $claim );
 
97
 
98
+ $date->modify( '+1 minute' );
99
+
100
+ $claim = $store->stake_claim( 10, $date );
101
+ $actions = $claim->get_actions();
102
+ $this->assertCount( 1, $actions );
103
+
104
+ $fetched_action_id = reset( $actions );
105
+ $fetched_action = $store->fetch_action( $fetched_action_id );
106
+
107
+ $this->assertEquals( $fetched_action_id, $action_id );
108
+ $this->assertEquals( $random, $fetched_action->get_hook() );
109
+ $this->assertEquals( $date->getTimestamp(), $fetched_action->get_schedule()->get_date()->getTimestamp(), '', 1 );
110
+
111
+ $store->release_claim( $claim );
112
 
113
+ // Make sure the 2nd instance of the cron action is scheduled to occur tomorrow still
114
+ $runner->process_action( $action_id );
115
 
116
+ $claim = $store->stake_claim( 10, $date );
117
  $actions = $claim->get_actions();
118
+ $this->assertCount( 1, $actions );
119
 
120
+ $fetched_action_id = reset( $actions );
121
+ $fetched_action = $store->fetch_action( $fetched_action_id );
122
 
123
+ $this->assertNotEquals( $fetched_action_id, $action_id );
124
+ $this->assertEquals( $random, $fetched_action->get_hook() );
125
+ $this->assertEquals( $date->getTimestamp(), $fetched_action->get_schedule()->get_date()->getTimestamp(), '', 1 );
126
+ }
127
+
128
+ public function test_next_instance_of_interval_action() {
129
+ // Create an action to recur every 24 hours, with the first instance scheduled to run 12 hours ago
130
+ $random = md5( rand() );
131
+ $date = as_get_datetime_object( '12 hours ago' );
132
+ $action_id = ActionScheduler::factory()->recurring( $random, array(), $date->getTimestamp(), DAY_IN_SECONDS );
133
+ $store = ActionScheduler::store();
134
+ $runner = ActionScheduler_Mocker::get_queue_runner( $store );
135
+
136
+ // Make sure the 1st instance of the action is scheduled to occur 12 hours ago
137
+ $claim = $store->stake_claim( 10, $date );
138
+ $actions = $claim->get_actions();
139
+ $this->assertCount( 1, $actions );
140
 
141
+ $fetched_action_id = reset( $actions );
142
+ $fetched_action = $store->fetch_action( $fetched_action_id );
143
+
144
+ $this->assertEquals( $fetched_action_id, $action_id );
145
+ $this->assertEquals( $random, $fetched_action->get_hook() );
146
+ $this->assertEquals( $date->getTimestamp(), $fetched_action->get_schedule()->get_date()->getTimestamp(), '', 1 );
147
+
148
+ $store->release_claim( $claim );
149
+
150
+ // Make sure after the queue is run, the 2nd instance of the action is scheduled to occur in 24 hours
151
+ $runner->run();
152
+
153
+ $date = as_get_datetime_object( '+1 day' );
154
+ $claim = $store->stake_claim( 10, $date );
155
+ $actions = $claim->get_actions();
156
+ $this->assertCount( 1, $actions );
157
+
158
+ $fetched_action_id = reset( $actions );
159
+ $fetched_action = $store->fetch_action( $fetched_action_id );
160
+
161
+ $this->assertNotEquals( $fetched_action_id, $action_id );
162
+ $this->assertEquals( $random, $fetched_action->get_hook() );
163
+ $this->assertEquals( $date->getTimestamp(), $fetched_action->get_schedule()->get_date()->getTimestamp(), '', 1 );
164
+
165
+ $store->release_claim( $claim );
166
+
167
+ // Make sure the 3rd instance of the cron action is scheduled for 24 hours from now, as the action was run early, ahead of schedule
168
+ $runner->process_action( $action_id );
169
+ $date = as_get_datetime_object( '+1 day' );
170
+
171
+ $claim = $store->stake_claim( 10, $date );
172
+ $actions = $claim->get_actions();
173
+ $this->assertCount( 1, $actions );
174
+
175
+ $fetched_action_id = reset( $actions );
176
+ $fetched_action = $store->fetch_action( $fetched_action_id );
177
+
178
+ $this->assertNotEquals( $fetched_action_id, $action_id );
179
+ $this->assertEquals( $random, $fetched_action->get_hook() );
180
+ $this->assertEquals( $date->getTimestamp(), $fetched_action->get_schedule()->get_date()->getTimestamp(), '', 1 );
181
  }
182
 
183
  public function test_hooked_into_wp_cron() {
184
+ $next = wp_next_scheduled( ActionScheduler_QueueRunner::WP_CRON_HOOK, array( 'WP Cron' ) );
185
  $this->assertNotEmpty($next);
186
  }
187
 
188
  public function test_batch_count_limit() {
189
  $store = ActionScheduler::store();
190
+ $runner = ActionScheduler_Mocker::get_queue_runner( $store );
191
 
192
  $mock = new MockAction();
193
  $random = md5(rand());
194
  add_action( $random, array( $mock, 'action' ) );
195
  $schedule = new ActionScheduler_SimpleSchedule(new ActionScheduler_DateTime('1 day ago'));
196
 
197
+ for ( $i = 0 ; $i < 2 ; $i++ ) {
198
  $action = new ActionScheduler_Action( $random, array($random), $schedule );
199
  $store->save_action( $action );
200
  }
201
 
202
+ $claim = $store->stake_claim();
 
 
 
 
203
 
204
  $actions_run = $runner->run();
205
 
 
206
  $this->assertEquals( 0, $mock->get_call_count() );
207
  $this->assertEquals( 0, $actions_run );
208
 
209
+ $store->release_claim( $claim );
 
210
 
211
  $actions_run = $runner->run();
212
+
213
+ $this->assertEquals( 2, $mock->get_call_count() );
214
+ $this->assertEquals( 2, $actions_run );
215
 
216
  remove_action( $random, array( $mock, 'action' ) );
217
  }
218
 
219
  public function test_changing_batch_count_limit() {
220
  $store = ActionScheduler::store();
221
+ $runner = ActionScheduler_Mocker::get_queue_runner( $store );
222
 
223
  $random = md5(rand());
224
  $schedule = new ActionScheduler_SimpleSchedule(new ActionScheduler_DateTime('1 day ago'));
includes/vendor/action-scheduler/tests/phpunit/schedules/ActionScheduler_CronSchedule_Test.php CHANGED
@@ -8,15 +8,46 @@ class ActionScheduler_CronSchedule_Test extends ActionScheduler_UnitTestCase {
8
  public function test_creation() {
9
  $time = as_get_datetime_object('tomorrow');
10
  $cron = CronExpression::factory('@daily');
11
- $schedule = new ActionScheduler_CronSchedule(as_get_datetime_object(), $cron);
12
- $this->assertEquals( $time, $schedule->next() );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
13
  }
14
 
15
  public function test_next() {
16
  $time = as_get_datetime_object('2013-06-14');
17
  $cron = CronExpression::factory('@daily');
18
  $schedule = new ActionScheduler_CronSchedule($time, $cron);
19
- $this->assertEquals( as_get_datetime_object('tomorrow'), $schedule->next( as_get_datetime_object() ) );
20
  }
21
 
22
  public function test_is_recurring() {
@@ -28,18 +59,18 @@ class ActionScheduler_CronSchedule_Test extends ActionScheduler_UnitTestCase {
28
  $time = as_get_datetime_object('2014-01-01');
29
  $cron = CronExpression::factory('0 0 10 10 *');
30
  $schedule = new ActionScheduler_CronSchedule($time, $cron);
31
- $this->assertEquals( as_get_datetime_object('2014-10-10'), $schedule->next() );
32
 
33
  $cron = CronExpression::factory('0 0 L 1/2 *');
34
  $schedule = new ActionScheduler_CronSchedule($time, $cron);
35
- $this->assertEquals( as_get_datetime_object('2014-01-31'), $schedule->next() );
36
- $this->assertEquals( as_get_datetime_object('2014-07-31'), $schedule->next( as_get_datetime_object('2014-06-01') ) );
37
- $this->assertEquals( as_get_datetime_object('2028-11-30'), $schedule->next( as_get_datetime_object('2028-11-01') ) );
38
 
39
  $cron = CronExpression::factory('30 14 * * MON#3 *');
40
  $schedule = new ActionScheduler_CronSchedule($time, $cron);
41
- $this->assertEquals( as_get_datetime_object('2014-01-20 14:30:00'), $schedule->next() );
42
- $this->assertEquals( as_get_datetime_object('2014-05-19 14:30:00'), $schedule->next( as_get_datetime_object('2014-05-01') ) );
43
  }
44
  }
45
 
8
  public function test_creation() {
9
  $time = as_get_datetime_object('tomorrow');
10
  $cron = CronExpression::factory('@daily');
11
+ $start = clone $time;
12
+ $start->modify( '-1 hour' );
13
+ $schedule = new ActionScheduler_CronSchedule( $start, $cron );
14
+ $this->assertEquals( $time, $schedule->get_date() );
15
+ $this->assertEquals( $start, $schedule->get_first_date() );
16
+
17
+ // Test delaying for a future start date
18
+ $start->modify( '+1 week' );
19
+ $time->modify( '+1 week' );
20
+
21
+ $schedule = new ActionScheduler_CronSchedule( $start, $cron );
22
+ $this->assertEquals( $time, $schedule->get_date() );
23
+ $this->assertEquals( $start, $schedule->get_first_date() );
24
+ }
25
+
26
+ public function test_creation_with_first_date() {
27
+ $time = as_get_datetime_object( 'tomorrow' );
28
+ $cron = CronExpression::factory( '@daily' );
29
+ $start = clone $time;
30
+ $start->modify( '-1 hour' );
31
+ $schedule = new ActionScheduler_CronSchedule( $start, $cron );
32
+ $this->assertEquals( $time, $schedule->get_date() );
33
+ $this->assertEquals( $start, $schedule->get_first_date() );
34
+
35
+ // Test delaying for a future start date
36
+ $first = clone $time;
37
+ $first->modify( '-1 day' );
38
+ $start->modify( '+1 week' );
39
+ $time->modify( '+1 week' );
40
+
41
+ $schedule = new ActionScheduler_CronSchedule( $start, $cron, $first );
42
+ $this->assertEquals( $time, $schedule->get_date() );
43
+ $this->assertEquals( $first, $schedule->get_first_date() );
44
  }
45
 
46
  public function test_next() {
47
  $time = as_get_datetime_object('2013-06-14');
48
  $cron = CronExpression::factory('@daily');
49
  $schedule = new ActionScheduler_CronSchedule($time, $cron);
50
+ $this->assertEquals( as_get_datetime_object('tomorrow'), $schedule->get_next( as_get_datetime_object() ) );
51
  }
52
 
53
  public function test_is_recurring() {
59
  $time = as_get_datetime_object('2014-01-01');
60
  $cron = CronExpression::factory('0 0 10 10 *');
61
  $schedule = new ActionScheduler_CronSchedule($time, $cron);
62
+ $this->assertEquals( as_get_datetime_object('2014-10-10'), $schedule->get_date() );
63
 
64
  $cron = CronExpression::factory('0 0 L 1/2 *');
65
  $schedule = new ActionScheduler_CronSchedule($time, $cron);
66
+ $this->assertEquals( as_get_datetime_object('2014-01-31'), $schedule->get_date() );
67
+ $this->assertEquals( as_get_datetime_object('2014-07-31'), $schedule->get_next( as_get_datetime_object('2014-06-01') ) );
68
+ $this->assertEquals( as_get_datetime_object('2028-11-30'), $schedule->get_next( as_get_datetime_object('2028-11-01') ) );
69
 
70
  $cron = CronExpression::factory('30 14 * * MON#3 *');
71
  $schedule = new ActionScheduler_CronSchedule($time, $cron);
72
+ $this->assertEquals( as_get_datetime_object('2014-01-20 14:30:00'), $schedule->get_date() );
73
+ $this->assertEquals( as_get_datetime_object('2014-05-19 14:30:00'), $schedule->get_next( as_get_datetime_object('2014-05-01') ) );
74
  }
75
  }
76
 
includes/vendor/action-scheduler/tests/phpunit/schedules/ActionScheduler_IntervalSchedule_Test.php CHANGED
@@ -8,16 +8,25 @@ class ActionScheduler_IntervalSchedule_Test extends ActionScheduler_UnitTestCase
8
  public function test_creation() {
9
  $time = as_get_datetime_object();
10
  $schedule = new ActionScheduler_IntervalSchedule($time, HOUR_IN_SECONDS);
11
- $this->assertEquals( $time, $schedule->next() );
 
 
 
 
 
 
 
 
 
12
  }
13
 
14
  public function test_next() {
15
  $now = time();
16
  $start = $now - 30;
17
  $schedule = new ActionScheduler_IntervalSchedule( as_get_datetime_object("@$start"), MINUTE_IN_SECONDS );
18
- $this->assertEquals( $start, $schedule->next()->getTimestamp() );
19
- $this->assertEquals( $now + MINUTE_IN_SECONDS, $schedule->next(as_get_datetime_object())->getTimestamp() );
20
- $this->assertEquals( $start, $schedule->next(as_get_datetime_object("@$start"))->getTimestamp() );
21
  }
22
 
23
  public function test_is_recurring() {
8
  public function test_creation() {
9
  $time = as_get_datetime_object();
10
  $schedule = new ActionScheduler_IntervalSchedule($time, HOUR_IN_SECONDS);
11
+ $this->assertEquals( $time, $schedule->get_date() );
12
+ $this->assertEquals( $time, $schedule->get_first_date() );
13
+ }
14
+
15
+ public function test_creation_with_first_date() {
16
+ $first = as_get_datetime_object();
17
+ $time = as_get_datetime_object( '+12 hours' );
18
+ $schedule = new ActionScheduler_IntervalSchedule( $time, HOUR_IN_SECONDS, $first );
19
+ $this->assertEquals( $time, $schedule->get_date() );
20
+ $this->assertEquals( $first, $schedule->get_first_date() );
21
  }
22
 
23
  public function test_next() {
24
  $now = time();
25
  $start = $now - 30;
26
  $schedule = new ActionScheduler_IntervalSchedule( as_get_datetime_object("@$start"), MINUTE_IN_SECONDS );
27
+ $this->assertEquals( $start, $schedule->get_date()->getTimestamp() );
28
+ $this->assertEquals( $now + MINUTE_IN_SECONDS, $schedule->get_next(as_get_datetime_object())->getTimestamp() );
29
+ $this->assertEquals( $start, $schedule->get_next( as_get_datetime_object( "@$start" ) )->getTimestamp() );
30
  }
31
 
32
  public function test_is_recurring() {
includes/vendor/action-scheduler/tests/phpunit/schedules/ActionScheduler_NullSchedule_Test.php CHANGED
@@ -7,7 +7,7 @@
7
  class ActionScheduler_NullSchedule_Test extends ActionScheduler_UnitTestCase {
8
  public function test_null_schedule() {
9
  $schedule = new ActionScheduler_NullSchedule();
10
- $this->assertNull( $schedule->next() );
11
  }
12
 
13
  public function test_is_recurring() {
7
  class ActionScheduler_NullSchedule_Test extends ActionScheduler_UnitTestCase {
8
  public function test_null_schedule() {
9
  $schedule = new ActionScheduler_NullSchedule();
10
+ $this->assertNull( $schedule->get_date() );
11
  }
12
 
13
  public function test_is_recurring() {
includes/vendor/action-scheduler/tests/phpunit/schedules/ActionScheduler_SimpleSchedule_Test.php CHANGED
@@ -8,25 +8,25 @@ class ActionScheduler_SimpleSchedule_Test extends ActionScheduler_UnitTestCase {
8
  public function test_creation() {
9
  $time = as_get_datetime_object();
10
  $schedule = new ActionScheduler_SimpleSchedule($time);
11
- $this->assertEquals( $time, $schedule->next() );
12
  }
13
 
14
  public function test_past_date() {
15
  $time = as_get_datetime_object('-1 day');
16
  $schedule = new ActionScheduler_SimpleSchedule($time);
17
- $this->assertEquals( $time, $schedule->next() );
18
  }
19
 
20
  public function test_future_date() {
21
  $time = as_get_datetime_object('+1 day');
22
  $schedule = new ActionScheduler_SimpleSchedule($time);
23
- $this->assertEquals( $time, $schedule->next() );
24
  }
25
 
26
  public function test_grace_period_for_next() {
27
  $time = as_get_datetime_object('3 seconds ago');
28
  $schedule = new ActionScheduler_SimpleSchedule($time);
29
- $this->assertEquals( $time, $schedule->next() );
30
  }
31
 
32
  public function test_is_recurring() {
8
  public function test_creation() {
9
  $time = as_get_datetime_object();
10
  $schedule = new ActionScheduler_SimpleSchedule($time);
11
+ $this->assertEquals( $time, $schedule->get_date() );
12
  }
13
 
14
  public function test_past_date() {
15
  $time = as_get_datetime_object('-1 day');
16
  $schedule = new ActionScheduler_SimpleSchedule($time);
17
+ $this->assertEquals( $time, $schedule->get_date() );
18
  }
19
 
20
  public function test_future_date() {
21
  $time = as_get_datetime_object('+1 day');
22
  $schedule = new ActionScheduler_SimpleSchedule($time);
23
+ $this->assertEquals( $time, $schedule->get_date() );
24
  }
25
 
26
  public function test_grace_period_for_next() {
27
  $time = as_get_datetime_object('3 seconds ago');
28
  $schedule = new ActionScheduler_SimpleSchedule($time);
29
+ $this->assertEquals( $time, $schedule->get_date() );
30
  }
31
 
32
  public function test_is_recurring() {
languages/mc-woocommerce.pot CHANGED
@@ -1,15 +1,15 @@
1
- # Copyright (C) 2019 Mailchimp
2
  # This file is distributed under the same license as the Mailchimp for WooCommerce plugin.
3
  msgid ""
4
  msgstr ""
5
- "Project-Id-Version: Mailchimp for WooCommerce 2.3.1\n"
6
  "Report-Msgid-Bugs-To: https://wordpress.org/support/plugin/mailchimp-for-woocommerce\n"
7
  "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
8
  "Language-Team: LANGUAGE <LL@li.org>\n"
9
  "MIME-Version: 1.0\n"
10
  "Content-Type: text/plain; charset=UTF-8\n"
11
  "Content-Transfer-Encoding: 8bit\n"
12
- "POT-Creation-Date: 2019-11-06T10:22:06+00:00\n"
13
  "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
14
  "X-Generator: WP-CLI 2.1.0\n"
15
  "X-Domain: mailchimp-for-woocommerce\n"
@@ -96,7 +96,7 @@ msgid "If you have a moment, please share why you are deactivating %s:"
96
  msgstr ""
97
 
98
  #: includes/class-mailchimp-woocommerce-deactivation-survey.php:379
99
- #: admin/class-mailchimp-woocommerce-admin.php:270
100
  msgid "Mailchimp for Woocommerce"
101
  msgstr ""
102
 
@@ -122,92 +122,100 @@ msgid "User ID"
122
  msgstr ""
123
 
124
  #: includes/class-mailchimp-woocommerce-newsletter.php:43
125
- #: admin/class-mailchimp-woocommerce-admin.php:748
126
  #: admin/partials/tabs/newsletter_settings.php:97
127
  msgid "Subscribe to our newsletter"
128
  msgstr ""
129
 
130
  #: includes/class-mailchimp-woocommerce-rest-api.php:141
131
- #: admin/partials/tabs/store_sync.php:169
132
  msgid "D, M j, Y g:i A"
133
  msgstr ""
134
 
135
- #: admin/class-mailchimp-woocommerce-admin.php:123
136
  msgid "Mailchimp - WooCommerce Setup"
137
  msgstr ""
138
 
139
- #: admin/class-mailchimp-woocommerce-admin.php:271
140
  msgid "We dectected that this site has the following constants defined, likely at wp-config.php file"
141
  msgstr ""
142
 
143
- #: admin/class-mailchimp-woocommerce-admin.php:273
144
  msgid "These constants are deprecated since Mailchimp for Woocommerce version 2.3. Please refer to the <a href=\"https://github.com/mailchimp/mc-woocommerce/wiki/\">plugin official wiki</a> for further details."
145
  msgstr ""
146
 
147
- #: admin/class-mailchimp-woocommerce-admin.php:393
148
  msgid "Store Disconnected"
149
  msgstr ""
150
 
151
- #: admin/class-mailchimp-woocommerce-admin.php:397
152
  msgid "Store Disconnect Failed"
153
  msgstr ""
154
 
155
- #: admin/class-mailchimp-woocommerce-admin.php:668
156
  msgid "As part of the Mailchimp Terms of Use, we require a contact email and a physical mailing address."
157
  msgstr ""
158
 
159
- #: admin/class-mailchimp-woocommerce-admin.php:676
160
  msgid "As part of the Mailchimp Terms of Use, we require a valid phone number for your store."
161
  msgstr ""
162
 
163
- #: admin/class-mailchimp-woocommerce-admin.php:684
164
  msgid "Mailchimp for WooCommerce requires a Store Name to connect your store."
165
  msgstr ""
166
 
167
  #. translators: %s - plugin name.
168
- #: admin/class-mailchimp-woocommerce-admin.php:702
169
  #: admin/partials/tabs/campaign_defaults.php:68
170
  msgid "You were subscribed to the newsletter from %s"
171
  msgstr ""
172
 
173
- #: admin/class-mailchimp-woocommerce-admin.php:707
174
  msgid "One or more fields were not updated"
175
  msgstr ""
176
 
177
- #: admin/class-mailchimp-woocommerce-admin.php:858
178
  msgid "You must supply your Mailchimp API key to pull the audiences."
179
  msgstr ""
180
 
181
- #: admin/class-mailchimp-woocommerce-admin.php:1320
182
  msgid "Starting the sync process..."
183
  msgstr ""
184
 
185
- #: admin/class-mailchimp-woocommerce-admin.php:1322
186
  msgid "The plugin has started the initial sync with your store, and the process will work in the background automatically."
187
  msgstr ""
188
 
189
- #: admin/class-mailchimp-woocommerce-admin.php:1324
190
  msgid "Sometimes the sync can take a while, especially on sites with lots of orders and/or products. It is safe to navigate away from this screen while it is running."
191
  msgstr ""
192
 
193
- #: admin/class-mailchimp-woocommerce-admin.php:1334
194
  msgid "Your store is synced with Mailchimp!"
195
  msgstr ""
196
 
197
  #. translators: %1$s: Number of synced orders %2$s: Audience name
198
- #: admin/class-mailchimp-woocommerce-admin.php:1337
199
  msgid "We've successfully synced %1$s orders to your Audience %2$s, that's awesome!"
200
  msgstr ""
201
 
202
  #. translators: %s - Wordpress.org plugin review URL.
203
- #: admin/class-mailchimp-woocommerce-admin.php:1345
204
  msgid "Could you please do us a favor and leave the plugin a 5-star <a href=%s target='_blank'>rating on Wordpress.org</a>? It helps our community know that we're working hard to make it better each day."
205
  msgstr ""
206
 
207
- #: admin/class-mailchimp-woocommerce-admin.php:1348
208
  msgid "Leave a Review"
209
  msgstr ""
210
 
 
 
 
 
 
 
 
 
211
  #: admin/partials/tabs/newsletter_settings.php:36
212
  #: admin/partials/mailchimp-woocommerce-admin-tabs.php:162
213
  #: admin/partials/mailchimp-woocommerce-admin-tabs.php:185
@@ -305,6 +313,108 @@ msgstr ""
305
  msgid "Size"
306
  msgstr ""
307
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
308
  #: admin/partials/tabs/logs.php:38
309
  msgid "Logging Preference"
310
  msgstr ""
@@ -399,82 +509,115 @@ msgstr ""
399
  msgid "Permission reminder message"
400
  msgstr ""
401
 
402
- #: admin/partials/tabs/store_sync.php:82
403
  msgid "Coupons"
404
  msgstr ""
405
 
406
- #: admin/partials/tabs/store_sync.php:92
407
  msgid "Products"
408
  msgstr ""
409
 
410
- #: admin/partials/tabs/store_sync.php:102
411
  msgid "Orders"
412
  msgstr ""
413
 
414
- #: admin/partials/tabs/store_sync.php:115
415
  msgid "Subscribers"
416
  msgstr ""
417
 
418
- #: admin/partials/tabs/store_sync.php:122
419
  msgid "Transactional"
420
  msgstr ""
421
 
422
- #: admin/partials/tabs/store_sync.php:129
423
  msgid "Unsubscribed"
424
  msgstr ""
425
 
426
- #: admin/partials/tabs/store_sync.php:148
427
  msgid "DISCONNECT STORE"
428
  msgstr ""
429
 
430
- #: admin/partials/tabs/store_sync.php:151
431
  msgid "Account Connected"
432
  msgstr ""
433
 
434
- #: admin/partials/tabs/store_sync.php:153
435
  msgid "Audience Connected"
436
  msgstr ""
437
 
438
- #: admin/partials/tabs/store_sync.php:159
439
  msgid "Status:"
440
  msgstr ""
441
 
442
- #: admin/partials/tabs/store_sync.php:160
443
  msgid "Sync Completed"
444
  msgstr ""
445
 
446
- #: admin/partials/tabs/store_sync.php:160
447
  msgid "Syncing..."
448
  msgstr ""
449
 
450
- #: admin/partials/tabs/store_sync.php:162
451
  msgid "Initial sync in progress"
452
  msgstr ""
453
 
454
- #: admin/partials/tabs/store_sync.php:166
455
  msgid "Last Updated:"
456
  msgstr ""
457
 
458
- #: admin/partials/tabs/store_sync.php:171
459
  msgid "Starting..."
460
  msgstr ""
461
 
462
- #: admin/partials/tabs/store_sync.php:182
 
 
 
 
 
 
 
 
463
  msgid "Advanced"
464
  msgstr ""
465
 
466
- #: admin/partials/tabs/store_sync.php:184
467
  msgid "You can resync your audience at any time without losing any of your e-commerce data."
468
  msgstr ""
469
 
470
- #: admin/partials/tabs/store_sync.php:186
471
  msgid "Force Resync"
472
  msgstr ""
473
 
474
- #: admin/partials/tabs/store_sync.php:189
475
  msgid "More Information"
476
  msgstr ""
477
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
478
  #: admin/partials/tabs/api_key.php:6
479
  #: admin/partials/tabs/api_key.php:11
480
  msgid "Connect your store to Mailchimp"
@@ -520,30 +663,14 @@ msgstr ""
520
  msgid "Name"
521
  msgstr ""
522
 
523
- #: admin/partials/tabs/store_info.php:26
524
- msgid "Email"
525
- msgstr ""
526
-
527
  #: admin/partials/tabs/store_info.php:33
528
  msgid "Street address"
529
  msgstr ""
530
 
531
- #: admin/partials/tabs/store_info.php:40
532
- msgid "City"
533
- msgstr ""
534
-
535
- #: admin/partials/tabs/store_info.php:47
536
- msgid "State"
537
- msgstr ""
538
-
539
  #: admin/partials/tabs/store_info.php:54
540
  msgid "Postal Code"
541
  msgstr ""
542
 
543
- #: admin/partials/tabs/store_info.php:61
544
- msgid "Country"
545
- msgstr ""
546
-
547
  #: admin/partials/tabs/store_info.php:87
548
  msgid "Phone Number"
549
  msgstr ""
@@ -568,14 +695,30 @@ msgstr ""
568
  msgid "Woocommerce Currency"
569
  msgstr ""
570
 
571
- #: admin/partials/tabs/store_info.php:126
572
- msgid "Timezone"
573
- msgstr ""
574
-
575
  #: admin/partials/tabs/store_info.php:130
576
  msgid "Select store's timezone"
577
  msgstr ""
578
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
579
  #: admin/partials/mailchimp-woocommerce-admin-tabs.php:65
580
  msgid "Mailchimp says: Please upgrade your PHP version to a minimum of 7.0"
581
  msgstr ""
1
+ # Copyright (C) 2020 Mailchimp
2
  # This file is distributed under the same license as the Mailchimp for WooCommerce plugin.
3
  msgid ""
4
  msgstr ""
5
+ "Project-Id-Version: Mailchimp for WooCommerce 2.3.2\n"
6
  "Report-Msgid-Bugs-To: https://wordpress.org/support/plugin/mailchimp-for-woocommerce\n"
7
  "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
8
  "Language-Team: LANGUAGE <LL@li.org>\n"
9
  "MIME-Version: 1.0\n"
10
  "Content-Type: text/plain; charset=UTF-8\n"
11
  "Content-Transfer-Encoding: 8bit\n"
12
+ "POT-Creation-Date: 2020-01-20T13:17:37+00:00\n"
13
  "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
14
  "X-Generator: WP-CLI 2.1.0\n"
15
  "X-Domain: mailchimp-for-woocommerce\n"
96
  msgstr ""
97
 
98
  #: includes/class-mailchimp-woocommerce-deactivation-survey.php:379
99
+ #: admin/class-mailchimp-woocommerce-admin.php:274
100
  msgid "Mailchimp for Woocommerce"
101
  msgstr ""
102
 
122
  msgstr ""
123
 
124
  #: includes/class-mailchimp-woocommerce-newsletter.php:43
125
+ #: admin/class-mailchimp-woocommerce-admin.php:870
126
  #: admin/partials/tabs/newsletter_settings.php:97
127
  msgid "Subscribe to our newsletter"
128
  msgstr ""
129
 
130
  #: includes/class-mailchimp-woocommerce-rest-api.php:141
131
+ #: admin/partials/tabs/store_sync.php:164
132
  msgid "D, M j, Y g:i A"
133
  msgstr ""
134
 
135
+ #: admin/class-mailchimp-woocommerce-admin.php:127
136
  msgid "Mailchimp - WooCommerce Setup"
137
  msgstr ""
138
 
139
+ #: admin/class-mailchimp-woocommerce-admin.php:275
140
  msgid "We dectected that this site has the following constants defined, likely at wp-config.php file"
141
  msgstr ""
142
 
143
+ #: admin/class-mailchimp-woocommerce-admin.php:277
144
  msgid "These constants are deprecated since Mailchimp for Woocommerce version 2.3. Please refer to the <a href=\"https://github.com/mailchimp/mc-woocommerce/wiki/\">plugin official wiki</a> for further details."
145
  msgstr ""
146
 
147
+ #: admin/class-mailchimp-woocommerce-admin.php:437
148
  msgid "Store Disconnected"
149
  msgstr ""
150
 
151
+ #: admin/class-mailchimp-woocommerce-admin.php:441
152
  msgid "Store Disconnect Failed"
153
  msgstr ""
154
 
155
+ #: admin/class-mailchimp-woocommerce-admin.php:784
156
  msgid "As part of the Mailchimp Terms of Use, we require a contact email and a physical mailing address."
157
  msgstr ""
158
 
159
+ #: admin/class-mailchimp-woocommerce-admin.php:792
160
  msgid "As part of the Mailchimp Terms of Use, we require a valid phone number for your store."
161
  msgstr ""
162
 
163
+ #: admin/class-mailchimp-woocommerce-admin.php:800
164
  msgid "Mailchimp for WooCommerce requires a Store Name to connect your store."
165
  msgstr ""
166
 
167
  #. translators: %s - plugin name.
168
+ #: admin/class-mailchimp-woocommerce-admin.php:818
169
  #: admin/partials/tabs/campaign_defaults.php:68
170
  msgid "You were subscribed to the newsletter from %s"
171
  msgstr ""
172
 
173
+ #: admin/class-mailchimp-woocommerce-admin.php:823
174
  msgid "One or more fields were not updated"
175
  msgstr ""
176
 
177
+ #: admin/class-mailchimp-woocommerce-admin.php:976
178
  msgid "You must supply your Mailchimp API key to pull the audiences."
179
  msgstr ""
180
 
181
+ #: admin/class-mailchimp-woocommerce-admin.php:1450
182
  msgid "Starting the sync process..."
183
  msgstr ""
184
 
185
+ #: admin/class-mailchimp-woocommerce-admin.php:1452
186
  msgid "The plugin has started the initial sync with your store, and the process will work in the background automatically."
187
  msgstr ""
188
 
189
+ #: admin/class-mailchimp-woocommerce-admin.php:1454
190
  msgid "Sometimes the sync can take a while, especially on sites with lots of orders and/or products. It is safe to navigate away from this screen while it is running."
191
  msgstr ""
192
 
193
+ #: admin/class-mailchimp-woocommerce-admin.php:1470
194
  msgid "Your store is synced with Mailchimp!"
195
  msgstr ""
196
 
197
  #. translators: %1$s: Number of synced orders %2$s: Audience name
198
+ #: admin/class-mailchimp-woocommerce-admin.php:1473
199
  msgid "We've successfully synced %1$s orders to your Audience %2$s, that's awesome!"
200
  msgstr ""
201
 
202
  #. translators: %s - Wordpress.org plugin review URL.
203
+ #: admin/class-mailchimp-woocommerce-admin.php:1481
204
  msgid "Could you please do us a favor and leave the plugin a 5-star <a href=%s target='_blank'>rating on Wordpress.org</a>? It helps our community know that we're working hard to make it better each day."
205
  msgstr ""
206
 
207
+ #: admin/class-mailchimp-woocommerce-admin.php:1484
208
  msgid "Leave a Review"
209
  msgstr ""
210
 
211
+ #: admin/class-mailchimp-woocommerce-admin.php:1517
212
+ msgid "Saved"
213
+ msgstr ""
214
+
215
+ #: admin/class-mailchimp-woocommerce-admin.php:1522
216
+ msgid "Error setting communications status"
217
+ msgstr ""
218
+
219
  #: admin/partials/tabs/newsletter_settings.php:36
220
  #: admin/partials/mailchimp-woocommerce-admin-tabs.php:162
221
  #: admin/partials/mailchimp-woocommerce-admin-tabs.php:185
313
  msgid "Size"
314
  msgstr ""
315
 
316
+ #: admin/partials/tabs/api_key_create_account.php:33
317
+ #: admin/partials/tabs/store_info.php:26
318
+ msgid "Email"
319
+ msgstr ""
320
+
321
+ #: admin/partials/tabs/api_key_create_account.php:40
322
+ msgid "Username"
323
+ msgstr ""
324
+
325
+ #: admin/partials/tabs/api_key_create_account.php:43
326
+ msgid "Suggested username: "
327
+ msgstr ""
328
+
329
+ #: admin/partials/tabs/api_key_create_account.php:48
330
+ msgid "Next Step"
331
+ msgstr ""
332
+
333
+ #: admin/partials/tabs/api_key_create_account.php:53
334
+ msgid "Invalid Email. Please double check."
335
+ msgstr ""
336
+
337
+ #: admin/partials/tabs/api_key_create_account.php:67
338
+ msgid "Address Line 1"
339
+ msgstr ""
340
+
341
+ #: admin/partials/tabs/api_key_create_account.php:74
342
+ msgid "Address Line 2"
343
+ msgstr ""
344
+
345
+ #: admin/partials/tabs/api_key_create_account.php:82
346
+ #: admin/partials/tabs/store_info.php:40
347
+ msgid "City"
348
+ msgstr ""
349
+
350
+ #: admin/partials/tabs/api_key_create_account.php:89
351
+ #: admin/partials/tabs/store_info.php:47
352
+ msgid "State"
353
+ msgstr ""
354
+
355
+ #: admin/partials/tabs/api_key_create_account.php:96
356
+ msgid "Zip"
357
+ msgstr ""
358
+
359
+ #: admin/partials/tabs/api_key_create_account.php:103
360
+ #: admin/partials/tabs/store_info.php:61
361
+ msgid "Country"
362
+ msgstr ""
363
+
364
+ #: admin/partials/tabs/api_key_create_account.php:128
365
+ msgid "Phone"
366
+ msgstr ""
367
+
368
+ #: admin/partials/tabs/api_key_create_account.php:135
369
+ #: admin/partials/tabs/store_info.php:126
370
+ msgid "Timezone"
371
+ msgstr ""
372
+
373
+ #. translators: %s - Mailchimp legal pages
374
+ #: admin/partials/tabs/api_key_create_account.php:161
375
+ msgid "By clicking the \"Get Started!\" button, you are creating a Mailchimp account, and you agree to Mailchimp's <a href=%s target=_blank>Terms of Use</a> and <a href=%s target=_blank>Privacy Policy</a>."
376
+ msgstr ""
377
+
378
+ #: admin/partials/tabs/api_key_create_account.php:167
379
+ msgid "Go Back"
380
+ msgstr ""
381
+
382
+ #: admin/partials/tabs/api_key_create_account.php:171
383
+ msgid "Get Started!"
384
+ msgstr ""
385
+
386
+ #: admin/partials/tabs/api_key_create_account.php:176
387
+ msgid "Invalid Address"
388
+ msgstr ""
389
+
390
+ #: admin/partials/tabs/api_key_create_account.php:177
391
+ msgid "Invalid City"
392
+ msgstr ""
393
+
394
+ #: admin/partials/tabs/api_key_create_account.php:178
395
+ msgid "Invalid State"
396
+ msgstr ""
397
+
398
+ #: admin/partials/tabs/api_key_create_account.php:179
399
+ msgid "Invalid Zip"
400
+ msgstr ""
401
+
402
+ #: admin/partials/tabs/api_key_create_account.php:180
403
+ msgid "Invalid Country"
404
+ msgstr ""
405
+
406
+ #: admin/partials/tabs/api_key_create_account.php:181
407
+ msgid "Invalid Phone"
408
+ msgstr ""
409
+
410
+ #: admin/partials/tabs/api_key_create_account.php:182
411
+ msgid "Invalid Timezone"
412
+ msgstr ""
413
+
414
+ #: admin/partials/tabs/api_key_create_account.php:183
415
+ msgid "Connecting..."
416
+ msgstr ""
417
+
418
  #: admin/partials/tabs/logs.php:38
419
  msgid "Logging Preference"
420
  msgstr ""
509
  msgid "Permission reminder message"
510
  msgstr ""
511
 
512
+ #: admin/partials/tabs/store_sync.php:77
513
  msgid "Coupons"
514
  msgstr ""
515
 
516
+ #: admin/partials/tabs/store_sync.php:87
517
  msgid "Products"
518
  msgstr ""
519
 
520
+ #: admin/partials/tabs/store_sync.php:97
521
  msgid "Orders"
522
  msgstr ""
523
 
524
+ #: admin/partials/tabs/store_sync.php:110
525
  msgid "Subscribers"
526
  msgstr ""
527
 
528
+ #: admin/partials/tabs/store_sync.php:117
529
  msgid "Transactional"
530
  msgstr ""
531
 
532
+ #: admin/partials/tabs/store_sync.php:124
533
  msgid "Unsubscribed"
534
  msgstr ""
535
 
536
+ #: admin/partials/tabs/store_sync.php:143
537
  msgid "DISCONNECT STORE"
538
  msgstr ""
539
 
540
+ #: admin/partials/tabs/store_sync.php:146
541
  msgid "Account Connected"
542
  msgstr ""
543
 
544
+ #: admin/partials/tabs/store_sync.php:148
545
  msgid "Audience Connected"
546
  msgstr ""
547
 
548
+ #: admin/partials/tabs/store_sync.php:154
549
  msgid "Status:"
550
  msgstr ""
551
 
552
+ #: admin/partials/tabs/store_sync.php:155
553
  msgid "Sync Completed"
554
  msgstr ""
555
 
556
+ #: admin/partials/tabs/store_sync.php:155
557
  msgid "Syncing..."
558
  msgstr ""
559
 
560
+ #: admin/partials/tabs/store_sync.php:157
561
  msgid "Initial sync in progress"
562
  msgstr ""
563
 
564
+ #: admin/partials/tabs/store_sync.php:161
565
  msgid "Last Updated:"
566
  msgstr ""
567
 
568
+ #: admin/partials/tabs/store_sync.php:166
569
  msgid "Starting..."
570
  msgstr ""
571
 
572
+ #: admin/partials/tabs/store_sync.php:193
573
+ msgid "enabled"
574
+ msgstr ""
575
+
576
+ #: admin/partials/tabs/store_sync.php:194
577
+ msgid "disabled"
578
+ msgstr ""
579
+
580
+ #: admin/partials/tabs/store_sync.php:208
581
  msgid "Advanced"
582
  msgstr ""
583
 
584
+ #: admin/partials/tabs/store_sync.php:210
585
  msgid "You can resync your audience at any time without losing any of your e-commerce data."
586
  msgstr ""
587
 
588
+ #: admin/partials/tabs/store_sync.php:212
589
  msgid "Force Resync"
590
  msgstr ""
591
 
592
+ #: admin/partials/tabs/store_sync.php:215
593
  msgid "More Information"
594
  msgstr ""
595
 
596
+ #. translators: %s - Plugin review URL.
597
+ #: admin/partials/tabs/store_sync.php:217
598
+ msgid "Is this plugin helping your e-commerce business? <a href=%s target=_blank>Please leave us a ★★★★★ review!</a>."
599
+ msgstr ""
600
+
601
+ #. translators: %s - WP-CLI URL.
602
+ #: admin/partials/tabs/store_sync.php:218
603
+ msgid "Have a larger store or having issues syncing? Consider using <a href=%s target=_blank>WP-CLI</a>."
604
+ msgstr ""
605
+
606
+ #. translators: %s - WP-CLI URL.
607
+ #: admin/partials/tabs/store_sync.php:219
608
+ msgid "Order and customer information will not sync if they contain an Amazon or generic email address."
609
+ msgstr ""
610
+
611
+ #. translators: %s - Mailchimp Support URL.
612
+ #: admin/partials/tabs/store_sync.php:220
613
+ msgid "Need help to connect your store? Visit the Mailchimp <a href=%s target=_blank>Knowledge Base</a>."
614
+ msgstr ""
615
+
616
+ #. translators: %s - Mailchimp Privacy Policy URL.
617
+ #: admin/partials/tabs/store_sync.php:221
618
+ msgid "By using this plugin, Mailchimp will process customer information in accordance with their <a href=%s target=_blank>Privacy Policy</a>."
619
+ msgstr ""
620
+
621
  #: admin/partials/tabs/api_key.php:6
622
  #: admin/partials/tabs/api_key.php:11
623
  msgid "Connect your store to Mailchimp"
663
  msgid "Name"
664
  msgstr ""
665
 
 
 
 
 
666
  #: admin/partials/tabs/store_info.php:33
667
  msgid "Street address"
668
  msgstr ""
669
 
 
 
 
 
 
 
 
 
670
  #: admin/partials/tabs/store_info.php:54
671
  msgid "Postal Code"
672
  msgstr ""
673
 
 
 
 
 
674
  #: admin/partials/tabs/store_info.php:87
675
  msgid "Phone Number"
676
  msgstr ""
695
  msgid "Woocommerce Currency"
696
  msgstr ""
697
 
 
 
 
 
698
  #: admin/partials/tabs/store_info.php:130
699
  msgid "Select store's timezone"
700
  msgstr ""
701
 
702
+ #: admin/partials/tabs/store_info.php:146
703
+ msgid "Optional Store Settings"
704
+ msgstr ""
705
+
706
+ #: admin/partials/tabs/store_info.php:152
707
+ msgid "Plugin Permission Level"
708
+ msgstr ""
709
+
710
+ #: admin/partials/tabs/store_info.php:153
711
+ msgid "Select the minimum permission capability to manage Mailchimp for Woocommerce options"
712
+ msgstr ""
713
+
714
+ #: admin/partials/tabs/store_info.php:160
715
+ msgid "Administrators Only"
716
+ msgstr ""
717
+
718
+ #: admin/partials/tabs/store_info.php:163
719
+ msgid "Shop Managers and Administrators"
720
+ msgstr ""
721
+
722
  #: admin/partials/mailchimp-woocommerce-admin-tabs.php:65
723
  msgid "Mailchimp says: Please upgrade your PHP version to a minimum of 7.0"
724
  msgstr ""
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: Connects WooCommerce to Mailchimp to sync your store data, send targeted campaigns to your customers, and sell more stuff.
19
- * Version: 2.3.1
20
  * Author: Mailchimp
21
  * Author URI: https://mailchimp.com
22
  * License: GPL-2.0+
@@ -24,9 +24,9 @@
24
  * Text Domain: mailchimp-for-woocommerce
25
  * Domain Path: /languages
26
  * Requires at least: 4.9
27
- * Tested up to: 5.3
28
  * WC requires at least: 3.5
29
- * WC tested up to: 3.8
30
  */
31
 
32
  // If this file is called directly, abort.
16
  * Plugin Name: Mailchimp for WooCommerce
17
  * Plugin URI: https://mailchimp.com/connect-your-store/
18
  * Description: Connects WooCommerce to Mailchimp to sync your store data, send targeted campaigns to your customers, and sell more stuff.
19
+ * Version: 2.3.2
20
  * Author: Mailchimp
21
  * Author URI: https://mailchimp.com
22
  * License: GPL-2.0+
24
  * Text Domain: mailchimp-for-woocommerce
25
  * Domain Path: /languages
26
  * Requires at least: 4.9
27
+ * Tested up to: 5.3.2
28
  * WC requires at least: 3.5
29
+ * WC tested up to: 3.9
30
  */
31
 
32
  // If this file is called directly, abort.
public/class-mailchimp-woocommerce-public.php CHANGED
@@ -68,9 +68,16 @@ class MailChimp_WooCommerce_Public {
68
  // Enqueued script with localized data.
69
  wp_enqueue_script($this->plugin_name, '', array(), $this->version, true);
70
 
71
- //if we have the connected_site script url saved, we need to inject it
72
- if (($site = mailchimp_get_connected_site_script_url()) && !empty($site)) {
73
- wp_enqueue_script($this->plugin_name.'_connected_site', $site, array(), $this->version, true);
74
- }
 
75
  }
 
 
 
 
 
 
76
  }
68
  // Enqueued script with localized data.
69
  wp_enqueue_script($this->plugin_name, '', array(), $this->version, true);
70
 
71
+ // if we have the "fragment" we can just inject this vs. loading the file
72
+ // otherwise, if we have the connected_site script url saved, we need to inject it and load from the CDN.
73
+ //if (($site = mailchimp_get_connected_site_script_url()) && !empty($site)) {
74
+ // wp_enqueue_script($this->plugin_name.'_connected_site', $site, array(), $this->version, true);
75
+ //}
76
  }
77
+
78
+ public function add_inline_footer_script(){
79
+ if (($fragment = mailchimp_get_connected_site_script_fragment()) && !empty($fragment)) {
80
+ echo $fragment;
81
+ }
82
+ }
83
  }