Version Description
- New: Added {{POSTIMAGE-URL}} keyword for Post Notification
- Update: Action Scheduler Library to 3.3.0
- Fix: Amazon SES batch sending issue [PRO]
=
Download this release
Release Info
Developer | Icegram |
Plugin | Email Subscribers & Newsletters |
Version | 4.9.1 |
Comparing to | |
See all releases |
Code changes from version 4.9.0 to 4.9.1
- email-subscribers.php +2 -2
- lite/includes/classes/class-es-handle-post-notification.php +10 -1
- lite/includes/libraries/action-scheduler/action-scheduler.php +25 -13
- lite/includes/libraries/action-scheduler/changelog.txt +32 -0
- lite/includes/libraries/action-scheduler/classes/ActionScheduler_ActionClaim.php +3 -3
- lite/includes/libraries/action-scheduler/classes/ActionScheduler_ActionFactory.php +30 -30
- lite/includes/libraries/action-scheduler/classes/ActionScheduler_AdminView.php +3 -4
- lite/includes/libraries/action-scheduler/classes/ActionScheduler_Compatibility.php +14 -4
- lite/includes/libraries/action-scheduler/classes/ActionScheduler_DataController.php +2 -2
- lite/includes/libraries/action-scheduler/classes/ActionScheduler_FatalErrorMonitor.php +10 -10
- lite/includes/libraries/action-scheduler/classes/ActionScheduler_ListTable.php +56 -30
- lite/includes/libraries/action-scheduler/classes/ActionScheduler_LogEntry.php +5 -5
- lite/includes/libraries/action-scheduler/classes/ActionScheduler_NullLogEntry.php +1 -1
- lite/includes/libraries/action-scheduler/classes/ActionScheduler_OptionLock.php +0 -1
- lite/includes/libraries/action-scheduler/classes/ActionScheduler_QueueCleaner.php +26 -29
- lite/includes/libraries/action-scheduler/classes/ActionScheduler_QueueRunner.php +6 -7
- lite/includes/libraries/action-scheduler/classes/ActionScheduler_Versions.php +13 -13
- lite/includes/libraries/action-scheduler/classes/ActionScheduler_WPCommentCleaner.php +3 -15
- lite/includes/libraries/action-scheduler/classes/ActionScheduler_wcSystemStatus.php +21 -9
- lite/includes/libraries/action-scheduler/classes/WP_CLI/ActionScheduler_WPCLI_QueueRunner.php +1 -1
- lite/includes/libraries/action-scheduler/classes/WP_CLI/Migration_Command.php +61 -103
- lite/includes/libraries/action-scheduler/classes/WP_CLI/ProgressBar.php +1 -1
- lite/includes/libraries/action-scheduler/classes/abstracts/ActionScheduler.php +14 -17
- lite/includes/libraries/action-scheduler/classes/abstracts/ActionScheduler_Abstract_ListTable.php +136 -58
- lite/includes/libraries/action-scheduler/classes/abstracts/ActionScheduler_Abstract_QueueRunner.php +2 -2
- lite/includes/libraries/action-scheduler/classes/abstracts/ActionScheduler_Abstract_RecurringSchedule.php +9 -13
- lite/includes/libraries/action-scheduler/classes/abstracts/ActionScheduler_Abstract_Schedule.php +2 -3
- lite/includes/libraries/action-scheduler/classes/abstracts/ActionScheduler_Abstract_Schema.php +47 -10
- lite/includes/libraries/action-scheduler/classes/abstracts/ActionScheduler_Lock.php +2 -2
- lite/includes/libraries/action-scheduler/classes/abstracts/ActionScheduler_Logger.php +9 -10
- lite/includes/libraries/action-scheduler/classes/abstracts/ActionScheduler_Store.php +99 -25
- lite/includes/libraries/action-scheduler/classes/abstracts/ActionScheduler_TimezoneHelper.php +9 -9
- lite/includes/libraries/action-scheduler/classes/actions/ActionScheduler_Action.php +9 -9
- lite/includes/libraries/action-scheduler/classes/actions/ActionScheduler_CanceledAction.php +3 -3
- lite/includes/libraries/action-scheduler/classes/actions/ActionScheduler_FinishedAction.php +2 -2
- lite/includes/libraries/action-scheduler/classes/actions/ActionScheduler_NullAction.php +2 -2
- lite/includes/libraries/action-scheduler/classes/data-stores/ActionScheduler_DBLogger.php +13 -9
- lite/includes/libraries/action-scheduler/classes/data-stores/ActionScheduler_DBStore.php +132 -116
- lite/includes/libraries/action-scheduler/classes/data-stores/ActionScheduler_HybridStore.php +17 -18
- lite/includes/libraries/action-scheduler/classes/data-stores/ActionScheduler_wpCommentLogger.php +36 -44
- lite/includes/libraries/action-scheduler/classes/data-stores/ActionScheduler_wpPostStore.php +351 -154
- lite/includes/libraries/action-scheduler/classes/data-stores/ActionScheduler_wpPostStore_PostStatusRegistrar.php +0 -1
- lite/includes/libraries/action-scheduler/classes/data-stores/ActionScheduler_wpPostStore_PostTypeRegistrar.php +23 -24
- lite/includes/libraries/action-scheduler/classes/data-stores/ActionScheduler_wpPostStore_TaxonomyRegistrar.php +6 -7
- lite/includes/libraries/action-scheduler/classes/migration/ActionMigrator.php +2 -2
- lite/includes/libraries/action-scheduler/classes/migration/ActionScheduler_DBStoreMigrator.php +5 -5
- lite/includes/libraries/action-scheduler/classes/migration/BatchFetcher.php +15 -20
- lite/includes/libraries/action-scheduler/classes/migration/Controller.php +24 -4
- lite/includes/libraries/action-scheduler/classes/migration/DryRun_LogMigrator.php +1 -1
- lite/includes/libraries/action-scheduler/classes/migration/Runner.php +8 -11
- lite/includes/libraries/action-scheduler/classes/migration/Scheduler.php +2 -2
- lite/includes/libraries/action-scheduler/classes/schedules/ActionScheduler_CanceledSchedule.php +1 -1
- lite/includes/libraries/action-scheduler/classes/schedules/ActionScheduler_CronSchedule.php +8 -11
- lite/includes/libraries/action-scheduler/classes/schedules/ActionScheduler_IntervalSchedule.php +6 -9
- lite/includes/libraries/action-scheduler/classes/schedules/ActionScheduler_NullSchedule.php +0 -1
- lite/includes/libraries/action-scheduler/classes/schedules/ActionScheduler_Schedule.php +2 -2
- lite/includes/libraries/action-scheduler/classes/schedules/ActionScheduler_SimpleSchedule.php +4 -7
- lite/includes/libraries/action-scheduler/classes/schema/ActionScheduler_LoggerSchema.php +51 -7
- lite/includes/libraries/action-scheduler/classes/schema/ActionScheduler_StoreSchema.php +58 -9
- lite/includes/libraries/action-scheduler/deprecated/ActionScheduler_AdminView_Deprecated.php +5 -5
- lite/includes/libraries/action-scheduler/deprecated/ActionScheduler_Schedule_Deprecated.php +2 -2
- lite/includes/libraries/action-scheduler/deprecated/ActionScheduler_Store_Deprecated.php +0 -1
- lite/includes/libraries/action-scheduler/deprecated/functions.php +24 -24
- lite/includes/libraries/action-scheduler/functions.php +94 -50
- lite/includes/libraries/action-scheduler/lib/cron-expression/CronExpression.php +302 -291
- lite/includes/libraries/action-scheduler/lib/cron-expression/CronExpression_AbstractField.php +83 -78
- lite/includes/libraries/action-scheduler/lib/cron-expression/CronExpression_DayOfMonthField.php +78 -74
- lite/includes/libraries/action-scheduler/lib/cron-expression/CronExpression_DayOfWeekField.php +93 -90
- lite/includes/libraries/action-scheduler/lib/cron-expression/CronExpression_FieldFactory.php +44 -43
- lite/includes/libraries/action-scheduler/lib/cron-expression/CronExpression_FieldInterface.php +29 -29
- lite/includes/libraries/action-scheduler/lib/cron-expression/CronExpression_HoursField.php +36 -33
- lite/includes/libraries/action-scheduler/lib/cron-expression/CronExpression_MinutesField.php +28 -25
- lite/includes/libraries/action-scheduler/lib/cron-expression/CronExpression_MonthField.php +43 -50
- lite/includes/libraries/action-scheduler/lib/cron-expression/CronExpression_YearField.php +32 -29
- lite/includes/libraries/action-scheduler/readme.txt +76 -0
- lite/languages/email-subscribers.pot +2 -2
- lite/public/partials/class-es-shortcode.php +1 -1
- readme.txt +11 -3
email-subscribers.php
CHANGED
@@ -3,7 +3,7 @@
|
|
3 |
* Plugin Name: Email Subscribers & Newsletters
|
4 |
* Plugin URI: https://www.icegram.com/
|
5 |
* Description: Add subscription forms on website, send HTML newsletters & automatically notify subscribers about new blog posts once it is published.
|
6 |
-
* Version: 4.9.
|
7 |
* Author: Icegram
|
8 |
* Author URI: https://www.icegram.com/
|
9 |
* Requires at least: 3.9
|
@@ -187,7 +187,7 @@ if ( 'premium' === $ig_es_plan ) {
|
|
187 |
/* ***************************** Initial Compatibility Work (End) ******************* */
|
188 |
|
189 |
if ( ! defined( 'ES_PLUGIN_VERSION' ) ) {
|
190 |
-
define( 'ES_PLUGIN_VERSION', '4.9.
|
191 |
}
|
192 |
|
193 |
// Plugin Folder Path.
|
3 |
* Plugin Name: Email Subscribers & Newsletters
|
4 |
* Plugin URI: https://www.icegram.com/
|
5 |
* Description: Add subscription forms on website, send HTML newsletters & automatically notify subscribers about new blog posts once it is published.
|
6 |
+
* Version: 4.9.1
|
7 |
* Author: Icegram
|
8 |
* Author URI: https://www.icegram.com/
|
9 |
* Requires at least: 3.9
|
187 |
/* ***************************** Initial Compatibility Work (End) ******************* */
|
188 |
|
189 |
if ( ! defined( 'ES_PLUGIN_VERSION' ) ) {
|
190 |
+
define( 'ES_PLUGIN_VERSION', '4.9.1' );
|
191 |
}
|
192 |
|
193 |
// Plugin Folder Path.
|
lite/includes/classes/class-es-handle-post-notification.php
CHANGED
@@ -176,6 +176,7 @@ class ES_Handle_Post_Notification {
|
|
176 |
// Size of {{POSTIMAGE}}
|
177 |
$post_thumbnail = '';
|
178 |
$post_thumbnail_link = '';
|
|
|
179 |
if ( ( function_exists( 'has_post_thumbnail' ) ) && ( has_post_thumbnail( $post_id ) ) ) {
|
180 |
$es_post_image_size = get_option( 'ig_es_post_image_size', 'full' );
|
181 |
switch ( $es_post_image_size ) {
|
@@ -196,8 +197,16 @@ class ES_Handle_Post_Notification {
|
|
196 |
$post_thumbnail_link = "<a href='" . $post_link . "' target='_blank'>" . $post_thumbnail . '</a>';
|
197 |
}
|
198 |
|
199 |
-
$es_templ_body
|
200 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
201 |
// Get post description
|
202 |
$post_description_length = 50;
|
203 |
$post_description = $post->post_content;
|
176 |
// Size of {{POSTIMAGE}}
|
177 |
$post_thumbnail = '';
|
178 |
$post_thumbnail_link = '';
|
179 |
+
$post_thumbnail_url = '';
|
180 |
if ( ( function_exists( 'has_post_thumbnail' ) ) && ( has_post_thumbnail( $post_id ) ) ) {
|
181 |
$es_post_image_size = get_option( 'ig_es_post_image_size', 'full' );
|
182 |
switch ( $es_post_image_size ) {
|
197 |
$post_thumbnail_link = "<a href='" . $post_link . "' target='_blank'>" . $post_thumbnail . '</a>';
|
198 |
}
|
199 |
|
200 |
+
$es_templ_body = str_replace( '{{POSTIMAGE}}', $post_thumbnail_link, $es_templ_body );
|
201 |
|
202 |
+
$post_thumbnail_id = get_post_thumbnail_id( $post_id );
|
203 |
+
|
204 |
+
if ( ! empty( $post_thumbnail_id ) ) {
|
205 |
+
$post_thumbnail_url = wp_get_attachment_url( $post_thumbnail_id );
|
206 |
+
}
|
207 |
+
|
208 |
+
$es_templ_body = str_replace( '{{POSTIMAGE-URL}}', $post_thumbnail_url, $es_templ_body );
|
209 |
+
|
210 |
// Get post description
|
211 |
$post_description_length = 50;
|
212 |
$post_description = $post->post_content;
|
lite/includes/libraries/action-scheduler/action-scheduler.php
CHANGED
@@ -1,11 +1,11 @@
|
|
1 |
<?php
|
2 |
-
|
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.
|
9 |
* License: GPLv3
|
10 |
*
|
11 |
* Copyright 2019 Automattic, Inc. (https://automattic.com/contact/)
|
@@ -23,30 +23,42 @@
|
|
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( '
|
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', '
|
36 |
|
37 |
-
|
|
|
|
|
|
|
38 |
$versions = ActionScheduler_Versions::instance();
|
39 |
-
$versions->register( '3.
|
40 |
}
|
41 |
|
42 |
-
|
43 |
-
|
44 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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 |
-
|
50 |
do_action( 'action_scheduler_pre_theme_init' );
|
51 |
ActionScheduler_Versions::initialize_latest_version();
|
52 |
}
|
1 |
<?php
|
2 |
+
/**
|
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.3.0
|
9 |
* License: GPLv3
|
10 |
*
|
11 |
* Copyright 2019 Automattic, Inc. (https://automattic.com/contact/)
|
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 |
+
* @package ActionScheduler
|
27 |
*/
|
28 |
|
29 |
+
if ( ! function_exists( 'action_scheduler_register_3_dot_3_dot_0' ) && function_exists( 'add_action' ) ) {
|
30 |
|
31 |
+
if ( ! class_exists( 'ActionScheduler_Versions', false ) ) {
|
32 |
+
require_once __DIR__ . '/classes/ActionScheduler_Versions.php';
|
33 |
add_action( 'plugins_loaded', array( 'ActionScheduler_Versions', 'initialize_latest_version' ), 1, 0 );
|
34 |
}
|
35 |
|
36 |
+
add_action( 'plugins_loaded', 'action_scheduler_register_3_dot_3_dot_0', 0, 0 );
|
37 |
|
38 |
+
/**
|
39 |
+
* Registers this version of Action Scheduler.
|
40 |
+
*/
|
41 |
+
function action_scheduler_register_3_dot_3_dot_0() {
|
42 |
$versions = ActionScheduler_Versions::instance();
|
43 |
+
$versions->register( '3.3.0', 'action_scheduler_initialize_3_dot_3_dot_0' );
|
44 |
}
|
45 |
|
46 |
+
/**
|
47 |
+
* Initializes this version of Action Scheduler.
|
48 |
+
*/
|
49 |
+
function action_scheduler_initialize_3_dot_3_dot_0() {
|
50 |
+
// A final safety check is required even here, because historic versions of Action Scheduler
|
51 |
+
// followed a different pattern (in some unusual cases, we could reach this point and the
|
52 |
+
// ActionScheduler class is already defined—so we need to guard against that).
|
53 |
+
if ( ! class_exists( 'ActionScheduler', false ) ) {
|
54 |
+
require_once __DIR__ . '/classes/abstracts/ActionScheduler.php';
|
55 |
+
ActionScheduler::init( __FILE__ );
|
56 |
+
}
|
57 |
}
|
58 |
|
59 |
// Support usage in themes - load this version if no plugin has loaded a version yet.
|
60 |
+
if ( did_action( 'plugins_loaded' ) && ! doing_action( 'plugins_loaded' ) && ! class_exists( 'ActionScheduler', false ) ) {
|
61 |
+
action_scheduler_initialize_3_dot_3_dot_0();
|
62 |
do_action( 'action_scheduler_pre_theme_init' );
|
63 |
ActionScheduler_Versions::initialize_latest_version();
|
64 |
}
|
lite/includes/libraries/action-scheduler/changelog.txt
ADDED
@@ -0,0 +1,32 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
*** Changelog ***
|
2 |
+
|
3 |
+
= 3.3.0 - 2021-09-15 =
|
4 |
+
* Enhancement - Adds as_has_scheduled_action() to provide a performant way to test for existing actions. #645
|
5 |
+
* Fix - Improves compatibility with environments where NO_ZERO_DATE is enabled. #519
|
6 |
+
* Fix - Adds safety checks to guard against errors when our database tables cannot be created. #645
|
7 |
+
* Dev - Now supports queries that use multiple statuses. #649
|
8 |
+
* Dev - Minimum requirements for WordPress and PHP bumped (to 5.2 and 5.6 respectively). #723
|
9 |
+
|
10 |
+
= 3.2.1 - 2021-06-21 =
|
11 |
+
* Fix - Add extra safety/account for different versions of AS and different loading patterns. #714
|
12 |
+
* Fix - Handle hidden columns (Tools → Scheduled Actions) | #600.
|
13 |
+
|
14 |
+
= 3.2.0 - 2021-06-03 =
|
15 |
+
* Fix - Add "no ordering" option to as_next_scheduled_action().
|
16 |
+
* Fix - Add secondary scheduled date checks when claiming actions (DBStore) | #634.
|
17 |
+
* Fix - Add secondary scheduled date checks when claiming actions (wpPostStore) | #634.
|
18 |
+
* Fix - Adds a new index to the action table, reducing the potential for deadlocks (props: @glagonikas).
|
19 |
+
* Fix - Fix unit tests infrastructure and adapt tests to PHP 8.
|
20 |
+
* Fix - Identify in-use data store.
|
21 |
+
* Fix - Improve test_migration_is_scheduled.
|
22 |
+
* Fix - PHP notice on list table.
|
23 |
+
* Fix - Speed up clean up and batch selects.
|
24 |
+
* Fix - Update pending dependencies.
|
25 |
+
* Fix - [PHP 8.0] Only pass action arg values through to do_action_ref_array().
|
26 |
+
* Fix - [PHP 8] Set the PHP version to 7.1 in composer.json for PHP 8 compatibility.
|
27 |
+
* Fix - add is_initialized() to docs.
|
28 |
+
* Fix - fix file permissions.
|
29 |
+
* Fix - fixes #664 by replacing __ with esc_html__.
|
30 |
+
|
31 |
+
= 3.1.6 - 2020-05-12 =
|
32 |
+
* Change log starts.
|
lite/includes/libraries/action-scheduler/classes/ActionScheduler_ActionClaim.php
CHANGED
@@ -4,11 +4,11 @@
|
|
4 |
* Class ActionScheduler_ActionClaim
|
5 |
*/
|
6 |
class ActionScheduler_ActionClaim {
|
7 |
-
private $id
|
8 |
private $action_ids = array();
|
9 |
|
10 |
public function __construct( $id, array $action_ids ) {
|
11 |
-
$this->id
|
12 |
$this->action_ids = $action_ids;
|
13 |
}
|
14 |
|
@@ -20,4 +20,4 @@ class ActionScheduler_ActionClaim {
|
|
20 |
return $this->action_ids;
|
21 |
}
|
22 |
}
|
23 |
-
|
4 |
* Class ActionScheduler_ActionClaim
|
5 |
*/
|
6 |
class ActionScheduler_ActionClaim {
|
7 |
+
private $id = '';
|
8 |
private $action_ids = array();
|
9 |
|
10 |
public function __construct( $id, array $action_ids ) {
|
11 |
+
$this->id = $id;
|
12 |
$this->action_ids = $action_ids;
|
13 |
}
|
14 |
|
20 |
return $this->action_ids;
|
21 |
}
|
22 |
}
|
23 |
+
|
lite/includes/libraries/action-scheduler/classes/ActionScheduler_ActionFactory.php
CHANGED
@@ -6,27 +6,27 @@
|
|
6 |
class ActionScheduler_ActionFactory {
|
7 |
|
8 |
/**
|
9 |
-
* @param string
|
10 |
-
* @param string
|
11 |
-
* @param array
|
12 |
* @param ActionScheduler_Schedule $schedule The action's schedule
|
13 |
-
* @param string
|
14 |
*
|
15 |
* @return ActionScheduler_Action An instance of the stored action
|
16 |
*/
|
17 |
public function get_stored_action( $status, $hook, array $args = array(), ActionScheduler_Schedule $schedule = null, $group = '' ) {
|
18 |
|
19 |
switch ( $status ) {
|
20 |
-
case ActionScheduler_Store::STATUS_PENDING:
|
21 |
$action_class = 'ActionScheduler_Action';
|
22 |
break;
|
23 |
-
case ActionScheduler_Store::STATUS_CANCELED:
|
24 |
$action_class = 'ActionScheduler_CanceledAction';
|
25 |
if ( ! is_null( $schedule ) && ! is_a( $schedule, 'ActionScheduler_CanceledSchedule' ) && ! is_a( $schedule, 'ActionScheduler_NullSchedule' ) ) {
|
26 |
$schedule = new ActionScheduler_CanceledSchedule( $schedule->get_date() );
|
27 |
}
|
28 |
break;
|
29 |
-
default:
|
30 |
$action_class = 'ActionScheduler_FinishedAction';
|
31 |
break;
|
32 |
}
|
@@ -58,29 +58,29 @@ class ActionScheduler_ActionFactory {
|
|
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
|
62 |
* @param string $group A group to put the action in
|
63 |
*
|
64 |
* @return int The ID of the stored action
|
65 |
*/
|
66 |
public function async( $hook, $args = array(), $group = '' ) {
|
67 |
$schedule = new ActionScheduler_NullSchedule();
|
68 |
-
$action
|
69 |
return $this->store( $action );
|
70 |
}
|
71 |
|
72 |
/**
|
73 |
* @param string $hook The hook to trigger when this action runs
|
74 |
-
* @param array
|
75 |
-
* @param int
|
76 |
* @param string $group A group to put the action in
|
77 |
*
|
78 |
* @return int The ID of the stored action
|
79 |
*/
|
80 |
public function single( $hook, $args = array(), $when = null, $group = '' ) {
|
81 |
-
$date
|
82 |
$schedule = new ActionScheduler_SimpleSchedule( $date );
|
83 |
-
$action
|
84 |
return $this->store( $action );
|
85 |
}
|
86 |
|
@@ -88,20 +88,20 @@ class ActionScheduler_ActionFactory {
|
|
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
|
92 |
-
* @param int
|
93 |
-
* @param int
|
94 |
* @param string $group A group to put the action in
|
95 |
*
|
96 |
* @return int The ID of the stored action
|
97 |
*/
|
98 |
public function recurring( $hook, $args = array(), $first = null, $interval = null, $group = '' ) {
|
99 |
-
if ( empty(
|
100 |
return $this->single( $hook, $args, $first, $group );
|
101 |
}
|
102 |
-
$date
|
103 |
$schedule = new ActionScheduler_IntervalSchedule( $date, $interval );
|
104 |
-
$action
|
105 |
return $this->store( $action );
|
106 |
}
|
107 |
|
@@ -109,23 +109,23 @@ class ActionScheduler_ActionFactory {
|
|
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
|
113 |
-
* @param int
|
114 |
-
*
|
115 |
-
*
|
116 |
-
* @param int
|
117 |
* @param string $group A group to put the action in
|
118 |
*
|
119 |
* @return int The ID of the stored action
|
120 |
*/
|
121 |
public function cron( $hook, $args = array(), $base_timestamp = null, $schedule = null, $group = '' ) {
|
122 |
-
if ( empty(
|
123 |
return $this->single( $hook, $args, $base_timestamp, $group );
|
124 |
}
|
125 |
-
$date
|
126 |
-
$cron
|
127 |
$schedule = new ActionScheduler_CronSchedule( $date, $cron );
|
128 |
-
$action
|
129 |
return $this->store( $action );
|
130 |
}
|
131 |
|
@@ -162,8 +162,8 @@ class ActionScheduler_ActionFactory {
|
|
162 |
}
|
163 |
|
164 |
$schedule_class = get_class( $schedule );
|
165 |
-
$new_schedule
|
166 |
-
$new_action
|
167 |
return $this->store( $new_action );
|
168 |
}
|
169 |
|
6 |
class ActionScheduler_ActionFactory {
|
7 |
|
8 |
/**
|
9 |
+
* @param string $status The action's status in the data store
|
10 |
+
* @param string $hook The hook to trigger when this action runs
|
11 |
+
* @param array $args Args to pass to callbacks when the hook is triggered
|
12 |
* @param ActionScheduler_Schedule $schedule The action's schedule
|
13 |
+
* @param string $group A group to put the action in
|
14 |
*
|
15 |
* @return ActionScheduler_Action An instance of the stored action
|
16 |
*/
|
17 |
public function get_stored_action( $status, $hook, array $args = array(), ActionScheduler_Schedule $schedule = null, $group = '' ) {
|
18 |
|
19 |
switch ( $status ) {
|
20 |
+
case ActionScheduler_Store::STATUS_PENDING :
|
21 |
$action_class = 'ActionScheduler_Action';
|
22 |
break;
|
23 |
+
case ActionScheduler_Store::STATUS_CANCELED :
|
24 |
$action_class = 'ActionScheduler_CanceledAction';
|
25 |
if ( ! is_null( $schedule ) && ! is_a( $schedule, 'ActionScheduler_CanceledSchedule' ) && ! is_a( $schedule, 'ActionScheduler_NullSchedule' ) ) {
|
26 |
$schedule = new ActionScheduler_CanceledSchedule( $schedule->get_date() );
|
27 |
}
|
28 |
break;
|
29 |
+
default :
|
30 |
$action_class = 'ActionScheduler_FinishedAction';
|
31 |
break;
|
32 |
}
|
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 int 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
|
75 |
+
* @param int $when Unix timestamp when the action will run
|
76 |
* @param string $group A group to put the action in
|
77 |
*
|
78 |
* @return int The ID of the stored action
|
79 |
*/
|
80 |
public function single( $hook, $args = array(), $when = null, $group = '' ) {
|
81 |
+
$date = as_get_datetime_object( $when );
|
82 |
$schedule = new ActionScheduler_SimpleSchedule( $date );
|
83 |
+
$action = new ActionScheduler_Action( $hook, $args, $schedule, $group );
|
84 |
return $this->store( $action );
|
85 |
}
|
86 |
|
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
|
93 |
+
* @param int $interval Seconds between runs
|
94 |
* @param string $group A group to put the action in
|
95 |
*
|
96 |
* @return int The ID of the stored action
|
97 |
*/
|
98 |
public function recurring( $hook, $args = array(), $first = null, $interval = null, $group = '' ) {
|
99 |
+
if ( empty($interval) ) {
|
100 |
return $this->single( $hook, $args, $first, $group );
|
101 |
}
|
102 |
+
$date = as_get_datetime_object( $first );
|
103 |
$schedule = new ActionScheduler_IntervalSchedule( $date, $interval );
|
104 |
+
$action = new ActionScheduler_Action( $hook, $args, $schedule, $group );
|
105 |
return $this->store( $action );
|
106 |
}
|
107 |
|
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 int 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 |
|
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 |
|
lite/includes/libraries/action-scheduler/classes/ActionScheduler_AdminView.php
CHANGED
@@ -2,12 +2,11 @@
|
|
2 |
|
3 |
/**
|
4 |
* Class ActionScheduler_AdminView
|
5 |
-
*
|
6 |
* @codeCoverageIgnore
|
7 |
*/
|
8 |
class ActionScheduler_AdminView extends ActionScheduler_AdminView_Deprecated {
|
9 |
|
10 |
-
private static $admin_view =
|
11 |
|
12 |
private static $screen_id = 'tools_page_action-scheduler';
|
13 |
|
@@ -21,7 +20,7 @@ class ActionScheduler_AdminView extends ActionScheduler_AdminView_Deprecated {
|
|
21 |
public static function instance() {
|
22 |
|
23 |
if ( empty( self::$admin_view ) ) {
|
24 |
-
$class
|
25 |
self::$admin_view = new $class();
|
26 |
}
|
27 |
|
@@ -79,7 +78,7 @@ class ActionScheduler_AdminView extends ActionScheduler_AdminView_Deprecated {
|
|
79 |
'action-scheduler',
|
80 |
array( $this, 'render_admin_ui' )
|
81 |
);
|
82 |
-
add_action( 'load-' . $hook_suffix, array( $this, 'process_admin_ui' ) );
|
83 |
}
|
84 |
|
85 |
/**
|
2 |
|
3 |
/**
|
4 |
* Class ActionScheduler_AdminView
|
|
|
5 |
* @codeCoverageIgnore
|
6 |
*/
|
7 |
class ActionScheduler_AdminView extends ActionScheduler_AdminView_Deprecated {
|
8 |
|
9 |
+
private static $admin_view = NULL;
|
10 |
|
11 |
private static $screen_id = 'tools_page_action-scheduler';
|
12 |
|
20 |
public static function instance() {
|
21 |
|
22 |
if ( empty( self::$admin_view ) ) {
|
23 |
+
$class = apply_filters('action_scheduler_admin_view_class', 'ActionScheduler_AdminView');
|
24 |
self::$admin_view = new $class();
|
25 |
}
|
26 |
|
78 |
'action-scheduler',
|
79 |
array( $this, 'render_admin_ui' )
|
80 |
);
|
81 |
+
add_action( 'load-' . $hook_suffix , array( $this, 'process_admin_ui' ) );
|
82 |
}
|
83 |
|
84 |
/**
|
lite/includes/libraries/action-scheduler/classes/ActionScheduler_Compatibility.php
CHANGED
@@ -83,17 +83,27 @@ class ActionScheduler_Compatibility {
|
|
83 |
*
|
84 |
* Only allows raising the existing limit and prevents lowering it. Wrapper for wc_set_time_limit(), when available.
|
85 |
*
|
86 |
-
* @param int The time limit in seconds.
|
87 |
*/
|
88 |
public static function raise_time_limit( $limit = 0 ) {
|
89 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
90 |
return;
|
91 |
}
|
92 |
|
93 |
if ( function_exists( 'wc_set_time_limit' ) ) {
|
94 |
wc_set_time_limit( $limit );
|
95 |
-
} elseif ( function_exists( 'set_time_limit' ) && false === strpos( ini_get( 'disable_functions' ), 'set_time_limit' ) ) {
|
96 |
-
@set_time_limit( $limit );
|
97 |
}
|
98 |
}
|
99 |
}
|
83 |
*
|
84 |
* Only allows raising the existing limit and prevents lowering it. Wrapper for wc_set_time_limit(), when available.
|
85 |
*
|
86 |
+
* @param int $limit The time limit in seconds.
|
87 |
*/
|
88 |
public static function raise_time_limit( $limit = 0 ) {
|
89 |
+
$limit = (int) $limit;
|
90 |
+
$max_execution_time = (int) ini_get( 'max_execution_time' );
|
91 |
+
|
92 |
+
/*
|
93 |
+
* If the max execution time is already unlimited (zero), or if it exceeds or is equal to the proposed
|
94 |
+
* limit, there is no reason for us to make further changes (we never want to lower it).
|
95 |
+
*/
|
96 |
+
if (
|
97 |
+
0 === $max_execution_time
|
98 |
+
|| ( $max_execution_time >= $limit && $limit !== 0 )
|
99 |
+
) {
|
100 |
return;
|
101 |
}
|
102 |
|
103 |
if ( function_exists( 'wc_set_time_limit' ) ) {
|
104 |
wc_set_time_limit( $limit );
|
105 |
+
} elseif ( function_exists( 'set_time_limit' ) && false === strpos( ini_get( 'disable_functions' ), 'set_time_limit' ) && ! ini_get( 'safe_mode' ) ) { // phpcs:ignore PHPCompatibility.IniDirectives.RemovedIniDirectives.safe_modeDeprecatedRemoved
|
106 |
+
@set_time_limit( $limit ); // phpcs:ignore WordPress.PHP.NoSilencedErrors.Discouraged
|
107 |
}
|
108 |
}
|
109 |
}
|
lite/includes/libraries/action-scheduler/classes/ActionScheduler_DataController.php
CHANGED
@@ -18,10 +18,10 @@ class ActionScheduler_DataController {
|
|
18 |
const DATASTORE_CLASS = 'ActionScheduler_DBStore';
|
19 |
|
20 |
/** Logger data store class name. */
|
21 |
-
const LOGGER_CLASS
|
22 |
|
23 |
/** Migration status option name. */
|
24 |
-
const STATUS_FLAG
|
25 |
|
26 |
/** Migration status option value. */
|
27 |
const STATUS_COMPLETE = 'complete';
|
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';
|
lite/includes/libraries/action-scheduler/classes/ActionScheduler_FatalErrorMonitor.php
CHANGED
@@ -5,9 +5,9 @@
|
|
5 |
*/
|
6 |
class ActionScheduler_FatalErrorMonitor {
|
7 |
/** @var ActionScheduler_ActionClaim */
|
8 |
-
private $claim =
|
9 |
/** @var ActionScheduler_Store */
|
10 |
-
private $store
|
11 |
private $action_id = 0;
|
12 |
|
13 |
public function __construct( ActionScheduler_Store $store ) {
|
@@ -18,19 +18,19 @@ class ActionScheduler_FatalErrorMonitor {
|
|
18 |
$this->claim = $claim;
|
19 |
add_action( 'shutdown', array( $this, 'handle_unexpected_shutdown' ) );
|
20 |
add_action( 'action_scheduler_before_execute', array( $this, 'track_current_action' ), 0, 1 );
|
21 |
-
add_action( 'action_scheduler_after_execute',
|
22 |
-
add_action( 'action_scheduler_execution_ignored',
|
23 |
-
add_action( 'action_scheduler_failed_execution',
|
24 |
}
|
25 |
|
26 |
public function detach() {
|
27 |
-
$this->claim =
|
28 |
$this->untrack_action();
|
29 |
remove_action( 'shutdown', array( $this, 'handle_unexpected_shutdown' ) );
|
30 |
remove_action( 'action_scheduler_before_execute', array( $this, 'track_current_action' ), 0 );
|
31 |
-
remove_action( 'action_scheduler_after_execute',
|
32 |
-
remove_action( 'action_scheduler_execution_ignored',
|
33 |
-
remove_action( 'action_scheduler_failed_execution',
|
34 |
}
|
35 |
|
36 |
public function track_current_action( $action_id ) {
|
@@ -44,7 +44,7 @@ class ActionScheduler_FatalErrorMonitor {
|
|
44 |
public function handle_unexpected_shutdown() {
|
45 |
if ( $error = error_get_last() ) {
|
46 |
if ( in_array( $error['type'], array( E_ERROR, E_PARSE, E_COMPILE_ERROR, E_USER_ERROR, E_RECOVERABLE_ERROR ) ) ) {
|
47 |
-
if ( !
|
48 |
$this->store->mark_failure( $this->action_id );
|
49 |
do_action( 'action_scheduler_unexpected_shutdown', $this->action_id, $error );
|
50 |
}
|
5 |
*/
|
6 |
class ActionScheduler_FatalErrorMonitor {
|
7 |
/** @var ActionScheduler_ActionClaim */
|
8 |
+
private $claim = NULL;
|
9 |
/** @var ActionScheduler_Store */
|
10 |
+
private $store = NULL;
|
11 |
private $action_id = 0;
|
12 |
|
13 |
public function __construct( ActionScheduler_Store $store ) {
|
18 |
$this->claim = $claim;
|
19 |
add_action( 'shutdown', array( $this, 'handle_unexpected_shutdown' ) );
|
20 |
add_action( 'action_scheduler_before_execute', array( $this, 'track_current_action' ), 0, 1 );
|
21 |
+
add_action( 'action_scheduler_after_execute', array( $this, 'untrack_action' ), 0, 0 );
|
22 |
+
add_action( 'action_scheduler_execution_ignored', array( $this, 'untrack_action' ), 0, 0 );
|
23 |
+
add_action( 'action_scheduler_failed_execution', array( $this, 'untrack_action' ), 0, 0 );
|
24 |
}
|
25 |
|
26 |
public function detach() {
|
27 |
+
$this->claim = NULL;
|
28 |
$this->untrack_action();
|
29 |
remove_action( 'shutdown', array( $this, 'handle_unexpected_shutdown' ) );
|
30 |
remove_action( 'action_scheduler_before_execute', array( $this, 'track_current_action' ), 0 );
|
31 |
+
remove_action( 'action_scheduler_after_execute', array( $this, 'untrack_action' ), 0 );
|
32 |
+
remove_action( 'action_scheduler_execution_ignored', array( $this, 'untrack_action' ), 0 );
|
33 |
+
remove_action( 'action_scheduler_failed_execution', array( $this, 'untrack_action' ), 0 );
|
34 |
}
|
35 |
|
36 |
public function track_current_action( $action_id ) {
|
44 |
public function handle_unexpected_shutdown() {
|
45 |
if ( $error = error_get_last() ) {
|
46 |
if ( in_array( $error['type'], array( E_ERROR, E_PARSE, E_COMPILE_ERROR, E_USER_ERROR, E_RECOVERABLE_ERROR ) ) ) {
|
47 |
+
if ( !empty($this->action_id) ) {
|
48 |
$this->store->mark_failure( $this->action_id );
|
49 |
do_action( 'action_scheduler_unexpected_shutdown', $this->action_id, $error );
|
50 |
}
|
lite/includes/libraries/action-scheduler/classes/ActionScheduler_ListTable.php
CHANGED
@@ -2,7 +2,6 @@
|
|
2 |
|
3 |
/**
|
4 |
* Implements the admin view of the actions.
|
5 |
-
*
|
6 |
* @codeCoverageIgnore
|
7 |
*/
|
8 |
class ActionScheduler_ListTable extends ActionScheduler_Abstract_ListTable {
|
@@ -77,8 +76,8 @@ class ActionScheduler_ListTable extends ActionScheduler_Abstract_ListTable {
|
|
77 |
/**
|
78 |
* Sets the current data store object into `store->action` and initialises the object.
|
79 |
*
|
80 |
-
* @param ActionScheduler_Store
|
81 |
-
* @param ActionScheduler_Logger
|
82 |
* @param ActionScheduler_QueueRunner $runner
|
83 |
*/
|
84 |
public function __construct( ActionScheduler_Store $store, ActionScheduler_Logger $logger, ActionScheduler_QueueRunner $runner ) {
|
@@ -126,9 +125,9 @@ class ActionScheduler_ListTable extends ActionScheduler_Abstract_ListTable {
|
|
126 |
|
127 |
$this->row_actions = array(
|
128 |
'hook' => array(
|
129 |
-
'run'
|
130 |
-
'name'
|
131 |
-
'desc'
|
132 |
),
|
133 |
'cancel' => array(
|
134 |
'name' => __( 'Cancel', 'action-scheduler' ),
|
@@ -183,8 +182,29 @@ class ActionScheduler_ListTable extends ActionScheduler_Abstract_ListTable {
|
|
183 |
'ajax' => false,
|
184 |
)
|
185 |
);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
186 |
}
|
187 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
188 |
/**
|
189 |
* Convert an interval of seconds into a two part human friendly string.
|
190 |
*
|
@@ -214,7 +234,7 @@ class ActionScheduler_ListTable extends ActionScheduler_Abstract_ListTable {
|
|
214 |
if ( ! empty( $output ) ) {
|
215 |
$output .= ' ';
|
216 |
}
|
217 |
-
$output
|
218 |
$seconds_remaining -= $periods_in_interval * self::$time_periods[ $time_period_index ]['seconds'];
|
219 |
$periods_included++;
|
220 |
}
|
@@ -292,7 +312,7 @@ class ActionScheduler_ListTable extends ActionScheduler_Abstract_ListTable {
|
|
292 |
* Prints the logs entries inline. We do so to avoid loading Javascript and other hacks to show it in a modal.
|
293 |
*
|
294 |
* @param ActionScheduler_LogEntry $log_entry
|
295 |
-
* @param DateTimezone
|
296 |
* @return string
|
297 |
*/
|
298 |
protected function get_log_entry_html( ActionScheduler_LogEntry $log_entry, DateTimezone $timezone ) {
|
@@ -310,7 +330,7 @@ class ActionScheduler_ListTable extends ActionScheduler_Abstract_ListTable {
|
|
310 |
* @return string
|
311 |
*/
|
312 |
protected function maybe_render_actions( $row, $column_name ) {
|
313 |
-
if ( 'pending' === strtolower( $row['status_name'] ) ) {
|
314 |
return parent::maybe_render_actions( $row, $column_name );
|
315 |
}
|
316 |
|
@@ -341,7 +361,7 @@ class ActionScheduler_ListTable extends ActionScheduler_Abstract_ListTable {
|
|
341 |
if ( ! in_array( $wpdb->prefix . $table_name, $found_tables ) ) {
|
342 |
$this->admin_notices[] = array(
|
343 |
'class' => 'error',
|
344 |
-
'message' => __( 'It appears one or more database tables were missing. Attempting to re-create the missing table(s).', 'action-scheduler' ),
|
345 |
);
|
346 |
$this->recreate_tables();
|
347 |
parent::display_admin_notices();
|
@@ -372,7 +392,7 @@ class ActionScheduler_ListTable extends ActionScheduler_Abstract_ListTable {
|
|
372 |
|
373 |
// No lock set or lock expired
|
374 |
if ( false === $async_request_lock_expiration || $async_request_lock_expiration < time() ) {
|
375 |
-
$in_progress_url
|
376 |
/* translators: %s: process URL */
|
377 |
$async_request_message = sprintf( __( 'A new queue has begun processing. <a href="%s">View actions in-progress »</a>', 'action-scheduler' ), esc_url( $in_progress_url ) );
|
378 |
} else {
|
@@ -391,20 +411,20 @@ class ActionScheduler_ListTable extends ActionScheduler_Abstract_ListTable {
|
|
391 |
if ( is_array( $notification ) ) {
|
392 |
delete_transient( 'action_scheduler_admin_notice' );
|
393 |
|
394 |
-
$action
|
395 |
$action_hook_html = '<strong><code>' . $action->get_hook() . '</code></strong>';
|
396 |
if ( 1 == $notification['success'] ) {
|
397 |
$class = 'updated';
|
398 |
switch ( $notification['row_action_type'] ) {
|
399 |
-
case 'run':
|
400 |
/* translators: %s: action HTML */
|
401 |
$action_message_html = sprintf( __( 'Successfully executed action: %s', 'action-scheduler' ), $action_hook_html );
|
402 |
break;
|
403 |
-
case 'cancel':
|
404 |
/* translators: %s: action HTML */
|
405 |
$action_message_html = sprintf( __( 'Successfully canceled action: %s', 'action-scheduler' ), $action_hook_html );
|
406 |
break;
|
407 |
-
default:
|
408 |
/* translators: %s: action HTML */
|
409 |
$action_message_html = sprintf( __( 'Successfully processed change for action: %s', 'action-scheduler' ), $action_hook_html );
|
410 |
break;
|
@@ -473,7 +493,7 @@ class ActionScheduler_ListTable extends ActionScheduler_Abstract_ListTable {
|
|
473 |
* Deletes actions based on their ID. This is the handler for the bulk delete. It assumes the data
|
474 |
* properly validated by the callee and it will delete the actions without any extra validation.
|
475 |
*
|
476 |
-
* @param array
|
477 |
* @param string $ids_sql Inherited and unused
|
478 |
*/
|
479 |
protected function bulk_delete( array $ids, $ids_sql ) {
|
@@ -523,23 +543,23 @@ class ActionScheduler_ListTable extends ActionScheduler_Abstract_ListTable {
|
|
523 |
/**
|
524 |
* Implements the logic behind processing an action once an action link is clicked on the list table.
|
525 |
*
|
526 |
-
* @param int
|
527 |
* @param string $row_action_type The type of action to perform on the action.
|
528 |
*/
|
529 |
protected function process_row_action( $action_id, $row_action_type ) {
|
530 |
try {
|
531 |
switch ( $row_action_type ) {
|
532 |
-
case 'run':
|
533 |
$this->runner->process_action( $action_id, 'Admin List Table' );
|
534 |
break;
|
535 |
-
case 'cancel':
|
536 |
$this->store->cancel_action( $action_id );
|
537 |
break;
|
538 |
}
|
539 |
-
$success
|
540 |
$error_message = '';
|
541 |
} catch ( Exception $e ) {
|
542 |
-
$success
|
543 |
$error_message = $e->getMessage();
|
544 |
}
|
545 |
|
@@ -552,8 +572,9 @@ class ActionScheduler_ListTable extends ActionScheduler_Abstract_ListTable {
|
|
552 |
public function prepare_items() {
|
553 |
$this->prepare_column_headers();
|
554 |
|
555 |
-
$per_page = $this->get_items_per_page( $this->
|
556 |
-
|
|
|
557 |
'per_page' => $per_page,
|
558 |
'offset' => $this->get_items_offset(),
|
559 |
'status' => $this->get_request_status(),
|
@@ -591,13 +612,11 @@ class ActionScheduler_ListTable extends ActionScheduler_Abstract_ListTable {
|
|
591 |
);
|
592 |
}
|
593 |
|
594 |
-
$this->set_pagination_args(
|
595 |
-
|
596 |
-
|
597 |
-
|
598 |
-
|
599 |
-
)
|
600 |
-
);
|
601 |
}
|
602 |
|
603 |
/**
|
@@ -614,4 +633,11 @@ class ActionScheduler_ListTable extends ActionScheduler_Abstract_ListTable {
|
|
614 |
protected function get_search_box_button_text() {
|
615 |
return __( 'Search hook, args and claim ID', 'action-scheduler' );
|
616 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
617 |
}
|
2 |
|
3 |
/**
|
4 |
* Implements the admin view of the actions.
|
|
|
5 |
* @codeCoverageIgnore
|
6 |
*/
|
7 |
class ActionScheduler_ListTable extends ActionScheduler_Abstract_ListTable {
|
76 |
/**
|
77 |
* Sets the current data store object into `store->action` and initialises the object.
|
78 |
*
|
79 |
+
* @param ActionScheduler_Store $store
|
80 |
+
* @param ActionScheduler_Logger $logger
|
81 |
* @param ActionScheduler_QueueRunner $runner
|
82 |
*/
|
83 |
public function __construct( ActionScheduler_Store $store, ActionScheduler_Logger $logger, ActionScheduler_QueueRunner $runner ) {
|
125 |
|
126 |
$this->row_actions = array(
|
127 |
'hook' => array(
|
128 |
+
'run' => array(
|
129 |
+
'name' => __( 'Run', 'action-scheduler' ),
|
130 |
+
'desc' => __( 'Process the action now as if it were run as part of a queue', 'action-scheduler' ),
|
131 |
),
|
132 |
'cancel' => array(
|
133 |
'name' => __( 'Cancel', 'action-scheduler' ),
|
182 |
'ajax' => false,
|
183 |
)
|
184 |
);
|
185 |
+
|
186 |
+
add_screen_option(
|
187 |
+
'per_page',
|
188 |
+
array(
|
189 |
+
'default' => $this->items_per_page,
|
190 |
+
)
|
191 |
+
);
|
192 |
+
|
193 |
+
add_filter( 'set_screen_option_' . $this->get_per_page_option_name(), array( $this, 'set_items_per_page_option' ), 10, 3 );
|
194 |
+
set_screen_options();
|
195 |
}
|
196 |
|
197 |
+
/**
|
198 |
+
* Handles setting the items_per_page option for this screen.
|
199 |
+
*
|
200 |
+
* @param mixed $status Default false (to skip saving the current option).
|
201 |
+
* @param string $option Screen option name.
|
202 |
+
* @param int $value Screen option value.
|
203 |
+
* @return int
|
204 |
+
*/
|
205 |
+
public function set_items_per_page_option( $status, $option, $value ) {
|
206 |
+
return $value;
|
207 |
+
}
|
208 |
/**
|
209 |
* Convert an interval of seconds into a two part human friendly string.
|
210 |
*
|
234 |
if ( ! empty( $output ) ) {
|
235 |
$output .= ' ';
|
236 |
}
|
237 |
+
$output .= sprintf( _n( self::$time_periods[ $time_period_index ]['names'][0], self::$time_periods[ $time_period_index ]['names'][1], $periods_in_interval, 'action-scheduler' ), $periods_in_interval );
|
238 |
$seconds_remaining -= $periods_in_interval * self::$time_periods[ $time_period_index ]['seconds'];
|
239 |
$periods_included++;
|
240 |
}
|
312 |
* Prints the logs entries inline. We do so to avoid loading Javascript and other hacks to show it in a modal.
|
313 |
*
|
314 |
* @param ActionScheduler_LogEntry $log_entry
|
315 |
+
* @param DateTimezone $timezone
|
316 |
* @return string
|
317 |
*/
|
318 |
protected function get_log_entry_html( ActionScheduler_LogEntry $log_entry, DateTimezone $timezone ) {
|
330 |
* @return string
|
331 |
*/
|
332 |
protected function maybe_render_actions( $row, $column_name ) {
|
333 |
+
if ( 'pending' === strtolower( $row[ 'status_name' ] ) ) {
|
334 |
return parent::maybe_render_actions( $row, $column_name );
|
335 |
}
|
336 |
|
361 |
if ( ! in_array( $wpdb->prefix . $table_name, $found_tables ) ) {
|
362 |
$this->admin_notices[] = array(
|
363 |
'class' => 'error',
|
364 |
+
'message' => __( 'It appears one or more database tables were missing. Attempting to re-create the missing table(s).' , 'action-scheduler' ),
|
365 |
);
|
366 |
$this->recreate_tables();
|
367 |
parent::display_admin_notices();
|
392 |
|
393 |
// No lock set or lock expired
|
394 |
if ( false === $async_request_lock_expiration || $async_request_lock_expiration < time() ) {
|
395 |
+
$in_progress_url = add_query_arg( 'status', 'in-progress', remove_query_arg( 'status' ) );
|
396 |
/* translators: %s: process URL */
|
397 |
$async_request_message = sprintf( __( 'A new queue has begun processing. <a href="%s">View actions in-progress »</a>', 'action-scheduler' ), esc_url( $in_progress_url ) );
|
398 |
} else {
|
411 |
if ( is_array( $notification ) ) {
|
412 |
delete_transient( 'action_scheduler_admin_notice' );
|
413 |
|
414 |
+
$action = $this->store->fetch_action( $notification['action_id'] );
|
415 |
$action_hook_html = '<strong><code>' . $action->get_hook() . '</code></strong>';
|
416 |
if ( 1 == $notification['success'] ) {
|
417 |
$class = 'updated';
|
418 |
switch ( $notification['row_action_type'] ) {
|
419 |
+
case 'run' :
|
420 |
/* translators: %s: action HTML */
|
421 |
$action_message_html = sprintf( __( 'Successfully executed action: %s', 'action-scheduler' ), $action_hook_html );
|
422 |
break;
|
423 |
+
case 'cancel' :
|
424 |
/* translators: %s: action HTML */
|
425 |
$action_message_html = sprintf( __( 'Successfully canceled action: %s', 'action-scheduler' ), $action_hook_html );
|
426 |
break;
|
427 |
+
default :
|
428 |
/* translators: %s: action HTML */
|
429 |
$action_message_html = sprintf( __( 'Successfully processed change for action: %s', 'action-scheduler' ), $action_hook_html );
|
430 |
break;
|
493 |
* Deletes actions based on their ID. This is the handler for the bulk delete. It assumes the data
|
494 |
* properly validated by the callee and it will delete the actions without any extra validation.
|
495 |
*
|
496 |
+
* @param array $ids
|
497 |
* @param string $ids_sql Inherited and unused
|
498 |
*/
|
499 |
protected function bulk_delete( array $ids, $ids_sql ) {
|
543 |
/**
|
544 |
* Implements the logic behind processing an action once an action link is clicked on the list table.
|
545 |
*
|
546 |
+
* @param int $action_id
|
547 |
* @param string $row_action_type The type of action to perform on the action.
|
548 |
*/
|
549 |
protected function process_row_action( $action_id, $row_action_type ) {
|
550 |
try {
|
551 |
switch ( $row_action_type ) {
|
552 |
+
case 'run' :
|
553 |
$this->runner->process_action( $action_id, 'Admin List Table' );
|
554 |
break;
|
555 |
+
case 'cancel' :
|
556 |
$this->store->cancel_action( $action_id );
|
557 |
break;
|
558 |
}
|
559 |
+
$success = 1;
|
560 |
$error_message = '';
|
561 |
} catch ( Exception $e ) {
|
562 |
+
$success = 0;
|
563 |
$error_message = $e->getMessage();
|
564 |
}
|
565 |
|
572 |
public function prepare_items() {
|
573 |
$this->prepare_column_headers();
|
574 |
|
575 |
+
$per_page = $this->get_items_per_page( $this->get_per_page_option_name(), $this->items_per_page );
|
576 |
+
|
577 |
+
$query = array(
|
578 |
'per_page' => $per_page,
|
579 |
'offset' => $this->get_items_offset(),
|
580 |
'status' => $this->get_request_status(),
|
612 |
);
|
613 |
}
|
614 |
|
615 |
+
$this->set_pagination_args( array(
|
616 |
+
'total_items' => $total_items,
|
617 |
+
'per_page' => $per_page,
|
618 |
+
'total_pages' => ceil( $total_items / $per_page ),
|
619 |
+
) );
|
|
|
|
|
620 |
}
|
621 |
|
622 |
/**
|
633 |
protected function get_search_box_button_text() {
|
634 |
return __( 'Search hook, args and claim ID', 'action-scheduler' );
|
635 |
}
|
636 |
+
|
637 |
+
/**
|
638 |
+
* {@inheritDoc}
|
639 |
+
*/
|
640 |
+
protected function get_per_page_option_name() {
|
641 |
+
return str_replace( '-', '_', $this->screen->id ) . '_per_page';
|
642 |
+
}
|
643 |
}
|
lite/includes/libraries/action-scheduler/classes/ActionScheduler_LogEntry.php
CHANGED
@@ -8,12 +8,12 @@ class ActionScheduler_LogEntry {
|
|
8 |
/**
|
9 |
* @var int $action_id
|
10 |
*/
|
11 |
-
protected $action_id =
|
12 |
|
13 |
/**
|
14 |
* @var string $message
|
15 |
*/
|
16 |
-
protected $message =
|
17 |
|
18 |
/**
|
19 |
* @var Datetime $date
|
@@ -23,8 +23,8 @@ class ActionScheduler_LogEntry {
|
|
23 |
/**
|
24 |
* Constructor
|
25 |
*
|
26 |
-
* @param mixed
|
27 |
-
* @param string
|
28 |
* @param Datetime $date Datetime object with the time when this log entry was created. If this parameter is
|
29 |
* not provided a new Datetime object (with current time) will be created.
|
30 |
*/
|
@@ -44,7 +44,7 @@ class ActionScheduler_LogEntry {
|
|
44 |
|
45 |
$this->action_id = $action_id;
|
46 |
$this->message = $message;
|
47 |
-
$this->date = $date ? $date : new Datetime
|
48 |
}
|
49 |
|
50 |
/**
|
8 |
/**
|
9 |
* @var int $action_id
|
10 |
*/
|
11 |
+
protected $action_id = '';
|
12 |
|
13 |
/**
|
14 |
* @var string $message
|
15 |
*/
|
16 |
+
protected $message = '';
|
17 |
|
18 |
/**
|
19 |
* @var Datetime $date
|
23 |
/**
|
24 |
* Constructor
|
25 |
*
|
26 |
+
* @param mixed $action_id Action ID
|
27 |
+
* @param string $message Message
|
28 |
* @param Datetime $date Datetime object with the time when this log entry was created. If this parameter is
|
29 |
* not provided a new Datetime object (with current time) will be created.
|
30 |
*/
|
44 |
|
45 |
$this->action_id = $action_id;
|
46 |
$this->message = $message;
|
47 |
+
$this->date = $date ? $date : new Datetime;
|
48 |
}
|
49 |
|
50 |
/**
|
lite/includes/libraries/action-scheduler/classes/ActionScheduler_NullLogEntry.php
CHANGED
@@ -8,4 +8,4 @@ class ActionScheduler_NullLogEntry extends ActionScheduler_LogEntry {
|
|
8 |
// nothing to see here
|
9 |
}
|
10 |
}
|
11 |
-
|
8 |
// nothing to see here
|
9 |
}
|
10 |
}
|
11 |
+
|
lite/includes/libraries/action-scheduler/classes/ActionScheduler_OptionLock.php
CHANGED
@@ -5,7 +5,6 @@
|
|
5 |
* for up-to a given duration.
|
6 |
*
|
7 |
* Class ActionScheduler_OptionLock
|
8 |
-
*
|
9 |
* @since 3.0.0
|
10 |
*/
|
11 |
class ActionScheduler_OptionLock extends ActionScheduler_Lock {
|
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 {
|
lite/includes/libraries/action-scheduler/classes/ActionScheduler_QueueCleaner.php
CHANGED
@@ -25,13 +25,13 @@ class ActionScheduler_QueueCleaner {
|
|
25 |
* @param int $batch_size The batch size.
|
26 |
*/
|
27 |
public function __construct( ActionScheduler_Store $store = null, $batch_size = 20 ) {
|
28 |
-
$this->store
|
29 |
$this->batch_size = $batch_size;
|
30 |
}
|
31 |
|
32 |
public function delete_old_actions() {
|
33 |
$lifespan = apply_filters( 'action_scheduler_retention_period', $this->month_in_seconds );
|
34 |
-
$cutoff
|
35 |
|
36 |
$statuses_to_purge = array(
|
37 |
ActionScheduler_Store::STATUS_COMPLETE,
|
@@ -39,14 +39,13 @@ class ActionScheduler_QueueCleaner {
|
|
39 |
);
|
40 |
|
41 |
foreach ( $statuses_to_purge as $status ) {
|
42 |
-
$actions_to_delete = $this->store->query_actions(
|
43 |
-
|
44 |
-
|
45 |
-
|
46 |
-
|
47 |
-
|
48 |
-
|
49 |
-
);
|
50 |
|
51 |
foreach ( $actions_to_delete as $action_id ) {
|
52 |
try {
|
@@ -85,16 +84,15 @@ class ActionScheduler_QueueCleaner {
|
|
85 |
if ( $timeout < 0 ) {
|
86 |
return;
|
87 |
}
|
88 |
-
$cutoff
|
89 |
-
$actions_to_reset = $this->store->query_actions(
|
90 |
-
|
91 |
-
|
92 |
-
|
93 |
-
|
94 |
-
|
95 |
-
|
96 |
-
|
97 |
-
);
|
98 |
|
99 |
foreach ( $actions_to_reset as $action_id ) {
|
100 |
$this->store->unclaim_action( $action_id );
|
@@ -116,15 +114,14 @@ class ActionScheduler_QueueCleaner {
|
|
116 |
if ( $timeout < 0 ) {
|
117 |
return;
|
118 |
}
|
119 |
-
$cutoff
|
120 |
-
$actions_to_reset = $this->store->query_actions(
|
121 |
-
|
122 |
-
|
123 |
-
|
124 |
-
|
125 |
-
|
126 |
-
|
127 |
-
);
|
128 |
|
129 |
foreach ( $actions_to_reset as $action_id ) {
|
130 |
$this->store->mark_failure( $action_id );
|
25 |
* @param int $batch_size The batch size.
|
26 |
*/
|
27 |
public function __construct( ActionScheduler_Store $store = null, $batch_size = 20 ) {
|
28 |
+
$this->store = $store ? $store : ActionScheduler_Store::instance();
|
29 |
$this->batch_size = $batch_size;
|
30 |
}
|
31 |
|
32 |
public function delete_old_actions() {
|
33 |
$lifespan = apply_filters( 'action_scheduler_retention_period', $this->month_in_seconds );
|
34 |
+
$cutoff = as_get_datetime_object($lifespan.' seconds ago');
|
35 |
|
36 |
$statuses_to_purge = array(
|
37 |
ActionScheduler_Store::STATUS_COMPLETE,
|
39 |
);
|
40 |
|
41 |
foreach ( $statuses_to_purge as $status ) {
|
42 |
+
$actions_to_delete = $this->store->query_actions( array(
|
43 |
+
'status' => $status,
|
44 |
+
'modified' => $cutoff,
|
45 |
+
'modified_compare' => '<=',
|
46 |
+
'per_page' => $this->get_batch_size(),
|
47 |
+
'orderby' => 'none',
|
48 |
+
) );
|
|
|
49 |
|
50 |
foreach ( $actions_to_delete as $action_id ) {
|
51 |
try {
|
84 |
if ( $timeout < 0 ) {
|
85 |
return;
|
86 |
}
|
87 |
+
$cutoff = as_get_datetime_object($timeout.' seconds ago');
|
88 |
+
$actions_to_reset = $this->store->query_actions( array(
|
89 |
+
'status' => ActionScheduler_Store::STATUS_PENDING,
|
90 |
+
'modified' => $cutoff,
|
91 |
+
'modified_compare' => '<=',
|
92 |
+
'claimed' => true,
|
93 |
+
'per_page' => $this->get_batch_size(),
|
94 |
+
'orderby' => 'none',
|
95 |
+
) );
|
|
|
96 |
|
97 |
foreach ( $actions_to_reset as $action_id ) {
|
98 |
$this->store->unclaim_action( $action_id );
|
114 |
if ( $timeout < 0 ) {
|
115 |
return;
|
116 |
}
|
117 |
+
$cutoff = as_get_datetime_object($timeout.' seconds ago');
|
118 |
+
$actions_to_reset = $this->store->query_actions( array(
|
119 |
+
'status' => ActionScheduler_Store::STATUS_RUNNING,
|
120 |
+
'modified' => $cutoff,
|
121 |
+
'modified_compare' => '<=',
|
122 |
+
'per_page' => $this->get_batch_size(),
|
123 |
+
'orderby' => 'none',
|
124 |
+
) );
|
|
|
125 |
|
126 |
foreach ( $actions_to_reset as $action_id ) {
|
127 |
$this->store->mark_failure( $action_id );
|
lite/includes/libraries/action-scheduler/classes/ActionScheduler_QueueRunner.php
CHANGED
@@ -19,8 +19,8 @@ class ActionScheduler_QueueRunner extends ActionScheduler_Abstract_QueueRunner {
|
|
19 |
* @codeCoverageIgnore
|
20 |
*/
|
21 |
public static function instance() {
|
22 |
-
if ( empty(
|
23 |
-
$class
|
24 |
self::$runner = new $class();
|
25 |
}
|
26 |
return self::$runner;
|
@@ -114,7 +114,6 @@ class ActionScheduler_QueueRunner extends ActionScheduler_Abstract_QueueRunner {
|
|
114 |
* that was the only context in which this method was run, and the self::WP_CRON_HOOK hook had no context
|
115 |
* passed along with it. New code calling this method directly, or by triggering the self::WP_CRON_HOOK,
|
116 |
* should set a context as the first parameter. For an example of this, refer to the code seen in
|
117 |
-
*
|
118 |
* @see ActionScheduler_AsyncRequest_QueueRunner::handle()
|
119 |
*
|
120 |
* @param string $context Optional identifer for the context in which this action is being processed, e.g. 'WP CLI' or 'WP Cron'
|
@@ -145,14 +144,14 @@ class ActionScheduler_QueueRunner extends ActionScheduler_Abstract_QueueRunner {
|
|
145 |
* Actions are processed by claiming a set of pending actions then processing each one until either the batch
|
146 |
* size is completed, or memory or time limits are reached, defined by @see $this->batch_limits_exceeded().
|
147 |
*
|
148 |
-
* @param int
|
149 |
* @param string $context Optional identifer for the context in which this action is being processed, e.g. 'WP CLI' or 'WP Cron'
|
150 |
* Generally, this should be capitalised and not localised as it's a proper noun.
|
151 |
* @return int The number of actions processed.
|
152 |
*/
|
153 |
protected function do_batch( $size = 100, $context = '' ) {
|
154 |
-
$claim = $this->store->stake_claim(
|
155 |
-
$this->monitor->attach(
|
156 |
$processed_actions = 0;
|
157 |
|
158 |
foreach ( $claim->get_actions() as $action_id ) {
|
@@ -167,7 +166,7 @@ class ActionScheduler_QueueRunner extends ActionScheduler_Abstract_QueueRunner {
|
|
167 |
break;
|
168 |
}
|
169 |
}
|
170 |
-
$this->store->release_claim(
|
171 |
$this->monitor->detach();
|
172 |
$this->clear_caches();
|
173 |
return $processed_actions;
|
19 |
* @codeCoverageIgnore
|
20 |
*/
|
21 |
public static function instance() {
|
22 |
+
if ( empty(self::$runner) ) {
|
23 |
+
$class = apply_filters('action_scheduler_queue_runner_class', 'ActionScheduler_QueueRunner');
|
24 |
self::$runner = new $class();
|
25 |
}
|
26 |
return self::$runner;
|
114 |
* that was the only context in which this method was run, and the self::WP_CRON_HOOK hook had no context
|
115 |
* passed along with it. New code calling this method directly, or by triggering the self::WP_CRON_HOOK,
|
116 |
* should set a context as the first parameter. For an example of this, refer to the code seen in
|
|
|
117 |
* @see ActionScheduler_AsyncRequest_QueueRunner::handle()
|
118 |
*
|
119 |
* @param string $context Optional identifer for the context in which this action is being processed, e.g. 'WP CLI' or 'WP Cron'
|
144 |
* Actions are processed by claiming a set of pending actions then processing each one until either the batch
|
145 |
* size is completed, or memory or time limits are reached, defined by @see $this->batch_limits_exceeded().
|
146 |
*
|
147 |
+
* @param int $size The maximum number of actions to process in the batch.
|
148 |
* @param string $context Optional identifer for the context in which this action is being processed, e.g. 'WP CLI' or 'WP Cron'
|
149 |
* Generally, this should be capitalised and not localised as it's a proper noun.
|
150 |
* @return int The number of actions processed.
|
151 |
*/
|
152 |
protected function do_batch( $size = 100, $context = '' ) {
|
153 |
+
$claim = $this->store->stake_claim($size);
|
154 |
+
$this->monitor->attach($claim);
|
155 |
$processed_actions = 0;
|
156 |
|
157 |
foreach ( $claim->get_actions() as $action_id ) {
|
166 |
break;
|
167 |
}
|
168 |
}
|
169 |
+
$this->store->release_claim($claim);
|
170 |
$this->monitor->detach();
|
171 |
$this->clear_caches();
|
172 |
return $processed_actions;
|
lite/includes/libraries/action-scheduler/classes/ActionScheduler_Versions.php
CHANGED
@@ -7,16 +7,16 @@ class ActionScheduler_Versions {
|
|
7 |
/**
|
8 |
* @var ActionScheduler_Versions
|
9 |
*/
|
10 |
-
private static $instance =
|
11 |
|
12 |
private $versions = array();
|
13 |
|
14 |
public function register( $version_string, $initialization_callback ) {
|
15 |
-
if ( isset(
|
16 |
-
return
|
17 |
}
|
18 |
-
$this->versions[
|
19 |
-
return
|
20 |
}
|
21 |
|
22 |
public function get_versions() {
|
@@ -24,20 +24,20 @@ class ActionScheduler_Versions {
|
|
24 |
}
|
25 |
|
26 |
public function latest_version() {
|
27 |
-
$keys = array_keys(
|
28 |
-
if ( empty(
|
29 |
return false;
|
30 |
}
|
31 |
uasort( $keys, 'version_compare' );
|
32 |
-
return end(
|
33 |
}
|
34 |
|
35 |
public function latest_version_callback() {
|
36 |
$latest = $this->latest_version();
|
37 |
-
if ( empty(
|
38 |
return '__return_null';
|
39 |
}
|
40 |
-
return $this->versions[
|
41 |
}
|
42 |
|
43 |
/**
|
@@ -45,7 +45,7 @@ class ActionScheduler_Versions {
|
|
45 |
* @codeCoverageIgnore
|
46 |
*/
|
47 |
public static function instance() {
|
48 |
-
if ( empty(
|
49 |
self::$instance = new self();
|
50 |
}
|
51 |
return self::$instance;
|
@@ -56,7 +56,7 @@ class ActionScheduler_Versions {
|
|
56 |
*/
|
57 |
public static function initialize_latest_version() {
|
58 |
$self = self::instance();
|
59 |
-
call_user_func(
|
60 |
}
|
61 |
}
|
62 |
-
|
7 |
/**
|
8 |
* @var ActionScheduler_Versions
|
9 |
*/
|
10 |
+
private static $instance = NULL;
|
11 |
|
12 |
private $versions = array();
|
13 |
|
14 |
public function register( $version_string, $initialization_callback ) {
|
15 |
+
if ( isset($this->versions[$version_string]) ) {
|
16 |
+
return FALSE;
|
17 |
}
|
18 |
+
$this->versions[$version_string] = $initialization_callback;
|
19 |
+
return TRUE;
|
20 |
}
|
21 |
|
22 |
public function get_versions() {
|
24 |
}
|
25 |
|
26 |
public function latest_version() {
|
27 |
+
$keys = array_keys($this->versions);
|
28 |
+
if ( empty($keys) ) {
|
29 |
return false;
|
30 |
}
|
31 |
uasort( $keys, 'version_compare' );
|
32 |
+
return end($keys);
|
33 |
}
|
34 |
|
35 |
public function latest_version_callback() {
|
36 |
$latest = $this->latest_version();
|
37 |
+
if ( empty($latest) || !isset($this->versions[$latest]) ) {
|
38 |
return '__return_null';
|
39 |
}
|
40 |
+
return $this->versions[$latest];
|
41 |
}
|
42 |
|
43 |
/**
|
45 |
* @codeCoverageIgnore
|
46 |
*/
|
47 |
public static function instance() {
|
48 |
+
if ( empty(self::$instance) ) {
|
49 |
self::$instance = new self();
|
50 |
}
|
51 |
return self::$instance;
|
56 |
*/
|
57 |
public static function initialize_latest_version() {
|
58 |
$self = self::instance();
|
59 |
+
call_user_func($self->latest_version_callback());
|
60 |
}
|
61 |
}
|
62 |
+
|
lite/includes/libraries/action-scheduler/classes/ActionScheduler_WPCommentCleaner.php
CHANGED
@@ -66,13 +66,7 @@ class ActionScheduler_WPCommentCleaner {
|
|
66 |
* Attached to the migration complete hook 'action_scheduler/migration_complete'.
|
67 |
*/
|
68 |
public static function maybe_schedule_cleanup() {
|
69 |
-
if ( (bool) get_comments(
|
70 |
-
array(
|
71 |
-
'type' => ActionScheduler_wpCommentLogger::TYPE,
|
72 |
-
'number' => 1,
|
73 |
-
'fields' => 'ids',
|
74 |
-
)
|
75 |
-
) ) {
|
76 |
update_option( self::$has_logs_option_key, 'yes' );
|
77 |
|
78 |
if ( ! as_next_scheduled_action( self::$cleanup_hook ) ) {
|
@@ -86,13 +80,7 @@ class ActionScheduler_WPCommentCleaner {
|
|
86 |
*/
|
87 |
public static function delete_all_action_comments() {
|
88 |
global $wpdb;
|
89 |
-
$wpdb->delete(
|
90 |
-
$wpdb->comments,
|
91 |
-
array(
|
92 |
-
'comment_type' => ActionScheduler_wpCommentLogger::TYPE,
|
93 |
-
'comment_agent' => ActionScheduler_wpCommentLogger::AGENT,
|
94 |
-
)
|
95 |
-
);
|
96 |
delete_option( self::$has_logs_option_key );
|
97 |
}
|
98 |
|
@@ -102,7 +90,7 @@ class ActionScheduler_WPCommentCleaner {
|
|
102 |
public static function register_admin_notice() {
|
103 |
add_action( 'admin_notices', array( __CLASS__, 'print_admin_notice' ) );
|
104 |
}
|
105 |
-
|
106 |
/**
|
107 |
* Prints details about the orphaned action logs and includes information on where to learn more.
|
108 |
*/
|
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 ) ) {
|
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 |
|
90 |
public static function register_admin_notice() {
|
91 |
add_action( 'admin_notices', array( __CLASS__, 'print_admin_notice' ) );
|
92 |
}
|
93 |
+
|
94 |
/**
|
95 |
* Prints details about the orphaned action logs and includes information on where to learn more.
|
96 |
*/
|
lite/includes/libraries/action-scheduler/classes/ActionScheduler_wcSystemStatus.php
CHANGED
@@ -12,7 +12,14 @@ class ActionScheduler_wcSystemStatus {
|
|
12 |
*/
|
13 |
protected $store;
|
14 |
|
15 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
16 |
$this->store = $store;
|
17 |
}
|
18 |
|
@@ -94,18 +101,23 @@ class ActionScheduler_wcSystemStatus {
|
|
94 |
* @param array $oldest_and_newest Date of the oldest and newest action with each status.
|
95 |
*/
|
96 |
protected function get_template( $status_labels, $action_counts, $oldest_and_newest ) {
|
97 |
-
$as_version
|
|
|
98 |
?>
|
99 |
|
100 |
<table class="wc_status_table widefat" cellspacing="0">
|
101 |
<thead>
|
102 |
<tr>
|
103 |
-
<th colspan="5" data-export-label="Action Scheduler"><h2><?php esc_html_e( 'Action Scheduler', 'action-scheduler' ); ?><?php echo wc_help_tip( esc_html__( 'This section shows
|
104 |
</tr>
|
105 |
<tr>
|
106 |
<td colspan="2" data-export-label="Version"><?php esc_html_e( 'Version:', 'action-scheduler' ); ?></td>
|
107 |
<td colspan="3"><?php echo esc_html( $as_version ); ?></td>
|
108 |
</tr>
|
|
|
|
|
|
|
|
|
109 |
<tr>
|
110 |
<td><strong><?php esc_html_e( 'Action Status', 'action-scheduler' ); ?></strong></td>
|
111 |
<td class="help"> </td>
|
@@ -121,9 +133,9 @@ class ActionScheduler_wcSystemStatus {
|
|
121 |
printf(
|
122 |
'<tr><td>%1$s</td><td> </td><td>%2$s<span style="display: none;">, Oldest: %3$s, Newest: %4$s</span></td><td>%3$s</td><td>%4$s</td></tr>',
|
123 |
esc_html( $status_labels[ $status ] ),
|
124 |
-
number_format_i18n( $count ),
|
125 |
-
$oldest_and_newest[ $status ]['oldest'],
|
126 |
-
$oldest_and_newest[ $status ]['newest']
|
127 |
);
|
128 |
}
|
129 |
?>
|
@@ -134,10 +146,10 @@ class ActionScheduler_wcSystemStatus {
|
|
134 |
}
|
135 |
|
136 |
/**
|
137 |
-
*
|
138 |
*
|
139 |
-
* @param string $name
|
140 |
-
* @param array $arguments
|
141 |
*
|
142 |
* @return mixed
|
143 |
* @link https://php.net/manual/en/language.oop5.overloading.php#language.oop5.overloading.methods
|
12 |
*/
|
13 |
protected $store;
|
14 |
|
15 |
+
/**
|
16 |
+
* Constructor method for ActionScheduler_wcSystemStatus.
|
17 |
+
*
|
18 |
+
* @param ActionScheduler_Store $store Active store object.
|
19 |
+
*
|
20 |
+
* @return void
|
21 |
+
*/
|
22 |
+
public function __construct( $store ) {
|
23 |
$this->store = $store;
|
24 |
}
|
25 |
|
101 |
* @param array $oldest_and_newest Date of the oldest and newest action with each status.
|
102 |
*/
|
103 |
protected function get_template( $status_labels, $action_counts, $oldest_and_newest ) {
|
104 |
+
$as_version = ActionScheduler_Versions::instance()->latest_version();
|
105 |
+
$as_datastore = get_class( ActionScheduler_Store::instance() );
|
106 |
?>
|
107 |
|
108 |
<table class="wc_status_table widefat" cellspacing="0">
|
109 |
<thead>
|
110 |
<tr>
|
111 |
+
<th colspan="5" data-export-label="Action Scheduler"><h2><?php esc_html_e( 'Action Scheduler', 'action-scheduler' ); ?><?php echo wc_help_tip( esc_html__( 'This section shows details of Action Scheduler.', 'action-scheduler' ) ); ?></h2></th>
|
112 |
</tr>
|
113 |
<tr>
|
114 |
<td colspan="2" data-export-label="Version"><?php esc_html_e( 'Version:', 'action-scheduler' ); ?></td>
|
115 |
<td colspan="3"><?php echo esc_html( $as_version ); ?></td>
|
116 |
</tr>
|
117 |
+
<tr>
|
118 |
+
<td colspan="2" data-export-label="Data store"><?php esc_html_e( 'Data store:', 'action-scheduler' ); ?></td>
|
119 |
+
<td colspan="3"><?php echo esc_html( $as_datastore ); ?></td>
|
120 |
+
</tr>
|
121 |
<tr>
|
122 |
<td><strong><?php esc_html_e( 'Action Status', 'action-scheduler' ); ?></strong></td>
|
123 |
<td class="help"> </td>
|
133 |
printf(
|
134 |
'<tr><td>%1$s</td><td> </td><td>%2$s<span style="display: none;">, Oldest: %3$s, Newest: %4$s</span></td><td>%3$s</td><td>%4$s</td></tr>',
|
135 |
esc_html( $status_labels[ $status ] ),
|
136 |
+
esc_html( number_format_i18n( $count ) ),
|
137 |
+
esc_html( $oldest_and_newest[ $status ]['oldest'] ),
|
138 |
+
esc_html( $oldest_and_newest[ $status ]['newest'] )
|
139 |
);
|
140 |
}
|
141 |
?>
|
146 |
}
|
147 |
|
148 |
/**
|
149 |
+
* Is triggered when invoking inaccessible methods in an object context.
|
150 |
*
|
151 |
+
* @param string $name Name of method called.
|
152 |
+
* @param array $arguments Parameters to invoke the method with.
|
153 |
*
|
154 |
* @return mixed
|
155 |
* @link https://php.net/manual/en/language.oop5.overloading.php#language.oop5.overloading.methods
|
lite/includes/libraries/action-scheduler/classes/WP_CLI/ActionScheduler_WPCLI_QueueRunner.php
CHANGED
@@ -143,7 +143,7 @@ class ActionScheduler_WPCLI_QueueRunner extends ActionScheduler_Abstract_QueueRu
|
|
143 |
*
|
144 |
* @author Jeremy Pry
|
145 |
*
|
146 |
-
* @param int
|
147 |
* @param null|ActionScheduler_Action $action The instance of the action. Default to null for backward compatibility.
|
148 |
*/
|
149 |
public function after_execute( $action_id, $action = null ) {
|
143 |
*
|
144 |
* @author Jeremy Pry
|
145 |
*
|
146 |
+
* @param int $action_id
|
147 |
* @param null|ActionScheduler_Action $action The instance of the action. Default to null for backward compatibility.
|
148 |
*/
|
149 |
public function after_execute( $action_id, $action = null ) {
|
lite/includes/libraries/action-scheduler/classes/WP_CLI/Migration_Command.php
CHANGED
@@ -32,42 +32,38 @@ class Migration_Command extends WP_CLI_Command {
|
|
32 |
return;
|
33 |
}
|
34 |
|
35 |
-
WP_CLI::add_command(
|
36 |
-
'
|
37 |
-
|
38 |
-
|
39 |
-
|
40 |
-
|
41 |
-
|
42 |
-
|
43 |
-
|
44 |
-
|
45 |
-
|
46 |
-
|
47 |
-
|
48 |
-
|
49 |
-
|
50 |
-
|
51 |
-
|
52 |
-
|
53 |
-
|
54 |
-
|
55 |
-
|
56 |
-
|
57 |
-
|
58 |
-
|
59 |
-
|
60 |
-
|
61 |
-
|
62 |
-
|
63 |
-
|
64 |
-
|
65 |
-
|
66 |
-
|
67 |
-
),
|
68 |
-
),
|
69 |
-
)
|
70 |
-
);
|
71 |
}
|
72 |
|
73 |
/**
|
@@ -85,14 +81,14 @@ class Migration_Command extends WP_CLI_Command {
|
|
85 |
$runner = new Runner( $config );
|
86 |
$runner->init_destination();
|
87 |
|
88 |
-
$batch_size = isset( $assoc_args['batch-size'] ) ? (int) $assoc_args['batch-size'] : 100;
|
89 |
-
$free_on = isset( $assoc_args['free-memory-on'] ) ? (int) $assoc_args['free-memory-on'] : 50;
|
90 |
-
$sleep = isset( $assoc_args['pause'] ) ? (int) $assoc_args['pause'] : 0;
|
91 |
\ActionScheduler_DataController::set_free_ticks( $free_on );
|
92 |
\ActionScheduler_DataController::set_sleep_time( $sleep );
|
93 |
|
94 |
do {
|
95 |
-
$actions_processed
|
96 |
$this->total_processed += $actions_processed;
|
97 |
} while ( $actions_processed > 0 );
|
98 |
|
@@ -113,15 +109,12 @@ class Migration_Command extends WP_CLI_Command {
|
|
113 |
* @return ActionScheduler\Migration\Config
|
114 |
*/
|
115 |
private function get_migration_config( $args ) {
|
116 |
-
$args = wp_parse_args(
|
117 |
-
|
118 |
-
|
119 |
-
'dry-run' => false,
|
120 |
-
)
|
121 |
-
);
|
122 |
|
123 |
$config = Controller::instance()->get_migration_config_object();
|
124 |
-
$config->set_dry_run( ! empty( $args['dry-run'] ) );
|
125 |
|
126 |
return $config;
|
127 |
}
|
@@ -130,61 +123,26 @@ class Migration_Command extends WP_CLI_Command {
|
|
130 |
* Hook command line logging into migration actions.
|
131 |
*/
|
132 |
private function init_logging() {
|
133 |
-
add_action(
|
134 |
-
'
|
135 |
-
|
136 |
-
|
137 |
-
|
138 |
-
|
139 |
-
|
140 |
-
|
141 |
-
|
142 |
-
|
143 |
-
|
144 |
-
|
145 |
-
|
146 |
-
|
147 |
-
|
148 |
-
)
|
149 |
-
|
150 |
-
|
151 |
-
|
152 |
-
|
153 |
-
|
154 |
-
10,
|
155 |
-
1
|
156 |
-
);
|
157 |
-
add_action(
|
158 |
-
'action_scheduler/migrate_action_incomplete',
|
159 |
-
function ( $source_id, $destination_id ) {
|
160 |
-
WP_CLI::warning( sprintf( 'Unable to remove source action with ID %d after migrating to new ID %d', $source_id, $destination_id ) );
|
161 |
-
},
|
162 |
-
10,
|
163 |
-
2
|
164 |
-
);
|
165 |
-
add_action(
|
166 |
-
'action_scheduler/migrated_action',
|
167 |
-
function ( $source_id, $destination_id ) {
|
168 |
-
WP_CLI::debug( sprintf( 'Migrated source action with ID %d to new store with ID %d', $source_id, $destination_id ) );
|
169 |
-
},
|
170 |
-
10,
|
171 |
-
2
|
172 |
-
);
|
173 |
-
add_action(
|
174 |
-
'action_scheduler/migration_batch_starting',
|
175 |
-
function ( $batch ) {
|
176 |
-
WP_CLI::debug( 'Beginning migration of batch: ' . print_r( $batch, true ) );
|
177 |
-
},
|
178 |
-
10,
|
179 |
-
1
|
180 |
-
);
|
181 |
-
add_action(
|
182 |
-
'action_scheduler/migration_batch_complete',
|
183 |
-
function ( $batch ) {
|
184 |
-
WP_CLI::log( sprintf( 'Completed migration of %d actions', count( $batch ) ) );
|
185 |
-
},
|
186 |
-
10,
|
187 |
-
1
|
188 |
-
);
|
189 |
}
|
190 |
}
|
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 |
/**
|
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 |
|
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 |
}
|
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 |
}
|
lite/includes/libraries/action-scheduler/classes/WP_CLI/ProgressBar.php
CHANGED
@@ -38,7 +38,7 @@ class ProgressBar {
|
|
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 ) {
|
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 ) {
|
lite/includes/libraries/action-scheduler/classes/abstracts/ActionScheduler.php
CHANGED
@@ -5,18 +5,17 @@ use Action_Scheduler\Migration\Controller;
|
|
5 |
|
6 |
/**
|
7 |
* Class ActionScheduler
|
8 |
-
*
|
9 |
* @codeCoverageIgnore
|
10 |
*/
|
11 |
abstract class ActionScheduler {
|
12 |
private static $plugin_file = '';
|
13 |
/** @var ActionScheduler_ActionFactory */
|
14 |
-
private static $factory =
|
15 |
/** @var bool */
|
16 |
private static $data_store_initialized = false;
|
17 |
|
18 |
public static function factory() {
|
19 |
-
if ( !
|
20 |
self::$factory = new ActionScheduler_ActionFactory();
|
21 |
}
|
22 |
return self::$factory;
|
@@ -44,29 +43,27 @@ abstract class ActionScheduler {
|
|
44 |
|
45 |
/**
|
46 |
* Get the absolute system path to the plugin directory, or a file therein
|
47 |
-
*
|
48 |
* @static
|
49 |
* @param string $path
|
50 |
* @return string
|
51 |
*/
|
52 |
public static function plugin_path( $path ) {
|
53 |
-
$base = dirname(
|
54 |
if ( $path ) {
|
55 |
-
return trailingslashit(
|
56 |
} else {
|
57 |
-
return untrailingslashit(
|
58 |
}
|
59 |
}
|
60 |
|
61 |
/**
|
62 |
* Get the absolute URL to the plugin directory, or a file therein
|
63 |
-
*
|
64 |
* @static
|
65 |
* @param string $path
|
66 |
* @return string
|
67 |
*/
|
68 |
public static function plugin_url( $path ) {
|
69 |
-
return plugins_url(
|
70 |
}
|
71 |
|
72 |
public static function autoload( $class ) {
|
@@ -94,7 +91,7 @@ abstract class ActionScheduler {
|
|
94 |
$dir = $classes_dir . 'schema' . $d;
|
95 |
} elseif ( strpos( $class, 'ActionScheduler' ) === 0 ) {
|
96 |
$segments = explode( '_', $class );
|
97 |
-
$type
|
98 |
|
99 |
switch ( $type ) {
|
100 |
case 'WPCLI':
|
@@ -122,7 +119,7 @@ abstract class ActionScheduler {
|
|
122 |
}
|
123 |
|
124 |
if ( file_exists( "{$dir}{$class}.php" ) ) {
|
125 |
-
include "{$dir}{$class}.php";
|
126 |
return;
|
127 |
}
|
128 |
}
|
@@ -142,7 +139,7 @@ abstract class ActionScheduler {
|
|
142 |
*/
|
143 |
do_action( 'action_scheduler_pre_init' );
|
144 |
|
145 |
-
require_once self::plugin_path( 'functions.php' );
|
146 |
ActionScheduler_DataController::init();
|
147 |
|
148 |
$store = self::store();
|
@@ -164,7 +161,7 @@ abstract class ActionScheduler {
|
|
164 |
}
|
165 |
|
166 |
if ( apply_filters( 'action_scheduler_load_deprecated_functions', true ) ) {
|
167 |
-
require_once self::plugin_path( 'deprecated/functions.php' );
|
168 |
}
|
169 |
|
170 |
if ( defined( 'WP_CLI' ) && WP_CLI ) {
|
@@ -251,7 +248,7 @@ abstract class ActionScheduler {
|
|
251 |
);
|
252 |
|
253 |
$segments = explode( '_', $class );
|
254 |
-
$segment
|
255 |
|
256 |
return isset( $migration_segments[ $segment ] ) && $migration_segments[ $segment ];
|
257 |
}
|
@@ -273,17 +270,17 @@ abstract class ActionScheduler {
|
|
273 |
);
|
274 |
|
275 |
$segments = explode( '_', $class );
|
276 |
-
$segment
|
277 |
|
278 |
return isset( $cli_segments[ $segment ] ) && $cli_segments[ $segment ];
|
279 |
}
|
280 |
|
281 |
final public function __clone() {
|
282 |
-
trigger_error(
|
283 |
}
|
284 |
|
285 |
final public function __wakeup() {
|
286 |
-
trigger_error(
|
287 |
}
|
288 |
|
289 |
final private function __construct() {}
|
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 |
/** @var bool */
|
15 |
private static $data_store_initialized = false;
|
16 |
|
17 |
public static function factory() {
|
18 |
+
if ( !isset(self::$factory) ) {
|
19 |
self::$factory = new ActionScheduler_ActionFactory();
|
20 |
}
|
21 |
return self::$factory;
|
43 |
|
44 |
/**
|
45 |
* Get the absolute system path to the plugin directory, or a file therein
|
|
|
46 |
* @static
|
47 |
* @param string $path
|
48 |
* @return string
|
49 |
*/
|
50 |
public static function plugin_path( $path ) {
|
51 |
+
$base = dirname(self::$plugin_file);
|
52 |
if ( $path ) {
|
53 |
+
return trailingslashit($base).$path;
|
54 |
} else {
|
55 |
+
return untrailingslashit($base);
|
56 |
}
|
57 |
}
|
58 |
|
59 |
/**
|
60 |
* Get the absolute URL to the plugin directory, or a file therein
|
|
|
61 |
* @static
|
62 |
* @param string $path
|
63 |
* @return string
|
64 |
*/
|
65 |
public static function plugin_url( $path ) {
|
66 |
+
return plugins_url($path, self::$plugin_file);
|
67 |
}
|
68 |
|
69 |
public static function autoload( $class ) {
|
91 |
$dir = $classes_dir . 'schema' . $d;
|
92 |
} elseif ( strpos( $class, 'ActionScheduler' ) === 0 ) {
|
93 |
$segments = explode( '_', $class );
|
94 |
+
$type = isset( $segments[ 1 ] ) ? $segments[ 1 ] : '';
|
95 |
|
96 |
switch ( $type ) {
|
97 |
case 'WPCLI':
|
119 |
}
|
120 |
|
121 |
if ( file_exists( "{$dir}{$class}.php" ) ) {
|
122 |
+
include( "{$dir}{$class}.php" );
|
123 |
return;
|
124 |
}
|
125 |
}
|
139 |
*/
|
140 |
do_action( 'action_scheduler_pre_init' );
|
141 |
|
142 |
+
require_once( self::plugin_path( 'functions.php' ) );
|
143 |
ActionScheduler_DataController::init();
|
144 |
|
145 |
$store = self::store();
|
161 |
}
|
162 |
|
163 |
if ( apply_filters( 'action_scheduler_load_deprecated_functions', true ) ) {
|
164 |
+
require_once( self::plugin_path( 'deprecated/functions.php' ) );
|
165 |
}
|
166 |
|
167 |
if ( defined( 'WP_CLI' ) && WP_CLI ) {
|
248 |
);
|
249 |
|
250 |
$segments = explode( '_', $class );
|
251 |
+
$segment = isset( $segments[ 1 ] ) ? $segments[ 1 ] : $class;
|
252 |
|
253 |
return isset( $migration_segments[ $segment ] ) && $migration_segments[ $segment ];
|
254 |
}
|
270 |
);
|
271 |
|
272 |
$segments = explode( '_', $class );
|
273 |
+
$segment = isset( $segments[ 1 ] ) ? $segments[ 1 ] : $class;
|
274 |
|
275 |
return isset( $cli_segments[ $segment ] ) && $cli_segments[ $segment ];
|
276 |
}
|
277 |
|
278 |
final public function __clone() {
|
279 |
+
trigger_error("Singleton. No cloning allowed!", E_USER_ERROR);
|
280 |
}
|
281 |
|
282 |
final public function __wakeup() {
|
283 |
+
trigger_error("Singleton. No serialization allowed!", E_USER_ERROR);
|
284 |
}
|
285 |
|
286 |
final private function __construct() {}
|
lite/includes/libraries/action-scheduler/classes/abstracts/ActionScheduler_Abstract_ListTable.php
CHANGED
@@ -25,22 +25,30 @@ abstract class ActionScheduler_Abstract_ListTable extends WP_List_Table {
|
|
25 |
|
26 |
/**
|
27 |
* The table name
|
|
|
|
|
28 |
*/
|
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 |
|
36 |
/**
|
37 |
* How many items do we render per page?
|
|
|
|
|
38 |
*/
|
39 |
protected $items_per_page = 10;
|
40 |
|
41 |
/**
|
42 |
* Enables search in this table listing. If this array
|
43 |
* is empty it means the listing is not searchable.
|
|
|
|
|
44 |
*/
|
45 |
protected $search_by = array();
|
46 |
|
@@ -48,6 +56,8 @@ abstract class ActionScheduler_Abstract_ListTable extends WP_List_Table {
|
|
48 |
* Columns to show in the table listing. It is a key => value pair. The
|
49 |
* key must much the table column name and the value is the label, which is
|
50 |
* automatically translated.
|
|
|
|
|
51 |
*/
|
52 |
protected $columns = array();
|
53 |
|
@@ -58,34 +68,51 @@ abstract class ActionScheduler_Abstract_ListTable extends WP_List_Table {
|
|
58 |
* The array of actions are key => value, where key is the method name
|
59 |
* (with the prefix row_action_<key>) and the value is the label
|
60 |
* and title.
|
|
|
|
|
61 |
*/
|
62 |
protected $row_actions = array();
|
63 |
|
64 |
/**
|
65 |
* The Primary key of our table
|
|
|
|
|
66 |
*/
|
67 |
protected $ID = 'ID';
|
68 |
|
69 |
/**
|
70 |
* Enables sorting, it expects an array
|
71 |
* of columns (the column names are the values)
|
|
|
|
|
72 |
*/
|
73 |
protected $sort_by = array();
|
74 |
|
|
|
|
|
|
|
|
|
|
|
75 |
protected $filter_by = array();
|
76 |
|
77 |
/**
|
78 |
-
*
|
|
|
|
|
79 |
*/
|
80 |
protected $status_counts = array();
|
81 |
|
82 |
/**
|
83 |
-
*
|
|
|
|
|
84 |
*/
|
85 |
protected $admin_notices = array();
|
86 |
|
87 |
/**
|
88 |
-
*
|
|
|
|
|
89 |
*/
|
90 |
protected $table_header;
|
91 |
|
@@ -99,6 +126,8 @@ abstract class ActionScheduler_Abstract_ListTable extends WP_List_Table {
|
|
99 |
* validations and afterwards will execute the bulk method, with two arguments. The first argument
|
100 |
* is the array with primary keys, the second argument is a string with a list of the primary keys,
|
101 |
* escaped and ready to use (with `IN`).
|
|
|
|
|
102 |
*/
|
103 |
protected $bulk_actions = array();
|
104 |
|
@@ -106,7 +135,11 @@ abstract class ActionScheduler_Abstract_ListTable extends WP_List_Table {
|
|
106 |
* Makes translation easier, it basically just wraps
|
107 |
* `_x` with some default (the package name).
|
108 |
*
|
109 |
-
* @
|
|
|
|
|
|
|
|
|
110 |
*/
|
111 |
protected function translate( $text, $context = '' ) {
|
112 |
return $text;
|
@@ -116,6 +149,10 @@ abstract class ActionScheduler_Abstract_ListTable extends WP_List_Table {
|
|
116 |
* Reads `$this->bulk_actions` and returns an array that WP_List_Table understands. It
|
117 |
* also validates that the bulk method handler exists. It throws an exception because
|
118 |
* this is a library meant for developers and missing a bulk method is a development-time error.
|
|
|
|
|
|
|
|
|
119 |
*/
|
120 |
protected function get_bulk_actions() {
|
121 |
$actions = array();
|
@@ -149,21 +186,28 @@ abstract class ActionScheduler_Abstract_ListTable extends WP_List_Table {
|
|
149 |
$method = 'bulk_' . $action;
|
150 |
if ( array_key_exists( $action, $this->bulk_actions ) && is_callable( array( $this, $method ) ) && ! empty( $_GET['ID'] ) && is_array( $_GET['ID'] ) ) {
|
151 |
$ids_sql = '(' . implode( ',', array_fill( 0, count( $_GET['ID'] ), '%s' ) ) . ')';
|
152 |
-
$
|
|
|
153 |
}
|
154 |
|
155 |
-
|
156 |
-
|
157 |
-
|
158 |
-
|
159 |
-
|
160 |
-
|
161 |
-
|
|
|
|
|
162 |
}
|
163 |
|
164 |
/**
|
165 |
* Default code for deleting entries.
|
166 |
* validated already by process_bulk_action()
|
|
|
|
|
|
|
|
|
167 |
*/
|
168 |
protected function bulk_delete( array $ids, $ids_sql ) {
|
169 |
$store = ActionScheduler::store();
|
@@ -179,7 +223,7 @@ abstract class ActionScheduler_Abstract_ListTable extends WP_List_Table {
|
|
179 |
protected function prepare_column_headers() {
|
180 |
$this->_column_headers = array(
|
181 |
$this->get_columns(),
|
182 |
-
|
183 |
$this->get_sortable_columns(),
|
184 |
);
|
185 |
}
|
@@ -219,7 +263,7 @@ abstract class ActionScheduler_Abstract_ListTable extends WP_List_Table {
|
|
219 |
protected function get_items_query_limit() {
|
220 |
global $wpdb;
|
221 |
|
222 |
-
$per_page = $this->get_items_per_page( $this->
|
223 |
return $wpdb->prepare( 'LIMIT %d', $per_page );
|
224 |
}
|
225 |
|
@@ -229,7 +273,7 @@ abstract class ActionScheduler_Abstract_ListTable extends WP_List_Table {
|
|
229 |
* @return int
|
230 |
*/
|
231 |
protected function get_items_offset() {
|
232 |
-
$per_page = $this->get_items_per_page( $this->
|
233 |
$current_page = $this->get_pagenum();
|
234 |
if ( 1 < $current_page ) {
|
235 |
$offset = $per_page * ( $current_page - 1 );
|
@@ -278,8 +322,8 @@ abstract class ActionScheduler_Abstract_ListTable extends WP_List_Table {
|
|
278 |
|
279 |
$valid_sortable_columns = array_values( $this->sort_by );
|
280 |
|
281 |
-
if ( ! empty( $_GET['orderby'] ) && in_array( $_GET['orderby'], $valid_sortable_columns ) ) {
|
282 |
-
$orderby = sanitize_text_field( $_GET['orderby'] );
|
283 |
} else {
|
284 |
$orderby = $valid_sortable_columns[0];
|
285 |
}
|
@@ -294,7 +338,7 @@ abstract class ActionScheduler_Abstract_ListTable extends WP_List_Table {
|
|
294 |
*/
|
295 |
protected function get_request_order() {
|
296 |
|
297 |
-
if ( ! empty( $_GET['order'] ) && 'desc' === strtolower( $_GET['order'] ) ) {
|
298 |
$order = 'DESC';
|
299 |
} else {
|
300 |
$order = 'ASC';
|
@@ -309,7 +353,7 @@ abstract class ActionScheduler_Abstract_ListTable extends WP_List_Table {
|
|
309 |
* @return string
|
310 |
*/
|
311 |
protected function get_request_status() {
|
312 |
-
$status = ( ! empty( $_GET['status'] ) ) ? $_GET['status'] : '';
|
313 |
return $status;
|
314 |
}
|
315 |
|
@@ -319,7 +363,7 @@ abstract class ActionScheduler_Abstract_ListTable extends WP_List_Table {
|
|
319 |
* @return string
|
320 |
*/
|
321 |
protected function get_request_search_query() {
|
322 |
-
$search_query = ( ! empty( $_GET['s'] ) ) ? $_GET['s'] : '';
|
323 |
return $search_query;
|
324 |
}
|
325 |
|
@@ -331,7 +375,7 @@ abstract class ActionScheduler_Abstract_ListTable extends WP_List_Table {
|
|
331 |
*/
|
332 |
protected function get_table_columns() {
|
333 |
$columns = array_keys( $this->columns );
|
334 |
-
if ( ! in_array( $this->ID, $columns ) ) {
|
335 |
$columns[] = $this->ID;
|
336 |
}
|
337 |
|
@@ -345,21 +389,22 @@ abstract class ActionScheduler_Abstract_ListTable extends WP_List_Table {
|
|
345 |
* If the current request does not have any search or if this list table does not support
|
346 |
* that feature it will return an empty string.
|
347 |
*
|
348 |
-
* TODO:
|
349 |
-
* - Improve search doing LIKE by word rather than by phrases.
|
350 |
-
*
|
351 |
* @return string
|
352 |
*/
|
353 |
protected function get_items_query_search() {
|
354 |
global $wpdb;
|
355 |
|
356 |
-
if ( empty( $_GET['s'] ) || empty( $this->search_by ) ) {
|
357 |
return '';
|
358 |
}
|
359 |
|
|
|
|
|
360 |
$filter = array();
|
361 |
foreach ( $this->search_by as $column ) {
|
362 |
-
$
|
|
|
|
|
363 |
}
|
364 |
return implode( ' OR ', $filter );
|
365 |
}
|
@@ -371,18 +416,18 @@ abstract class ActionScheduler_Abstract_ListTable extends WP_List_Table {
|
|
371 |
protected function get_items_query_filters() {
|
372 |
global $wpdb;
|
373 |
|
374 |
-
if ( ! $this->filter_by || empty( $_GET['filter_by'] ) || ! is_array( $_GET['filter_by'] ) ) {
|
375 |
return '';
|
376 |
}
|
377 |
|
378 |
$filter = array();
|
379 |
|
380 |
foreach ( $this->filter_by as $column => $options ) {
|
381 |
-
if ( empty( $_GET['filter_by'][ $column ] ) || empty( $options[ $_GET['filter_by'][ $column ] ] ) ) {
|
382 |
continue;
|
383 |
}
|
384 |
|
385 |
-
$filter[] = $wpdb->prepare( "`$column` = %s", $_GET['filter_by'][ $column ] );
|
386 |
}
|
387 |
|
388 |
return implode( ' AND ', $filter );
|
@@ -405,9 +450,9 @@ abstract class ActionScheduler_Abstract_ListTable extends WP_List_Table {
|
|
405 |
|
406 |
$this->process_row_actions();
|
407 |
|
408 |
-
if ( ! empty( $_REQUEST['_wp_http_referer'] ) ) {
|
409 |
// _wp_http_referer is used only on bulk actions, we remove it to keep the $_GET shorter
|
410 |
-
|
411 |
exit;
|
412 |
}
|
413 |
|
@@ -432,11 +477,11 @@ abstract class ActionScheduler_Abstract_ListTable extends WP_List_Table {
|
|
432 |
|
433 |
$sql = "SELECT $columns FROM {$this->table_name} {$where} {$order} {$limit} {$offset}";
|
434 |
|
435 |
-
$this->set_items( $wpdb->get_results( $sql, ARRAY_A ) );
|
436 |
|
437 |
$query_count = "SELECT COUNT({$this->ID}) FROM {$this->table_name} {$where}";
|
438 |
-
$total_items = $wpdb->get_var( $query_count );
|
439 |
-
$per_page = $this->get_items_per_page( $this->
|
440 |
$this->set_pagination_args(
|
441 |
array(
|
442 |
'total_items' => $total_items,
|
@@ -446,6 +491,11 @@ abstract class ActionScheduler_Abstract_ListTable extends WP_List_Table {
|
|
446 |
);
|
447 |
}
|
448 |
|
|
|
|
|
|
|
|
|
|
|
449 |
public function extra_tablenav( $which ) {
|
450 |
if ( ! $this->filter_by || 'top' !== $which ) {
|
451 |
return;
|
@@ -454,7 +504,7 @@ abstract class ActionScheduler_Abstract_ListTable extends WP_List_Table {
|
|
454 |
echo '<div class="alignleft actions">';
|
455 |
|
456 |
foreach ( $this->filter_by as $id => $options ) {
|
457 |
-
$default = ! empty( $_GET['filter_by'][ $id ] ) ? $_GET['filter_by'][ $id ] : '';
|
458 |
if ( empty( $options[ $default ] ) ) {
|
459 |
$default = '';
|
460 |
}
|
@@ -462,7 +512,7 @@ abstract class ActionScheduler_Abstract_ListTable extends WP_List_Table {
|
|
462 |
echo '<select name="filter_by[' . esc_attr( $id ) . ']" class="first" id="filter-by-' . esc_attr( $id ) . '">';
|
463 |
|
464 |
foreach ( $options as $value => $label ) {
|
465 |
-
echo '<option value="' . esc_attr( $value ) . '" ' . esc_html( $value
|
466 |
. esc_html( $label )
|
467 |
. '</option>';
|
468 |
}
|
@@ -477,6 +527,8 @@ abstract class ActionScheduler_Abstract_ListTable extends WP_List_Table {
|
|
477 |
/**
|
478 |
* Set the data for displaying. It will attempt to unserialize (There is a chance that some columns
|
479 |
* are serialized). This can be override in child classes for futher data transformation.
|
|
|
|
|
480 |
*/
|
481 |
protected function set_items( array $items ) {
|
482 |
$this->items = array();
|
@@ -489,6 +541,8 @@ abstract class ActionScheduler_Abstract_ListTable extends WP_List_Table {
|
|
489 |
* Renders the checkbox for each row, this is the first column and it is named ID regardless
|
490 |
* of how the primary key is named (to keep the code simpler). The bulk actions will do the proper
|
491 |
* name transformation though using `$this->ID`.
|
|
|
|
|
492 |
*/
|
493 |
public function column_cb( $row ) {
|
494 |
return '<input name="ID[]" type="checkbox" value="' . esc_attr( $row[ $this->ID ] ) . '" />';
|
@@ -500,9 +554,9 @@ abstract class ActionScheduler_Abstract_ListTable extends WP_List_Table {
|
|
500 |
* This method renders the action menu, it reads the definition from the $row_actions property,
|
501 |
* and it checks that the row action method exists before rendering it.
|
502 |
*
|
503 |
-
* @param array
|
504 |
-
* @param $column_name
|
505 |
-
* @return
|
506 |
*/
|
507 |
protected function maybe_render_actions( $row, $column_name ) {
|
508 |
if ( empty( $this->row_actions[ $column_name ] ) ) {
|
@@ -539,31 +593,46 @@ abstract class ActionScheduler_Abstract_ListTable extends WP_List_Table {
|
|
539 |
return $actions;
|
540 |
}
|
541 |
|
|
|
|
|
|
|
|
|
|
|
542 |
protected function process_row_actions() {
|
543 |
$parameters = array( 'row_action', 'row_id', 'nonce' );
|
544 |
foreach ( $parameters as $parameter ) {
|
545 |
-
if ( empty( $_REQUEST[ $parameter ] ) ) {
|
546 |
return;
|
547 |
}
|
548 |
}
|
549 |
|
550 |
-
$
|
|
|
|
|
|
|
551 |
|
552 |
-
if ( $
|
553 |
-
$this->$method( $
|
554 |
}
|
555 |
|
556 |
-
|
557 |
-
|
558 |
-
|
559 |
-
|
560 |
-
|
561 |
-
|
562 |
-
|
|
|
|
|
563 |
}
|
564 |
|
565 |
/**
|
566 |
* Default column formatting, it will escape everythig for security.
|
|
|
|
|
|
|
|
|
|
|
567 |
*/
|
568 |
public function column_default( $item, $column_name ) {
|
569 |
$column_html = esc_html( $item[ $column_name ] );
|
@@ -588,7 +657,7 @@ abstract class ActionScheduler_Abstract_ListTable extends WP_List_Table {
|
|
588 |
*/
|
589 |
protected function display_admin_notices() {
|
590 |
foreach ( $this->admin_notices as $notice ) {
|
591 |
-
echo '<div id="message" class="' . $notice['class'] . '">';
|
592 |
echo ' <p>' . wp_kses_post( $notice['message'] ) . '</p>';
|
593 |
echo '</div>';
|
594 |
}
|
@@ -602,7 +671,7 @@ abstract class ActionScheduler_Abstract_ListTable extends WP_List_Table {
|
|
602 |
$status_list_items = array();
|
603 |
$request_status = $this->get_request_status();
|
604 |
|
605 |
-
// Helper to set 'all' filter when not set on status counts passed in
|
606 |
if ( ! isset( $this->status_counts['all'] ) ) {
|
607 |
$this->status_counts = array( 'all' => array_sum( $this->status_counts ) ) + $this->status_counts;
|
608 |
}
|
@@ -626,7 +695,7 @@ abstract class ActionScheduler_Abstract_ListTable extends WP_List_Table {
|
|
626 |
|
627 |
if ( $status_list_items ) {
|
628 |
echo '<ul class="subsubsub">';
|
629 |
-
echo implode( " | \n", $status_list_items );
|
630 |
echo '</ul>';
|
631 |
}
|
632 |
}
|
@@ -638,14 +707,14 @@ abstract class ActionScheduler_Abstract_ListTable extends WP_List_Table {
|
|
638 |
*/
|
639 |
protected function display_table() {
|
640 |
echo '<form id="' . esc_attr( $this->_args['plural'] ) . '-filter" method="get">';
|
641 |
-
foreach ( $_GET as $key => $value ) {
|
642 |
-
if ( '_' === $key[0] || 'paged' === $key ) {
|
643 |
continue;
|
644 |
}
|
645 |
echo '<input type="hidden" name="' . esc_attr( $key ) . '" value="' . esc_attr( $value ) . '" />';
|
646 |
}
|
647 |
if ( ! empty( $this->search_by ) ) {
|
648 |
-
echo $this->search_box( $this->get_search_box_button_text(), 'plugin' ); //
|
649 |
}
|
650 |
parent::display();
|
651 |
echo '</form>';
|
@@ -658,9 +727,9 @@ abstract class ActionScheduler_Abstract_ListTable extends WP_List_Table {
|
|
658 |
$this->process_bulk_action();
|
659 |
$this->process_row_actions();
|
660 |
|
661 |
-
if ( ! empty( $_REQUEST['_wp_http_referer'] ) ) {
|
662 |
// _wp_http_referer is used only on bulk actions, we remove it to keep the $_GET shorter
|
663 |
-
|
664 |
exit;
|
665 |
}
|
666 |
}
|
@@ -685,4 +754,13 @@ abstract class ActionScheduler_Abstract_ListTable extends WP_List_Table {
|
|
685 |
protected function get_search_box_placeholder() {
|
686 |
return esc_html__( 'Search', 'action-scheduler' );
|
687 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
688 |
}
|
25 |
|
26 |
/**
|
27 |
* The table name
|
28 |
+
*
|
29 |
+
* @var string
|
30 |
*/
|
31 |
protected $table_name;
|
32 |
|
33 |
/**
|
34 |
* Package name, used to get options from WP_List_Table::get_items_per_page.
|
35 |
+
*
|
36 |
+
* @var string
|
37 |
*/
|
38 |
protected $package;
|
39 |
|
40 |
/**
|
41 |
* How many items do we render per page?
|
42 |
+
*
|
43 |
+
* @var int
|
44 |
*/
|
45 |
protected $items_per_page = 10;
|
46 |
|
47 |
/**
|
48 |
* Enables search in this table listing. If this array
|
49 |
* is empty it means the listing is not searchable.
|
50 |
+
*
|
51 |
+
* @var array
|
52 |
*/
|
53 |
protected $search_by = array();
|
54 |
|
56 |
* Columns to show in the table listing. It is a key => value pair. The
|
57 |
* key must much the table column name and the value is the label, which is
|
58 |
* automatically translated.
|
59 |
+
*
|
60 |
+
* @var array
|
61 |
*/
|
62 |
protected $columns = array();
|
63 |
|
68 |
* The array of actions are key => value, where key is the method name
|
69 |
* (with the prefix row_action_<key>) and the value is the label
|
70 |
* and title.
|
71 |
+
*
|
72 |
+
* @var array
|
73 |
*/
|
74 |
protected $row_actions = array();
|
75 |
|
76 |
/**
|
77 |
* The Primary key of our table
|
78 |
+
*
|
79 |
+
* @var string
|
80 |
*/
|
81 |
protected $ID = 'ID';
|
82 |
|
83 |
/**
|
84 |
* Enables sorting, it expects an array
|
85 |
* of columns (the column names are the values)
|
86 |
+
*
|
87 |
+
* @var array
|
88 |
*/
|
89 |
protected $sort_by = array();
|
90 |
|
91 |
+
/**
|
92 |
+
* The default sort order
|
93 |
+
*
|
94 |
+
* @var string
|
95 |
+
*/
|
96 |
protected $filter_by = array();
|
97 |
|
98 |
/**
|
99 |
+
* The status name => count combinations for this table's items. Used to display status filters.
|
100 |
+
*
|
101 |
+
* @var array
|
102 |
*/
|
103 |
protected $status_counts = array();
|
104 |
|
105 |
/**
|
106 |
+
* Notices to display when loading the table. Array of arrays of form array( 'class' => {updated|error}, 'message' => 'This is the notice text display.' ).
|
107 |
+
*
|
108 |
+
* @var array
|
109 |
*/
|
110 |
protected $admin_notices = array();
|
111 |
|
112 |
/**
|
113 |
+
* Localised string displayed in the <h1> element above the able.
|
114 |
+
*
|
115 |
+
* @var string
|
116 |
*/
|
117 |
protected $table_header;
|
118 |
|
126 |
* validations and afterwards will execute the bulk method, with two arguments. The first argument
|
127 |
* is the array with primary keys, the second argument is a string with a list of the primary keys,
|
128 |
* escaped and ready to use (with `IN`).
|
129 |
+
*
|
130 |
+
* @var array
|
131 |
*/
|
132 |
protected $bulk_actions = array();
|
133 |
|
135 |
* Makes translation easier, it basically just wraps
|
136 |
* `_x` with some default (the package name).
|
137 |
*
|
138 |
+
* @param string $text The new text to translate.
|
139 |
+
* @param string $context The context of the text.
|
140 |
+
* @return string|void The translated text.
|
141 |
+
*
|
142 |
+
* @deprecated 3.0.0 Use `_x()` instead.
|
143 |
*/
|
144 |
protected function translate( $text, $context = '' ) {
|
145 |
return $text;
|
149 |
* Reads `$this->bulk_actions` and returns an array that WP_List_Table understands. It
|
150 |
* also validates that the bulk method handler exists. It throws an exception because
|
151 |
* this is a library meant for developers and missing a bulk method is a development-time error.
|
152 |
+
*
|
153 |
+
* @return array
|
154 |
+
*
|
155 |
+
* @throws RuntimeException Throws RuntimeException when the bulk action does not have a callback method.
|
156 |
*/
|
157 |
protected function get_bulk_actions() {
|
158 |
$actions = array();
|
186 |
$method = 'bulk_' . $action;
|
187 |
if ( array_key_exists( $action, $this->bulk_actions ) && is_callable( array( $this, $method ) ) && ! empty( $_GET['ID'] ) && is_array( $_GET['ID'] ) ) {
|
188 |
$ids_sql = '(' . implode( ',', array_fill( 0, count( $_GET['ID'] ), '%s' ) ) . ')';
|
189 |
+
$id = array_map( 'absint', $_GET['ID'] );
|
190 |
+
$this->$method( $id, $wpdb->prepare( $ids_sql, $id ) ); //phpcs:ignore WordPress.DB.PreparedSQL
|
191 |
}
|
192 |
|
193 |
+
if ( isset( $_SERVER['REQUEST_URI'] ) ) {
|
194 |
+
wp_safe_redirect(
|
195 |
+
remove_query_arg(
|
196 |
+
array( '_wp_http_referer', '_wpnonce', 'ID', 'action', 'action2' ),
|
197 |
+
esc_url_raw( wp_unslash( $_SERVER['REQUEST_URI'] ) )
|
198 |
+
)
|
199 |
+
);
|
200 |
+
exit;
|
201 |
+
}
|
202 |
}
|
203 |
|
204 |
/**
|
205 |
* Default code for deleting entries.
|
206 |
* validated already by process_bulk_action()
|
207 |
+
*
|
208 |
+
* @param array $ids ids of the items to delete.
|
209 |
+
* @param string $ids_sql the sql for the ids.
|
210 |
+
* @return void
|
211 |
*/
|
212 |
protected function bulk_delete( array $ids, $ids_sql ) {
|
213 |
$store = ActionScheduler::store();
|
223 |
protected function prepare_column_headers() {
|
224 |
$this->_column_headers = array(
|
225 |
$this->get_columns(),
|
226 |
+
get_hidden_columns( $this->screen ),
|
227 |
$this->get_sortable_columns(),
|
228 |
);
|
229 |
}
|
263 |
protected function get_items_query_limit() {
|
264 |
global $wpdb;
|
265 |
|
266 |
+
$per_page = $this->get_items_per_page( $this->get_per_page_option_name(), $this->items_per_page );
|
267 |
return $wpdb->prepare( 'LIMIT %d', $per_page );
|
268 |
}
|
269 |
|
273 |
* @return int
|
274 |
*/
|
275 |
protected function get_items_offset() {
|
276 |
+
$per_page = $this->get_items_per_page( $this->get_per_page_option_name(), $this->items_per_page );
|
277 |
$current_page = $this->get_pagenum();
|
278 |
if ( 1 < $current_page ) {
|
279 |
$offset = $per_page * ( $current_page - 1 );
|
322 |
|
323 |
$valid_sortable_columns = array_values( $this->sort_by );
|
324 |
|
325 |
+
if ( ! empty( $_GET['orderby'] ) && in_array( $_GET['orderby'], $valid_sortable_columns, true ) ) { //phpcs:ignore WordPress.Security.NonceVerification.Recommended
|
326 |
+
$orderby = sanitize_text_field( wp_unslash( $_GET['orderby'] ) ); //phpcs:ignore WordPress.Security.NonceVerification.Recommended
|
327 |
} else {
|
328 |
$orderby = $valid_sortable_columns[0];
|
329 |
}
|
338 |
*/
|
339 |
protected function get_request_order() {
|
340 |
|
341 |
+
if ( ! empty( $_GET['order'] ) && 'desc' === strtolower( sanitize_text_field( wp_unslash( $_GET['order'] ) ) ) ) { //phpcs:ignore WordPress.Security.NonceVerification.Recommended
|
342 |
$order = 'DESC';
|
343 |
} else {
|
344 |
$order = 'ASC';
|
353 |
* @return string
|
354 |
*/
|
355 |
protected function get_request_status() {
|
356 |
+
$status = ( ! empty( $_GET['status'] ) ) ? sanitize_text_field( wp_unslash( $_GET['status'] ) ) : ''; //phpcs:ignore WordPress.Security.NonceVerification.Recommended
|
357 |
return $status;
|
358 |
}
|
359 |
|
363 |
* @return string
|
364 |
*/
|
365 |
protected function get_request_search_query() {
|
366 |
+
$search_query = ( ! empty( $_GET['s'] ) ) ? sanitize_text_field( wp_unslash( $_GET['s'] ) ) : ''; //phpcs:ignore WordPress.Security.NonceVerification.Recommended
|
367 |
return $search_query;
|
368 |
}
|
369 |
|
375 |
*/
|
376 |
protected function get_table_columns() {
|
377 |
$columns = array_keys( $this->columns );
|
378 |
+
if ( ! in_array( $this->ID, $columns, true ) ) {
|
379 |
$columns[] = $this->ID;
|
380 |
}
|
381 |
|
389 |
* If the current request does not have any search or if this list table does not support
|
390 |
* that feature it will return an empty string.
|
391 |
*
|
|
|
|
|
|
|
392 |
* @return string
|
393 |
*/
|
394 |
protected function get_items_query_search() {
|
395 |
global $wpdb;
|
396 |
|
397 |
+
if ( empty( $_GET['s'] ) || empty( $this->search_by ) ) { //phpcs:ignore WordPress.Security.NonceVerification.Recommended
|
398 |
return '';
|
399 |
}
|
400 |
|
401 |
+
$search_string = sanitize_text_field( wp_unslash( $_GET['s'] ) ); //phpcs:ignore WordPress.Security.NonceVerification.Recommended
|
402 |
+
|
403 |
$filter = array();
|
404 |
foreach ( $this->search_by as $column ) {
|
405 |
+
$wild = '%';
|
406 |
+
$sql_like = $wild . $wpdb->esc_like( $search_string ) . $wild;
|
407 |
+
$filter[] = $wpdb->prepare( '`' . $column . '` LIKE %s', $sql_like ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended, WordPress.DB.PreparedSQL.NotPrepared
|
408 |
}
|
409 |
return implode( ' OR ', $filter );
|
410 |
}
|
416 |
protected function get_items_query_filters() {
|
417 |
global $wpdb;
|
418 |
|
419 |
+
if ( ! $this->filter_by || empty( $_GET['filter_by'] ) || ! is_array( $_GET['filter_by'] ) ) { //phpcs:ignore WordPress.Security.NonceVerification.Recommended
|
420 |
return '';
|
421 |
}
|
422 |
|
423 |
$filter = array();
|
424 |
|
425 |
foreach ( $this->filter_by as $column => $options ) {
|
426 |
+
if ( empty( $_GET['filter_by'][ $column ] ) || empty( $options[ $_GET['filter_by'][ $column ] ] ) ) { //phpcs:ignore WordPress.Security.NonceVerification.Recommended
|
427 |
continue;
|
428 |
}
|
429 |
|
430 |
+
$filter[] = $wpdb->prepare( "`$column` = %s", sanitize_text_field( wp_unslash( $_GET['filter_by'][ $column ] ) ) ); //phpcs:ignore WordPress.Security.NonceVerification.Recommended, WordPress.DB.PreparedSQL.InterpolatedNotPrepared
|
431 |
}
|
432 |
|
433 |
return implode( ' AND ', $filter );
|
450 |
|
451 |
$this->process_row_actions();
|
452 |
|
453 |
+
if ( ! empty( $_REQUEST['_wp_http_referer'] && ! empty( $_SERVER['REQUEST_URI'] ) ) ) { //phpcs:ignore WordPress.Security.NonceVerification.Recommended
|
454 |
// _wp_http_referer is used only on bulk actions, we remove it to keep the $_GET shorter
|
455 |
+
wp_safe_redirect( remove_query_arg( array( '_wp_http_referer', '_wpnonce' ), esc_url_raw( wp_unslash( $_SERVER['REQUEST_URI'] ) ) ) );
|
456 |
exit;
|
457 |
}
|
458 |
|
477 |
|
478 |
$sql = "SELECT $columns FROM {$this->table_name} {$where} {$order} {$limit} {$offset}";
|
479 |
|
480 |
+
$this->set_items( $wpdb->get_results( $sql, ARRAY_A ) ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
|
481 |
|
482 |
$query_count = "SELECT COUNT({$this->ID}) FROM {$this->table_name} {$where}";
|
483 |
+
$total_items = $wpdb->get_var( $query_count ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
|
484 |
+
$per_page = $this->get_items_per_page( $this->get_per_page_option_name(), $this->items_per_page );
|
485 |
$this->set_pagination_args(
|
486 |
array(
|
487 |
'total_items' => $total_items,
|
491 |
);
|
492 |
}
|
493 |
|
494 |
+
/**
|
495 |
+
* Display the table.
|
496 |
+
*
|
497 |
+
* @param string $which The name of the table.
|
498 |
+
*/
|
499 |
public function extra_tablenav( $which ) {
|
500 |
if ( ! $this->filter_by || 'top' !== $which ) {
|
501 |
return;
|
504 |
echo '<div class="alignleft actions">';
|
505 |
|
506 |
foreach ( $this->filter_by as $id => $options ) {
|
507 |
+
$default = ! empty( $_GET['filter_by'][ $id ] ) ? sanitize_text_field( wp_unslash( $_GET['filter_by'][ $id ] ) ) : ''; //phpcs:ignore WordPress.Security.NonceVerification.Recommended
|
508 |
if ( empty( $options[ $default ] ) ) {
|
509 |
$default = '';
|
510 |
}
|
512 |
echo '<select name="filter_by[' . esc_attr( $id ) . ']" class="first" id="filter-by-' . esc_attr( $id ) . '">';
|
513 |
|
514 |
foreach ( $options as $value => $label ) {
|
515 |
+
echo '<option value="' . esc_attr( $value ) . '" ' . esc_html( $value === $default ? 'selected' : '' ) . '>'
|
516 |
. esc_html( $label )
|
517 |
. '</option>';
|
518 |
}
|
527 |
/**
|
528 |
* Set the data for displaying. It will attempt to unserialize (There is a chance that some columns
|
529 |
* are serialized). This can be override in child classes for futher data transformation.
|
530 |
+
*
|
531 |
+
* @param array $items Items array.
|
532 |
*/
|
533 |
protected function set_items( array $items ) {
|
534 |
$this->items = array();
|
541 |
* Renders the checkbox for each row, this is the first column and it is named ID regardless
|
542 |
* of how the primary key is named (to keep the code simpler). The bulk actions will do the proper
|
543 |
* name transformation though using `$this->ID`.
|
544 |
+
*
|
545 |
+
* @param array $row The row to render.
|
546 |
*/
|
547 |
public function column_cb( $row ) {
|
548 |
return '<input name="ID[]" type="checkbox" value="' . esc_attr( $row[ $this->ID ] ) . '" />';
|
554 |
* This method renders the action menu, it reads the definition from the $row_actions property,
|
555 |
* and it checks that the row action method exists before rendering it.
|
556 |
*
|
557 |
+
* @param array $row Row to be rendered.
|
558 |
+
* @param string $column_name Column name.
|
559 |
+
* @return string
|
560 |
*/
|
561 |
protected function maybe_render_actions( $row, $column_name ) {
|
562 |
if ( empty( $this->row_actions[ $column_name ] ) ) {
|
593 |
return $actions;
|
594 |
}
|
595 |
|
596 |
+
/**
|
597 |
+
* Process the bulk actions.
|
598 |
+
*
|
599 |
+
* @return void
|
600 |
+
*/
|
601 |
protected function process_row_actions() {
|
602 |
$parameters = array( 'row_action', 'row_id', 'nonce' );
|
603 |
foreach ( $parameters as $parameter ) {
|
604 |
+
if ( empty( $_REQUEST[ $parameter ] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
|
605 |
return;
|
606 |
}
|
607 |
}
|
608 |
|
609 |
+
$action = sanitize_text_field( wp_unslash( $_REQUEST['row_action'] ) ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended, WordPress.Security.ValidatedSanitizedInput.InputNotValidated
|
610 |
+
$row_id = sanitize_text_field( wp_unslash( $_REQUEST['row_id'] ) ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended, WordPress.Security.ValidatedSanitizedInput.InputNotValidated
|
611 |
+
$nonce = sanitize_text_field( wp_unslash( $_REQUEST['nonce'] ) ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended, WordPress.Security.ValidatedSanitizedInput.InputNotValidated
|
612 |
+
$method = 'row_action_' . $action; // phpcs:ignore WordPress.Security.NonceVerification.Recommended
|
613 |
|
614 |
+
if ( wp_verify_nonce( $nonce, $action . '::' . $row_id ) && method_exists( $this, $method ) ) {
|
615 |
+
$this->$method( sanitize_text_field( wp_unslash( $row_id ) ) ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended
|
616 |
}
|
617 |
|
618 |
+
if ( isset( $_SERVER['REQUEST_URI'] ) ) {
|
619 |
+
wp_safe_redirect(
|
620 |
+
remove_query_arg(
|
621 |
+
array( 'row_id', 'row_action', 'nonce' ),
|
622 |
+
esc_url_raw( wp_unslash( $_SERVER['REQUEST_URI'] ) )
|
623 |
+
)
|
624 |
+
);
|
625 |
+
exit;
|
626 |
+
}
|
627 |
}
|
628 |
|
629 |
/**
|
630 |
* Default column formatting, it will escape everythig for security.
|
631 |
+
*
|
632 |
+
* @param array $item The item array.
|
633 |
+
* @param string $column_name Column name to display.
|
634 |
+
*
|
635 |
+
* @return string
|
636 |
*/
|
637 |
public function column_default( $item, $column_name ) {
|
638 |
$column_html = esc_html( $item[ $column_name ] );
|
657 |
*/
|
658 |
protected function display_admin_notices() {
|
659 |
foreach ( $this->admin_notices as $notice ) {
|
660 |
+
echo '<div id="message" class="' . esc_attr( $notice['class'] ) . '">';
|
661 |
echo ' <p>' . wp_kses_post( $notice['message'] ) . '</p>';
|
662 |
echo '</div>';
|
663 |
}
|
671 |
$status_list_items = array();
|
672 |
$request_status = $this->get_request_status();
|
673 |
|
674 |
+
// Helper to set 'all' filter when not set on status counts passed in.
|
675 |
if ( ! isset( $this->status_counts['all'] ) ) {
|
676 |
$this->status_counts = array( 'all' => array_sum( $this->status_counts ) ) + $this->status_counts;
|
677 |
}
|
695 |
|
696 |
if ( $status_list_items ) {
|
697 |
echo '<ul class="subsubsub">';
|
698 |
+
echo implode( " | \n", $status_list_items ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
699 |
echo '</ul>';
|
700 |
}
|
701 |
}
|
707 |
*/
|
708 |
protected function display_table() {
|
709 |
echo '<form id="' . esc_attr( $this->_args['plural'] ) . '-filter" method="get">';
|
710 |
+
foreach ( $_GET as $key => $value ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
|
711 |
+
if ( '_' === $key[0] || 'paged' === $key || 'ID' === $key ) {
|
712 |
continue;
|
713 |
}
|
714 |
echo '<input type="hidden" name="' . esc_attr( $key ) . '" value="' . esc_attr( $value ) . '" />';
|
715 |
}
|
716 |
if ( ! empty( $this->search_by ) ) {
|
717 |
+
echo $this->search_box( $this->get_search_box_button_text(), 'plugin' ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
718 |
}
|
719 |
parent::display();
|
720 |
echo '</form>';
|
727 |
$this->process_bulk_action();
|
728 |
$this->process_row_actions();
|
729 |
|
730 |
+
if ( ! empty( $_REQUEST['_wp_http_referer'] ) && ! empty( $_SERVER['REQUEST_URI'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
|
731 |
// _wp_http_referer is used only on bulk actions, we remove it to keep the $_GET shorter
|
732 |
+
wp_safe_redirect( remove_query_arg( array( '_wp_http_referer', '_wpnonce' ), esc_url_raw( wp_unslash( $_SERVER['REQUEST_URI'] ) ) ) );
|
733 |
exit;
|
734 |
}
|
735 |
}
|
754 |
protected function get_search_box_placeholder() {
|
755 |
return esc_html__( 'Search', 'action-scheduler' );
|
756 |
}
|
757 |
+
|
758 |
+
/**
|
759 |
+
* Gets the screen per_page option name.
|
760 |
+
*
|
761 |
+
* @return string
|
762 |
+
*/
|
763 |
+
protected function get_per_page_option_name() {
|
764 |
+
return $this->package . '_items_per_page';
|
765 |
+
}
|
766 |
}
|
lite/includes/libraries/action-scheduler/classes/abstracts/ActionScheduler_Abstract_QueueRunner.php
CHANGED
@@ -43,7 +43,7 @@ abstract class ActionScheduler_Abstract_QueueRunner extends ActionScheduler_Abst
|
|
43 |
/**
|
44 |
* Process an individual action.
|
45 |
*
|
46 |
-
* @param int
|
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 |
*/
|
@@ -83,7 +83,7 @@ abstract class ActionScheduler_Abstract_QueueRunner extends ActionScheduler_Abst
|
|
83 |
* Schedule the next instance of the action if necessary.
|
84 |
*
|
85 |
* @param ActionScheduler_Action $action
|
86 |
-
* @param int
|
87 |
*/
|
88 |
protected function schedule_next_instance( ActionScheduler_Action $action, $action_id ) {
|
89 |
try {
|
43 |
/**
|
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 |
*/
|
83 |
* Schedule the next instance of the action if necessary.
|
84 |
*
|
85 |
* @param ActionScheduler_Action $action
|
86 |
+
* @param int $action_id
|
87 |
*/
|
88 |
protected function schedule_next_instance( ActionScheduler_Action $action, $action_id ) {
|
89 |
try {
|
lite/includes/libraries/action-scheduler/classes/abstracts/ActionScheduler_Abstract_RecurringSchedule.php
CHANGED
@@ -15,14 +15,14 @@ abstract class ActionScheduler_Abstract_RecurringSchedule extends ActionSchedule
|
|
15 |
*
|
16 |
* @var DateTime
|
17 |
*/
|
18 |
-
private $first_date =
|
19 |
|
20 |
/**
|
21 |
* Timestamp equivalent of @see $this->first_date
|
22 |
*
|
23 |
* @var int
|
24 |
*/
|
25 |
-
protected $first_timestamp =
|
26 |
|
27 |
/**
|
28 |
* The recurrance between each time an action is run using this schedule.
|
@@ -35,8 +35,8 @@ abstract class ActionScheduler_Abstract_RecurringSchedule extends ActionSchedule
|
|
35 |
protected $recurrence;
|
36 |
|
37 |
/**
|
38 |
-
* @param DateTime
|
39 |
-
* @param mixed
|
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 ) {
|
@@ -70,19 +70,15 @@ abstract class ActionScheduler_Abstract_RecurringSchedule extends ActionSchedule
|
|
70 |
|
71 |
/**
|
72 |
* For PHP 5.2 compat, since DateTime objects can't be serialized
|
73 |
-
*
|
74 |
* @return array
|
75 |
*/
|
76 |
public function __sleep() {
|
77 |
-
$sleep_params
|
78 |
$this->first_timestamp = $this->first_date->getTimestamp();
|
79 |
-
return array_merge(
|
80 |
-
|
81 |
-
|
82 |
-
|
83 |
-
'recurrence',
|
84 |
-
)
|
85 |
-
);
|
86 |
}
|
87 |
|
88 |
/**
|
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.
|
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 ) {
|
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 |
/**
|
lite/includes/libraries/action-scheduler/classes/abstracts/ActionScheduler_Abstract_Schedule.php
CHANGED
@@ -10,14 +10,14 @@ abstract class ActionScheduler_Abstract_Schedule extends ActionScheduler_Schedul
|
|
10 |
*
|
11 |
* @var DateTime
|
12 |
*/
|
13 |
-
private $scheduled_date =
|
14 |
|
15 |
/**
|
16 |
* Timestamp equivalent of @see $this->scheduled_date
|
17 |
*
|
18 |
* @var int
|
19 |
*/
|
20 |
-
protected $scheduled_timestamp =
|
21 |
|
22 |
/**
|
23 |
* @param DateTime $date The date & time to run the action.
|
@@ -67,7 +67,6 @@ abstract class ActionScheduler_Abstract_Schedule extends ActionScheduler_Schedul
|
|
67 |
|
68 |
/**
|
69 |
* For PHP 5.2 compat, since DateTime objects can't be serialized
|
70 |
-
*
|
71 |
* @return array
|
72 |
*/
|
73 |
public function __sleep() {
|
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.
|
67 |
|
68 |
/**
|
69 |
* For PHP 5.2 compat, since DateTime objects can't be serialized
|
|
|
70 |
* @return array
|
71 |
*/
|
72 |
public function __sleep() {
|
lite/includes/libraries/action-scheduler/classes/abstracts/ActionScheduler_Abstract_Schema.php
CHANGED
@@ -17,10 +17,21 @@ abstract class ActionScheduler_Abstract_Schema {
|
|
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.
|
@@ -42,6 +53,13 @@ abstract class ActionScheduler_Abstract_Schema {
|
|
42 |
// create the tables
|
43 |
if ( $this->schema_update_required() || $force_update ) {
|
44 |
foreach ( $this->tables as $table ) {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
45 |
$this->update_table( $table );
|
46 |
}
|
47 |
$this->mark_schema_update_complete();
|
@@ -63,29 +81,29 @@ abstract class ActionScheduler_Abstract_Schema {
|
|
63 |
* @return bool
|
64 |
*/
|
65 |
private function schema_update_required() {
|
66 |
-
$option_name
|
67 |
-
$
|
68 |
|
69 |
// Check for schema option stored by the Action Scheduler Custom Tables plugin in case site has migrated from that plugin with an older schema
|
70 |
-
if ( 0 === $
|
71 |
|
72 |
$plugin_option_name = 'schema-';
|
73 |
|
74 |
switch ( static::class ) {
|
75 |
-
case 'ActionScheduler_StoreSchema':
|
76 |
$plugin_option_name .= 'Action_Scheduler\Custom_Tables\DB_Store_Table_Maker';
|
77 |
break;
|
78 |
-
case 'ActionScheduler_LoggerSchema':
|
79 |
$plugin_option_name .= 'Action_Scheduler\Custom_Tables\DB_Logger_Table_Maker';
|
80 |
break;
|
81 |
}
|
82 |
|
83 |
-
$
|
84 |
|
85 |
delete_option( $plugin_option_name );
|
86 |
}
|
87 |
|
88 |
-
return version_compare( $
|
89 |
}
|
90 |
|
91 |
/**
|
@@ -111,7 +129,7 @@ abstract class ActionScheduler_Abstract_Schema {
|
|
111 |
* @return void
|
112 |
*/
|
113 |
private function update_table( $table ) {
|
114 |
-
require_once ABSPATH . 'wp-admin/includes/upgrade.php';
|
115 |
$definition = $this->get_table_definition( $table );
|
116 |
if ( $definition ) {
|
117 |
$updated = dbDelta( $definition );
|
@@ -130,6 +148,25 @@ abstract class ActionScheduler_Abstract_Schema {
|
|
130 |
* table prefix for the current blog
|
131 |
*/
|
132 |
protected function get_full_table_name( $table ) {
|
133 |
-
return $GLOBALS['wpdb']->prefix . $table;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
134 |
}
|
135 |
}
|
17 |
*/
|
18 |
protected $schema_version = 1;
|
19 |
|
20 |
+
/**
|
21 |
+
* @var string Schema version stored in database.
|
22 |
+
*/
|
23 |
+
protected $db_version;
|
24 |
+
|
25 |
/**
|
26 |
* @var array Names of tables that will be registered by this class.
|
27 |
*/
|
28 |
+
protected $tables = [];
|
29 |
+
|
30 |
+
/**
|
31 |
+
* Can optionally be used by concrete classes to carry out additional initialization work
|
32 |
+
* as needed.
|
33 |
+
*/
|
34 |
+
public function init() {}
|
35 |
|
36 |
/**
|
37 |
* Register tables with WordPress, and create them if needed.
|
53 |
// create the tables
|
54 |
if ( $this->schema_update_required() || $force_update ) {
|
55 |
foreach ( $this->tables as $table ) {
|
56 |
+
/**
|
57 |
+
* Allow custom processing before updating a table schema.
|
58 |
+
*
|
59 |
+
* @param string $table Name of table being updated.
|
60 |
+
* @param string $db_version Existing version of the table being updated.
|
61 |
+
*/
|
62 |
+
do_action( 'action_scheduler_before_schema_update', $table, $this->db_version );
|
63 |
$this->update_table( $table );
|
64 |
}
|
65 |
$this->mark_schema_update_complete();
|
81 |
* @return bool
|
82 |
*/
|
83 |
private function schema_update_required() {
|
84 |
+
$option_name = 'schema-' . static::class;
|
85 |
+
$this->db_version = get_option( $option_name, 0 );
|
86 |
|
87 |
// Check for schema option stored by the Action Scheduler Custom Tables plugin in case site has migrated from that plugin with an older schema
|
88 |
+
if ( 0 === $this->db_version ) {
|
89 |
|
90 |
$plugin_option_name = 'schema-';
|
91 |
|
92 |
switch ( static::class ) {
|
93 |
+
case 'ActionScheduler_StoreSchema' :
|
94 |
$plugin_option_name .= 'Action_Scheduler\Custom_Tables\DB_Store_Table_Maker';
|
95 |
break;
|
96 |
+
case 'ActionScheduler_LoggerSchema' :
|
97 |
$plugin_option_name .= 'Action_Scheduler\Custom_Tables\DB_Logger_Table_Maker';
|
98 |
break;
|
99 |
}
|
100 |
|
101 |
+
$this->db_version = get_option( $plugin_option_name, 0 );
|
102 |
|
103 |
delete_option( $plugin_option_name );
|
104 |
}
|
105 |
|
106 |
+
return version_compare( $this->db_version, $this->schema_version, '<' );
|
107 |
}
|
108 |
|
109 |
/**
|
129 |
* @return void
|
130 |
*/
|
131 |
private function update_table( $table ) {
|
132 |
+
require_once( ABSPATH . 'wp-admin/includes/upgrade.php' );
|
133 |
$definition = $this->get_table_definition( $table );
|
134 |
if ( $definition ) {
|
135 |
$updated = dbDelta( $definition );
|
148 |
* table prefix for the current blog
|
149 |
*/
|
150 |
protected function get_full_table_name( $table ) {
|
151 |
+
return $GLOBALS[ 'wpdb' ]->prefix . $table;
|
152 |
+
}
|
153 |
+
|
154 |
+
/**
|
155 |
+
* Confirms that all of the tables registered by this schema class have been created.
|
156 |
+
*
|
157 |
+
* @return bool
|
158 |
+
*/
|
159 |
+
public function tables_exist() {
|
160 |
+
global $wpdb;
|
161 |
+
|
162 |
+
$existing_tables = $wpdb->get_col( 'SHOW TABLES' );
|
163 |
+
$expected_tables = array_map(
|
164 |
+
function ( $table_name ) use ( $wpdb ) {
|
165 |
+
return $wpdb->prefix . $table_name;
|
166 |
+
},
|
167 |
+
$this->tables
|
168 |
+
);
|
169 |
+
|
170 |
+
return count( array_intersect( $existing_tables, $expected_tables ) ) === count( $expected_tables );
|
171 |
}
|
172 |
}
|
lite/includes/libraries/action-scheduler/classes/abstracts/ActionScheduler_Lock.php
CHANGED
@@ -8,7 +8,7 @@
|
|
8 |
abstract class ActionScheduler_Lock {
|
9 |
|
10 |
/** @var ActionScheduler_Lock */
|
11 |
-
private static $locker =
|
12 |
|
13 |
/** @var int */
|
14 |
protected static $lock_duration = MINUTE_IN_SECONDS;
|
@@ -54,7 +54,7 @@ abstract class ActionScheduler_Lock {
|
|
54 |
*/
|
55 |
public static function instance() {
|
56 |
if ( empty( self::$locker ) ) {
|
57 |
-
$class
|
58 |
self::$locker = new $class();
|
59 |
}
|
60 |
return self::$locker;
|
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;
|
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;
|
lite/includes/libraries/action-scheduler/classes/abstracts/ActionScheduler_Logger.php
CHANGED
@@ -2,31 +2,30 @@
|
|
2 |
|
3 |
/**
|
4 |
* Class ActionScheduler_Logger
|
5 |
-
*
|
6 |
* @codeCoverageIgnore
|
7 |
*/
|
8 |
abstract class ActionScheduler_Logger {
|
9 |
-
private static $logger =
|
10 |
|
11 |
/**
|
12 |
* @return ActionScheduler_Logger
|
13 |
*/
|
14 |
public static function instance() {
|
15 |
-
if ( empty(
|
16 |
-
$class
|
17 |
self::$logger = new $class();
|
18 |
}
|
19 |
return self::$logger;
|
20 |
}
|
21 |
|
22 |
/**
|
23 |
-
* @param string
|
24 |
-
* @param string
|
25 |
* @param DateTime $date
|
26 |
*
|
27 |
* @return string The log entry ID
|
28 |
*/
|
29 |
-
abstract public function log( $action_id, $message, DateTime $date =
|
30 |
|
31 |
/**
|
32 |
* @param string $entry_id
|
@@ -87,7 +86,7 @@ abstract class ActionScheduler_Logger {
|
|
87 |
$this->log( $action_id, $message );
|
88 |
}
|
89 |
|
90 |
-
public function log_completed_action( $action_id, $action =
|
91 |
if ( ! empty( $context ) ) {
|
92 |
/* translators: %s: context */
|
93 |
$message = sprintf( __( 'action complete via %s', 'action-scheduler' ), $context );
|
@@ -135,12 +134,12 @@ abstract class ActionScheduler_Logger {
|
|
135 |
}
|
136 |
|
137 |
/**
|
138 |
-
* @param string
|
139 |
* @param Exception|NULL $exception The exception which occured when fetching the action. NULL by default for backward compatibility.
|
140 |
*
|
141 |
* @return ActionScheduler_LogEntry[]
|
142 |
*/
|
143 |
-
public function log_failed_fetch_action( $action_id, Exception $exception =
|
144 |
|
145 |
if ( ! is_null( $exception ) ) {
|
146 |
/* translators: %s: exception message */
|
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
|
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 );
|
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 */
|
lite/includes/libraries/action-scheduler/classes/abstracts/ActionScheduler_Store.php
CHANGED
@@ -2,7 +2,6 @@
|
|
2 |
|
3 |
/**
|
4 |
* Class ActionScheduler_Store
|
5 |
-
*
|
6 |
* @codeCoverageIgnore
|
7 |
*/
|
8 |
abstract class ActionScheduler_Store extends ActionScheduler_Store_Deprecated {
|
@@ -14,20 +13,20 @@ abstract class ActionScheduler_Store extends ActionScheduler_Store_Deprecated {
|
|
14 |
const DEFAULT_CLASS = 'ActionScheduler_wpPostStore';
|
15 |
|
16 |
/** @var ActionScheduler_Store */
|
17 |
-
private static $store =
|
18 |
|
19 |
/** @var int */
|
20 |
protected static $max_args_length = 191;
|
21 |
|
22 |
/**
|
23 |
* @param ActionScheduler_Action $action
|
24 |
-
* @param DateTime
|
25 |
-
*
|
26 |
-
*
|
27 |
*
|
28 |
* @return int The action ID
|
29 |
*/
|
30 |
-
abstract public function save_action( ActionScheduler_Action $action, DateTime $scheduled_date =
|
31 |
|
32 |
/**
|
33 |
* @param string $action_id
|
@@ -37,20 +36,94 @@ abstract class ActionScheduler_Store extends ActionScheduler_Store_Deprecated {
|
|
37 |
abstract public function fetch_action( $action_id );
|
38 |
|
39 |
/**
|
40 |
-
*
|
41 |
-
*
|
42 |
-
*
|
|
|
|
|
|
|
|
|
|
|
43 |
*/
|
44 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
45 |
|
46 |
/**
|
47 |
-
*
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
48 |
* @param string $query_type Whether to select or count the results. Default, select.
|
49 |
*
|
50 |
-
* @return array|
|
51 |
*/
|
52 |
abstract public function query_actions( $query = array(), $query_type = 'select' );
|
53 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
54 |
/**
|
55 |
* Get a count of all actions in the store, grouped by status
|
56 |
*
|
@@ -140,7 +213,7 @@ abstract class ActionScheduler_Store extends ActionScheduler_Store_Deprecated {
|
|
140 |
* @return string
|
141 |
*/
|
142 |
protected function validate_sql_comparator( $comparison_operator ) {
|
143 |
-
if ( in_array( $comparison_operator, array(
|
144 |
return $comparison_operator;
|
145 |
}
|
146 |
return '=';
|
@@ -150,10 +223,10 @@ abstract class ActionScheduler_Store extends ActionScheduler_Store_Deprecated {
|
|
150 |
* Get the time MySQL formated date/time string for an action's (next) scheduled date.
|
151 |
*
|
152 |
* @param ActionScheduler_Action $action
|
153 |
-
* @param DateTime
|
154 |
* @return string
|
155 |
*/
|
156 |
-
protected function get_scheduled_date_string( ActionScheduler_Action $action, DateTime $scheduled_date =
|
157 |
$next = null === $scheduled_date ? $action->get_schedule()->get_date() : $scheduled_date;
|
158 |
if ( ! $next ) {
|
159 |
return '0000-00-00 00:00:00';
|
@@ -167,10 +240,10 @@ abstract class ActionScheduler_Store extends ActionScheduler_Store_Deprecated {
|
|
167 |
* Get the time MySQL formated date/time string for an action's (next) scheduled date.
|
168 |
*
|
169 |
* @param ActionScheduler_Action $action
|
170 |
-
* @param DateTime
|
171 |
* @return string
|
172 |
*/
|
173 |
-
protected function get_scheduled_date_string_local( ActionScheduler_Action $action, DateTime $scheduled_date =
|
174 |
$next = null === $scheduled_date ? $action->get_schedule()->get_date() : $scheduled_date;
|
175 |
if ( ! $next ) {
|
176 |
return '0000-00-00 00:00:00';
|
@@ -246,6 +319,7 @@ abstract class ActionScheduler_Store extends ActionScheduler_Store_Deprecated {
|
|
246 |
'hook' => $hook,
|
247 |
'status' => self::STATUS_PENDING,
|
248 |
'per_page' => 1000,
|
|
|
249 |
)
|
250 |
);
|
251 |
|
@@ -270,6 +344,7 @@ abstract class ActionScheduler_Store extends ActionScheduler_Store_Deprecated {
|
|
270 |
'group' => $group,
|
271 |
'status' => self::STATUS_PENDING,
|
272 |
'per_page' => 1000,
|
|
|
273 |
)
|
274 |
);
|
275 |
|
@@ -311,16 +386,15 @@ abstract class ActionScheduler_Store extends ActionScheduler_Store_Deprecated {
|
|
311 |
* Check if there are any pending scheduled actions due to run.
|
312 |
*
|
313 |
* @param ActionScheduler_Action $action
|
314 |
-
* @param DateTime
|
315 |
* @return string
|
316 |
*/
|
317 |
public function has_pending_actions_due() {
|
318 |
-
$pending_actions = $this->query_actions(
|
319 |
-
|
320 |
-
|
321 |
-
|
322 |
-
|
323 |
-
);
|
324 |
|
325 |
return ! empty( $pending_actions );
|
326 |
}
|
@@ -340,7 +414,7 @@ abstract class ActionScheduler_Store extends ActionScheduler_Store_Deprecated {
|
|
340 |
*/
|
341 |
public static function instance() {
|
342 |
if ( empty( self::$store ) ) {
|
343 |
-
$class
|
344 |
self::$store = new $class();
|
345 |
}
|
346 |
return self::$store;
|
2 |
|
3 |
/**
|
4 |
* Class ActionScheduler_Store
|
|
|
5 |
* @codeCoverageIgnore
|
6 |
*/
|
7 |
abstract class ActionScheduler_Store extends ActionScheduler_Store_Deprecated {
|
13 |
const DEFAULT_CLASS = 'ActionScheduler_wpPostStore';
|
14 |
|
15 |
/** @var ActionScheduler_Store */
|
16 |
+
private static $store = NULL;
|
17 |
|
18 |
/** @var int */
|
19 |
protected static $max_args_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 int The action ID
|
28 |
*/
|
29 |
+
abstract public function save_action( ActionScheduler_Action $action, DateTime $scheduled_date = NULL );
|
30 |
|
31 |
/**
|
32 |
* @param string $action_id
|
36 |
abstract public function fetch_action( $action_id );
|
37 |
|
38 |
/**
|
39 |
+
* Find an action.
|
40 |
+
*
|
41 |
+
* Note: the query ordering changes based on the passed 'status' value.
|
42 |
+
*
|
43 |
+
* @param string $hook Action hook.
|
44 |
+
* @param array $params Parameters of the action to find.
|
45 |
+
*
|
46 |
+
* @return string|null ID of the next action matching the criteria or NULL if not found.
|
47 |
*/
|
48 |
+
public function find_action( $hook, $params = array() ) {
|
49 |
+
$params = wp_parse_args(
|
50 |
+
$params,
|
51 |
+
array(
|
52 |
+
'args' => null,
|
53 |
+
'status' => self::STATUS_PENDING,
|
54 |
+
'group' => '',
|
55 |
+
)
|
56 |
+
);
|
57 |
+
|
58 |
+
// These params are fixed for this method.
|
59 |
+
$params['hook'] = $hook;
|
60 |
+
$params['orderby'] = 'date';
|
61 |
+
$params['per_page'] = 1;
|
62 |
+
|
63 |
+
if ( ! empty( $params['status'] ) ) {
|
64 |
+
if ( self::STATUS_PENDING === $params['status'] ) {
|
65 |
+
$params['order'] = 'ASC'; // Find the next action that matches.
|
66 |
+
} else {
|
67 |
+
$params['order'] = 'DESC'; // Find the most recent action that matches.
|
68 |
+
}
|
69 |
+
}
|
70 |
+
|
71 |
+
$results = $this->query_actions( $params );
|
72 |
+
|
73 |
+
return empty( $results ) ? null : $results[0];
|
74 |
+
}
|
75 |
|
76 |
/**
|
77 |
+
* Query for action count or list of action IDs.
|
78 |
+
*
|
79 |
+
* @since x.x.x $query['status'] accepts array of statuses instead of a single status.
|
80 |
+
*
|
81 |
+
* @param array $query {
|
82 |
+
* Query filtering options.
|
83 |
+
*
|
84 |
+
* @type string $hook The name of the actions. Optional.
|
85 |
+
* @type string|array $status The status or statuses of the actions. Optional.
|
86 |
+
* @type array $args The args array of the actions. Optional.
|
87 |
+
* @type DateTime $date The scheduled date of the action. Used in UTC timezone. Optional.
|
88 |
+
* @type string $date_compare Operator for selecting by $date param. Accepted values are '!=', '>', '>=', '<', '<=', '='. Defaults to '<='.
|
89 |
+
* @type DateTime $modified The last modified date of the action. Used in UTC timezone. Optional.
|
90 |
+
* @type string $modified_compare Operator for comparing $modified param. Accepted values are '!=', '>', '>=', '<', '<=', '='. Defaults to '<='.
|
91 |
+
* @type string $group The group the action belongs to. Optional.
|
92 |
+
* @type bool|int $claimed TRUE to find claimed actions, FALSE to find unclaimed actions, an int to find a specific claim ID. Optional.
|
93 |
+
* @type int $per_page Number of results to return. Defaults to 5.
|
94 |
+
* @type int $offset The query pagination offset. Defaults to 0.
|
95 |
+
* @type int $orderby Accepted values are 'hook', 'group', 'modified', 'date' or 'none'. Defaults to 'date'.
|
96 |
+
* @type string $order Accepted values are 'ASC' or 'DESC'. Defaults to 'ASC'.
|
97 |
+
* }
|
98 |
* @param string $query_type Whether to select or count the results. Default, select.
|
99 |
*
|
100 |
+
* @return string|array|null The IDs of actions matching the query. Null on failure.
|
101 |
*/
|
102 |
abstract public function query_actions( $query = array(), $query_type = 'select' );
|
103 |
|
104 |
+
/**
|
105 |
+
* Run query to get a single action ID.
|
106 |
+
*
|
107 |
+
* @since x.x.x
|
108 |
+
*
|
109 |
+
* @see ActionScheduler_Store::query_actions for $query arg usage but 'per_page' and 'offset' can't be used.
|
110 |
+
*
|
111 |
+
* @param array $query Query parameters.
|
112 |
+
*
|
113 |
+
* @return int|null
|
114 |
+
*/
|
115 |
+
public function query_action( $query ) {
|
116 |
+
$query['per_page'] = 1;
|
117 |
+
$query['offset'] = 0;
|
118 |
+
$results = $this->query_actions( $query );
|
119 |
+
|
120 |
+
if ( empty( $results ) ) {
|
121 |
+
return null;
|
122 |
+
} else {
|
123 |
+
return (int) $results[0];
|
124 |
+
}
|
125 |
+
}
|
126 |
+
|
127 |
/**
|
128 |
* Get a count of all actions in the store, grouped by status
|
129 |
*
|
213 |
* @return string
|
214 |
*/
|
215 |
protected function validate_sql_comparator( $comparison_operator ) {
|
216 |
+
if ( in_array( $comparison_operator, array('!=', '>', '>=', '<', '<=', '=') ) ) {
|
217 |
return $comparison_operator;
|
218 |
}
|
219 |
return '=';
|
223 |
* Get the time MySQL formated date/time string for an action's (next) scheduled date.
|
224 |
*
|
225 |
* @param ActionScheduler_Action $action
|
226 |
+
* @param DateTime $scheduled_date (optional)
|
227 |
* @return string
|
228 |
*/
|
229 |
+
protected function get_scheduled_date_string( ActionScheduler_Action $action, DateTime $scheduled_date = NULL ) {
|
230 |
$next = null === $scheduled_date ? $action->get_schedule()->get_date() : $scheduled_date;
|
231 |
if ( ! $next ) {
|
232 |
return '0000-00-00 00:00:00';
|
240 |
* Get the time MySQL formated date/time string for an action's (next) scheduled date.
|
241 |
*
|
242 |
* @param ActionScheduler_Action $action
|
243 |
+
* @param DateTime $scheduled_date (optional)
|
244 |
* @return string
|
245 |
*/
|
246 |
+
protected function get_scheduled_date_string_local( ActionScheduler_Action $action, DateTime $scheduled_date = NULL ) {
|
247 |
$next = null === $scheduled_date ? $action->get_schedule()->get_date() : $scheduled_date;
|
248 |
if ( ! $next ) {
|
249 |
return '0000-00-00 00:00:00';
|
319 |
'hook' => $hook,
|
320 |
'status' => self::STATUS_PENDING,
|
321 |
'per_page' => 1000,
|
322 |
+
'orderby' => 'action_id',
|
323 |
)
|
324 |
);
|
325 |
|
344 |
'group' => $group,
|
345 |
'status' => self::STATUS_PENDING,
|
346 |
'per_page' => 1000,
|
347 |
+
'orderby' => 'action_id',
|
348 |
)
|
349 |
);
|
350 |
|
386 |
* Check if there are any pending scheduled actions due to run.
|
387 |
*
|
388 |
* @param ActionScheduler_Action $action
|
389 |
+
* @param DateTime $scheduled_date (optional)
|
390 |
* @return string
|
391 |
*/
|
392 |
public function has_pending_actions_due() {
|
393 |
+
$pending_actions = $this->query_actions( array(
|
394 |
+
'date' => as_get_datetime_object(),
|
395 |
+
'status' => ActionScheduler_Store::STATUS_PENDING,
|
396 |
+
'orderby' => 'none',
|
397 |
+
) );
|
|
|
398 |
|
399 |
return ! empty( $pending_actions );
|
400 |
}
|
414 |
*/
|
415 |
public static function instance() {
|
416 |
if ( empty( self::$store ) ) {
|
417 |
+
$class = apply_filters( 'action_scheduler_store_class', self::DEFAULT_CLASS );
|
418 |
self::$store = new $class();
|
419 |
}
|
420 |
return self::$store;
|
lite/includes/libraries/action-scheduler/classes/abstracts/ActionScheduler_TimezoneHelper.php
CHANGED
@@ -4,7 +4,7 @@
|
|
4 |
* Class ActionScheduler_TimezoneHelper
|
5 |
*/
|
6 |
abstract class ActionScheduler_TimezoneHelper {
|
7 |
-
private static $local_timezone =
|
8 |
|
9 |
/**
|
10 |
* Set a DateTime's timezone to the WordPress site's timezone, or a UTC offset
|
@@ -99,21 +99,21 @@ abstract class ActionScheduler_TimezoneHelper {
|
|
99 |
/**
|
100 |
* @deprecated 2.1.0
|
101 |
*/
|
102 |
-
public static function get_local_timezone( $reset =
|
103 |
_deprecated_function( __FUNCTION__, '2.1.0', 'ActionScheduler_TimezoneHelper::set_local_timezone()' );
|
104 |
if ( $reset ) {
|
105 |
-
self::$local_timezone =
|
106 |
}
|
107 |
-
if ( !
|
108 |
-
$tzstring = get_option(
|
109 |
|
110 |
-
if ( empty(
|
111 |
-
$gmt_offset = get_option(
|
112 |
if ( $gmt_offset == 0 ) {
|
113 |
$tzstring = 'UTC';
|
114 |
} else {
|
115 |
$gmt_offset *= HOUR_IN_SECONDS;
|
116 |
-
$tzstring
|
117 |
|
118 |
// If there's no timezone string, try again with no DST.
|
119 |
if ( false === $tzstring ) {
|
@@ -145,7 +145,7 @@ abstract class ActionScheduler_TimezoneHelper {
|
|
145 |
}
|
146 |
}
|
147 |
|
148 |
-
self::$local_timezone = new DateTimeZone(
|
149 |
}
|
150 |
return self::$local_timezone;
|
151 |
}
|
4 |
* Class ActionScheduler_TimezoneHelper
|
5 |
*/
|
6 |
abstract class ActionScheduler_TimezoneHelper {
|
7 |
+
private static $local_timezone = NULL;
|
8 |
|
9 |
/**
|
10 |
* Set a DateTime's timezone to the WordPress site's timezone, or a UTC offset
|
99 |
/**
|
100 |
* @deprecated 2.1.0
|
101 |
*/
|
102 |
+
public static function get_local_timezone( $reset = FALSE ) {
|
103 |
_deprecated_function( __FUNCTION__, '2.1.0', 'ActionScheduler_TimezoneHelper::set_local_timezone()' );
|
104 |
if ( $reset ) {
|
105 |
+
self::$local_timezone = NULL;
|
106 |
}
|
107 |
+
if ( !isset(self::$local_timezone) ) {
|
108 |
+
$tzstring = get_option('timezone_string');
|
109 |
|
110 |
+
if ( empty($tzstring) ) {
|
111 |
+
$gmt_offset = get_option('gmt_offset');
|
112 |
if ( $gmt_offset == 0 ) {
|
113 |
$tzstring = 'UTC';
|
114 |
} else {
|
115 |
$gmt_offset *= HOUR_IN_SECONDS;
|
116 |
+
$tzstring = timezone_name_from_abbr( '', $gmt_offset, 1 );
|
117 |
|
118 |
// If there's no timezone string, try again with no DST.
|
119 |
if ( false === $tzstring ) {
|
145 |
}
|
146 |
}
|
147 |
|
148 |
+
self::$local_timezone = new DateTimeZone($tzstring);
|
149 |
}
|
150 |
return self::$local_timezone;
|
151 |
}
|
lite/includes/libraries/action-scheduler/classes/actions/ActionScheduler_Action.php
CHANGED
@@ -7,19 +7,19 @@ class ActionScheduler_Action {
|
|
7 |
protected $hook = '';
|
8 |
protected $args = array();
|
9 |
/** @var ActionScheduler_Schedule */
|
10 |
-
protected $schedule =
|
11 |
-
protected $group
|
12 |
|
13 |
-
public function __construct( $hook, array $args = array(), ActionScheduler_Schedule $schedule =
|
14 |
$schedule = empty( $schedule ) ? new ActionScheduler_NullSchedule() : $schedule;
|
15 |
-
$this->set_hook(
|
16 |
-
$this->set_schedule(
|
17 |
-
$this->set_args(
|
18 |
-
$this->set_group(
|
19 |
}
|
20 |
|
21 |
public function execute() {
|
22 |
-
return do_action_ref_array( $this->get_hook(), $this->get_args() );
|
23 |
}
|
24 |
|
25 |
/**
|
@@ -70,6 +70,6 @@ class ActionScheduler_Action {
|
|
70 |
* @return bool If the action has been finished
|
71 |
*/
|
72 |
public function is_finished() {
|
73 |
-
return
|
74 |
}
|
75 |
}
|
7 |
protected $hook = '';
|
8 |
protected $args = array();
|
9 |
/** @var ActionScheduler_Schedule */
|
10 |
+
protected $schedule = NULL;
|
11 |
+
protected $group = '';
|
12 |
|
13 |
+
public function __construct( $hook, array $args = array(), ActionScheduler_Schedule $schedule = NULL, $group = '' ) {
|
14 |
$schedule = empty( $schedule ) ? new ActionScheduler_NullSchedule() : $schedule;
|
15 |
+
$this->set_hook($hook);
|
16 |
+
$this->set_schedule($schedule);
|
17 |
+
$this->set_args($args);
|
18 |
+
$this->set_group($group);
|
19 |
}
|
20 |
|
21 |
public function execute() {
|
22 |
+
return do_action_ref_array( $this->get_hook(), array_values( $this->get_args() ) );
|
23 |
}
|
24 |
|
25 |
/**
|
70 |
* @return bool If the action has been finished
|
71 |
*/
|
72 |
public function is_finished() {
|
73 |
+
return FALSE;
|
74 |
}
|
75 |
}
|
lite/includes/libraries/action-scheduler/classes/actions/ActionScheduler_CanceledAction.php
CHANGED
@@ -9,10 +9,10 @@
|
|
9 |
class ActionScheduler_CanceledAction extends ActionScheduler_FinishedAction {
|
10 |
|
11 |
/**
|
12 |
-
* @param string
|
13 |
-
* @param array
|
14 |
* @param ActionScheduler_Schedule $schedule
|
15 |
-
* @param string
|
16 |
*/
|
17 |
public function __construct( $hook, array $args = array(), ActionScheduler_Schedule $schedule = null, $group = '' ) {
|
18 |
parent::__construct( $hook, $args, $schedule, $group );
|
9 |
class ActionScheduler_CanceledAction extends ActionScheduler_FinishedAction {
|
10 |
|
11 |
/**
|
12 |
+
* @param string $hook
|
13 |
+
* @param array $args
|
14 |
* @param ActionScheduler_Schedule $schedule
|
15 |
+
* @param string $group
|
16 |
*/
|
17 |
public function __construct( $hook, array $args = array(), ActionScheduler_Schedule $schedule = null, $group = '' ) {
|
18 |
parent::__construct( $hook, $args, $schedule, $group );
|
lite/includes/libraries/action-scheduler/classes/actions/ActionScheduler_FinishedAction.php
CHANGED
@@ -10,7 +10,7 @@ class ActionScheduler_FinishedAction extends ActionScheduler_Action {
|
|
10 |
}
|
11 |
|
12 |
public function is_finished() {
|
13 |
-
return
|
14 |
}
|
15 |
}
|
16 |
-
|
10 |
}
|
11 |
|
12 |
public function is_finished() {
|
13 |
+
return TRUE;
|
14 |
}
|
15 |
}
|
16 |
+
|
lite/includes/libraries/action-scheduler/classes/actions/ActionScheduler_NullAction.php
CHANGED
@@ -5,7 +5,7 @@
|
|
5 |
*/
|
6 |
class ActionScheduler_NullAction extends ActionScheduler_Action {
|
7 |
|
8 |
-
public function __construct( $hook = '', array $args = array(), ActionScheduler_Schedule $schedule =
|
9 |
$this->set_schedule( new ActionScheduler_NullSchedule() );
|
10 |
}
|
11 |
|
@@ -13,4 +13,4 @@ class ActionScheduler_NullAction extends ActionScheduler_Action {
|
|
13 |
// don't execute
|
14 |
}
|
15 |
}
|
16 |
-
|
5 |
*/
|
6 |
class ActionScheduler_NullAction extends ActionScheduler_Action {
|
7 |
|
8 |
+
public function __construct( $hook = '', array $args = array(), ActionScheduler_Schedule $schedule = NULL ) {
|
9 |
$this->set_schedule( new ActionScheduler_NullSchedule() );
|
10 |
}
|
11 |
|
13 |
// don't execute
|
14 |
}
|
15 |
}
|
16 |
+
|
lite/includes/libraries/action-scheduler/classes/data-stores/ActionScheduler_DBLogger.php
CHANGED
@@ -29,7 +29,7 @@ class ActionScheduler_DBLogger extends ActionScheduler_Logger {
|
|
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(
|
35 |
$wpdb->actionscheduler_logs,
|
@@ -53,7 +53,7 @@ class ActionScheduler_DBLogger extends ActionScheduler_Logger {
|
|
53 |
* @return ActionScheduler_LogEntry
|
54 |
*/
|
55 |
public function get_entry( $entry_id ) {
|
56 |
-
/** @var \wpdb $wpdb */
|
57 |
global $wpdb;
|
58 |
$entry = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$wpdb->actionscheduler_logs} WHERE log_id=%d", $entry_id ) );
|
59 |
|
@@ -72,7 +72,11 @@ class ActionScheduler_DBLogger extends ActionScheduler_Logger {
|
|
72 |
return new ActionScheduler_NullLogEntry();
|
73 |
}
|
74 |
|
75 |
-
|
|
|
|
|
|
|
|
|
76 |
|
77 |
return new ActionScheduler_LogEntry( $record->action_id, $record->message, $date );
|
78 |
}
|
@@ -85,7 +89,7 @@ class ActionScheduler_DBLogger extends ActionScheduler_Logger {
|
|
85 |
* @return ActionScheduler_LogEntry[]
|
86 |
*/
|
87 |
public function get_logs( $action_id ) {
|
88 |
-
/** @var \wpdb $wpdb */
|
89 |
global $wpdb;
|
90 |
|
91 |
$records = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM {$wpdb->actionscheduler_logs} WHERE action_id=%d", $action_id ) );
|
@@ -99,8 +103,8 @@ class ActionScheduler_DBLogger extends ActionScheduler_Logger {
|
|
99 |
* @codeCoverageIgnore
|
100 |
*/
|
101 |
public function init() {
|
102 |
-
|
103 |
$table_maker = new ActionScheduler_LoggerSchema();
|
|
|
104 |
$table_maker->register_tables();
|
105 |
|
106 |
parent::init();
|
@@ -114,7 +118,7 @@ class ActionScheduler_DBLogger extends ActionScheduler_Logger {
|
|
114 |
* @param int $action_id Action ID.
|
115 |
*/
|
116 |
public function clear_deleted_action_logs( $action_id ) {
|
117 |
-
/** @var \wpdb $wpdb */
|
118 |
global $wpdb;
|
119 |
$wpdb->delete( $wpdb->actionscheduler_logs, array( 'action_id' => $action_id ), array( '%d' ) );
|
120 |
}
|
@@ -129,7 +133,7 @@ class ActionScheduler_DBLogger extends ActionScheduler_Logger {
|
|
129 |
return;
|
130 |
}
|
131 |
|
132 |
-
/** @var \wpdb $wpdb */
|
133 |
global $wpdb;
|
134 |
$date = as_get_datetime_object();
|
135 |
$date_gmt = $date->format( 'Y-m-d H:i:s' );
|
@@ -141,10 +145,10 @@ class ActionScheduler_DBLogger extends ActionScheduler_Logger {
|
|
141 |
$value_rows = array();
|
142 |
|
143 |
foreach ( $action_ids as $action_id ) {
|
144 |
-
$value_rows[] = $wpdb->prepare( $format, $action_id );
|
145 |
}
|
146 |
$sql_query .= implode( ',', $value_rows );
|
147 |
|
148 |
-
$wpdb->query( $sql_query );
|
149 |
}
|
150 |
}
|
29 |
ActionScheduler_TimezoneHelper::set_local_timezone( $date );
|
30 |
$date_local = $date->format( 'Y-m-d H:i:s' );
|
31 |
|
32 |
+
/** @var \wpdb $wpdb */ //phpcs:ignore Generic.Commenting.DocComment.MissingShort
|
33 |
global $wpdb;
|
34 |
$wpdb->insert(
|
35 |
$wpdb->actionscheduler_logs,
|
53 |
* @return ActionScheduler_LogEntry
|
54 |
*/
|
55 |
public function get_entry( $entry_id ) {
|
56 |
+
/** @var \wpdb $wpdb */ //phpcs:ignore Generic.Commenting.DocComment.MissingShort
|
57 |
global $wpdb;
|
58 |
$entry = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$wpdb->actionscheduler_logs} WHERE log_id=%d", $entry_id ) );
|
59 |
|
72 |
return new ActionScheduler_NullLogEntry();
|
73 |
}
|
74 |
|
75 |
+
if ( is_null( $record->log_date_gmt ) ) {
|
76 |
+
$date = as_get_datetime_object( ActionScheduler_StoreSchema::DEFAULT_DATE );
|
77 |
+
} else {
|
78 |
+
$date = as_get_datetime_object( $record->log_date_gmt );
|
79 |
+
}
|
80 |
|
81 |
return new ActionScheduler_LogEntry( $record->action_id, $record->message, $date );
|
82 |
}
|
89 |
* @return ActionScheduler_LogEntry[]
|
90 |
*/
|
91 |
public function get_logs( $action_id ) {
|
92 |
+
/** @var \wpdb $wpdb */ //phpcs:ignore Generic.Commenting.DocComment.MissingShort
|
93 |
global $wpdb;
|
94 |
|
95 |
$records = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM {$wpdb->actionscheduler_logs} WHERE action_id=%d", $action_id ) );
|
103 |
* @codeCoverageIgnore
|
104 |
*/
|
105 |
public function init() {
|
|
|
106 |
$table_maker = new ActionScheduler_LoggerSchema();
|
107 |
+
$table_maker->init();
|
108 |
$table_maker->register_tables();
|
109 |
|
110 |
parent::init();
|
118 |
* @param int $action_id Action ID.
|
119 |
*/
|
120 |
public function clear_deleted_action_logs( $action_id ) {
|
121 |
+
/** @var \wpdb $wpdb */ //phpcs:ignore Generic.Commenting.DocComment.MissingShort
|
122 |
global $wpdb;
|
123 |
$wpdb->delete( $wpdb->actionscheduler_logs, array( 'action_id' => $action_id ), array( '%d' ) );
|
124 |
}
|
133 |
return;
|
134 |
}
|
135 |
|
136 |
+
/** @var \wpdb $wpdb */ //phpcs:ignore Generic.Commenting.DocComment.MissingShort
|
137 |
global $wpdb;
|
138 |
$date = as_get_datetime_object();
|
139 |
$date_gmt = $date->format( 'Y-m-d H:i:s' );
|
145 |
$value_rows = array();
|
146 |
|
147 |
foreach ( $action_ids as $action_id ) {
|
148 |
+
$value_rows[] = $wpdb->prepare( $format, $action_id ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
|
149 |
}
|
150 |
$sql_query .= implode( ',', $value_rows );
|
151 |
|
152 |
+
$wpdb->query( $sql_query ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
|
153 |
}
|
154 |
}
|
lite/includes/libraries/action-scheduler/classes/data-stores/ActionScheduler_DBStore.php
CHANGED
@@ -9,6 +9,16 @@
|
|
9 |
*/
|
10 |
class ActionScheduler_DBStore extends ActionScheduler_Store {
|
11 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
12 |
/** @var int */
|
13 |
protected static $max_args_length = 8000;
|
14 |
|
@@ -22,6 +32,7 @@ class ActionScheduler_DBStore extends ActionScheduler_Store {
|
|
22 |
*/
|
23 |
public function init() {
|
24 |
$table_maker = new ActionScheduler_StoreSchema();
|
|
|
25 |
$table_maker->register_tables();
|
26 |
}
|
27 |
|
@@ -29,9 +40,10 @@ class ActionScheduler_DBStore extends ActionScheduler_Store {
|
|
29 |
* Save an action.
|
30 |
*
|
31 |
* @param ActionScheduler_Action $action Action object.
|
32 |
-
* @param DateTime
|
33 |
*
|
34 |
* @return int Action ID.
|
|
|
35 |
*/
|
36 |
public function save_action( ActionScheduler_Action $action, \DateTime $date = null ) {
|
37 |
try {
|
@@ -45,7 +57,7 @@ class ActionScheduler_DBStore extends ActionScheduler_Store {
|
|
45 |
'status' => ( $action->is_finished() ? self::STATUS_COMPLETE : self::STATUS_PENDING ),
|
46 |
'scheduled_date_gmt' => $this->get_scheduled_date_string( $action, $date ),
|
47 |
'scheduled_date_local' => $this->get_scheduled_date_string_local( $action, $date ),
|
48 |
-
'schedule' => serialize( $action->get_schedule() ),
|
49 |
'group_id' => $this->get_group_id( $action->get_group() ),
|
50 |
);
|
51 |
$args = wp_json_encode( $action->get_args() );
|
@@ -61,9 +73,9 @@ class ActionScheduler_DBStore extends ActionScheduler_Store {
|
|
61 |
$action_id = $wpdb->insert_id;
|
62 |
|
63 |
if ( is_wp_error( $action_id ) ) {
|
64 |
-
throw new RuntimeException( $action_id->get_error_message() );
|
65 |
} elseif ( empty( $action_id ) ) {
|
66 |
-
throw new RuntimeException( $wpdb->last_error ? $wpdb->last_error : __( 'Database error.', 'action-scheduler' ) );
|
67 |
}
|
68 |
|
69 |
do_action( 'action_scheduler_stored_action', $action_id );
|
@@ -161,6 +173,19 @@ class ActionScheduler_DBStore extends ActionScheduler_Store {
|
|
161 |
unset( $data->extended_args );
|
162 |
}
|
163 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
164 |
try {
|
165 |
$action = $this->make_action_from_db_record( $data );
|
166 |
} catch ( ActionScheduler_InvalidActionException $exception ) {
|
@@ -191,7 +216,7 @@ class ActionScheduler_DBStore extends ActionScheduler_Store {
|
|
191 |
|
192 |
$hook = $data->hook;
|
193 |
$args = json_decode( $data->args, true );
|
194 |
-
$schedule = unserialize( $data->schedule );
|
195 |
|
196 |
$this->validate_args( $args, $data->action_id );
|
197 |
$this->validate_schedule( $schedule, $data->action_id );
|
@@ -204,71 +229,20 @@ class ActionScheduler_DBStore extends ActionScheduler_Store {
|
|
204 |
return ActionScheduler::factory()->get_stored_action( $data->status, $data->hook, $args, $schedule, $group );
|
205 |
}
|
206 |
|
207 |
-
/**
|
208 |
-
* Find an action.
|
209 |
-
*
|
210 |
-
* @param string $hook Action hook.
|
211 |
-
* @param array $params Parameters of the action to find.
|
212 |
-
*
|
213 |
-
* @return string|null ID of the next action matching the criteria or NULL if not found.
|
214 |
-
*/
|
215 |
-
public function find_action( $hook, $params = array() ) {
|
216 |
-
$params = wp_parse_args(
|
217 |
-
$params,
|
218 |
-
array(
|
219 |
-
'args' => null,
|
220 |
-
'status' => self::STATUS_PENDING,
|
221 |
-
'group' => '',
|
222 |
-
)
|
223 |
-
);
|
224 |
-
|
225 |
-
/** @var wpdb $wpdb */
|
226 |
-
global $wpdb;
|
227 |
-
$query = "SELECT a.action_id FROM {$wpdb->actionscheduler_actions} a";
|
228 |
-
$args = array();
|
229 |
-
if ( ! empty( $params['group'] ) ) {
|
230 |
-
$query .= " INNER JOIN {$wpdb->actionscheduler_groups} g ON g.group_id=a.group_id AND g.slug=%s";
|
231 |
-
$args[] = $params['group'];
|
232 |
-
}
|
233 |
-
$query .= ' WHERE a.hook=%s';
|
234 |
-
$args[] = $hook;
|
235 |
-
if ( ! is_null( $params['args'] ) ) {
|
236 |
-
$query .= ' AND a.args=%s';
|
237 |
-
$args[] = $this->get_args_for_query( $params['args'] );
|
238 |
-
}
|
239 |
-
|
240 |
-
$order = 'ASC';
|
241 |
-
if ( ! empty( $params['status'] ) ) {
|
242 |
-
$query .= ' AND a.status=%s';
|
243 |
-
$args[] = $params['status'];
|
244 |
-
|
245 |
-
if ( self::STATUS_PENDING == $params['status'] ) {
|
246 |
-
$order = 'ASC'; // Find the next action that matches.
|
247 |
-
} else {
|
248 |
-
$order = 'DESC'; // Find the most recent action that matches.
|
249 |
-
}
|
250 |
-
}
|
251 |
-
|
252 |
-
$query .= " ORDER BY scheduled_date_gmt $order LIMIT 1";
|
253 |
-
|
254 |
-
$query = $wpdb->prepare( $query, $args );
|
255 |
-
|
256 |
-
$id = $wpdb->get_var( $query );
|
257 |
-
|
258 |
-
return $id;
|
259 |
-
}
|
260 |
-
|
261 |
/**
|
262 |
* Returns the SQL statement to query (or count) actions.
|
263 |
*
|
|
|
|
|
264 |
* @param array $query Filtering options.
|
265 |
* @param string $select_or_count Whether the SQL should select and return the IDs or just the row count.
|
266 |
*
|
267 |
* @return string SQL statement already properly escaped.
|
|
|
268 |
*/
|
269 |
protected function get_query_actions_sql( array $query, $select_or_count = 'select' ) {
|
270 |
|
271 |
-
if ( ! in_array( $select_or_count, array( 'select', 'count' ) ) ) {
|
272 |
throw new InvalidArgumentException( __( 'Invalid value for select or count parameter. Cannot query actions.', 'action-scheduler' ) );
|
273 |
}
|
274 |
|
@@ -318,8 +292,10 @@ class ActionScheduler_DBStore extends ActionScheduler_Store {
|
|
318 |
}
|
319 |
|
320 |
if ( $query['status'] ) {
|
321 |
-
$
|
322 |
-
$
|
|
|
|
|
323 |
}
|
324 |
|
325 |
if ( $query['date'] instanceof \DateTime ) {
|
@@ -340,9 +316,9 @@ class ActionScheduler_DBStore extends ActionScheduler_Store {
|
|
340 |
$sql_params[] = $date_string;
|
341 |
}
|
342 |
|
343 |
-
if ( $query['claimed']
|
344 |
$sql .= ' AND a.claim_id != 0';
|
345 |
-
} elseif ( $query['claimed']
|
346 |
$sql .= ' AND a.claim_id = 0';
|
347 |
} elseif ( ! is_null( $query['claimed'] ) ) {
|
348 |
$sql .= ' AND a.claim_id = %d';
|
@@ -365,27 +341,32 @@ class ActionScheduler_DBStore extends ActionScheduler_Store {
|
|
365 |
}
|
366 |
|
367 |
if ( 'select' === $select_or_count ) {
|
|
|
|
|
|
|
|
|
|
|
368 |
switch ( $query['orderby'] ) {
|
369 |
case 'hook':
|
370 |
-
$
|
371 |
break;
|
372 |
case 'group':
|
373 |
-
$
|
374 |
break;
|
375 |
case 'modified':
|
376 |
-
$
|
|
|
|
|
|
|
|
|
|
|
377 |
break;
|
378 |
case 'date':
|
379 |
default:
|
380 |
-
$
|
381 |
break;
|
382 |
}
|
383 |
-
|
384 |
-
$order = 'ASC';
|
385 |
-
} else {
|
386 |
-
$order = 'DESC';
|
387 |
-
}
|
388 |
-
$sql .= " ORDER BY $orderby $order";
|
389 |
if ( $query['per_page'] > 0 ) {
|
390 |
$sql .= ' LIMIT %d, %d';
|
391 |
$sql_params[] = $query['offset'];
|
@@ -394,19 +375,23 @@ class ActionScheduler_DBStore extends ActionScheduler_Store {
|
|
394 |
}
|
395 |
|
396 |
if ( ! empty( $sql_params ) ) {
|
397 |
-
$sql = $wpdb->prepare( $sql, $sql_params );
|
398 |
}
|
399 |
|
400 |
return $sql;
|
401 |
}
|
402 |
|
403 |
/**
|
404 |
-
* Query for action count
|
405 |
*
|
406 |
-
* @
|
407 |
-
* @param string $query_type Whether to select or count the results. Default, select.
|
408 |
*
|
409 |
-
* @
|
|
|
|
|
|
|
|
|
|
|
410 |
*/
|
411 |
public function query_actions( $query = array(), $query_type = 'select' ) {
|
412 |
/** @var wpdb $wpdb */
|
@@ -414,7 +399,7 @@ class ActionScheduler_DBStore extends ActionScheduler_Store {
|
|
414 |
|
415 |
$sql = $this->get_query_actions_sql( $query, $query_type );
|
416 |
|
417 |
-
return ( 'count' === $query_type ) ? $wpdb->get_var( $sql ) : $wpdb->get_col( $sql );
|
418 |
}
|
419 |
|
420 |
/**
|
@@ -432,8 +417,8 @@ class ActionScheduler_DBStore extends ActionScheduler_Store {
|
|
432 |
$actions_count_by_status = array();
|
433 |
$action_stati_and_labels = $this->get_status_labels();
|
434 |
|
435 |
-
foreach ( $wpdb->get_results( $sql ) as $action_data ) {
|
436 |
-
// Ignore any actions with invalid status
|
437 |
if ( array_key_exists( $action_data->status, $action_stati_and_labels ) ) {
|
438 |
$actions_count_by_status[ $action_data->status ] = $action_data->count;
|
439 |
}
|
@@ -448,6 +433,7 @@ class ActionScheduler_DBStore extends ActionScheduler_Store {
|
|
448 |
* @param int $action_id Action ID.
|
449 |
*
|
450 |
* @return void
|
|
|
451 |
*/
|
452 |
public function cancel_action( $action_id ) {
|
453 |
/** @var \wpdb $wpdb */
|
@@ -507,7 +493,7 @@ class ActionScheduler_DBStore extends ActionScheduler_Store {
|
|
507 |
}
|
508 |
|
509 |
// Don't cancel actions that are already canceled.
|
510 |
-
if ( isset( $query_args['status'] ) && $query_args['status']
|
511 |
return;
|
512 |
}
|
513 |
|
@@ -517,6 +503,7 @@ class ActionScheduler_DBStore extends ActionScheduler_Store {
|
|
517 |
array(
|
518 |
'per_page' => 1000,
|
519 |
'status' => self::STATUS_PENDING,
|
|
|
520 |
)
|
521 |
);
|
522 |
|
@@ -532,8 +519,8 @@ class ActionScheduler_DBStore extends ActionScheduler_Store {
|
|
532 |
array_unshift( $parameters, self::STATUS_CANCELED );
|
533 |
|
534 |
$wpdb->query(
|
535 |
-
$wpdb->prepare(
|
536 |
-
"UPDATE {$wpdb->actionscheduler_actions} SET status = %s WHERE action_id IN {$query_in}",
|
537 |
$parameters
|
538 |
)
|
539 |
);
|
@@ -546,13 +533,14 @@ class ActionScheduler_DBStore extends ActionScheduler_Store {
|
|
546 |
* Delete an action.
|
547 |
*
|
548 |
* @param int $action_id Action ID.
|
|
|
549 |
*/
|
550 |
public function delete_action( $action_id ) {
|
551 |
/** @var \wpdb $wpdb */
|
552 |
global $wpdb;
|
553 |
$deleted = $wpdb->delete( $wpdb->actionscheduler_actions, array( 'action_id' => $action_id ), array( '%d' ) );
|
554 |
if ( empty( $deleted ) ) {
|
555 |
-
throw new \InvalidArgumentException( sprintf( __( 'Unidentified action %s', 'action-scheduler' ), $action_id ) );
|
556 |
}
|
557 |
do_action( 'action_scheduler_deleted_action', $action_id );
|
558 |
}
|
@@ -562,7 +550,6 @@ class ActionScheduler_DBStore extends ActionScheduler_Store {
|
|
562 |
*
|
563 |
* @param string $action_id Action ID.
|
564 |
*
|
565 |
-
* @throws \InvalidArgumentException
|
566 |
* @return \DateTime The local date the action is scheduled to run, or the date that it ran.
|
567 |
*/
|
568 |
public function get_date( $action_id ) {
|
@@ -576,7 +563,7 @@ class ActionScheduler_DBStore extends ActionScheduler_Store {
|
|
576 |
*
|
577 |
* @param int $action_id Action ID.
|
578 |
*
|
579 |
-
* @throws \InvalidArgumentException
|
580 |
* @return \DateTime The GMT date the action is scheduled to run, or the date that it ran.
|
581 |
*/
|
582 |
protected function get_date_gmt( $action_id ) {
|
@@ -584,9 +571,9 @@ class ActionScheduler_DBStore extends ActionScheduler_Store {
|
|
584 |
global $wpdb;
|
585 |
$record = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$wpdb->actionscheduler_actions} WHERE action_id=%d", $action_id ) );
|
586 |
if ( empty( $record ) ) {
|
587 |
-
throw new \InvalidArgumentException( sprintf( __( 'Unidentified action %s', 'action-scheduler' ), $action_id ) );
|
588 |
}
|
589 |
-
if ( $record->status
|
590 |
return as_get_datetime_object( $record->scheduled_date_gmt );
|
591 |
} else {
|
592 |
return as_get_datetime_object( $record->last_attempt_gmt );
|
@@ -598,13 +585,18 @@ class ActionScheduler_DBStore extends ActionScheduler_Store {
|
|
598 |
*
|
599 |
* @param int $max_actions Maximum number of action to include in claim.
|
600 |
* @param \DateTime $before_date Jobs must be schedule before this date. Defaults to now.
|
|
|
|
|
601 |
*
|
602 |
* @return ActionScheduler_ActionClaim
|
603 |
*/
|
604 |
public function stake_claim( $max_actions = 10, \DateTime $before_date = null, $hooks = array(), $group = '' ) {
|
605 |
$claim_id = $this->generate_claim_id();
|
|
|
|
|
606 |
$this->claim_actions( $claim_id, $max_actions, $before_date, $hooks, $group );
|
607 |
-
$action_ids
|
|
|
608 |
|
609 |
return new ActionScheduler_ActionClaim( $claim_id, $action_ids );
|
610 |
}
|
@@ -629,9 +621,12 @@ class ActionScheduler_DBStore extends ActionScheduler_Store {
|
|
629 |
* @param string $claim_id Claim Id.
|
630 |
* @param int $limit Number of action to include in claim.
|
631 |
* @param \DateTime $before_date Should use UTC timezone.
|
|
|
|
|
632 |
*
|
633 |
* @return int The number of actions that were claimed.
|
634 |
-
* @throws \
|
|
|
635 |
*/
|
636 |
protected function claim_actions( $claim_id, $limit, \DateTime $before_date = null, $hooks = array(), $group = '' ) {
|
637 |
/** @var \wpdb $wpdb */
|
@@ -640,7 +635,7 @@ class ActionScheduler_DBStore extends ActionScheduler_Store {
|
|
640 |
$now = as_get_datetime_object();
|
641 |
$date = is_null( $before_date ) ? $now : clone $before_date;
|
642 |
|
643 |
-
// can't use $wpdb->update() because of the <= condition
|
644 |
$update = "UPDATE {$wpdb->actionscheduler_actions} SET claim_id=%d, last_attempt_gmt=%s, last_attempt_local=%s";
|
645 |
$params = array(
|
646 |
$claim_id,
|
@@ -662,7 +657,7 @@ class ActionScheduler_DBStore extends ActionScheduler_Store {
|
|
662 |
|
663 |
$group_id = $this->get_group_id( $group, false );
|
664 |
|
665 |
-
// throw exception if no matching group found, this matches ActionScheduler_wpPostStore's behaviour
|
666 |
if ( empty( $group_id ) ) {
|
667 |
/* translators: %s: group name */
|
668 |
throw new InvalidArgumentException( sprintf( __( 'The group "%s" does not exist.', 'action-scheduler' ), $group ) );
|
@@ -672,13 +667,19 @@ class ActionScheduler_DBStore extends ActionScheduler_Store {
|
|
672 |
$params[] = $group_id;
|
673 |
}
|
674 |
|
675 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
676 |
$params[] = $limit;
|
677 |
|
678 |
-
$sql
|
679 |
-
|
680 |
-
|
681 |
-
if ( $rows_affected === false ) {
|
682 |
throw new \RuntimeException( __( 'Unable to claim actions. Database error.', 'action-scheduler' ) );
|
683 |
}
|
684 |
|
@@ -694,9 +695,9 @@ class ActionScheduler_DBStore extends ActionScheduler_Store {
|
|
694 |
global $wpdb;
|
695 |
|
696 |
$sql = "SELECT COUNT(DISTINCT claim_id) FROM {$wpdb->actionscheduler_actions} WHERE claim_id != 0 AND status IN ( %s, %s)";
|
697 |
-
$sql = $wpdb->prepare( $sql, array( self::STATUS_PENDING, self::STATUS_RUNNING ) );
|
698 |
|
699 |
-
return (int) $wpdb->get_var( $sql );
|
700 |
}
|
701 |
|
702 |
/**
|
@@ -710,28 +711,39 @@ class ActionScheduler_DBStore extends ActionScheduler_Store {
|
|
710 |
global $wpdb;
|
711 |
|
712 |
$sql = "SELECT claim_id FROM {$wpdb->actionscheduler_actions} WHERE action_id=%d";
|
713 |
-
$sql = $wpdb->prepare( $sql, $action_id );
|
714 |
|
715 |
-
return (int) $wpdb->get_var( $sql );
|
716 |
}
|
717 |
|
718 |
/**
|
719 |
* Retrieve the action IDs of action in a claim.
|
720 |
*
|
721 |
-
* @param
|
722 |
-
*
|
723 |
* @return int[]
|
724 |
*/
|
725 |
public function find_actions_by_claim_id( $claim_id ) {
|
726 |
/** @var \wpdb $wpdb */
|
727 |
global $wpdb;
|
728 |
|
729 |
-
$
|
730 |
-
$
|
|
|
731 |
|
732 |
-
$
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
733 |
|
734 |
-
return
|
735 |
}
|
736 |
|
737 |
/**
|
@@ -769,6 +781,7 @@ class ActionScheduler_DBStore extends ActionScheduler_Store {
|
|
769 |
* Mark an action as failed.
|
770 |
*
|
771 |
* @param int $action_id Action ID.
|
|
|
772 |
*/
|
773 |
public function mark_failure( $action_id ) {
|
774 |
/** @var \wpdb $wpdb */
|
@@ -781,7 +794,7 @@ class ActionScheduler_DBStore extends ActionScheduler_Store {
|
|
781 |
array( '%d' )
|
782 |
);
|
783 |
if ( empty( $updated ) ) {
|
784 |
-
throw new \InvalidArgumentException( sprintf( __( 'Unidentified action %s', 'action-scheduler' ), $action_id ) );
|
785 |
}
|
786 |
}
|
787 |
|
@@ -797,8 +810,8 @@ class ActionScheduler_DBStore extends ActionScheduler_Store {
|
|
797 |
global $wpdb;
|
798 |
|
799 |
$sql = "UPDATE {$wpdb->actionscheduler_actions} SET attempts = attempts+1, status=%s, last_attempt_gmt = %s, last_attempt_local = %s WHERE action_id = %d";
|
800 |
-
$sql = $wpdb->prepare( $sql, self::STATUS_RUNNING, current_time( 'mysql', true ), current_time( 'mysql' ), $action_id );
|
801 |
-
$wpdb->query( $sql );
|
802 |
}
|
803 |
|
804 |
/**
|
@@ -807,6 +820,7 @@ class ActionScheduler_DBStore extends ActionScheduler_Store {
|
|
807 |
* @param int $action_id Action ID.
|
808 |
*
|
809 |
* @return void
|
|
|
810 |
*/
|
811 |
public function mark_complete( $action_id ) {
|
812 |
/** @var \wpdb $wpdb */
|
@@ -823,7 +837,7 @@ class ActionScheduler_DBStore extends ActionScheduler_Store {
|
|
823 |
array( '%d' )
|
824 |
);
|
825 |
if ( empty( $updated ) ) {
|
826 |
-
throw new \InvalidArgumentException( sprintf( __( 'Unidentified action %s', 'action-scheduler' ), $action_id ) );
|
827 |
}
|
828 |
}
|
829 |
|
@@ -833,15 +847,17 @@ class ActionScheduler_DBStore extends ActionScheduler_Store {
|
|
833 |
* @param int $action_id Action ID.
|
834 |
*
|
835 |
* @return string
|
|
|
|
|
836 |
*/
|
837 |
public function get_status( $action_id ) {
|
838 |
/** @var \wpdb $wpdb */
|
839 |
global $wpdb;
|
840 |
$sql = "SELECT status FROM {$wpdb->actionscheduler_actions} WHERE action_id=%d";
|
841 |
-
$sql = $wpdb->prepare( $sql, $action_id );
|
842 |
-
$status = $wpdb->get_var( $sql );
|
843 |
|
844 |
-
if (
|
845 |
throw new \InvalidArgumentException( __( 'Invalid action ID. No status found.', 'action-scheduler' ) );
|
846 |
} elseif ( empty( $status ) ) {
|
847 |
throw new \RuntimeException( __( 'Unknown status found for action.', 'action-scheduler' ) );
|
9 |
*/
|
10 |
class ActionScheduler_DBStore extends ActionScheduler_Store {
|
11 |
|
12 |
+
/**
|
13 |
+
* Used to share information about the before_date property of claims internally.
|
14 |
+
*
|
15 |
+
* This is used in preference to passing the same information as a method param
|
16 |
+
* for backwards-compatibility reasons.
|
17 |
+
*
|
18 |
+
* @var DateTime|null
|
19 |
+
*/
|
20 |
+
private $claim_before_date = null;
|
21 |
+
|
22 |
/** @var int */
|
23 |
protected static $max_args_length = 8000;
|
24 |
|
32 |
*/
|
33 |
public function init() {
|
34 |
$table_maker = new ActionScheduler_StoreSchema();
|
35 |
+
$table_maker->init();
|
36 |
$table_maker->register_tables();
|
37 |
}
|
38 |
|
40 |
* Save an action.
|
41 |
*
|
42 |
* @param ActionScheduler_Action $action Action object.
|
43 |
+
* @param DateTime $date Optional schedule date. Default null.
|
44 |
*
|
45 |
* @return int Action ID.
|
46 |
+
* @throws RuntimeException Throws exception when saving the action fails.
|
47 |
*/
|
48 |
public function save_action( ActionScheduler_Action $action, \DateTime $date = null ) {
|
49 |
try {
|
57 |
'status' => ( $action->is_finished() ? self::STATUS_COMPLETE : self::STATUS_PENDING ),
|
58 |
'scheduled_date_gmt' => $this->get_scheduled_date_string( $action, $date ),
|
59 |
'scheduled_date_local' => $this->get_scheduled_date_string_local( $action, $date ),
|
60 |
+
'schedule' => serialize( $action->get_schedule() ), // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.serialize_serialize
|
61 |
'group_id' => $this->get_group_id( $action->get_group() ),
|
62 |
);
|
63 |
$args = wp_json_encode( $action->get_args() );
|
73 |
$action_id = $wpdb->insert_id;
|
74 |
|
75 |
if ( is_wp_error( $action_id ) ) {
|
76 |
+
throw new \RuntimeException( $action_id->get_error_message() );
|
77 |
} elseif ( empty( $action_id ) ) {
|
78 |
+
throw new \RuntimeException( $wpdb->last_error ? $wpdb->last_error : __( 'Database error.', 'action-scheduler' ) );
|
79 |
}
|
80 |
|
81 |
do_action( 'action_scheduler_stored_action', $action_id );
|
173 |
unset( $data->extended_args );
|
174 |
}
|
175 |
|
176 |
+
// Convert NULL dates to zero dates.
|
177 |
+
$date_fields = array(
|
178 |
+
'scheduled_date_gmt',
|
179 |
+
'scheduled_date_local',
|
180 |
+
'last_attempt_gmt',
|
181 |
+
'last_attempt_gmt',
|
182 |
+
);
|
183 |
+
foreach ( $date_fields as $date_field ) {
|
184 |
+
if ( is_null( $data->$date_field ) ) {
|
185 |
+
$data->$date_field = ActionScheduler_StoreSchema::DEFAULT_DATE;
|
186 |
+
}
|
187 |
+
}
|
188 |
+
|
189 |
try {
|
190 |
$action = $this->make_action_from_db_record( $data );
|
191 |
} catch ( ActionScheduler_InvalidActionException $exception ) {
|
216 |
|
217 |
$hook = $data->hook;
|
218 |
$args = json_decode( $data->args, true );
|
219 |
+
$schedule = unserialize( $data->schedule ); // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.serialize_unserialize
|
220 |
|
221 |
$this->validate_args( $args, $data->action_id );
|
222 |
$this->validate_schedule( $schedule, $data->action_id );
|
229 |
return ActionScheduler::factory()->get_stored_action( $data->status, $data->hook, $args, $schedule, $group );
|
230 |
}
|
231 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
232 |
/**
|
233 |
* Returns the SQL statement to query (or count) actions.
|
234 |
*
|
235 |
+
* @since x.x.x $query['status'] accepts array of statuses instead of a single status.
|
236 |
+
*
|
237 |
* @param array $query Filtering options.
|
238 |
* @param string $select_or_count Whether the SQL should select and return the IDs or just the row count.
|
239 |
*
|
240 |
* @return string SQL statement already properly escaped.
|
241 |
+
* @throws InvalidArgumentException If the query is invalid.
|
242 |
*/
|
243 |
protected function get_query_actions_sql( array $query, $select_or_count = 'select' ) {
|
244 |
|
245 |
+
if ( ! in_array( $select_or_count, array( 'select', 'count' ), true ) ) {
|
246 |
throw new InvalidArgumentException( __( 'Invalid value for select or count parameter. Cannot query actions.', 'action-scheduler' ) );
|
247 |
}
|
248 |
|
292 |
}
|
293 |
|
294 |
if ( $query['status'] ) {
|
295 |
+
$statuses = (array) $query['status'];
|
296 |
+
$placeholders = array_fill( 0, count( $statuses ), '%s' );
|
297 |
+
$sql .= ' AND a.status IN (' . join( ', ', $placeholders ) . ')';
|
298 |
+
$sql_params = array_merge( $sql_params, array_values( $statuses ) );
|
299 |
}
|
300 |
|
301 |
if ( $query['date'] instanceof \DateTime ) {
|
316 |
$sql_params[] = $date_string;
|
317 |
}
|
318 |
|
319 |
+
if ( true === $query['claimed'] ) {
|
320 |
$sql .= ' AND a.claim_id != 0';
|
321 |
+
} elseif ( false === $query['claimed'] ) {
|
322 |
$sql .= ' AND a.claim_id = 0';
|
323 |
} elseif ( ! is_null( $query['claimed'] ) ) {
|
324 |
$sql .= ' AND a.claim_id = %d';
|
341 |
}
|
342 |
|
343 |
if ( 'select' === $select_or_count ) {
|
344 |
+
if ( 'ASC' === strtoupper( $query['order'] ) ) {
|
345 |
+
$order = 'ASC';
|
346 |
+
} else {
|
347 |
+
$order = 'DESC';
|
348 |
+
}
|
349 |
switch ( $query['orderby'] ) {
|
350 |
case 'hook':
|
351 |
+
$sql .= " ORDER BY a.hook $order";
|
352 |
break;
|
353 |
case 'group':
|
354 |
+
$sql .= " ORDER BY g.slug $order";
|
355 |
break;
|
356 |
case 'modified':
|
357 |
+
$sql .= " ORDER BY a.last_attempt_gmt $order";
|
358 |
+
break;
|
359 |
+
case 'none':
|
360 |
+
break;
|
361 |
+
case 'action_id':
|
362 |
+
$sql .= " ORDER BY a.action_id $order";
|
363 |
break;
|
364 |
case 'date':
|
365 |
default:
|
366 |
+
$sql .= " ORDER BY a.scheduled_date_gmt $order";
|
367 |
break;
|
368 |
}
|
369 |
+
|
|
|
|
|
|
|
|
|
|
|
370 |
if ( $query['per_page'] > 0 ) {
|
371 |
$sql .= ' LIMIT %d, %d';
|
372 |
$sql_params[] = $query['offset'];
|
375 |
}
|
376 |
|
377 |
if ( ! empty( $sql_params ) ) {
|
378 |
+
$sql = $wpdb->prepare( $sql, $sql_params ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
|
379 |
}
|
380 |
|
381 |
return $sql;
|
382 |
}
|
383 |
|
384 |
/**
|
385 |
+
* Query for action count or list of action IDs.
|
386 |
*
|
387 |
+
* @since x.x.x $query['status'] accepts array of statuses instead of a single status.
|
|
|
388 |
*
|
389 |
+
* @see ActionScheduler_Store::query_actions for $query arg usage.
|
390 |
+
*
|
391 |
+
* @param array $query Query filtering options.
|
392 |
+
* @param string $query_type Whether to select or count the results. Defaults to select.
|
393 |
+
*
|
394 |
+
* @return string|array|null The IDs of actions matching the query. Null on failure.
|
395 |
*/
|
396 |
public function query_actions( $query = array(), $query_type = 'select' ) {
|
397 |
/** @var wpdb $wpdb */
|
399 |
|
400 |
$sql = $this->get_query_actions_sql( $query, $query_type );
|
401 |
|
402 |
+
return ( 'count' === $query_type ) ? $wpdb->get_var( $sql ) : $wpdb->get_col( $sql ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.DirectDatabaseQuery.NoSql, WordPress.DB.DirectDatabaseQuery.NoCaching
|
403 |
}
|
404 |
|
405 |
/**
|
417 |
$actions_count_by_status = array();
|
418 |
$action_stati_and_labels = $this->get_status_labels();
|
419 |
|
420 |
+
foreach ( $wpdb->get_results( $sql ) as $action_data ) { // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
|
421 |
+
// Ignore any actions with invalid status.
|
422 |
if ( array_key_exists( $action_data->status, $action_stati_and_labels ) ) {
|
423 |
$actions_count_by_status[ $action_data->status ] = $action_data->count;
|
424 |
}
|
433 |
* @param int $action_id Action ID.
|
434 |
*
|
435 |
* @return void
|
436 |
+
* @throws \InvalidArgumentException If the action update failed.
|
437 |
*/
|
438 |
public function cancel_action( $action_id ) {
|
439 |
/** @var \wpdb $wpdb */
|
493 |
}
|
494 |
|
495 |
// Don't cancel actions that are already canceled.
|
496 |
+
if ( isset( $query_args['status'] ) && self::STATUS_CANCELED === $query_args['status'] ) {
|
497 |
return;
|
498 |
}
|
499 |
|
503 |
array(
|
504 |
'per_page' => 1000,
|
505 |
'status' => self::STATUS_PENDING,
|
506 |
+
'orderby' => 'action_id',
|
507 |
)
|
508 |
);
|
509 |
|
519 |
array_unshift( $parameters, self::STATUS_CANCELED );
|
520 |
|
521 |
$wpdb->query(
|
522 |
+
$wpdb->prepare(
|
523 |
+
"UPDATE {$wpdb->actionscheduler_actions} SET status = %s WHERE action_id IN {$query_in}", // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
|
524 |
$parameters
|
525 |
)
|
526 |
);
|
533 |
* Delete an action.
|
534 |
*
|
535 |
* @param int $action_id Action ID.
|
536 |
+
* @throws \InvalidArgumentException If the action deletion failed.
|
537 |
*/
|
538 |
public function delete_action( $action_id ) {
|
539 |
/** @var \wpdb $wpdb */
|
540 |
global $wpdb;
|
541 |
$deleted = $wpdb->delete( $wpdb->actionscheduler_actions, array( 'action_id' => $action_id ), array( '%d' ) );
|
542 |
if ( empty( $deleted ) ) {
|
543 |
+
throw new \InvalidArgumentException( sprintf( __( 'Unidentified action %s', 'action-scheduler' ), $action_id ) ); //phpcs:ignore WordPress.WP.I18n.MissingTranslatorsComment
|
544 |
}
|
545 |
do_action( 'action_scheduler_deleted_action', $action_id );
|
546 |
}
|
550 |
*
|
551 |
* @param string $action_id Action ID.
|
552 |
*
|
|
|
553 |
* @return \DateTime The local date the action is scheduled to run, or the date that it ran.
|
554 |
*/
|
555 |
public function get_date( $action_id ) {
|
563 |
*
|
564 |
* @param int $action_id Action ID.
|
565 |
*
|
566 |
+
* @throws \InvalidArgumentException If action cannot be identified.
|
567 |
* @return \DateTime The GMT date the action is scheduled to run, or the date that it ran.
|
568 |
*/
|
569 |
protected function get_date_gmt( $action_id ) {
|
571 |
global $wpdb;
|
572 |
$record = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$wpdb->actionscheduler_actions} WHERE action_id=%d", $action_id ) );
|
573 |
if ( empty( $record ) ) {
|
574 |
+
throw new \InvalidArgumentException( sprintf( __( 'Unidentified action %s', 'action-scheduler' ), $action_id ) ); //phpcs:ignore WordPress.WP.I18n.MissingTranslatorsComment
|
575 |
}
|
576 |
+
if ( self::STATUS_PENDING === $record->status ) {
|
577 |
return as_get_datetime_object( $record->scheduled_date_gmt );
|
578 |
} else {
|
579 |
return as_get_datetime_object( $record->last_attempt_gmt );
|
585 |
*
|
586 |
* @param int $max_actions Maximum number of action to include in claim.
|
587 |
* @param \DateTime $before_date Jobs must be schedule before this date. Defaults to now.
|
588 |
+
* @param array $hooks Hooks to filter for.
|
589 |
+
* @param string $group Group to filter for.
|
590 |
*
|
591 |
* @return ActionScheduler_ActionClaim
|
592 |
*/
|
593 |
public function stake_claim( $max_actions = 10, \DateTime $before_date = null, $hooks = array(), $group = '' ) {
|
594 |
$claim_id = $this->generate_claim_id();
|
595 |
+
|
596 |
+
$this->claim_before_date = $before_date;
|
597 |
$this->claim_actions( $claim_id, $max_actions, $before_date, $hooks, $group );
|
598 |
+
$action_ids = $this->find_actions_by_claim_id( $claim_id );
|
599 |
+
$this->claim_before_date = null;
|
600 |
|
601 |
return new ActionScheduler_ActionClaim( $claim_id, $action_ids );
|
602 |
}
|
621 |
* @param string $claim_id Claim Id.
|
622 |
* @param int $limit Number of action to include in claim.
|
623 |
* @param \DateTime $before_date Should use UTC timezone.
|
624 |
+
* @param array $hooks Hooks to filter for.
|
625 |
+
* @param string $group Group to filter for.
|
626 |
*
|
627 |
* @return int The number of actions that were claimed.
|
628 |
+
* @throws \InvalidArgumentException Throws InvalidArgumentException if group doesn't exist.
|
629 |
+
* @throws \RuntimeException Throws RuntimeException if unable to claim action.
|
630 |
*/
|
631 |
protected function claim_actions( $claim_id, $limit, \DateTime $before_date = null, $hooks = array(), $group = '' ) {
|
632 |
/** @var \wpdb $wpdb */
|
635 |
$now = as_get_datetime_object();
|
636 |
$date = is_null( $before_date ) ? $now : clone $before_date;
|
637 |
|
638 |
+
// can't use $wpdb->update() because of the <= condition.
|
639 |
$update = "UPDATE {$wpdb->actionscheduler_actions} SET claim_id=%d, last_attempt_gmt=%s, last_attempt_local=%s";
|
640 |
$params = array(
|
641 |
$claim_id,
|
657 |
|
658 |
$group_id = $this->get_group_id( $group, false );
|
659 |
|
660 |
+
// throw exception if no matching group found, this matches ActionScheduler_wpPostStore's behaviour.
|
661 |
if ( empty( $group_id ) ) {
|
662 |
/* translators: %s: group name */
|
663 |
throw new InvalidArgumentException( sprintf( __( 'The group "%s" does not exist.', 'action-scheduler' ), $group ) );
|
667 |
$params[] = $group_id;
|
668 |
}
|
669 |
|
670 |
+
/**
|
671 |
+
* Sets the order-by clause used in the action claim query.
|
672 |
+
*
|
673 |
+
* @since x.x.x
|
674 |
+
*
|
675 |
+
* @param string $order_by_sql
|
676 |
+
*/
|
677 |
+
$order = apply_filters( 'action_scheduler_claim_actions_order_by', 'ORDER BY attempts ASC, scheduled_date_gmt ASC, action_id ASC' );
|
678 |
$params[] = $limit;
|
679 |
|
680 |
+
$sql = $wpdb->prepare( "{$update} {$where} {$order} LIMIT %d", $params ); // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.PreparedSQLPlaceholders
|
681 |
+
$rows_affected = $wpdb->query( $sql ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
|
682 |
+
if ( false === $rows_affected ) {
|
|
|
683 |
throw new \RuntimeException( __( 'Unable to claim actions. Database error.', 'action-scheduler' ) );
|
684 |
}
|
685 |
|
695 |
global $wpdb;
|
696 |
|
697 |
$sql = "SELECT COUNT(DISTINCT claim_id) FROM {$wpdb->actionscheduler_actions} WHERE claim_id != 0 AND status IN ( %s, %s)";
|
698 |
+
$sql = $wpdb->prepare( $sql, array( self::STATUS_PENDING, self::STATUS_RUNNING ) ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
|
699 |
|
700 |
+
return (int) $wpdb->get_var( $sql ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
|
701 |
}
|
702 |
|
703 |
/**
|
711 |
global $wpdb;
|
712 |
|
713 |
$sql = "SELECT claim_id FROM {$wpdb->actionscheduler_actions} WHERE action_id=%d";
|
714 |
+
$sql = $wpdb->prepare( $sql, $action_id ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
|
715 |
|
716 |
+
return (int) $wpdb->get_var( $sql ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
|
717 |
}
|
718 |
|
719 |
/**
|
720 |
* Retrieve the action IDs of action in a claim.
|
721 |
*
|
722 |
+
* @param int $claim_id Claim ID.
|
|
|
723 |
* @return int[]
|
724 |
*/
|
725 |
public function find_actions_by_claim_id( $claim_id ) {
|
726 |
/** @var \wpdb $wpdb */
|
727 |
global $wpdb;
|
728 |
|
729 |
+
$action_ids = array();
|
730 |
+
$before_date = isset( $this->claim_before_date ) ? $this->claim_before_date : as_get_datetime_object();
|
731 |
+
$cut_off = $before_date->format( 'Y-m-d H:i:s' );
|
732 |
|
733 |
+
$sql = $wpdb->prepare(
|
734 |
+
"SELECT action_id, scheduled_date_gmt FROM {$wpdb->actionscheduler_actions} WHERE claim_id = %d",
|
735 |
+
$claim_id
|
736 |
+
);
|
737 |
+
|
738 |
+
// Verify that the scheduled date for each action is within the expected bounds (in some unusual
|
739 |
+
// cases, we cannot depend on MySQL to honor all of the WHERE conditions we specify).
|
740 |
+
foreach ( $wpdb->get_results( $sql ) as $claimed_action ) { // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
|
741 |
+
if ( $claimed_action->scheduled_date_gmt <= $cut_off ) {
|
742 |
+
$action_ids[] = absint( $claimed_action->action_id );
|
743 |
+
}
|
744 |
+
}
|
745 |
|
746 |
+
return $action_ids;
|
747 |
}
|
748 |
|
749 |
/**
|
781 |
* Mark an action as failed.
|
782 |
*
|
783 |
* @param int $action_id Action ID.
|
784 |
+
* @throws \InvalidArgumentException Throw an exception if action was not updated.
|
785 |
*/
|
786 |
public function mark_failure( $action_id ) {
|
787 |
/** @var \wpdb $wpdb */
|
794 |
array( '%d' )
|
795 |
);
|
796 |
if ( empty( $updated ) ) {
|
797 |
+
throw new \InvalidArgumentException( sprintf( __( 'Unidentified action %s', 'action-scheduler' ), $action_id ) ); //phpcs:ignore WordPress.WP.I18n.MissingTranslatorsComment
|
798 |
}
|
799 |
}
|
800 |
|
810 |
global $wpdb;
|
811 |
|
812 |
$sql = "UPDATE {$wpdb->actionscheduler_actions} SET attempts = attempts+1, status=%s, last_attempt_gmt = %s, last_attempt_local = %s WHERE action_id = %d";
|
813 |
+
$sql = $wpdb->prepare( $sql, self::STATUS_RUNNING, current_time( 'mysql', true ), current_time( 'mysql' ), $action_id ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
|
814 |
+
$wpdb->query( $sql ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
|
815 |
}
|
816 |
|
817 |
/**
|
820 |
* @param int $action_id Action ID.
|
821 |
*
|
822 |
* @return void
|
823 |
+
* @throws \InvalidArgumentException Throw an exception if action was not updated.
|
824 |
*/
|
825 |
public function mark_complete( $action_id ) {
|
826 |
/** @var \wpdb $wpdb */
|
837 |
array( '%d' )
|
838 |
);
|
839 |
if ( empty( $updated ) ) {
|
840 |
+
throw new \InvalidArgumentException( sprintf( __( 'Unidentified action %s', 'action-scheduler' ), $action_id ) ); //phpcs:ignore WordPress.WP.I18n.MissingTranslatorsComment
|
841 |
}
|
842 |
}
|
843 |
|
847 |
* @param int $action_id Action ID.
|
848 |
*
|
849 |
* @return string
|
850 |
+
* @throws \InvalidArgumentException Throw an exception if not status was found for action_id.
|
851 |
+
* @throws \RuntimeException Throw an exception if action status could not be retrieved.
|
852 |
*/
|
853 |
public function get_status( $action_id ) {
|
854 |
/** @var \wpdb $wpdb */
|
855 |
global $wpdb;
|
856 |
$sql = "SELECT status FROM {$wpdb->actionscheduler_actions} WHERE action_id=%d";
|
857 |
+
$sql = $wpdb->prepare( $sql, $action_id ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
|
858 |
+
$status = $wpdb->get_var( $sql ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
|
859 |
|
860 |
+
if ( null === $status ) {
|
861 |
throw new \InvalidArgumentException( __( 'Invalid action ID. No status found.', 'action-scheduler' ) );
|
862 |
} elseif ( empty( $status ) ) {
|
863 |
throw new \RuntimeException( __( 'Unknown status found for action.', 'action-scheduler' ) );
|
lite/includes/libraries/action-scheduler/classes/data-stores/ActionScheduler_HybridStore.php
CHANGED
@@ -53,10 +53,10 @@ class ActionScheduler_HybridStore extends Store {
|
|
53 |
* @codeCoverageIgnore
|
54 |
*/
|
55 |
public function init() {
|
56 |
-
add_action( 'action_scheduler/created_table',
|
57 |
$this->primary_store->init();
|
58 |
$this->secondary_store->init();
|
59 |
-
remove_action( 'action_scheduler/created_table',
|
60 |
}
|
61 |
|
62 |
/**
|
@@ -78,7 +78,7 @@ class ActionScheduler_HybridStore extends Store {
|
|
78 |
/** @var \wpdb $wpdb */
|
79 |
global $wpdb;
|
80 |
/**
|
81 |
-
* A default date of '0000-00-00 00:00:00' is invalid in MySQL 5.7 when configured with
|
82 |
* sql_mode including both STRICT_TRANS_TABLES and NO_ZERO_DATE.
|
83 |
*/
|
84 |
$default_date = new DateTime( 'tomorrow' );
|
@@ -88,7 +88,7 @@ class ActionScheduler_HybridStore extends Store {
|
|
88 |
|
89 |
$row_count = $wpdb->insert(
|
90 |
$wpdb->{ActionScheduler_StoreSchema::ACTIONS_TABLE},
|
91 |
-
|
92 |
'action_id' => $this->demarkation_id,
|
93 |
'hook' => '',
|
94 |
'status' => '',
|
@@ -96,12 +96,12 @@ class ActionScheduler_HybridStore extends Store {
|
|
96 |
'scheduled_date_local' => $date_local,
|
97 |
'last_attempt_gmt' => $date_gmt,
|
98 |
'last_attempt_local' => $date_local,
|
99 |
-
|
100 |
);
|
101 |
if ( $row_count > 0 ) {
|
102 |
$wpdb->delete(
|
103 |
$wpdb->{ActionScheduler_StoreSchema::ACTIONS_TABLE},
|
104 |
-
|
105 |
);
|
106 |
}
|
107 |
}
|
@@ -140,10 +140,10 @@ class ActionScheduler_HybridStore extends Store {
|
|
140 |
*
|
141 |
* @return string
|
142 |
*/
|
143 |
-
public function find_action( $hook, $params =
|
144 |
$found_unmigrated_action = $this->secondary_store->find_action( $hook, $params );
|
145 |
if ( ! empty( $found_unmigrated_action ) ) {
|
146 |
-
$this->migrate(
|
147 |
}
|
148 |
|
149 |
return $this->primary_store->find_action( $hook, $params );
|
@@ -154,12 +154,12 @@ class ActionScheduler_HybridStore extends Store {
|
|
154 |
* If any are found, migrate them immediately. Then the secondary
|
155 |
* store will contain the canonical results.
|
156 |
*
|
157 |
-
* @param array
|
158 |
* @param string $query_type Whether to select or count the results. Default, select.
|
159 |
*
|
160 |
* @return int[]
|
161 |
*/
|
162 |
-
public function query_actions( $query =
|
163 |
$found_unmigrated_actions = $this->secondary_store->query_actions( $query, 'select' );
|
164 |
if ( ! empty( $found_unmigrated_actions ) ) {
|
165 |
$this->migrate( $found_unmigrated_actions );
|
@@ -352,19 +352,19 @@ class ActionScheduler_HybridStore extends Store {
|
|
352 |
*/
|
353 |
protected function get_store_from_action_id( $action_id, $primary_first = false ) {
|
354 |
if ( $primary_first ) {
|
355 |
-
$stores =
|
356 |
$this->primary_store,
|
357 |
$this->secondary_store,
|
358 |
-
|
359 |
} elseif ( $action_id < $this->demarkation_id ) {
|
360 |
-
$stores =
|
361 |
$this->secondary_store,
|
362 |
$this->primary_store,
|
363 |
-
|
364 |
} else {
|
365 |
-
$stores =
|
366 |
$this->primary_store,
|
367 |
-
|
368 |
}
|
369 |
|
370 |
foreach ( $stores as $store ) {
|
@@ -376,8 +376,7 @@ class ActionScheduler_HybridStore extends Store {
|
|
376 |
return null;
|
377 |
}
|
378 |
|
379 |
-
/*
|
380 |
-
* * * * * * * * * * * * * * * * * * * * * * * * * *
|
381 |
* All claim-related functions should operate solely
|
382 |
* on the primary store.
|
383 |
* * * * * * * * * * * * * * * * * * * * * * * * * * */
|
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 |
/**
|
78 |
/** @var \wpdb $wpdb */
|
79 |
global $wpdb;
|
80 |
/**
|
81 |
+
* A default date of '0000-00-00 00:00:00' is invalid in MySQL 5.7 when configured with
|
82 |
* sql_mode including both STRICT_TRANS_TABLES and NO_ZERO_DATE.
|
83 |
*/
|
84 |
$default_date = new DateTime( 'tomorrow' );
|
88 |
|
89 |
$row_count = $wpdb->insert(
|
90 |
$wpdb->{ActionScheduler_StoreSchema::ACTIONS_TABLE},
|
91 |
+
[
|
92 |
'action_id' => $this->demarkation_id,
|
93 |
'hook' => '',
|
94 |
'status' => '',
|
96 |
'scheduled_date_local' => $date_local,
|
97 |
'last_attempt_gmt' => $date_gmt,
|
98 |
'last_attempt_local' => $date_local,
|
99 |
+
]
|
100 |
);
|
101 |
if ( $row_count > 0 ) {
|
102 |
$wpdb->delete(
|
103 |
$wpdb->{ActionScheduler_StoreSchema::ACTIONS_TABLE},
|
104 |
+
[ 'action_id' => $this->demarkation_id ]
|
105 |
);
|
106 |
}
|
107 |
}
|
140 |
*
|
141 |
* @return string
|
142 |
*/
|
143 |
+
public function find_action( $hook, $params = [] ) {
|
144 |
$found_unmigrated_action = $this->secondary_store->find_action( $hook, $params );
|
145 |
if ( ! empty( $found_unmigrated_action ) ) {
|
146 |
+
$this->migrate( [ $found_unmigrated_action ] );
|
147 |
}
|
148 |
|
149 |
return $this->primary_store->find_action( $hook, $params );
|
154 |
* If any are found, migrate them immediately. Then the secondary
|
155 |
* store will contain the canonical results.
|
156 |
*
|
157 |
+
* @param array $query
|
158 |
* @param string $query_type Whether to select or count the results. Default, select.
|
159 |
*
|
160 |
* @return int[]
|
161 |
*/
|
162 |
+
public function query_actions( $query = [], $query_type = 'select' ) {
|
163 |
$found_unmigrated_actions = $this->secondary_store->query_actions( $query, 'select' );
|
164 |
if ( ! empty( $found_unmigrated_actions ) ) {
|
165 |
$this->migrate( $found_unmigrated_actions );
|
352 |
*/
|
353 |
protected function get_store_from_action_id( $action_id, $primary_first = false ) {
|
354 |
if ( $primary_first ) {
|
355 |
+
$stores = [
|
356 |
$this->primary_store,
|
357 |
$this->secondary_store,
|
358 |
+
];
|
359 |
} elseif ( $action_id < $this->demarkation_id ) {
|
360 |
+
$stores = [
|
361 |
$this->secondary_store,
|
362 |
$this->primary_store,
|
363 |
+
];
|
364 |
} else {
|
365 |
+
$stores = [
|
366 |
$this->primary_store,
|
367 |
+
];
|
368 |
}
|
369 |
|
370 |
foreach ( $stores as $store ) {
|
376 |
return null;
|
377 |
}
|
378 |
|
379 |
+
/* * * * * * * * * * * * * * * * * * * * * * * * * * *
|
|
|
380 |
* All claim-related functions should operate solely
|
381 |
* on the primary store.
|
382 |
* * * * * * * * * * * * * * * * * * * * * * * * * * */
|
lite/includes/libraries/action-scheduler/classes/data-stores/ActionScheduler_wpCommentLogger.php
CHANGED
@@ -5,17 +5,17 @@
|
|
5 |
*/
|
6 |
class ActionScheduler_wpCommentLogger extends ActionScheduler_Logger {
|
7 |
const AGENT = 'ActionScheduler';
|
8 |
-
const TYPE
|
9 |
|
10 |
/**
|
11 |
-
* @param string
|
12 |
-
* @param string
|
13 |
* @param DateTime $date
|
14 |
*
|
15 |
* @return string The log entry ID
|
16 |
*/
|
17 |
-
public function log( $action_id, $message, DateTime $date =
|
18 |
-
if ( empty(
|
19 |
$date = as_get_datetime_object();
|
20 |
} else {
|
21 |
$date = as_get_datetime_object( clone $date );
|
@@ -26,18 +26,18 @@ class ActionScheduler_wpCommentLogger extends ActionScheduler_Logger {
|
|
26 |
|
27 |
protected function create_wp_comment( $action_id, $message, DateTime $date ) {
|
28 |
|
29 |
-
$comment_date_gmt = $date->format(
|
30 |
ActionScheduler_TimezoneHelper::set_local_timezone( $date );
|
31 |
$comment_data = array(
|
32 |
-
'comment_post_ID'
|
33 |
-
'comment_date'
|
34 |
'comment_date_gmt' => $comment_date_gmt,
|
35 |
-
'comment_author'
|
36 |
-
'comment_content'
|
37 |
-
'comment_agent'
|
38 |
-
'comment_type'
|
39 |
);
|
40 |
-
return wp_insert_comment(
|
41 |
}
|
42 |
|
43 |
/**
|
@@ -47,7 +47,7 @@ class ActionScheduler_wpCommentLogger extends ActionScheduler_Logger {
|
|
47 |
*/
|
48 |
public function get_entry( $entry_id ) {
|
49 |
$comment = $this->get_comment( $entry_id );
|
50 |
-
if ( empty(
|
51 |
return new ActionScheduler_NullLogEntry();
|
52 |
}
|
53 |
|
@@ -63,22 +63,20 @@ class ActionScheduler_wpCommentLogger extends ActionScheduler_Logger {
|
|
63 |
*/
|
64 |
public function get_logs( $action_id ) {
|
65 |
$status = 'all';
|
66 |
-
if ( get_post_status(
|
67 |
$status = 'post-trashed';
|
68 |
}
|
69 |
-
$comments = get_comments(
|
70 |
-
|
71 |
-
|
72 |
-
|
73 |
-
|
74 |
-
|
75 |
-
|
76 |
-
|
77 |
-
);
|
78 |
-
$logs = array();
|
79 |
foreach ( $comments as $c ) {
|
80 |
$entry = $this->get_entry( $c );
|
81 |
-
if ( !
|
82 |
$logs[] = $entry;
|
83 |
}
|
84 |
}
|
@@ -95,23 +93,23 @@ class ActionScheduler_wpCommentLogger extends ActionScheduler_Logger {
|
|
95 |
* @param WP_Comment_Query $query
|
96 |
*/
|
97 |
public function filter_comment_queries( $query ) {
|
98 |
-
foreach ( array(
|
99 |
-
if ( !
|
100 |
return; // don't slow down queries that wouldn't include action_log comments anyway
|
101 |
}
|
102 |
}
|
103 |
-
$query->query_vars['action_log_filter'] =
|
104 |
add_filter( 'comments_clauses', array( $this, 'filter_comment_query_clauses' ), 10, 2 );
|
105 |
}
|
106 |
|
107 |
/**
|
108 |
-
* @param array
|
109 |
* @param WP_Comment_Query $query
|
110 |
*
|
111 |
* @return array
|
112 |
*/
|
113 |
public function filter_comment_query_clauses( $clauses, $query ) {
|
114 |
-
if ( !
|
115 |
$clauses['where'] .= $this->get_where_clause();
|
116 |
}
|
117 |
return $clauses;
|
@@ -121,7 +119,7 @@ class ActionScheduler_wpCommentLogger extends ActionScheduler_Logger {
|
|
121 |
* Make sure Action Scheduler logs are excluded from comment feeds, which use WP_Query, not
|
122 |
* the WP_Comment_Query class handled by @see self::filter_comment_queries().
|
123 |
*
|
124 |
-
* @param string
|
125 |
* @param WP_Query $query
|
126 |
*
|
127 |
* @return string
|
@@ -147,7 +145,7 @@ class ActionScheduler_wpCommentLogger extends ActionScheduler_Logger {
|
|
147 |
* Remove action log entries from wp_count_comments()
|
148 |
*
|
149 |
* @param array $stats
|
150 |
-
* @param int
|
151 |
*
|
152 |
* @return object
|
153 |
*/
|
@@ -176,15 +174,9 @@ class ActionScheduler_wpCommentLogger extends ActionScheduler_Logger {
|
|
176 |
|
177 |
$count = $wpdb->get_results( "SELECT comment_approved, COUNT( * ) AS num_comments FROM {$wpdb->comments} WHERE comment_type NOT IN('order_note','action_log') GROUP BY comment_approved", ARRAY_A );
|
178 |
|
179 |
-
$total
|
180 |
-
$stats
|
181 |
-
$approved = array(
|
182 |
-
'0' => 'moderated',
|
183 |
-
'1' => 'approved',
|
184 |
-
'spam' => 'spam',
|
185 |
-
'trash' => 'trash',
|
186 |
-
'post-trashed' => 'post-trashed',
|
187 |
-
);
|
188 |
|
189 |
foreach ( (array) $count as $row ) {
|
190 |
// Don't count post-trashed toward totals
|
@@ -239,10 +231,10 @@ class ActionScheduler_wpCommentLogger extends ActionScheduler_Logger {
|
|
239 |
}
|
240 |
|
241 |
public function disable_comment_counting() {
|
242 |
-
wp_defer_comment_counting(
|
243 |
}
|
244 |
public function enable_comment_counting() {
|
245 |
-
wp_defer_comment_counting(
|
246 |
}
|
247 |
|
248 |
}
|
5 |
*/
|
6 |
class ActionScheduler_wpCommentLogger extends ActionScheduler_Logger {
|
7 |
const AGENT = 'ActionScheduler';
|
8 |
+
const TYPE = 'action_log';
|
9 |
|
10 |
/**
|
11 |
+
* @param string $action_id
|
12 |
+
* @param string $message
|
13 |
* @param DateTime $date
|
14 |
*
|
15 |
* @return string The log entry ID
|
16 |
*/
|
17 |
+
public function log( $action_id, $message, DateTime $date = NULL ) {
|
18 |
+
if ( empty($date) ) {
|
19 |
$date = as_get_datetime_object();
|
20 |
} else {
|
21 |
$date = as_get_datetime_object( clone $date );
|
26 |
|
27 |
protected function create_wp_comment( $action_id, $message, DateTime $date ) {
|
28 |
|
29 |
+
$comment_date_gmt = $date->format('Y-m-d H:i:s');
|
30 |
ActionScheduler_TimezoneHelper::set_local_timezone( $date );
|
31 |
$comment_data = array(
|
32 |
+
'comment_post_ID' => $action_id,
|
33 |
+
'comment_date' => $date->format('Y-m-d H:i:s'),
|
34 |
'comment_date_gmt' => $comment_date_gmt,
|
35 |
+
'comment_author' => self::AGENT,
|
36 |
+
'comment_content' => $message,
|
37 |
+
'comment_agent' => self::AGENT,
|
38 |
+
'comment_type' => self::TYPE,
|
39 |
);
|
40 |
+
return wp_insert_comment($comment_data);
|
41 |
}
|
42 |
|
43 |
/**
|
47 |
*/
|
48 |
public function get_entry( $entry_id ) {
|
49 |
$comment = $this->get_comment( $entry_id );
|
50 |
+
if ( empty($comment) || $comment->comment_type != self::TYPE ) {
|
51 |
return new ActionScheduler_NullLogEntry();
|
52 |
}
|
53 |
|
63 |
*/
|
64 |
public function get_logs( $action_id ) {
|
65 |
$status = 'all';
|
66 |
+
if ( get_post_status($action_id) == 'trash' ) {
|
67 |
$status = 'post-trashed';
|
68 |
}
|
69 |
+
$comments = get_comments(array(
|
70 |
+
'post_id' => $action_id,
|
71 |
+
'orderby' => 'comment_date_gmt',
|
72 |
+
'order' => 'ASC',
|
73 |
+
'type' => self::TYPE,
|
74 |
+
'status' => $status,
|
75 |
+
));
|
76 |
+
$logs = array();
|
|
|
|
|
77 |
foreach ( $comments as $c ) {
|
78 |
$entry = $this->get_entry( $c );
|
79 |
+
if ( !empty($entry) ) {
|
80 |
$logs[] = $entry;
|
81 |
}
|
82 |
}
|
93 |
* @param WP_Comment_Query $query
|
94 |
*/
|
95 |
public function filter_comment_queries( $query ) {
|
96 |
+
foreach ( array('ID', 'parent', 'post_author', 'post_name', 'post_parent', 'type', 'post_type', 'post_id', 'post_ID') as $key ) {
|
97 |
+
if ( !empty($query->query_vars[$key]) ) {
|
98 |
return; // don't slow down queries that wouldn't include action_log comments anyway
|
99 |
}
|
100 |
}
|
101 |
+
$query->query_vars['action_log_filter'] = TRUE;
|
102 |
add_filter( 'comments_clauses', array( $this, 'filter_comment_query_clauses' ), 10, 2 );
|
103 |
}
|
104 |
|
105 |
/**
|
106 |
+
* @param array $clauses
|
107 |
* @param WP_Comment_Query $query
|
108 |
*
|
109 |
* @return array
|
110 |
*/
|
111 |
public function filter_comment_query_clauses( $clauses, $query ) {
|
112 |
+
if ( !empty($query->query_vars['action_log_filter']) ) {
|
113 |
$clauses['where'] .= $this->get_where_clause();
|
114 |
}
|
115 |
return $clauses;
|
119 |
* Make sure Action Scheduler logs are excluded from comment feeds, which use WP_Query, not
|
120 |
* the WP_Comment_Query class handled by @see self::filter_comment_queries().
|
121 |
*
|
122 |
+
* @param string $where
|
123 |
* @param WP_Query $query
|
124 |
*
|
125 |
* @return string
|
145 |
* Remove action log entries from wp_count_comments()
|
146 |
*
|
147 |
* @param array $stats
|
148 |
+
* @param int $post_id
|
149 |
*
|
150 |
* @return object
|
151 |
*/
|
174 |
|
175 |
$count = $wpdb->get_results( "SELECT comment_approved, COUNT( * ) AS num_comments FROM {$wpdb->comments} WHERE comment_type NOT IN('order_note','action_log') GROUP BY comment_approved", ARRAY_A );
|
176 |
|
177 |
+
$total = 0;
|
178 |
+
$stats = array();
|
179 |
+
$approved = array( '0' => 'moderated', '1' => 'approved', 'spam' => 'spam', 'trash' => 'trash', 'post-trashed' => 'post-trashed' );
|
|
|
|
|
|
|
|
|
|
|
|
|
180 |
|
181 |
foreach ( (array) $count as $row ) {
|
182 |
// Don't count post-trashed toward totals
|
231 |
}
|
232 |
|
233 |
public function disable_comment_counting() {
|
234 |
+
wp_defer_comment_counting(true);
|
235 |
}
|
236 |
public function enable_comment_counting() {
|
237 |
+
wp_defer_comment_counting(false);
|
238 |
}
|
239 |
|
240 |
}
|
lite/includes/libraries/action-scheduler/classes/data-stores/ActionScheduler_wpPostStore.php
CHANGED
@@ -9,9 +9,32 @@ class ActionScheduler_wpPostStore extends ActionScheduler_Store {
|
|
9 |
const SCHEDULE_META_KEY = '_action_manager_schedule';
|
10 |
const DEPENDENCIES_MET = 'as-post-store-dependencies-met';
|
11 |
|
12 |
-
/**
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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 );
|
@@ -22,15 +45,24 @@ class ActionScheduler_wpPostStore extends ActionScheduler_Store {
|
|
22 |
do_action( 'action_scheduler_stored_action', $post_id );
|
23 |
return $post_id;
|
24 |
} catch ( Exception $e ) {
|
|
|
25 |
throw new RuntimeException( sprintf( __( 'Error saving action: %s', 'action-scheduler' ), $e->getMessage() ), 0 );
|
26 |
}
|
27 |
}
|
28 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
29 |
protected function create_post_array( ActionScheduler_Action $action, DateTime $scheduled_date = null ) {
|
30 |
$post = array(
|
31 |
'post_type' => self::POST_TYPE,
|
32 |
'post_title' => $action->get_hook(),
|
33 |
-
'post_content' =>
|
34 |
'post_status' => ( $action->is_finished() ? 'publish' : 'pending' ),
|
35 |
'post_date_gmt' => $this->get_scheduled_date_string( $action, $scheduled_date ),
|
36 |
'post_date' => $this->get_scheduled_date_string_local( $action, $scheduled_date ),
|
@@ -38,6 +70,13 @@ class ActionScheduler_wpPostStore extends ActionScheduler_Store {
|
|
38 |
return $post;
|
39 |
}
|
40 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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 );
|
@@ -64,10 +103,17 @@ class ActionScheduler_wpPostStore extends ActionScheduler_Store {
|
|
64 |
return $post_id;
|
65 |
}
|
66 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
67 |
public function filter_insert_post_data( $postdata ) {
|
68 |
-
if ( $postdata['post_type']
|
69 |
$postdata['post_author'] = 0;
|
70 |
-
if ( $postdata['post_status']
|
71 |
$postdata['post_status'] = 'publish';
|
72 |
}
|
73 |
}
|
@@ -103,16 +149,31 @@ class ActionScheduler_wpPostStore extends ActionScheduler_Store {
|
|
103 |
* @return string
|
104 |
*/
|
105 |
public function set_unique_post_slug( $override_slug, $slug, $post_ID, $post_status, $post_type ) {
|
106 |
-
if ( self::POST_TYPE
|
107 |
$override_slug = uniqid( self::POST_TYPE . '-', true ) . '-' . wp_generate_password( 32, false );
|
108 |
}
|
109 |
return $override_slug;
|
110 |
}
|
111 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
112 |
protected function save_post_schedule( $post_id, $schedule ) {
|
113 |
update_post_meta( $post_id, self::SCHEDULE_META_KEY, $schedule );
|
114 |
}
|
115 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
116 |
protected function save_action_group( $post_id, $group ) {
|
117 |
if ( empty( $group ) ) {
|
118 |
wp_set_object_terms( $post_id, array(), self::GROUP_TAXONOMY, false );
|
@@ -121,9 +182,15 @@ class ActionScheduler_wpPostStore extends ActionScheduler_Store {
|
|
121 |
}
|
122 |
}
|
123 |
|
|
|
|
|
|
|
|
|
|
|
|
|
124 |
public function fetch_action( $action_id ) {
|
125 |
$post = $this->get_post( $action_id );
|
126 |
-
if ( empty( $post ) || $post->post_type
|
127 |
return $this->get_null_action();
|
128 |
}
|
129 |
|
@@ -137,6 +204,12 @@ class ActionScheduler_wpPostStore extends ActionScheduler_Store {
|
|
137 |
return $action;
|
138 |
}
|
139 |
|
|
|
|
|
|
|
|
|
|
|
|
|
140 |
protected function get_post( $action_id ) {
|
141 |
if ( empty( $action_id ) ) {
|
142 |
return null;
|
@@ -144,10 +217,21 @@ class ActionScheduler_wpPostStore extends ActionScheduler_Store {
|
|
144 |
return get_post( $action_id );
|
145 |
}
|
146 |
|
|
|
|
|
|
|
|
|
|
|
147 |
protected function get_null_action() {
|
148 |
return new ActionScheduler_NullAction();
|
149 |
}
|
150 |
|
|
|
|
|
|
|
|
|
|
|
|
|
151 |
protected function make_action_from_post( $post ) {
|
152 |
$hook = $post->post_title;
|
153 |
|
@@ -164,9 +248,11 @@ class ActionScheduler_wpPostStore extends ActionScheduler_Store {
|
|
164 |
}
|
165 |
|
166 |
/**
|
167 |
-
*
|
|
|
|
|
168 |
*
|
169 |
-
* @throws InvalidArgumentException if $post_status not in known status fields returned by $this->get_status_labels()
|
170 |
* @return string
|
171 |
*/
|
172 |
protected function get_action_status_by_post_status( $post_status ) {
|
@@ -190,8 +276,11 @@ class ActionScheduler_wpPostStore extends ActionScheduler_Store {
|
|
190 |
}
|
191 |
|
192 |
/**
|
193 |
-
*
|
194 |
-
*
|
|
|
|
|
|
|
195 |
* @return string
|
196 |
*/
|
197 |
protected function get_post_status_by_action_status( $action_status ) {
|
@@ -214,75 +303,18 @@ class ActionScheduler_wpPostStore extends ActionScheduler_Store {
|
|
214 |
return $post_status;
|
215 |
}
|
216 |
|
217 |
-
/**
|
218 |
-
* @param string $hook
|
219 |
-
* @param array $params
|
220 |
-
*
|
221 |
-
* @return string ID of the next action matching the criteria or NULL if not found
|
222 |
-
*/
|
223 |
-
public function find_action( $hook, $params = array() ) {
|
224 |
-
$params = wp_parse_args(
|
225 |
-
$params,
|
226 |
-
array(
|
227 |
-
'args' => null,
|
228 |
-
'status' => ActionScheduler_Store::STATUS_PENDING,
|
229 |
-
'group' => '',
|
230 |
-
)
|
231 |
-
);
|
232 |
-
/** @var wpdb $wpdb */
|
233 |
-
global $wpdb;
|
234 |
-
$query = "SELECT p.ID FROM {$wpdb->posts} p";
|
235 |
-
$args = array();
|
236 |
-
if ( ! empty( $params['group'] ) ) {
|
237 |
-
$query .= " INNER JOIN {$wpdb->term_relationships} tr ON tr.object_id=p.ID";
|
238 |
-
$query .= " INNER JOIN {$wpdb->term_taxonomy} tt ON tr.term_taxonomy_id=tt.term_taxonomy_id";
|
239 |
-
$query .= " INNER JOIN {$wpdb->terms} t ON tt.term_id=t.term_id AND t.slug=%s";
|
240 |
-
$args[] = $params['group'];
|
241 |
-
}
|
242 |
-
$query .= ' WHERE p.post_title=%s';
|
243 |
-
$args[] = $hook;
|
244 |
-
$query .= ' AND p.post_type=%s';
|
245 |
-
$args[] = self::POST_TYPE;
|
246 |
-
if ( ! is_null( $params['args'] ) ) {
|
247 |
-
$query .= ' AND p.post_content=%s';
|
248 |
-
$args[] = json_encode( $params['args'] );
|
249 |
-
}
|
250 |
-
|
251 |
-
if ( ! empty( $params['status'] ) ) {
|
252 |
-
$query .= ' AND p.post_status=%s';
|
253 |
-
$args[] = $this->get_post_status_by_action_status( $params['status'] );
|
254 |
-
}
|
255 |
-
|
256 |
-
switch ( $params['status'] ) {
|
257 |
-
case self::STATUS_COMPLETE:
|
258 |
-
case self::STATUS_RUNNING:
|
259 |
-
case self::STATUS_FAILED:
|
260 |
-
$order = 'DESC'; // Find the most recent action that matches
|
261 |
-
break;
|
262 |
-
case self::STATUS_PENDING:
|
263 |
-
default:
|
264 |
-
$order = 'ASC'; // Find the next action that matches
|
265 |
-
break;
|
266 |
-
}
|
267 |
-
$query .= " ORDER BY post_date_gmt $order LIMIT 1";
|
268 |
-
|
269 |
-
$query = $wpdb->prepare( $query, $args );
|
270 |
-
|
271 |
-
$id = $wpdb->get_var( $query );
|
272 |
-
return $id;
|
273 |
-
}
|
274 |
-
|
275 |
/**
|
276 |
* Returns the SQL statement to query (or count) actions.
|
277 |
*
|
278 |
-
* @param array $query Filtering options
|
279 |
-
* @param string $select_or_count Whether the SQL should select and return the IDs or just the row count
|
280 |
-
*
|
|
|
281 |
* @return string SQL statement. The returned SQL is already properly escaped.
|
282 |
*/
|
283 |
protected function get_query_actions_sql( array $query, $select_or_count = 'select' ) {
|
284 |
|
285 |
-
if ( ! in_array( $select_or_count, array( 'select', 'count' ) ) ) {
|
286 |
throw new InvalidArgumentException( __( 'Invalid schedule. Cannot save action.', 'action-scheduler' ) );
|
287 |
}
|
288 |
|
@@ -306,7 +338,11 @@ class ActionScheduler_wpPostStore extends ActionScheduler_Store {
|
|
306 |
)
|
307 |
);
|
308 |
|
309 |
-
/**
|
|
|
|
|
|
|
|
|
310 |
global $wpdb;
|
311 |
$sql = ( 'count' === $select_or_count ) ? 'SELECT count(p.ID)' : 'SELECT p.ID ';
|
312 |
$sql .= "FROM {$wpdb->posts} p";
|
@@ -330,12 +366,14 @@ class ActionScheduler_wpPostStore extends ActionScheduler_Store {
|
|
330 |
}
|
331 |
if ( ! is_null( $query['args'] ) ) {
|
332 |
$sql .= ' AND p.post_content=%s';
|
333 |
-
$sql_params[] =
|
334 |
}
|
335 |
|
336 |
-
if (
|
337 |
-
$
|
338 |
-
$
|
|
|
|
|
339 |
}
|
340 |
|
341 |
if ( $query['date'] instanceof DateTime ) {
|
@@ -356,9 +394,9 @@ class ActionScheduler_wpPostStore extends ActionScheduler_Store {
|
|
356 |
$sql_params[] = $date_string;
|
357 |
}
|
358 |
|
359 |
-
if ( $query['claimed']
|
360 |
$sql .= " AND p.post_password != ''";
|
361 |
-
} elseif ( $query['claimed']
|
362 |
$sql .= " AND p.post_password = ''";
|
363 |
} elseif ( ! is_null( $query['claimed'] ) ) {
|
364 |
$sql .= ' AND p.post_password = %s';
|
@@ -408,21 +446,32 @@ class ActionScheduler_wpPostStore extends ActionScheduler_Store {
|
|
408 |
}
|
409 |
}
|
410 |
|
411 |
-
return $wpdb->prepare( $sql, $sql_params );
|
412 |
}
|
413 |
|
414 |
/**
|
415 |
-
*
|
416 |
-
*
|
417 |
-
* @
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
418 |
*/
|
419 |
public function query_actions( $query = array(), $query_type = 'select' ) {
|
420 |
-
/**
|
|
|
|
|
|
|
|
|
421 |
global $wpdb;
|
422 |
|
423 |
$sql = $this->get_query_actions_sql( $query, $query_type );
|
424 |
|
425 |
-
return ( 'count' === $query_type ) ? $wpdb->get_var( $sql ) : $wpdb->get_col( $sql );
|
426 |
}
|
427 |
|
428 |
/**
|
@@ -441,7 +490,7 @@ class ActionScheduler_wpPostStore extends ActionScheduler_Store {
|
|
441 |
try {
|
442 |
$action_status_name = $this->get_action_status_by_post_status( $post_status_name );
|
443 |
} catch ( Exception $e ) {
|
444 |
-
// Ignore any post statuses that aren't for actions
|
445 |
continue;
|
446 |
}
|
447 |
if ( array_key_exists( $action_status_name, $action_stati_and_labels ) ) {
|
@@ -453,13 +502,16 @@ class ActionScheduler_wpPostStore extends ActionScheduler_Store {
|
|
453 |
}
|
454 |
|
455 |
/**
|
456 |
-
*
|
457 |
*
|
458 |
-
* @
|
|
|
|
|
459 |
*/
|
460 |
public function cancel_action( $action_id ) {
|
461 |
$post = get_post( $action_id );
|
462 |
-
if ( empty( $post ) || ( $post->post_type
|
|
|
463 |
throw new InvalidArgumentException( sprintf( __( 'Unidentified action %s', 'action-scheduler' ), $action_id ) );
|
464 |
}
|
465 |
do_action( 'action_scheduler_canceled_action', $action_id );
|
@@ -468,9 +520,17 @@ class ActionScheduler_wpPostStore extends ActionScheduler_Store {
|
|
468 |
remove_filter( 'pre_wp_unique_post_slug', array( $this, 'set_unique_post_slug' ), 10 );
|
469 |
}
|
470 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
471 |
public function delete_action( $action_id ) {
|
472 |
$post = get_post( $action_id );
|
473 |
-
if ( empty( $post ) || ( $post->post_type
|
|
|
474 |
throw new InvalidArgumentException( sprintf( __( 'Unidentified action %s', 'action-scheduler' ), $action_id ) );
|
475 |
}
|
476 |
do_action( 'action_scheduler_deleted_action', $action_id );
|
@@ -479,9 +539,9 @@ class ActionScheduler_wpPostStore extends ActionScheduler_Store {
|
|
479 |
}
|
480 |
|
481 |
/**
|
482 |
-
*
|
483 |
*
|
484 |
-
* @
|
485 |
* @return ActionScheduler_DateTime The date the action is schedule to run, or the date that it ran.
|
486 |
*/
|
487 |
public function get_date( $action_id ) {
|
@@ -490,17 +550,20 @@ class ActionScheduler_wpPostStore extends ActionScheduler_Store {
|
|
490 |
}
|
491 |
|
492 |
/**
|
493 |
-
*
|
494 |
*
|
495 |
-
* @
|
|
|
|
|
496 |
* @return ActionScheduler_DateTime The date the action is schedule to run, or the date that it ran.
|
497 |
*/
|
498 |
public function get_date_gmt( $action_id ) {
|
499 |
$post = get_post( $action_id );
|
500 |
-
if ( empty( $post ) || ( $post->post_type
|
|
|
501 |
throw new InvalidArgumentException( sprintf( __( 'Unidentified action %s', 'action-scheduler' ), $action_id ) );
|
502 |
}
|
503 |
-
if ( $post->post_status
|
504 |
return as_get_datetime_object( $post->post_modified_gmt );
|
505 |
} else {
|
506 |
return as_get_datetime_object( $post->post_date_gmt );
|
@@ -508,7 +571,9 @@ class ActionScheduler_wpPostStore extends ActionScheduler_Store {
|
|
508 |
}
|
509 |
|
510 |
/**
|
511 |
-
*
|
|
|
|
|
512 |
* @param DateTime $before_date Jobs must be schedule before this date. Defaults to now.
|
513 |
* @param array $hooks Claim only actions with a hook or hooks.
|
514 |
* @param string $group Claim only actions in the given group.
|
@@ -518,40 +583,53 @@ class ActionScheduler_wpPostStore extends ActionScheduler_Store {
|
|
518 |
* @throws InvalidArgumentException When the given group is not valid.
|
519 |
*/
|
520 |
public function stake_claim( $max_actions = 10, DateTime $before_date = null, $hooks = array(), $group = '' ) {
|
521 |
-
$
|
|
|
522 |
$this->claim_actions( $claim_id, $max_actions, $before_date, $hooks, $group );
|
523 |
-
$action_ids
|
|
|
524 |
|
525 |
return new ActionScheduler_ActionClaim( $claim_id, $action_ids );
|
526 |
}
|
527 |
|
528 |
/**
|
|
|
|
|
529 |
* @return int
|
530 |
*/
|
531 |
public function get_claim_count() {
|
532 |
global $wpdb;
|
533 |
|
534 |
-
|
535 |
-
|
536 |
-
|
537 |
-
|
|
|
|
|
|
|
538 |
}
|
539 |
|
|
|
|
|
|
|
|
|
|
|
540 |
protected function generate_claim_id() {
|
541 |
-
$claim_id = md5( microtime( true ) .
|
542 |
-
return substr( $claim_id, 0, 20 ); // to fit in db field with 20 char limit
|
543 |
}
|
544 |
|
545 |
/**
|
546 |
-
*
|
547 |
-
*
|
|
|
|
|
548 |
* @param DateTime $before_date Should use UTC timezone.
|
549 |
* @param array $hooks Claim only actions with a hook or hooks.
|
550 |
* @param string $group Claim only actions in the given group.
|
551 |
*
|
552 |
-
* @return int The number of actions that were claimed
|
553 |
-
* @throws RuntimeException
|
554 |
-
* @throws InvalidArgumentException When the group is invalid.
|
555 |
*/
|
556 |
protected function claim_actions( $claim_id, $limit, DateTime $before_date = null, $hooks = array(), $group = '' ) {
|
557 |
// Set up initial variables.
|
@@ -564,7 +642,11 @@ class ActionScheduler_wpPostStore extends ActionScheduler_Store {
|
|
564 |
return 0;
|
565 |
}
|
566 |
|
567 |
-
/**
|
|
|
|
|
|
|
|
|
568 |
global $wpdb;
|
569 |
|
570 |
/*
|
@@ -608,8 +690,9 @@ class ActionScheduler_wpPostStore extends ActionScheduler_Store {
|
|
608 |
$params[] = $limit;
|
609 |
|
610 |
// Run the query and gather results.
|
611 |
-
$rows_affected = $wpdb->query( $wpdb->prepare( "{$update} {$where} {$order}", $params ) );
|
612 |
-
|
|
|
613 |
throw new RuntimeException( __( 'Unable to claim actions. Database error.', 'action-scheduler' ) );
|
614 |
}
|
615 |
|
@@ -630,6 +713,7 @@ class ActionScheduler_wpPostStore extends ActionScheduler_Store {
|
|
630 |
protected function get_actions_by_group( $group, $limit, DateTime $date ) {
|
631 |
// Ensure the group exists before continuing.
|
632 |
if ( ! term_exists( $group, self::GROUP_TAXONOMY ) ) {
|
|
|
633 |
throw new InvalidArgumentException( sprintf( __( 'The group "%s" does not exist.', 'action-scheduler' ), $group ) );
|
634 |
}
|
635 |
|
@@ -653,7 +737,7 @@ class ActionScheduler_wpPostStore extends ActionScheduler_Store {
|
|
653 |
'before' => $date->format( 'Y-m-d H:i' ),
|
654 |
'inclusive' => true,
|
655 |
),
|
656 |
-
'tax_query' => array(
|
657 |
array(
|
658 |
'taxonomy' => self::GROUP_TAXONOMY,
|
659 |
'field' => 'slug',
|
@@ -667,57 +751,129 @@ class ActionScheduler_wpPostStore extends ActionScheduler_Store {
|
|
667 |
}
|
668 |
|
669 |
/**
|
670 |
-
*
|
|
|
|
|
671 |
* @return array
|
672 |
*/
|
673 |
public function find_actions_by_claim_id( $claim_id ) {
|
674 |
-
/**
|
|
|
|
|
|
|
|
|
675 |
global $wpdb;
|
676 |
-
|
677 |
-
$
|
678 |
-
$
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
679 |
return $action_ids;
|
680 |
}
|
681 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
682 |
public function release_claim( ActionScheduler_ActionClaim $claim ) {
|
683 |
$action_ids = $this->find_actions_by_claim_id( $claim->get_id() );
|
684 |
if ( empty( $action_ids ) ) {
|
685 |
-
return; // nothing to do
|
686 |
}
|
687 |
$action_id_string = implode( ',', array_map( 'intval', $action_ids ) );
|
688 |
-
/**
|
|
|
|
|
|
|
|
|
689 |
global $wpdb;
|
690 |
-
|
691 |
-
|
692 |
-
$result = $wpdb->query(
|
693 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
694 |
/* translators: %s: claim ID */
|
695 |
throw new RuntimeException( sprintf( __( 'Unable to unlock claim %s. Database error.', 'action-scheduler' ), $claim->get_id() ) );
|
696 |
}
|
697 |
}
|
698 |
|
699 |
/**
|
700 |
-
*
|
|
|
|
|
|
|
701 |
*/
|
702 |
public function unclaim_action( $action_id ) {
|
703 |
-
/**
|
|
|
|
|
|
|
|
|
704 |
global $wpdb;
|
705 |
-
|
706 |
-
|
707 |
-
$result = $wpdb->query(
|
708 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
709 |
/* translators: %s: action ID */
|
710 |
throw new RuntimeException( sprintf( __( 'Unable to unlock claim on action %s. Database error.', 'action-scheduler' ), $action_id ) );
|
711 |
}
|
712 |
}
|
713 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
714 |
public function mark_failure( $action_id ) {
|
715 |
-
/**
|
|
|
|
|
|
|
|
|
716 |
global $wpdb;
|
717 |
-
|
718 |
-
|
719 |
-
$result = $wpdb->query(
|
720 |
-
|
|
|
|
|
721 |
/* translators: %s: action ID */
|
722 |
throw new RuntimeException( sprintf( __( 'Unable to mark failure on action %s. Database error.', 'action-scheduler' ), $action_id ) );
|
723 |
}
|
@@ -726,7 +882,7 @@ class ActionScheduler_wpPostStore extends ActionScheduler_Store {
|
|
726 |
/**
|
727 |
* Return an action's claim ID, as stored in the post password column
|
728 |
*
|
729 |
-
* @param
|
730 |
* @return mixed
|
731 |
*/
|
732 |
public function get_claim_id( $action_id ) {
|
@@ -736,46 +892,85 @@ class ActionScheduler_wpPostStore extends ActionScheduler_Store {
|
|
736 |
/**
|
737 |
* Return an action's status, as stored in the post status column
|
738 |
*
|
739 |
-
* @param
|
|
|
740 |
* @return mixed
|
|
|
741 |
*/
|
742 |
public function get_status( $action_id ) {
|
743 |
$status = $this->get_post_column( $action_id, 'post_status' );
|
744 |
|
745 |
-
if (
|
746 |
throw new InvalidArgumentException( __( 'Invalid action ID. No status found.', 'action-scheduler' ) );
|
747 |
}
|
748 |
|
749 |
return $this->get_action_status_by_post_status( $status );
|
750 |
}
|
751 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
752 |
private function get_post_column( $action_id, $column_name ) {
|
753 |
-
/**
|
|
|
|
|
|
|
|
|
754 |
global $wpdb;
|
755 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
756 |
}
|
757 |
|
758 |
/**
|
759 |
-
*
|
|
|
|
|
760 |
*/
|
761 |
public function log_execution( $action_id ) {
|
762 |
-
/**
|
|
|
|
|
|
|
|
|
763 |
global $wpdb;
|
764 |
|
765 |
-
|
766 |
-
$
|
767 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
768 |
}
|
769 |
|
770 |
/**
|
771 |
* Record that an action was completed.
|
772 |
*
|
773 |
-
* @param
|
774 |
-
*
|
|
|
|
|
775 |
*/
|
776 |
public function mark_complete( $action_id ) {
|
777 |
$post = get_post( $action_id );
|
778 |
-
if ( empty( $post ) || ( $post->post_type
|
|
|
779 |
throw new InvalidArgumentException( sprintf( __( 'Unidentified action %s', 'action-scheduler' ), $action_id ) );
|
780 |
}
|
781 |
add_filter( 'wp_insert_post_data', array( $this, 'filter_insert_post_data' ), 10, 1 );
|
@@ -811,6 +1006,7 @@ class ActionScheduler_wpPostStore extends ActionScheduler_Store {
|
|
811 |
/**
|
812 |
* Determine whether the post store can be migrated.
|
813 |
*
|
|
|
814 |
* @return bool
|
815 |
*/
|
816 |
public function migration_dependencies_met( $setting ) {
|
@@ -819,7 +1015,7 @@ class ActionScheduler_wpPostStore extends ActionScheduler_Store {
|
|
819 |
$dependencies_met = get_transient( self::DEPENDENCIES_MET );
|
820 |
if ( empty( $dependencies_met ) ) {
|
821 |
$maximum_args_length = apply_filters( 'action_scheduler_maximum_args_length', 191 );
|
822 |
-
$found_action = $wpdb->get_var(
|
823 |
$wpdb->prepare(
|
824 |
"SELECT ID FROM {$wpdb->posts} WHERE post_type = %s AND CHAR_LENGTH(post_content) > %d LIMIT 1",
|
825 |
$maximum_args_length,
|
@@ -830,7 +1026,7 @@ class ActionScheduler_wpPostStore extends ActionScheduler_Store {
|
|
830 |
set_transient( self::DEPENDENCIES_MET, $dependencies_met, DAY_IN_SECONDS );
|
831 |
}
|
832 |
|
833 |
-
return 'yes'
|
834 |
}
|
835 |
|
836 |
/**
|
@@ -840,19 +1036,20 @@ class ActionScheduler_wpPostStore extends ActionScheduler_Store {
|
|
840 |
* as we prepare to move to custom tables, and can use an indexed VARCHAR column instead, we want to warn
|
841 |
* developers of this impending requirement.
|
842 |
*
|
843 |
-
* @param ActionScheduler_Action $action
|
844 |
*/
|
845 |
protected function validate_action( ActionScheduler_Action $action ) {
|
846 |
try {
|
847 |
parent::validate_action( $action );
|
848 |
} catch ( Exception $e ) {
|
|
|
849 |
$message = sprintf( __( '%s Support for strings longer than this will be removed in a future version.', 'action-scheduler' ), $e->getMessage() );
|
850 |
-
_doing_it_wrong( 'ActionScheduler_Action::$args', $message, '2.1.0' );
|
851 |
}
|
852 |
}
|
853 |
|
854 |
/**
|
855 |
-
* @codeCoverageIgnore
|
856 |
*/
|
857 |
public function init() {
|
858 |
add_filter( 'action_scheduler_migration_dependencies_met', array( $this, 'migration_dependencies_met' ) );
|
9 |
const SCHEDULE_META_KEY = '_action_manager_schedule';
|
10 |
const DEPENDENCIES_MET = 'as-post-store-dependencies-met';
|
11 |
|
12 |
+
/**
|
13 |
+
* Used to share information about the before_date property of claims internally.
|
14 |
+
*
|
15 |
+
* This is used in preference to passing the same information as a method param
|
16 |
+
* for backwards-compatibility reasons.
|
17 |
+
*
|
18 |
+
* @var DateTime|null
|
19 |
+
*/
|
20 |
+
private $claim_before_date = null;
|
21 |
+
|
22 |
+
/**
|
23 |
+
* Local Timezone.
|
24 |
+
*
|
25 |
+
* @var DateTimeZone
|
26 |
+
*/
|
27 |
protected $local_timezone = null;
|
28 |
|
29 |
+
/**
|
30 |
+
* Save action.
|
31 |
+
*
|
32 |
+
* @param ActionScheduler_Action $action Scheduled Action.
|
33 |
+
* @param DateTime $scheduled_date Scheduled Date.
|
34 |
+
*
|
35 |
+
* @throws RuntimeException Throws an exception if the action could not be saved.
|
36 |
+
* @return int
|
37 |
+
*/
|
38 |
public function save_action( ActionScheduler_Action $action, DateTime $scheduled_date = null ) {
|
39 |
try {
|
40 |
$this->validate_action( $action );
|
45 |
do_action( 'action_scheduler_stored_action', $post_id );
|
46 |
return $post_id;
|
47 |
} catch ( Exception $e ) {
|
48 |
+
/* translators: %s: action error message */
|
49 |
throw new RuntimeException( sprintf( __( 'Error saving action: %s', 'action-scheduler' ), $e->getMessage() ), 0 );
|
50 |
}
|
51 |
}
|
52 |
|
53 |
+
/**
|
54 |
+
* Create post array.
|
55 |
+
*
|
56 |
+
* @param ActionScheduler_Action $action Scheduled Action.
|
57 |
+
* @param DateTime $scheduled_date Scheduled Date.
|
58 |
+
*
|
59 |
+
* @return array Returns an array of post data.
|
60 |
+
*/
|
61 |
protected function create_post_array( ActionScheduler_Action $action, DateTime $scheduled_date = null ) {
|
62 |
$post = array(
|
63 |
'post_type' => self::POST_TYPE,
|
64 |
'post_title' => $action->get_hook(),
|
65 |
+
'post_content' => wp_json_encode( $action->get_args() ),
|
66 |
'post_status' => ( $action->is_finished() ? 'publish' : 'pending' ),
|
67 |
'post_date_gmt' => $this->get_scheduled_date_string( $action, $scheduled_date ),
|
68 |
'post_date' => $this->get_scheduled_date_string_local( $action, $scheduled_date ),
|
70 |
return $post;
|
71 |
}
|
72 |
|
73 |
+
/**
|
74 |
+
* Save post array.
|
75 |
+
*
|
76 |
+
* @param array $post_array Post array.
|
77 |
+
* @return int Returns the post ID.
|
78 |
+
* @throws RuntimeException Throws an exception if the action could not be saved.
|
79 |
+
*/
|
80 |
protected function save_post_array( $post_array ) {
|
81 |
add_filter( 'wp_insert_post_data', array( $this, 'filter_insert_post_data' ), 10, 1 );
|
82 |
add_filter( 'pre_wp_unique_post_slug', array( $this, 'set_unique_post_slug' ), 10, 5 );
|
103 |
return $post_id;
|
104 |
}
|
105 |
|
106 |
+
/**
|
107 |
+
* Filter insert post data.
|
108 |
+
*
|
109 |
+
* @param array $postdata Post data to filter.
|
110 |
+
*
|
111 |
+
* @return array
|
112 |
+
*/
|
113 |
public function filter_insert_post_data( $postdata ) {
|
114 |
+
if ( self::POST_TYPE === $postdata['post_type'] ) {
|
115 |
$postdata['post_author'] = 0;
|
116 |
+
if ( 'future' === $postdata['post_status'] ) {
|
117 |
$postdata['post_status'] = 'publish';
|
118 |
}
|
119 |
}
|
149 |
* @return string
|
150 |
*/
|
151 |
public function set_unique_post_slug( $override_slug, $slug, $post_ID, $post_status, $post_type ) {
|
152 |
+
if ( self::POST_TYPE === $post_type ) {
|
153 |
$override_slug = uniqid( self::POST_TYPE . '-', true ) . '-' . wp_generate_password( 32, false );
|
154 |
}
|
155 |
return $override_slug;
|
156 |
}
|
157 |
|
158 |
+
/**
|
159 |
+
* Save post schedule.
|
160 |
+
*
|
161 |
+
* @param int $post_id Post ID of the scheduled action.
|
162 |
+
* @param string $schedule Schedule to save.
|
163 |
+
*
|
164 |
+
* @return void
|
165 |
+
*/
|
166 |
protected function save_post_schedule( $post_id, $schedule ) {
|
167 |
update_post_meta( $post_id, self::SCHEDULE_META_KEY, $schedule );
|
168 |
}
|
169 |
|
170 |
+
/**
|
171 |
+
* Save action group.
|
172 |
+
*
|
173 |
+
* @param int $post_id Post ID.
|
174 |
+
* @param string $group Group to save.
|
175 |
+
* @return void
|
176 |
+
*/
|
177 |
protected function save_action_group( $post_id, $group ) {
|
178 |
if ( empty( $group ) ) {
|
179 |
wp_set_object_terms( $post_id, array(), self::GROUP_TAXONOMY, false );
|
182 |
}
|
183 |
}
|
184 |
|
185 |
+
/**
|
186 |
+
* Fetch actions.
|
187 |
+
*
|
188 |
+
* @param int $action_id Action ID.
|
189 |
+
* @return object
|
190 |
+
*/
|
191 |
public function fetch_action( $action_id ) {
|
192 |
$post = $this->get_post( $action_id );
|
193 |
+
if ( empty( $post ) || self::POST_TYPE !== $post->post_type ) {
|
194 |
return $this->get_null_action();
|
195 |
}
|
196 |
|
204 |
return $action;
|
205 |
}
|
206 |
|
207 |
+
/**
|
208 |
+
* Get post.
|
209 |
+
*
|
210 |
+
* @param string $action_id - Action ID.
|
211 |
+
* @return WP_Post|null
|
212 |
+
*/
|
213 |
protected function get_post( $action_id ) {
|
214 |
if ( empty( $action_id ) ) {
|
215 |
return null;
|
217 |
return get_post( $action_id );
|
218 |
}
|
219 |
|
220 |
+
/**
|
221 |
+
* Get NULL action.
|
222 |
+
*
|
223 |
+
* @return ActionScheduler_NullAction
|
224 |
+
*/
|
225 |
protected function get_null_action() {
|
226 |
return new ActionScheduler_NullAction();
|
227 |
}
|
228 |
|
229 |
+
/**
|
230 |
+
* Make action from post.
|
231 |
+
*
|
232 |
+
* @param WP_Post $post Post object.
|
233 |
+
* @return WP_Post
|
234 |
+
*/
|
235 |
protected function make_action_from_post( $post ) {
|
236 |
$hook = $post->post_title;
|
237 |
|
248 |
}
|
249 |
|
250 |
/**
|
251 |
+
* Get action status by post status.
|
252 |
+
*
|
253 |
+
* @param string $post_status Post status.
|
254 |
*
|
255 |
+
* @throws InvalidArgumentException Throw InvalidArgumentException if $post_status not in known status fields returned by $this->get_status_labels().
|
256 |
* @return string
|
257 |
*/
|
258 |
protected function get_action_status_by_post_status( $post_status ) {
|
276 |
}
|
277 |
|
278 |
/**
|
279 |
+
* Get post status by action status.
|
280 |
+
*
|
281 |
+
* @param string $action_status Action status.
|
282 |
+
*
|
283 |
+
* @throws InvalidArgumentException Throws InvalidArgumentException if $post_status not in known status fields returned by $this->get_status_labels().
|
284 |
* @return string
|
285 |
*/
|
286 |
protected function get_post_status_by_action_status( $action_status ) {
|
303 |
return $post_status;
|
304 |
}
|
305 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
306 |
/**
|
307 |
* Returns the SQL statement to query (or count) actions.
|
308 |
*
|
309 |
+
* @param array $query - Filtering options.
|
310 |
+
* @param string $select_or_count - Whether the SQL should select and return the IDs or just the row count.
|
311 |
+
*
|
312 |
+
* @throws InvalidArgumentException - Throw InvalidArgumentException if $select_or_count not count or select.
|
313 |
* @return string SQL statement. The returned SQL is already properly escaped.
|
314 |
*/
|
315 |
protected function get_query_actions_sql( array $query, $select_or_count = 'select' ) {
|
316 |
|
317 |
+
if ( ! in_array( $select_or_count, array( 'select', 'count' ), true ) ) {
|
318 |
throw new InvalidArgumentException( __( 'Invalid schedule. Cannot save action.', 'action-scheduler' ) );
|
319 |
}
|
320 |
|
338 |
)
|
339 |
);
|
340 |
|
341 |
+
/**
|
342 |
+
* Global wpdb object.
|
343 |
+
*
|
344 |
+
* @var wpdb $wpdb
|
345 |
+
*/
|
346 |
global $wpdb;
|
347 |
$sql = ( 'count' === $select_or_count ) ? 'SELECT count(p.ID)' : 'SELECT p.ID ';
|
348 |
$sql .= "FROM {$wpdb->posts} p";
|
366 |
}
|
367 |
if ( ! is_null( $query['args'] ) ) {
|
368 |
$sql .= ' AND p.post_content=%s';
|
369 |
+
$sql_params[] = wp_json_encode( $query['args'] );
|
370 |
}
|
371 |
|
372 |
+
if ( $query['status'] ) {
|
373 |
+
$post_statuses = array_map( array( $this, 'get_post_status_by_action_status' ), (array) $query['status'] );
|
374 |
+
$placeholders = array_fill( 0, count( $post_statuses ), '%s' );
|
375 |
+
$sql .= ' AND p.post_status IN (' . join( ', ', $placeholders ) . ')';
|
376 |
+
$sql_params = array_merge( $sql_params, array_values( $post_statuses ) );
|
377 |
}
|
378 |
|
379 |
if ( $query['date'] instanceof DateTime ) {
|
394 |
$sql_params[] = $date_string;
|
395 |
}
|
396 |
|
397 |
+
if ( true === $query['claimed'] ) {
|
398 |
$sql .= " AND p.post_password != ''";
|
399 |
+
} elseif ( false === $query['claimed'] ) {
|
400 |
$sql .= " AND p.post_password = ''";
|
401 |
} elseif ( ! is_null( $query['claimed'] ) ) {
|
402 |
$sql .= ' AND p.post_password = %s';
|
446 |
}
|
447 |
}
|
448 |
|
449 |
+
return $wpdb->prepare( $sql, $sql_params ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
|
450 |
}
|
451 |
|
452 |
/**
|
453 |
+
* Query for action count or list of action IDs.
|
454 |
+
*
|
455 |
+
* @since x.x.x $query['status'] accepts array of statuses instead of a single status.
|
456 |
+
*
|
457 |
+
* @see ActionScheduler_Store::query_actions for $query arg usage.
|
458 |
+
*
|
459 |
+
* @param array $query Query filtering options.
|
460 |
+
* @param string $query_type Whether to select or count the results. Defaults to select.
|
461 |
+
*
|
462 |
+
* @return string|array|null The IDs of actions matching the query. Null on failure.
|
463 |
*/
|
464 |
public function query_actions( $query = array(), $query_type = 'select' ) {
|
465 |
+
/**
|
466 |
+
* Global $wpdb object.
|
467 |
+
*
|
468 |
+
* @var wpdb $wpdb
|
469 |
+
*/
|
470 |
global $wpdb;
|
471 |
|
472 |
$sql = $this->get_query_actions_sql( $query, $query_type );
|
473 |
|
474 |
+
return ( 'count' === $query_type ) ? $wpdb->get_var( $sql ) : $wpdb->get_col( $sql ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching,WordPress.DB.PreparedSQL.NotPrepared
|
475 |
}
|
476 |
|
477 |
/**
|
490 |
try {
|
491 |
$action_status_name = $this->get_action_status_by_post_status( $post_status_name );
|
492 |
} catch ( Exception $e ) {
|
493 |
+
// Ignore any post statuses that aren't for actions.
|
494 |
continue;
|
495 |
}
|
496 |
if ( array_key_exists( $action_status_name, $action_stati_and_labels ) ) {
|
502 |
}
|
503 |
|
504 |
/**
|
505 |
+
* Cancel action.
|
506 |
*
|
507 |
+
* @param int $action_id Action ID.
|
508 |
+
*
|
509 |
+
* @throws InvalidArgumentException If $action_id is not identified.
|
510 |
*/
|
511 |
public function cancel_action( $action_id ) {
|
512 |
$post = get_post( $action_id );
|
513 |
+
if ( empty( $post ) || ( self::POST_TYPE !== $post->post_type ) ) {
|
514 |
+
/* translators: %s is the action ID */
|
515 |
throw new InvalidArgumentException( sprintf( __( 'Unidentified action %s', 'action-scheduler' ), $action_id ) );
|
516 |
}
|
517 |
do_action( 'action_scheduler_canceled_action', $action_id );
|
520 |
remove_filter( 'pre_wp_unique_post_slug', array( $this, 'set_unique_post_slug' ), 10 );
|
521 |
}
|
522 |
|
523 |
+
/**
|
524 |
+
* Delete action.
|
525 |
+
*
|
526 |
+
* @param int $action_id Action ID.
|
527 |
+
* @return void
|
528 |
+
* @throws InvalidArgumentException If action is not identified.
|
529 |
+
*/
|
530 |
public function delete_action( $action_id ) {
|
531 |
$post = get_post( $action_id );
|
532 |
+
if ( empty( $post ) || ( self::POST_TYPE !== $post->post_type ) ) {
|
533 |
+
/* translators: %s is the action ID */
|
534 |
throw new InvalidArgumentException( sprintf( __( 'Unidentified action %s', 'action-scheduler' ), $action_id ) );
|
535 |
}
|
536 |
do_action( 'action_scheduler_deleted_action', $action_id );
|
539 |
}
|
540 |
|
541 |
/**
|
542 |
+
* Get date for claim id.
|
543 |
*
|
544 |
+
* @param int $action_id Action ID.
|
545 |
* @return ActionScheduler_DateTime The date the action is schedule to run, or the date that it ran.
|
546 |
*/
|
547 |
public function get_date( $action_id ) {
|
550 |
}
|
551 |
|
552 |
/**
|
553 |
+
* Get Date GMT.
|
554 |
*
|
555 |
+
* @param int $action_id Action ID.
|
556 |
+
*
|
557 |
+
* @throws InvalidArgumentException If $action_id is not identified.
|
558 |
* @return ActionScheduler_DateTime The date the action is schedule to run, or the date that it ran.
|
559 |
*/
|
560 |
public function get_date_gmt( $action_id ) {
|
561 |
$post = get_post( $action_id );
|
562 |
+
if ( empty( $post ) || ( self::POST_TYPE !== $post->post_type ) ) {
|
563 |
+
/* translators: %s is the action ID */
|
564 |
throw new InvalidArgumentException( sprintf( __( 'Unidentified action %s', 'action-scheduler' ), $action_id ) );
|
565 |
}
|
566 |
+
if ( 'publish' === $post->post_status ) {
|
567 |
return as_get_datetime_object( $post->post_modified_gmt );
|
568 |
} else {
|
569 |
return as_get_datetime_object( $post->post_date_gmt );
|
571 |
}
|
572 |
|
573 |
/**
|
574 |
+
* Stake claim.
|
575 |
+
*
|
576 |
+
* @param int $max_actions Maximum number of actions.
|
577 |
* @param DateTime $before_date Jobs must be schedule before this date. Defaults to now.
|
578 |
* @param array $hooks Claim only actions with a hook or hooks.
|
579 |
* @param string $group Claim only actions in the given group.
|
583 |
* @throws InvalidArgumentException When the given group is not valid.
|
584 |
*/
|
585 |
public function stake_claim( $max_actions = 10, DateTime $before_date = null, $hooks = array(), $group = '' ) {
|
586 |
+
$this->claim_before_date = $before_date;
|
587 |
+
$claim_id = $this->generate_claim_id();
|
588 |
$this->claim_actions( $claim_id, $max_actions, $before_date, $hooks, $group );
|
589 |
+
$action_ids = $this->find_actions_by_claim_id( $claim_id );
|
590 |
+
$this->claim_before_date = null;
|
591 |
|
592 |
return new ActionScheduler_ActionClaim( $claim_id, $action_ids );
|
593 |
}
|
594 |
|
595 |
/**
|
596 |
+
* Get claim count.
|
597 |
+
*
|
598 |
* @return int
|
599 |
*/
|
600 |
public function get_claim_count() {
|
601 |
global $wpdb;
|
602 |
|
603 |
+
// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching
|
604 |
+
return $wpdb->get_var(
|
605 |
+
$wpdb->prepare(
|
606 |
+
"SELECT COUNT(DISTINCT post_password) FROM {$wpdb->posts} WHERE post_password != '' AND post_type = %s AND post_status IN ('in-progress','pending')",
|
607 |
+
array( self::POST_TYPE )
|
608 |
+
)
|
609 |
+
);
|
610 |
}
|
611 |
|
612 |
+
/**
|
613 |
+
* Generate claim id.
|
614 |
+
*
|
615 |
+
* @return string
|
616 |
+
*/
|
617 |
protected function generate_claim_id() {
|
618 |
+
$claim_id = md5( microtime( true ) . wp_rand( 0, 1000 ) );
|
619 |
+
return substr( $claim_id, 0, 20 ); // to fit in db field with 20 char limit.
|
620 |
}
|
621 |
|
622 |
/**
|
623 |
+
* Claim actions.
|
624 |
+
*
|
625 |
+
* @param string $claim_id Claim ID.
|
626 |
+
* @param int $limit Limit.
|
627 |
* @param DateTime $before_date Should use UTC timezone.
|
628 |
* @param array $hooks Claim only actions with a hook or hooks.
|
629 |
* @param string $group Claim only actions in the given group.
|
630 |
*
|
631 |
+
* @return int The number of actions that were claimed.
|
632 |
+
* @throws RuntimeException When there is a database error.
|
|
|
633 |
*/
|
634 |
protected function claim_actions( $claim_id, $limit, DateTime $before_date = null, $hooks = array(), $group = '' ) {
|
635 |
// Set up initial variables.
|
642 |
return 0;
|
643 |
}
|
644 |
|
645 |
+
/**
|
646 |
+
* Global wpdb object.
|
647 |
+
*
|
648 |
+
* @var wpdb $wpdb
|
649 |
+
*/
|
650 |
global $wpdb;
|
651 |
|
652 |
/*
|
690 |
$params[] = $limit;
|
691 |
|
692 |
// Run the query and gather results.
|
693 |
+
$rows_affected = $wpdb->query( $wpdb->prepare( "{$update} {$where} {$order}", $params ) ); // phpcs:ignore // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.PreparedSQLPlaceholders.UnfinishedPrepare
|
694 |
+
|
695 |
+
if ( false === $rows_affected ) {
|
696 |
throw new RuntimeException( __( 'Unable to claim actions. Database error.', 'action-scheduler' ) );
|
697 |
}
|
698 |
|
713 |
protected function get_actions_by_group( $group, $limit, DateTime $date ) {
|
714 |
// Ensure the group exists before continuing.
|
715 |
if ( ! term_exists( $group, self::GROUP_TAXONOMY ) ) {
|
716 |
+
/* translators: %s is the group name */
|
717 |
throw new InvalidArgumentException( sprintf( __( 'The group "%s" does not exist.', 'action-scheduler' ), $group ) );
|
718 |
}
|
719 |
|
737 |
'before' => $date->format( 'Y-m-d H:i' ),
|
738 |
'inclusive' => true,
|
739 |
),
|
740 |
+
'tax_query' => array( // phpcs:ignore WordPress.DB.SlowDBQuery
|
741 |
array(
|
742 |
'taxonomy' => self::GROUP_TAXONOMY,
|
743 |
'field' => 'slug',
|
751 |
}
|
752 |
|
753 |
/**
|
754 |
+
* Find actions by claim ID.
|
755 |
+
*
|
756 |
+
* @param string $claim_id Claim ID.
|
757 |
* @return array
|
758 |
*/
|
759 |
public function find_actions_by_claim_id( $claim_id ) {
|
760 |
+
/**
|
761 |
+
* Global wpdb object.
|
762 |
+
*
|
763 |
+
* @var wpdb $wpdb
|
764 |
+
*/
|
765 |
global $wpdb;
|
766 |
+
|
767 |
+
$action_ids = array();
|
768 |
+
$before_date = isset( $this->claim_before_date ) ? $this->claim_before_date : as_get_datetime_object();
|
769 |
+
$cut_off = $before_date->format( 'Y-m-d H:i:s' );
|
770 |
+
|
771 |
+
// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
|
772 |
+
$results = $wpdb->get_results(
|
773 |
+
$wpdb->prepare(
|
774 |
+
"SELECT ID, post_date_gmt FROM {$wpdb->posts} WHERE post_type = %s AND post_password = %s",
|
775 |
+
array(
|
776 |
+
self::POST_TYPE,
|
777 |
+
$claim_id,
|
778 |
+
)
|
779 |
+
)
|
780 |
+
);
|
781 |
+
|
782 |
+
// Verify that the scheduled date for each action is within the expected bounds (in some unusual
|
783 |
+
// cases, we cannot depend on MySQL to honor all of the WHERE conditions we specify).
|
784 |
+
foreach ( $results as $claimed_action ) {
|
785 |
+
if ( $claimed_action->post_date_gmt <= $cut_off ) {
|
786 |
+
$action_ids[] = absint( $claimed_action->ID );
|
787 |
+
}
|
788 |
+
}
|
789 |
+
|
790 |
return $action_ids;
|
791 |
}
|
792 |
|
793 |
+
/**
|
794 |
+
* Release claim.
|
795 |
+
*
|
796 |
+
* @param ActionScheduler_ActionClaim $claim Claim object to release.
|
797 |
+
* @return void
|
798 |
+
* @throws RuntimeException When the claim is not unlocked.
|
799 |
+
*/
|
800 |
public function release_claim( ActionScheduler_ActionClaim $claim ) {
|
801 |
$action_ids = $this->find_actions_by_claim_id( $claim->get_id() );
|
802 |
if ( empty( $action_ids ) ) {
|
803 |
+
return; // nothing to do.
|
804 |
}
|
805 |
$action_id_string = implode( ',', array_map( 'intval', $action_ids ) );
|
806 |
+
/**
|
807 |
+
* Global wpdb object.
|
808 |
+
*
|
809 |
+
* @var wpdb $wpdb
|
810 |
+
*/
|
811 |
global $wpdb;
|
812 |
+
|
813 |
+
// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
|
814 |
+
$result = $wpdb->query(
|
815 |
+
$wpdb->prepare(
|
816 |
+
"UPDATE {$wpdb->posts} SET post_password = '' WHERE ID IN ($action_id_string) AND post_password = %s", //phpcs:ignore
|
817 |
+
array(
|
818 |
+
$claim->get_id(),
|
819 |
+
)
|
820 |
+
)
|
821 |
+
);
|
822 |
+
if ( false === $result ) {
|
823 |
/* translators: %s: claim ID */
|
824 |
throw new RuntimeException( sprintf( __( 'Unable to unlock claim %s. Database error.', 'action-scheduler' ), $claim->get_id() ) );
|
825 |
}
|
826 |
}
|
827 |
|
828 |
/**
|
829 |
+
* Unclaim action.
|
830 |
+
*
|
831 |
+
* @param string $action_id Action ID.
|
832 |
+
* @throws RuntimeException When unable to unlock claim on action ID.
|
833 |
*/
|
834 |
public function unclaim_action( $action_id ) {
|
835 |
+
/**
|
836 |
+
* Global wpdb object.
|
837 |
+
*
|
838 |
+
* @var wpdb $wpdb
|
839 |
+
*/
|
840 |
global $wpdb;
|
841 |
+
|
842 |
+
//phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
|
843 |
+
$result = $wpdb->query(
|
844 |
+
$wpdb->prepare(
|
845 |
+
"UPDATE {$wpdb->posts} SET post_password = '' WHERE ID = %d AND post_type = %s",
|
846 |
+
$action_id,
|
847 |
+
self::POST_TYPE
|
848 |
+
)
|
849 |
+
);
|
850 |
+
if ( false === $result ) {
|
851 |
/* translators: %s: action ID */
|
852 |
throw new RuntimeException( sprintf( __( 'Unable to unlock claim on action %s. Database error.', 'action-scheduler' ), $action_id ) );
|
853 |
}
|
854 |
}
|
855 |
|
856 |
+
/**
|
857 |
+
* Mark failure on action.
|
858 |
+
*
|
859 |
+
* @param int $action_id Action ID.
|
860 |
+
*
|
861 |
+
* @return void
|
862 |
+
* @throws RuntimeException When unable to mark failure on action ID.
|
863 |
+
*/
|
864 |
public function mark_failure( $action_id ) {
|
865 |
+
/**
|
866 |
+
* Global wpdb object.
|
867 |
+
*
|
868 |
+
* @var wpdb $wpdb
|
869 |
+
*/
|
870 |
global $wpdb;
|
871 |
+
|
872 |
+
// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
|
873 |
+
$result = $wpdb->query(
|
874 |
+
$wpdb->prepare( "UPDATE {$wpdb->posts} SET post_status = %s WHERE ID = %d AND post_type = %s", self::STATUS_FAILED, $action_id, self::POST_TYPE )
|
875 |
+
);
|
876 |
+
if ( false === $result ) {
|
877 |
/* translators: %s: action ID */
|
878 |
throw new RuntimeException( sprintf( __( 'Unable to mark failure on action %s. Database error.', 'action-scheduler' ), $action_id ) );
|
879 |
}
|
882 |
/**
|
883 |
* Return an action's claim ID, as stored in the post password column
|
884 |
*
|
885 |
+
* @param int $action_id Action ID.
|
886 |
* @return mixed
|
887 |
*/
|
888 |
public function get_claim_id( $action_id ) {
|
892 |
/**
|
893 |
* Return an action's status, as stored in the post status column
|
894 |
*
|
895 |
+
* @param int $action_id Action ID.
|
896 |
+
*
|
897 |
* @return mixed
|
898 |
+
* @throws InvalidArgumentException When the action ID is invalid.
|
899 |
*/
|
900 |
public function get_status( $action_id ) {
|
901 |
$status = $this->get_post_column( $action_id, 'post_status' );
|
902 |
|
903 |
+
if ( null === $status ) {
|
904 |
throw new InvalidArgumentException( __( 'Invalid action ID. No status found.', 'action-scheduler' ) );
|
905 |
}
|
906 |
|
907 |
return $this->get_action_status_by_post_status( $status );
|
908 |
}
|
909 |
|
910 |
+
/**
|
911 |
+
* Get post column
|
912 |
+
*
|
913 |
+
* @param string $action_id Action ID.
|
914 |
+
* @param string $column_name Column Name.
|
915 |
+
*
|
916 |
+
* @return string|null
|
917 |
+
*/
|
918 |
private function get_post_column( $action_id, $column_name ) {
|
919 |
+
/**
|
920 |
+
* Global wpdb object.
|
921 |
+
*
|
922 |
+
* @var wpdb $wpdb
|
923 |
+
*/
|
924 |
global $wpdb;
|
925 |
+
|
926 |
+
// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
|
927 |
+
return $wpdb->get_var(
|
928 |
+
$wpdb->prepare(
|
929 |
+
"SELECT {$column_name} FROM {$wpdb->posts} WHERE ID=%d AND post_type=%s", // phpcs:ignore
|
930 |
+
$action_id,
|
931 |
+
self::POST_TYPE
|
932 |
+
)
|
933 |
+
);
|
934 |
}
|
935 |
|
936 |
/**
|
937 |
+
* Log Execution.
|
938 |
+
*
|
939 |
+
* @param string $action_id Action ID.
|
940 |
*/
|
941 |
public function log_execution( $action_id ) {
|
942 |
+
/**
|
943 |
+
* Global wpdb object.
|
944 |
+
*
|
945 |
+
* @var wpdb $wpdb
|
946 |
+
*/
|
947 |
global $wpdb;
|
948 |
|
949 |
+
// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
|
950 |
+
$wpdb->query(
|
951 |
+
$wpdb->prepare(
|
952 |
+
"UPDATE {$wpdb->posts} SET menu_order = menu_order+1, post_status=%s, post_modified_gmt = %s, post_modified = %s WHERE ID = %d AND post_type = %s",
|
953 |
+
self::STATUS_RUNNING,
|
954 |
+
current_time( 'mysql', true ),
|
955 |
+
current_time( 'mysql' ),
|
956 |
+
$action_id,
|
957 |
+
self::POST_TYPE
|
958 |
+
)
|
959 |
+
);
|
960 |
}
|
961 |
|
962 |
/**
|
963 |
* Record that an action was completed.
|
964 |
*
|
965 |
+
* @param string $action_id ID of the completed action.
|
966 |
+
*
|
967 |
+
* @throws InvalidArgumentException When the action ID is invalid.
|
968 |
+
* @throws RuntimeException When there was an error executing the action.
|
969 |
*/
|
970 |
public function mark_complete( $action_id ) {
|
971 |
$post = get_post( $action_id );
|
972 |
+
if ( empty( $post ) || ( self::POST_TYPE !== $post->post_type ) ) {
|
973 |
+
/* translators: %s is the action ID */
|
974 |
throw new InvalidArgumentException( sprintf( __( 'Unidentified action %s', 'action-scheduler' ), $action_id ) );
|
975 |
}
|
976 |
add_filter( 'wp_insert_post_data', array( $this, 'filter_insert_post_data' ), 10, 1 );
|
1006 |
/**
|
1007 |
* Determine whether the post store can be migrated.
|
1008 |
*
|
1009 |
+
* @param [type] $setting - Setting value.
|
1010 |
* @return bool
|
1011 |
*/
|
1012 |
public function migration_dependencies_met( $setting ) {
|
1015 |
$dependencies_met = get_transient( self::DEPENDENCIES_MET );
|
1016 |
if ( empty( $dependencies_met ) ) {
|
1017 |
$maximum_args_length = apply_filters( 'action_scheduler_maximum_args_length', 191 );
|
1018 |
+
$found_action = $wpdb->get_var( // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
|
1019 |
$wpdb->prepare(
|
1020 |
"SELECT ID FROM {$wpdb->posts} WHERE post_type = %s AND CHAR_LENGTH(post_content) > %d LIMIT 1",
|
1021 |
$maximum_args_length,
|
1026 |
set_transient( self::DEPENDENCIES_MET, $dependencies_met, DAY_IN_SECONDS );
|
1027 |
}
|
1028 |
|
1029 |
+
return 'yes' === $dependencies_met ? $setting : false;
|
1030 |
}
|
1031 |
|
1032 |
/**
|
1036 |
* as we prepare to move to custom tables, and can use an indexed VARCHAR column instead, we want to warn
|
1037 |
* developers of this impending requirement.
|
1038 |
*
|
1039 |
+
* @param ActionScheduler_Action $action Action object.
|
1040 |
*/
|
1041 |
protected function validate_action( ActionScheduler_Action $action ) {
|
1042 |
try {
|
1043 |
parent::validate_action( $action );
|
1044 |
} catch ( Exception $e ) {
|
1045 |
+
/* translators: %s is the error message */
|
1046 |
$message = sprintf( __( '%s Support for strings longer than this will be removed in a future version.', 'action-scheduler' ), $e->getMessage() );
|
1047 |
+
_doing_it_wrong( 'ActionScheduler_Action::$args', esc_html( $message ), '2.1.0' );
|
1048 |
}
|
1049 |
}
|
1050 |
|
1051 |
/**
|
1052 |
+
* (@codeCoverageIgnore)
|
1053 |
*/
|
1054 |
public function init() {
|
1055 |
add_filter( 'action_scheduler_migration_dependencies_met', array( $this, 'migration_dependencies_met' ) );
|
lite/includes/libraries/action-scheduler/classes/data-stores/ActionScheduler_wpPostStore_PostStatusRegistrar.php
CHANGED
@@ -2,7 +2,6 @@
|
|
2 |
|
3 |
/**
|
4 |
* Class ActionScheduler_wpPostStore_PostStatusRegistrar
|
5 |
-
*
|
6 |
* @codeCoverageIgnore
|
7 |
*/
|
8 |
class ActionScheduler_wpPostStore_PostStatusRegistrar {
|
2 |
|
3 |
/**
|
4 |
* Class ActionScheduler_wpPostStore_PostStatusRegistrar
|
|
|
5 |
* @codeCoverageIgnore
|
6 |
*/
|
7 |
class ActionScheduler_wpPostStore_PostStatusRegistrar {
|
lite/includes/libraries/action-scheduler/classes/data-stores/ActionScheduler_wpPostStore_PostTypeRegistrar.php
CHANGED
@@ -2,7 +2,6 @@
|
|
2 |
|
3 |
/**
|
4 |
* Class ActionScheduler_wpPostStore_PostTypeRegistrar
|
5 |
-
*
|
6 |
* @codeCoverageIgnore
|
7 |
*/
|
8 |
class ActionScheduler_wpPostStore_PostTypeRegistrar {
|
@@ -17,35 +16,35 @@ class ActionScheduler_wpPostStore_PostTypeRegistrar {
|
|
17 |
*/
|
18 |
protected function post_type_args() {
|
19 |
$args = array(
|
20 |
-
'label'
|
21 |
-
'description'
|
22 |
-
'public'
|
23 |
'map_meta_cap' => true,
|
24 |
'hierarchical' => false,
|
25 |
-
'supports'
|
26 |
-
'rewrite'
|
27 |
-
'query_var'
|
28 |
-
'can_export'
|
29 |
-
'ep_mask'
|
30 |
-
'labels'
|
31 |
-
'name'
|
32 |
-
'singular_name'
|
33 |
-
'menu_name'
|
34 |
-
'add_new'
|
35 |
-
'add_new_item'
|
36 |
-
'edit'
|
37 |
-
'edit_item'
|
38 |
-
'new_item'
|
39 |
-
'view'
|
40 |
-
'view_item'
|
41 |
-
'search_items'
|
42 |
-
'not_found'
|
43 |
'not_found_in_trash' => __( 'No actions found in trash', 'action-scheduler' ),
|
44 |
),
|
45 |
);
|
46 |
|
47 |
-
$args = apply_filters(
|
48 |
return $args;
|
49 |
}
|
50 |
}
|
51 |
-
|
2 |
|
3 |
/**
|
4 |
* Class ActionScheduler_wpPostStore_PostTypeRegistrar
|
|
|
5 |
* @codeCoverageIgnore
|
6 |
*/
|
7 |
class ActionScheduler_wpPostStore_PostTypeRegistrar {
|
16 |
*/
|
17 |
protected function post_type_args() {
|
18 |
$args = array(
|
19 |
+
'label' => __( 'Scheduled Actions', 'action-scheduler' ),
|
20 |
+
'description' => __( 'Scheduled actions are hooks triggered on a cetain date and time.', 'action-scheduler' ),
|
21 |
+
'public' => false,
|
22 |
'map_meta_cap' => true,
|
23 |
'hierarchical' => false,
|
24 |
+
'supports' => array('title', 'editor','comments'),
|
25 |
+
'rewrite' => false,
|
26 |
+
'query_var' => false,
|
27 |
+
'can_export' => true,
|
28 |
+
'ep_mask' => EP_NONE,
|
29 |
+
'labels' => array(
|
30 |
+
'name' => __( 'Scheduled Actions', 'action-scheduler' ),
|
31 |
+
'singular_name' => __( 'Scheduled Action', 'action-scheduler' ),
|
32 |
+
'menu_name' => _x( 'Scheduled Actions', 'Admin menu name', 'action-scheduler' ),
|
33 |
+
'add_new' => __( 'Add', 'action-scheduler' ),
|
34 |
+
'add_new_item' => __( 'Add New Scheduled Action', 'action-scheduler' ),
|
35 |
+
'edit' => __( 'Edit', 'action-scheduler' ),
|
36 |
+
'edit_item' => __( 'Edit Scheduled Action', 'action-scheduler' ),
|
37 |
+
'new_item' => __( 'New Scheduled Action', 'action-scheduler' ),
|
38 |
+
'view' => __( 'View Action', 'action-scheduler' ),
|
39 |
+
'view_item' => __( 'View Action', 'action-scheduler' ),
|
40 |
+
'search_items' => __( 'Search Scheduled Actions', 'action-scheduler' ),
|
41 |
+
'not_found' => __( 'No actions found', 'action-scheduler' ),
|
42 |
'not_found_in_trash' => __( 'No actions found in trash', 'action-scheduler' ),
|
43 |
),
|
44 |
);
|
45 |
|
46 |
+
$args = apply_filters('action_scheduler_post_type_args', $args);
|
47 |
return $args;
|
48 |
}
|
49 |
}
|
50 |
+
|
lite/includes/libraries/action-scheduler/classes/data-stores/ActionScheduler_wpPostStore_TaxonomyRegistrar.php
CHANGED
@@ -2,7 +2,6 @@
|
|
2 |
|
3 |
/**
|
4 |
* Class ActionScheduler_wpPostStore_TaxonomyRegistrar
|
5 |
-
*
|
6 |
* @codeCoverageIgnore
|
7 |
*/
|
8 |
class ActionScheduler_wpPostStore_TaxonomyRegistrar {
|
@@ -12,16 +11,16 @@ class ActionScheduler_wpPostStore_TaxonomyRegistrar {
|
|
12 |
|
13 |
protected function taxonomy_args() {
|
14 |
$args = array(
|
15 |
-
'label'
|
16 |
-
'public'
|
17 |
-
'hierarchical'
|
18 |
'show_admin_column' => true,
|
19 |
-
'query_var'
|
20 |
-
'rewrite'
|
21 |
);
|
22 |
|
23 |
$args = apply_filters( 'action_scheduler_taxonomy_args', $args );
|
24 |
return $args;
|
25 |
}
|
26 |
}
|
27 |
-
|
2 |
|
3 |
/**
|
4 |
* Class ActionScheduler_wpPostStore_TaxonomyRegistrar
|
|
|
5 |
* @codeCoverageIgnore
|
6 |
*/
|
7 |
class ActionScheduler_wpPostStore_TaxonomyRegistrar {
|
11 |
|
12 |
protected function taxonomy_args() {
|
13 |
$args = array(
|
14 |
+
'label' => __( 'Action Group', 'action-scheduler' ),
|
15 |
+
'public' => false,
|
16 |
+
'hierarchical' => false,
|
17 |
'show_admin_column' => true,
|
18 |
+
'query_var' => false,
|
19 |
+
'rewrite' => false,
|
20 |
);
|
21 |
|
22 |
$args = apply_filters( 'action_scheduler_taxonomy_args', $args );
|
23 |
return $args;
|
24 |
}
|
25 |
}
|
26 |
+
|
lite/includes/libraries/action-scheduler/classes/migration/ActionMigrator.php
CHANGED
@@ -79,10 +79,10 @@ class ActionMigrator {
|
|
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 |
}
|
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 |
}
|
lite/includes/libraries/action-scheduler/classes/migration/ActionScheduler_DBStoreMigrator.php
CHANGED
@@ -17,13 +17,13 @@ class ActionScheduler_DBStoreMigrator extends ActionScheduler_DBStore {
|
|
17 |
* that when first saving the action.
|
18 |
*
|
19 |
* @param ActionScheduler_Action $action
|
20 |
-
* @param \DateTime
|
21 |
-
* @param \DateTime
|
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;
|
@@ -31,10 +31,10 @@ class ActionScheduler_DBStoreMigrator extends ActionScheduler_DBStore {
|
|
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 |
}
|
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;
|
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 |
}
|
lite/includes/libraries/action-scheduler/classes/migration/BatchFetcher.php
CHANGED
@@ -3,6 +3,7 @@
|
|
3 |
|
4 |
namespace Action_Scheduler\Migration;
|
5 |
|
|
|
6 |
use ActionScheduler_Store as Store;
|
7 |
|
8 |
/**
|
@@ -42,7 +43,7 @@ class BatchFetcher {
|
|
42 |
}
|
43 |
}
|
44 |
|
45 |
-
return
|
46 |
}
|
47 |
|
48 |
/**
|
@@ -54,38 +55,32 @@ class BatchFetcher {
|
|
54 |
*/
|
55 |
private function get_query_strategies( $count ) {
|
56 |
$now = as_get_datetime_object();
|
57 |
-
$args =
|
58 |
'date' => $now,
|
59 |
'per_page' => $count,
|
60 |
'offset' => 0,
|
61 |
'orderby' => 'date',
|
62 |
'order' => 'ASC',
|
63 |
-
|
64 |
|
65 |
-
$priorities =
|
66 |
Store::STATUS_PENDING,
|
67 |
Store::STATUS_FAILED,
|
68 |
Store::STATUS_CANCELED,
|
69 |
Store::STATUS_COMPLETE,
|
70 |
Store::STATUS_RUNNING,
|
71 |
'', // any other unanticipated status
|
72 |
-
|
73 |
|
74 |
foreach ( $priorities as $status ) {
|
75 |
-
yield wp_parse_args(
|
76 |
-
|
77 |
-
|
78 |
-
|
79 |
-
|
80 |
-
$
|
81 |
-
|
82 |
-
|
83 |
-
array(
|
84 |
-
'status' => $status,
|
85 |
-
'date_compare' => '>=',
|
86 |
-
),
|
87 |
-
$args
|
88 |
-
);
|
89 |
}
|
90 |
}
|
91 |
-
}
|
3 |
|
4 |
namespace Action_Scheduler\Migration;
|
5 |
|
6 |
+
|
7 |
use ActionScheduler_Store as Store;
|
8 |
|
9 |
/**
|
43 |
}
|
44 |
}
|
45 |
|
46 |
+
return [];
|
47 |
}
|
48 |
|
49 |
/**
|
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 |
+
}
|
lite/includes/libraries/action-scheduler/classes/migration/Controller.php
CHANGED
@@ -2,7 +2,9 @@
|
|
2 |
|
3 |
namespace Action_Scheduler\Migration;
|
4 |
|
5 |
-
use
|
|
|
|
|
6 |
use Action_Scheduler\WP_CLI\ProgressBar;
|
7 |
|
8 |
/**
|
@@ -87,12 +89,30 @@ class Controller {
|
|
87 |
}
|
88 |
|
89 |
/**
|
90 |
-
* Set up the background migration process
|
91 |
*
|
92 |
* @return void
|
93 |
*/
|
94 |
public function schedule_migration() {
|
95 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
96 |
return;
|
97 |
}
|
98 |
|
@@ -139,7 +159,7 @@ class Controller {
|
|
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>',
|
143 |
}
|
144 |
|
145 |
/**
|
2 |
|
3 |
namespace Action_Scheduler\Migration;
|
4 |
|
5 |
+
use ActionScheduler_DataController;
|
6 |
+
use ActionScheduler_LoggerSchema;
|
7 |
+
use ActionScheduler_StoreSchema;
|
8 |
use Action_Scheduler\WP_CLI\ProgressBar;
|
9 |
|
10 |
/**
|
89 |
}
|
90 |
|
91 |
/**
|
92 |
+
* Set up the background migration process.
|
93 |
*
|
94 |
* @return void
|
95 |
*/
|
96 |
public function schedule_migration() {
|
97 |
+
$logging_tables = new ActionScheduler_LoggerSchema();
|
98 |
+
$store_tables = new ActionScheduler_StoreSchema();
|
99 |
+
|
100 |
+
/*
|
101 |
+
* In some unusual cases, the expected tables may not have been created. In such cases
|
102 |
+
* we do not schedule a migration as doing so will lead to fatal error conditions.
|
103 |
+
*
|
104 |
+
* In such cases the user will likely visit the Tools > Scheduled Actions screen to
|
105 |
+
* investigate, and will see appropriate messaging (this step also triggers an attempt
|
106 |
+
* to rebuild any missing tables).
|
107 |
+
*
|
108 |
+
* @see https://github.com/woocommerce/action-scheduler/issues/653
|
109 |
+
*/
|
110 |
+
if (
|
111 |
+
ActionScheduler_DataController::is_migration_complete()
|
112 |
+
|| $this->migration_scheduler->is_migration_scheduled()
|
113 |
+
|| ! $store_tables->tables_exist()
|
114 |
+
|| ! $logging_tables->tables_exist()
|
115 |
+
) {
|
116 |
return;
|
117 |
}
|
118 |
|
159 |
* Show a dashboard notice that migration is in progress.
|
160 |
*/
|
161 |
public function display_migration_notice() {
|
162 |
+
printf( '<div class="notice notice-warning"><p>%s</p></div>', esc_html__( 'Action Scheduler migration in progress. The list of scheduled actions may be incomplete.', 'action-scheduler' ) );
|
163 |
}
|
164 |
|
165 |
/**
|
lite/includes/libraries/action-scheduler/classes/migration/DryRun_LogMigrator.php
CHANGED
@@ -20,4 +20,4 @@ class DryRun_LogMigrator extends LogMigrator {
|
|
20 |
public function migrate( $source_action_id, $destination_action_id ) {
|
21 |
// no-op
|
22 |
}
|
23 |
-
}
|
20 |
public function migrate( $source_action_id, $destination_action_id ) {
|
21 |
// no-op
|
22 |
}
|
23 |
+
}
|
lite/includes/libraries/action-scheduler/classes/migration/Runner.php
CHANGED
@@ -70,7 +70,7 @@ class Runner {
|
|
70 |
* @return int Size of batch processed.
|
71 |
*/
|
72 |
public function run( $batch_size = 10 ) {
|
73 |
-
$batch
|
74 |
$batch_size = count( $batch );
|
75 |
|
76 |
if ( ! $batch_size ) {
|
@@ -102,17 +102,14 @@ class Runner {
|
|
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(
|
|
|
|
|
|
|
|
|
106 |
$destination_action_id,
|
107 |
-
|
108 |
-
|
109 |
-
__( 'Migrated action with ID %1$d in %2$s to ID %3$d in %4$s', 'action-scheduler' ),
|
110 |
-
$source_action_id,
|
111 |
-
get_class( $this->source_store ),
|
112 |
-
$destination_action_id,
|
113 |
-
get_class( $this->destination_store )
|
114 |
-
)
|
115 |
-
);
|
116 |
}
|
117 |
|
118 |
if ( $this->progress_bar ) {
|
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 ) {
|
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 ) {
|
lite/includes/libraries/action-scheduler/classes/migration/Scheduler.php
CHANGED
@@ -14,10 +14,10 @@ namespace Action_Scheduler\Migration;
|
|
14 |
*/
|
15 |
class Scheduler {
|
16 |
/** Migration action hook. */
|
17 |
-
const HOOK
|
18 |
|
19 |
/** Migration action group. */
|
20 |
-
const GROUP
|
21 |
|
22 |
/**
|
23 |
* Set up the callback for the scheduled job.
|
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.
|
lite/includes/libraries/action-scheduler/classes/schedules/ActionScheduler_CanceledSchedule.php
CHANGED
@@ -8,7 +8,7 @@ class ActionScheduler_CanceledSchedule extends ActionScheduler_SimpleSchedule {
|
|
8 |
/**
|
9 |
* Deprecated property @see $this->__wakeup() for details.
|
10 |
**/
|
11 |
-
private $timestamp =
|
12 |
|
13 |
/**
|
14 |
* @param DateTime $after
|
8 |
/**
|
9 |
* Deprecated property @see $this->__wakeup() for details.
|
10 |
**/
|
11 |
+
private $timestamp = NULL;
|
12 |
|
13 |
/**
|
14 |
* @param DateTime $after
|
lite/includes/libraries/action-scheduler/classes/schedules/ActionScheduler_CronSchedule.php
CHANGED
@@ -8,20 +8,20 @@ class ActionScheduler_CronSchedule extends ActionScheduler_Abstract_RecurringSch
|
|
8 |
/**
|
9 |
* Deprecated property @see $this->__wakeup() for details.
|
10 |
**/
|
11 |
-
private $start_timestamp =
|
12 |
|
13 |
/**
|
14 |
* Deprecated property @see $this->__wakeup() for details.
|
15 |
**/
|
16 |
-
private $cron =
|
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
|
23 |
* @param CronExpression|string $recurrence The CronExpression used to calculate the schedule's next instance.
|
24 |
-
* @param DateTime|null
|
25 |
*/
|
26 |
public function __construct( DateTime $start, $recurrence, DateTime $first = null ) {
|
27 |
if ( ! is_a( $recurrence, 'CronExpression' ) ) {
|
@@ -75,13 +75,10 @@ class ActionScheduler_CronSchedule extends ActionScheduler_Abstract_RecurringSch
|
|
75 |
$this->start_timestamp = $this->scheduled_timestamp;
|
76 |
$this->cron = $this->recurrence;
|
77 |
|
78 |
-
return array_merge(
|
79 |
-
|
80 |
-
|
81 |
-
|
82 |
-
'cron',
|
83 |
-
)
|
84 |
-
);
|
85 |
}
|
86 |
|
87 |
/**
|
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' ) ) {
|
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 |
/**
|
lite/includes/libraries/action-scheduler/classes/schedules/ActionScheduler_IntervalSchedule.php
CHANGED
@@ -8,12 +8,12 @@ class ActionScheduler_IntervalSchedule extends ActionScheduler_Abstract_Recurrin
|
|
8 |
/**
|
9 |
* Deprecated property @see $this->__wakeup() for details.
|
10 |
**/
|
11 |
-
private $start_timestamp =
|
12 |
|
13 |
/**
|
14 |
* Deprecated property @see $this->__wakeup() for details.
|
15 |
**/
|
16 |
-
private $interval_in_seconds =
|
17 |
|
18 |
/**
|
19 |
* Calculate when this schedule should start after a given date & time using
|
@@ -55,13 +55,10 @@ class ActionScheduler_IntervalSchedule extends ActionScheduler_Abstract_Recurrin
|
|
55 |
$this->start_timestamp = $this->scheduled_timestamp;
|
56 |
$this->interval_in_seconds = $this->recurrence;
|
57 |
|
58 |
-
return array_merge(
|
59 |
-
|
60 |
-
|
61 |
-
|
62 |
-
'interval_in_seconds',
|
63 |
-
)
|
64 |
-
);
|
65 |
}
|
66 |
|
67 |
/**
|
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
|
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 |
/**
|
lite/includes/libraries/action-scheduler/classes/schedules/ActionScheduler_NullSchedule.php
CHANGED
@@ -16,7 +16,6 @@ class ActionScheduler_NullSchedule extends ActionScheduler_SimpleSchedule {
|
|
16 |
|
17 |
/**
|
18 |
* This schedule has no scheduled DateTime, so we need to override the parent __sleep()
|
19 |
-
*
|
20 |
* @return array
|
21 |
*/
|
22 |
public function __sleep() {
|
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() {
|
lite/includes/libraries/action-scheduler/classes/schedules/ActionScheduler_Schedule.php
CHANGED
@@ -8,11 +8,11 @@ interface ActionScheduler_Schedule {
|
|
8 |
* @param DateTime $after
|
9 |
* @return DateTime|null
|
10 |
*/
|
11 |
-
public function next( DateTime $after =
|
12 |
|
13 |
/**
|
14 |
* @return bool
|
15 |
*/
|
16 |
public function is_recurring();
|
17 |
}
|
18 |
-
|
8 |
* @param DateTime $after
|
9 |
* @return DateTime|null
|
10 |
*/
|
11 |
+
public function next( DateTime $after = NULL );
|
12 |
|
13 |
/**
|
14 |
* @return bool
|
15 |
*/
|
16 |
public function is_recurring();
|
17 |
}
|
18 |
+
|
lite/includes/libraries/action-scheduler/classes/schedules/ActionScheduler_SimpleSchedule.php
CHANGED
@@ -8,7 +8,7 @@ class ActionScheduler_SimpleSchedule extends ActionScheduler_Abstract_Schedule {
|
|
8 |
/**
|
9 |
* Deprecated property @see $this->__wakeup() for details.
|
10 |
**/
|
11 |
-
private $timestamp =
|
12 |
|
13 |
/**
|
14 |
* @param DateTime $after
|
@@ -45,12 +45,9 @@ class ActionScheduler_SimpleSchedule extends ActionScheduler_Abstract_Schedule {
|
|
45 |
|
46 |
$this->timestamp = $this->scheduled_timestamp;
|
47 |
|
48 |
-
return array_merge(
|
49 |
-
|
50 |
-
|
51 |
-
'timestamp',
|
52 |
-
)
|
53 |
-
);
|
54 |
}
|
55 |
|
56 |
/**
|
8 |
/**
|
9 |
* Deprecated property @see $this->__wakeup() for details.
|
10 |
**/
|
11 |
+
private $timestamp = NULL;
|
12 |
|
13 |
/**
|
14 |
* @param DateTime $after
|
45 |
|
46 |
$this->timestamp = $this->scheduled_timestamp;
|
47 |
|
48 |
+
return array_merge( $sleep_params, array(
|
49 |
+
'timestamp',
|
50 |
+
) );
|
|
|
|
|
|
|
51 |
}
|
52 |
|
53 |
/**
|
lite/includes/libraries/action-scheduler/classes/schema/ActionScheduler_LoggerSchema.php
CHANGED
@@ -13,27 +13,36 @@ class ActionScheduler_LoggerSchema extends ActionScheduler_Abstract_Schema {
|
|
13 |
/**
|
14 |
* @var int Increment this value to trigger a schema update.
|
15 |
*/
|
16 |
-
protected $schema_version =
|
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
|
27 |
-
$charset_collate
|
28 |
switch ( $table ) {
|
29 |
|
30 |
case self::LOG_TABLE:
|
|
|
|
|
31 |
return "CREATE TABLE {$table_name} (
|
32 |
log_id bigint(20) unsigned NOT NULL auto_increment,
|
33 |
action_id bigint(20) unsigned NOT NULL,
|
34 |
message text NOT NULL,
|
35 |
-
log_date_gmt datetime
|
36 |
-
log_date_local datetime
|
37 |
PRIMARY KEY (log_id),
|
38 |
KEY action_id (action_id),
|
39 |
KEY log_date_gmt (log_date_gmt)
|
@@ -43,4 +52,39 @@ class ActionScheduler_LoggerSchema extends ActionScheduler_Abstract_Schema {
|
|
43 |
return '';
|
44 |
}
|
45 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
46 |
}
|
13 |
/**
|
14 |
* @var int Increment this value to trigger a schema update.
|
15 |
*/
|
16 |
+
protected $schema_version = 3;
|
17 |
|
18 |
public function __construct() {
|
19 |
+
$this->tables = [
|
20 |
self::LOG_TABLE,
|
21 |
+
];
|
22 |
+
}
|
23 |
+
|
24 |
+
/**
|
25 |
+
* Performs additional setup work required to support this schema.
|
26 |
+
*/
|
27 |
+
public function init() {
|
28 |
+
add_action( 'action_scheduler_before_schema_update', array( $this, 'update_schema_3_0' ), 10, 2 );
|
29 |
}
|
30 |
|
31 |
protected function get_table_definition( $table ) {
|
32 |
global $wpdb;
|
33 |
+
$table_name = $wpdb->$table;
|
34 |
+
$charset_collate = $wpdb->get_charset_collate();
|
35 |
switch ( $table ) {
|
36 |
|
37 |
case self::LOG_TABLE:
|
38 |
+
|
39 |
+
$default_date = ActionScheduler_StoreSchema::DEFAULT_DATE;
|
40 |
return "CREATE TABLE {$table_name} (
|
41 |
log_id bigint(20) unsigned NOT NULL auto_increment,
|
42 |
action_id bigint(20) unsigned NOT NULL,
|
43 |
message text NOT NULL,
|
44 |
+
log_date_gmt datetime NULL default '${default_date}',
|
45 |
+
log_date_local datetime NULL default '${default_date}',
|
46 |
PRIMARY KEY (log_id),
|
47 |
KEY action_id (action_id),
|
48 |
KEY log_date_gmt (log_date_gmt)
|
52 |
return '';
|
53 |
}
|
54 |
}
|
55 |
+
|
56 |
+
/**
|
57 |
+
* Update the logs table schema, allowing datetime fields to be NULL.
|
58 |
+
*
|
59 |
+
* This is needed because the NOT NULL constraint causes a conflict with some versions of MySQL
|
60 |
+
* configured with sql_mode=NO_ZERO_DATE, which can for instance lead to tables not being created.
|
61 |
+
*
|
62 |
+
* Most other schema updates happen via ActionScheduler_Abstract_Schema::update_table(), however
|
63 |
+
* that method relies on dbDelta() and this change is not possible when using that function.
|
64 |
+
*
|
65 |
+
* @param string $table Name of table being updated.
|
66 |
+
* @param string $db_version The existing schema version of the table.
|
67 |
+
*/
|
68 |
+
public function update_schema_3_0( $table, $db_version ) {
|
69 |
+
global $wpdb;
|
70 |
+
|
71 |
+
if ( 'actionscheduler_logs' !== $table || version_compare( $db_version, '3', '>=' ) ) {
|
72 |
+
return;
|
73 |
+
}
|
74 |
+
|
75 |
+
// phpcs:disable WordPress.DB.PreparedSQL.InterpolatedNotPrepared
|
76 |
+
$table_name = $wpdb->prefix . 'actionscheduler_logs';
|
77 |
+
$table_list = $wpdb->get_col( "SHOW TABLES LIKE '${table_name}'" );
|
78 |
+
$default_date = ActionScheduler_StoreSchema::DEFAULT_DATE;
|
79 |
+
|
80 |
+
if ( ! empty( $table_list ) ) {
|
81 |
+
$query = "
|
82 |
+
ALTER TABLE ${table_name}
|
83 |
+
MODIFY COLUMN log_date_gmt datetime NULL default '${default_date}',
|
84 |
+
MODIFY COLUMN log_date_local datetime NULL default '${default_date}'
|
85 |
+
";
|
86 |
+
$wpdb->query( $query ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
|
87 |
+
}
|
88 |
+
// phpcs:enable WordPress.DB.PreparedSQL.InterpolatedNotPrepared
|
89 |
+
}
|
90 |
}
|
lite/includes/libraries/action-scheduler/classes/schema/ActionScheduler_StoreSchema.php
CHANGED
@@ -11,18 +11,26 @@ 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 =
|
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 ) {
|
@@ -30,21 +38,23 @@ class ActionScheduler_StoreSchema extends ActionScheduler_Abstract_Schema {
|
|
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 |
return "CREATE TABLE {$table_name} (
|
37 |
action_id bigint(20) unsigned NOT NULL auto_increment,
|
38 |
hook varchar(191) NOT NULL,
|
39 |
status varchar(20) NOT NULL,
|
40 |
-
scheduled_date_gmt datetime
|
41 |
-
scheduled_date_local datetime
|
42 |
args varchar($max_index_length),
|
43 |
schedule longtext,
|
44 |
group_id bigint(20) unsigned NOT NULL default '0',
|
45 |
attempts int(11) NOT NULL default '0',
|
46 |
-
last_attempt_gmt datetime
|
47 |
-
last_attempt_local datetime
|
48 |
claim_id bigint(20) unsigned NOT NULL default '0',
|
49 |
extended_args varchar(8000) DEFAULT NULL,
|
50 |
PRIMARY KEY (action_id),
|
@@ -54,18 +64,20 @@ class ActionScheduler_StoreSchema extends ActionScheduler_Abstract_Schema {
|
|
54 |
KEY args (args($max_index_length)),
|
55 |
KEY group_id (group_id),
|
56 |
KEY last_attempt_gmt (last_attempt_gmt),
|
57 |
-
KEY
|
58 |
) $charset_collate";
|
59 |
|
60 |
case self::CLAIMS_TABLE:
|
|
|
61 |
return "CREATE TABLE {$table_name} (
|
62 |
claim_id bigint(20) unsigned NOT NULL auto_increment,
|
63 |
-
date_created_gmt datetime
|
64 |
PRIMARY KEY (claim_id),
|
65 |
KEY date_created_gmt (date_created_gmt)
|
66 |
) $charset_collate";
|
67 |
|
68 |
case self::GROUPS_TABLE:
|
|
|
69 |
return "CREATE TABLE {$table_name} (
|
70 |
group_id bigint(20) unsigned NOT NULL auto_increment,
|
71 |
slug varchar(255) NOT NULL,
|
@@ -77,4 +89,41 @@ class ActionScheduler_StoreSchema extends ActionScheduler_Abstract_Schema {
|
|
77 |
return '';
|
78 |
}
|
79 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
80 |
}
|
11 |
const ACTIONS_TABLE = 'actionscheduler_actions';
|
12 |
const CLAIMS_TABLE = 'actionscheduler_claims';
|
13 |
const GROUPS_TABLE = 'actionscheduler_groups';
|
14 |
+
const DEFAULT_DATE = '0000-00-00 00:00:00';
|
15 |
|
16 |
/**
|
17 |
* @var int Increment this value to trigger a schema update.
|
18 |
*/
|
19 |
+
protected $schema_version = 6;
|
20 |
|
21 |
public function __construct() {
|
22 |
+
$this->tables = [
|
23 |
self::ACTIONS_TABLE,
|
24 |
self::CLAIMS_TABLE,
|
25 |
self::GROUPS_TABLE,
|
26 |
+
];
|
27 |
+
}
|
28 |
+
|
29 |
+
/**
|
30 |
+
* Performs additional setup work required to support this schema.
|
31 |
+
*/
|
32 |
+
public function init() {
|
33 |
+
add_action( 'action_scheduler_before_schema_update', array( $this, 'update_schema_5_0' ), 10, 2 );
|
34 |
}
|
35 |
|
36 |
protected function get_table_definition( $table ) {
|
38 |
$table_name = $wpdb->$table;
|
39 |
$charset_collate = $wpdb->get_charset_collate();
|
40 |
$max_index_length = 191; // @see wp_get_db_schema()
|
41 |
+
$default_date = self::DEFAULT_DATE;
|
42 |
switch ( $table ) {
|
43 |
|
44 |
case self::ACTIONS_TABLE:
|
45 |
+
|
46 |
return "CREATE TABLE {$table_name} (
|
47 |
action_id bigint(20) unsigned NOT NULL auto_increment,
|
48 |
hook varchar(191) NOT NULL,
|
49 |
status varchar(20) NOT NULL,
|
50 |
+
scheduled_date_gmt datetime NULL default '${default_date}',
|
51 |
+
scheduled_date_local datetime NULL default '${default_date}',
|
52 |
args varchar($max_index_length),
|
53 |
schedule longtext,
|
54 |
group_id bigint(20) unsigned NOT NULL default '0',
|
55 |
attempts int(11) NOT NULL default '0',
|
56 |
+
last_attempt_gmt datetime NULL default '${default_date}',
|
57 |
+
last_attempt_local datetime NULL default '${default_date}',
|
58 |
claim_id bigint(20) unsigned NOT NULL default '0',
|
59 |
extended_args varchar(8000) DEFAULT NULL,
|
60 |
PRIMARY KEY (action_id),
|
64 |
KEY args (args($max_index_length)),
|
65 |
KEY group_id (group_id),
|
66 |
KEY last_attempt_gmt (last_attempt_gmt),
|
67 |
+
KEY `claim_id_status_scheduled_date_gmt` (`claim_id`, `status`, `scheduled_date_gmt`)
|
68 |
) $charset_collate";
|
69 |
|
70 |
case self::CLAIMS_TABLE:
|
71 |
+
|
72 |
return "CREATE TABLE {$table_name} (
|
73 |
claim_id bigint(20) unsigned NOT NULL auto_increment,
|
74 |
+
date_created_gmt datetime NULL default '${default_date}',
|
75 |
PRIMARY KEY (claim_id),
|
76 |
KEY date_created_gmt (date_created_gmt)
|
77 |
) $charset_collate";
|
78 |
|
79 |
case self::GROUPS_TABLE:
|
80 |
+
|
81 |
return "CREATE TABLE {$table_name} (
|
82 |
group_id bigint(20) unsigned NOT NULL auto_increment,
|
83 |
slug varchar(255) NOT NULL,
|
89 |
return '';
|
90 |
}
|
91 |
}
|
92 |
+
|
93 |
+
/**
|
94 |
+
* Update the actions table schema, allowing datetime fields to be NULL.
|
95 |
+
*
|
96 |
+
* This is needed because the NOT NULL constraint causes a conflict with some versions of MySQL
|
97 |
+
* configured with sql_mode=NO_ZERO_DATE, which can for instance lead to tables not being created.
|
98 |
+
*
|
99 |
+
* Most other schema updates happen via ActionScheduler_Abstract_Schema::update_table(), however
|
100 |
+
* that method relies on dbDelta() and this change is not possible when using that function.
|
101 |
+
*
|
102 |
+
* @param string $table Name of table being updated.
|
103 |
+
* @param string $db_version The existing schema version of the table.
|
104 |
+
*/
|
105 |
+
public function update_schema_5_0( $table, $db_version ) {
|
106 |
+
global $wpdb;
|
107 |
+
|
108 |
+
if ( 'actionscheduler_actions' !== $table || version_compare( $db_version, '5', '>=' ) ) {
|
109 |
+
return;
|
110 |
+
}
|
111 |
+
|
112 |
+
// phpcs:disable WordPress.DB.PreparedSQL.InterpolatedNotPrepared
|
113 |
+
$table_name = $wpdb->prefix . 'actionscheduler_actions';
|
114 |
+
$table_list = $wpdb->get_col( "SHOW TABLES LIKE '${table_name}'" );
|
115 |
+
$default_date = self::DEFAULT_DATE;
|
116 |
+
|
117 |
+
if ( ! empty( $table_list ) ) {
|
118 |
+
$query = "
|
119 |
+
ALTER TABLE ${table_name}
|
120 |
+
MODIFY COLUMN scheduled_date_gmt datetime NULL default '${default_date}',
|
121 |
+
MODIFY COLUMN scheduled_date_local datetime NULL default '${default_date}',
|
122 |
+
MODIFY COLUMN last_attempt_gmt datetime NULL default '${default_date}',
|
123 |
+
MODIFY COLUMN last_attempt_local datetime NULL default '${default_date}'
|
124 |
+
";
|
125 |
+
$wpdb->query( $query ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
|
126 |
+
}
|
127 |
+
// phpcs:enable WordPress.DB.PreparedSQL.InterpolatedNotPrepared
|
128 |
+
}
|
129 |
}
|
lite/includes/libraries/action-scheduler/deprecated/ActionScheduler_AdminView_Deprecated.php
CHANGED
@@ -68,7 +68,7 @@ class ActionScheduler_AdminView_Deprecated {
|
|
68 |
* Print the content for our custom columns.
|
69 |
*
|
70 |
* @param string $column_name The key for the column for which we should output our content.
|
71 |
-
* @param int
|
72 |
*/
|
73 |
public static function list_table_column_content( $column_name, $post_id ) {
|
74 |
_deprecated_function( __METHOD__, '2.0.0' );
|
@@ -115,18 +115,18 @@ class ActionScheduler_AdminView_Deprecated {
|
|
115 |
/**
|
116 |
* Filter search queries to allow searching by Claim ID (i.e. post_password).
|
117 |
*
|
118 |
-
* @param string
|
119 |
* @param WP_Query $query Instance of a WP_Query object
|
120 |
* @return string MySQL orderby string.
|
121 |
*/
|
122 |
-
public function custom_orderby( $orderby, $query )
|
123 |
_deprecated_function( __METHOD__, '2.0.0' );
|
124 |
}
|
125 |
|
126 |
/**
|
127 |
* Filter search queries to allow searching by Claim ID (i.e. post_password).
|
128 |
*
|
129 |
-
* @param string
|
130 |
* @param WP_Query $query Instance of a WP_Query object
|
131 |
* @return string MySQL search string.
|
132 |
*/
|
@@ -144,4 +144,4 @@ class ActionScheduler_AdminView_Deprecated {
|
|
144 |
_deprecated_function( __METHOD__, '2.0.0' );
|
145 |
return $messages;
|
146 |
}
|
147 |
-
}
|
68 |
* Print the content for our custom columns.
|
69 |
*
|
70 |
* @param string $column_name The key for the column for which we should output our content.
|
71 |
+
* @param int $post_id The ID of the 'scheduled-action' post for which this row relates.
|
72 |
*/
|
73 |
public static function list_table_column_content( $column_name, $post_id ) {
|
74 |
_deprecated_function( __METHOD__, '2.0.0' );
|
115 |
/**
|
116 |
* Filter search queries to allow searching by Claim ID (i.e. post_password).
|
117 |
*
|
118 |
+
* @param string $orderby MySQL orderby string.
|
119 |
* @param WP_Query $query Instance of a WP_Query object
|
120 |
* @return string MySQL orderby string.
|
121 |
*/
|
122 |
+
public function custom_orderby( $orderby, $query ){
|
123 |
_deprecated_function( __METHOD__, '2.0.0' );
|
124 |
}
|
125 |
|
126 |
/**
|
127 |
* Filter search queries to allow searching by Claim ID (i.e. post_password).
|
128 |
*
|
129 |
+
* @param string $search MySQL search string.
|
130 |
* @param WP_Query $query Instance of a WP_Query object
|
131 |
* @return string MySQL search string.
|
132 |
*/
|
144 |
_deprecated_function( __METHOD__, '2.0.0' );
|
145 |
return $messages;
|
146 |
}
|
147 |
+
}
|
lite/includes/libraries/action-scheduler/deprecated/ActionScheduler_Schedule_Deprecated.php
CHANGED
@@ -9,7 +9,7 @@ abstract class ActionScheduler_Schedule_Deprecated implements ActionScheduler_Sc
|
|
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 |
*/
|
@@ -22,7 +22,7 @@ abstract class ActionScheduler_Schedule_Deprecated implements ActionScheduler_Sc
|
|
22 |
$replacement_method = 'get_next( $after )';
|
23 |
}
|
24 |
|
25 |
-
_deprecated_function( __METHOD__, '3.0.0', __CLASS__ . '::' . $replacement_method );
|
26 |
|
27 |
return $return_value;
|
28 |
}
|
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 DateTime to calculate against.
|
13 |
*
|
14 |
* @return DateTime|null
|
15 |
*/
|
22 |
$replacement_method = 'get_next( $after )';
|
23 |
}
|
24 |
|
25 |
+
_deprecated_function( __METHOD__, '3.0.0', __CLASS__ . '::' . $replacement_method ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
26 |
|
27 |
return $return_value;
|
28 |
}
|
lite/includes/libraries/action-scheduler/deprecated/ActionScheduler_Store_Deprecated.php
CHANGED
@@ -2,7 +2,6 @@
|
|
2 |
|
3 |
/**
|
4 |
* Class ActionScheduler_Store_Deprecated
|
5 |
-
*
|
6 |
* @codeCoverageIgnore
|
7 |
*/
|
8 |
abstract class ActionScheduler_Store_Deprecated {
|
2 |
|
3 |
/**
|
4 |
* Class ActionScheduler_Store_Deprecated
|
|
|
5 |
* @codeCoverageIgnore
|
6 |
*/
|
7 |
abstract class ActionScheduler_Store_Deprecated {
|
lite/includes/libraries/action-scheduler/deprecated/functions.php
CHANGED
@@ -11,9 +11,9 @@
|
|
11 |
/**
|
12 |
* Schedule an action to run one time
|
13 |
*
|
14 |
-
* @param int
|
15 |
* @param string $hook The hook to trigger
|
16 |
-
* @param array
|
17 |
* @param string $group The group to assign this job to
|
18 |
*
|
19 |
* @return string The job ID
|
@@ -26,10 +26,10 @@ function wc_schedule_single_action( $timestamp, $hook, $args = array(), $group =
|
|
26 |
/**
|
27 |
* Schedule a recurring action
|
28 |
*
|
29 |
-
* @param int
|
30 |
-
* @param int
|
31 |
* @param string $hook The hook to trigger
|
32 |
-
* @param array
|
33 |
* @param string $group The group to assign this job to
|
34 |
*
|
35 |
* @deprecated 2.1.0
|
@@ -44,7 +44,7 @@ function wc_schedule_recurring_action( $timestamp, $interval_in_seconds, $hook,
|
|
44 |
/**
|
45 |
* Schedule an action that recurs on a cron-like schedule.
|
46 |
*
|
47 |
-
* @param int
|
48 |
* @param string $schedule A cron-link schedule string
|
49 |
* @see http://en.wikipedia.org/wiki/Cron
|
50 |
* * * * * * *
|
@@ -57,7 +57,7 @@ function wc_schedule_recurring_action( $timestamp, $interval_in_seconds, $hook,
|
|
57 |
* | +-------------------- hour (0 - 23)
|
58 |
* +------------------------- min (0 - 59)
|
59 |
* @param string $hook The hook to trigger
|
60 |
-
* @param array
|
61 |
* @param string $group The group to assign this job to
|
62 |
*
|
63 |
* @deprecated 2.1.0
|
@@ -73,7 +73,7 @@ function wc_schedule_cron_action( $timestamp, $schedule, $hook, $args = array(),
|
|
73 |
* Cancel the next occurrence of a job.
|
74 |
*
|
75 |
* @param string $hook The hook that the job will trigger
|
76 |
-
* @param array
|
77 |
* @param string $group
|
78 |
*
|
79 |
* @deprecated 2.1.0
|
@@ -85,14 +85,14 @@ function wc_unschedule_action( $hook, $args = array(), $group = '' ) {
|
|
85 |
|
86 |
/**
|
87 |
* @param string $hook
|
88 |
-
* @param array
|
89 |
* @param string $group
|
90 |
*
|
91 |
* @deprecated 2.1.0
|
92 |
*
|
93 |
* @return int|bool The timestamp for the next occurrence, or false if nothing was found
|
94 |
*/
|
95 |
-
function wc_next_scheduled_action( $hook, $args =
|
96 |
_deprecated_function( __FUNCTION__, '2.1.0', 'as_next_scheduled_action()' );
|
97 |
return as_next_scheduled_action( $hook, $args, $group );
|
98 |
}
|
@@ -100,20 +100,20 @@ function wc_next_scheduled_action( $hook, $args = null, $group = '' ) {
|
|
100 |
/**
|
101 |
* Find scheduled actions
|
102 |
*
|
103 |
-
* @param array
|
104 |
-
*
|
105 |
-
*
|
106 |
-
*
|
107 |
-
*
|
108 |
-
*
|
109 |
-
*
|
110 |
-
*
|
111 |
-
*
|
112 |
-
*
|
113 |
-
*
|
114 |
-
*
|
115 |
-
*
|
116 |
-
*
|
117 |
* @param string $return_format OBJECT, ARRAY_A, or ids
|
118 |
*
|
119 |
* @deprecated 2.1.0
|
11 |
/**
|
12 |
* Schedule an action to run one time
|
13 |
*
|
14 |
+
* @param int $timestamp When the job will run
|
15 |
* @param string $hook The hook to trigger
|
16 |
+
* @param array $args Arguments to pass when the hook triggers
|
17 |
* @param string $group The group to assign this job to
|
18 |
*
|
19 |
* @return string The job ID
|
26 |
/**
|
27 |
* Schedule a recurring action
|
28 |
*
|
29 |
+
* @param int $timestamp When the first instance of the job will run
|
30 |
+
* @param int $interval_in_seconds How long to wait between runs
|
31 |
* @param string $hook The hook to trigger
|
32 |
+
* @param array $args Arguments to pass when the hook triggers
|
33 |
* @param string $group The group to assign this job to
|
34 |
*
|
35 |
* @deprecated 2.1.0
|
44 |
/**
|
45 |
* Schedule an action that recurs on a cron-like schedule.
|
46 |
*
|
47 |
+
* @param int $timestamp The schedule will start on or after this time
|
48 |
* @param string $schedule A cron-link schedule string
|
49 |
* @see http://en.wikipedia.org/wiki/Cron
|
50 |
* * * * * * *
|
57 |
* | +-------------------- hour (0 - 23)
|
58 |
* +------------------------- min (0 - 59)
|
59 |
* @param string $hook The hook to trigger
|
60 |
+
* @param array $args Arguments to pass when the hook triggers
|
61 |
* @param string $group The group to assign this job to
|
62 |
*
|
63 |
* @deprecated 2.1.0
|
73 |
* Cancel the next occurrence of a job.
|
74 |
*
|
75 |
* @param string $hook The hook that the job will trigger
|
76 |
+
* @param array $args Args that would have been passed to the job
|
77 |
* @param string $group
|
78 |
*
|
79 |
* @deprecated 2.1.0
|
85 |
|
86 |
/**
|
87 |
* @param string $hook
|
88 |
+
* @param array $args
|
89 |
* @param string $group
|
90 |
*
|
91 |
* @deprecated 2.1.0
|
92 |
*
|
93 |
* @return int|bool The timestamp for the next occurrence, or false if nothing was found
|
94 |
*/
|
95 |
+
function wc_next_scheduled_action( $hook, $args = NULL, $group = '' ) {
|
96 |
_deprecated_function( __FUNCTION__, '2.1.0', 'as_next_scheduled_action()' );
|
97 |
return as_next_scheduled_action( $hook, $args, $group );
|
98 |
}
|
100 |
/**
|
101 |
* Find scheduled actions
|
102 |
*
|
103 |
+
* @param array $args Possible arguments, with their default values:
|
104 |
+
* 'hook' => '' - the name of the action that will be triggered
|
105 |
+
* 'args' => NULL - the args array that will be passed with the action
|
106 |
+
* 'date' => NULL - the scheduled date of the action. Expects a DateTime object, a unix timestamp, or a string that can parsed with strtotime(). Used in UTC timezone.
|
107 |
+
* 'date_compare' => '<=' - operator for testing "date". accepted values are '!=', '>', '>=', '<', '<=', '='
|
108 |
+
* 'modified' => NULL - the date the action was last updated. Expects a DateTime object, a unix timestamp, or a string that can parsed with strtotime(). Used in UTC timezone.
|
109 |
+
* 'modified_compare' => '<=' - operator for testing "modified". accepted values are '!=', '>', '>=', '<', '<=', '='
|
110 |
+
* 'group' => '' - the group the action belongs to
|
111 |
+
* 'status' => '' - ActionScheduler_Store::STATUS_COMPLETE or ActionScheduler_Store::STATUS_PENDING
|
112 |
+
* 'claimed' => NULL - TRUE to find claimed actions, FALSE to find unclaimed actions, a string to find a specific claim ID
|
113 |
+
* 'per_page' => 5 - Number of results to return
|
114 |
+
* 'offset' => 0
|
115 |
+
* 'orderby' => 'date' - accepted values are 'hook', 'group', 'modified', or 'date'
|
116 |
+
* 'order' => 'ASC'
|
117 |
* @param string $return_format OBJECT, ARRAY_A, or ids
|
118 |
*
|
119 |
* @deprecated 2.1.0
|
lite/includes/libraries/action-scheduler/functions.php
CHANGED
@@ -22,9 +22,9 @@ function as_enqueue_async_action( $hook, $args = array(), $group = '' ) {
|
|
22 |
/**
|
23 |
* Schedule an action to run one time
|
24 |
*
|
25 |
-
* @param int
|
26 |
* @param string $hook The hook to trigger.
|
27 |
-
* @param array
|
28 |
* @param string $group The group to assign this job to.
|
29 |
*
|
30 |
* @return int The action ID.
|
@@ -39,10 +39,10 @@ function as_schedule_single_action( $timestamp, $hook, $args = array(), $group =
|
|
39 |
/**
|
40 |
* Schedule a recurring action
|
41 |
*
|
42 |
-
* @param int
|
43 |
-
* @param int
|
44 |
* @param string $hook The hook to trigger.
|
45 |
-
* @param array
|
46 |
* @param string $group The group to assign this job to.
|
47 |
*
|
48 |
* @return int The action ID.
|
@@ -57,9 +57,9 @@ function as_schedule_recurring_action( $timestamp, $interval_in_seconds, $hook,
|
|
57 |
/**
|
58 |
* Schedule an action that recurs on a cron-like schedule.
|
59 |
*
|
60 |
-
* @param int
|
61 |
-
*
|
62 |
-
*
|
63 |
* @param string $schedule A cron-link schedule string
|
64 |
* @see http://en.wikipedia.org/wiki/Cron
|
65 |
* * * * * * *
|
@@ -72,7 +72,7 @@ function as_schedule_recurring_action( $timestamp, $interval_in_seconds, $hook,
|
|
72 |
* | +-------------------- hour (0 - 23)
|
73 |
* +------------------------- min (0 - 59)
|
74 |
* @param string $hook The hook to trigger.
|
75 |
-
* @param array
|
76 |
* @param string $group The group to assign this job to.
|
77 |
*
|
78 |
* @return int The action ID.
|
@@ -95,7 +95,7 @@ function as_schedule_cron_action( $timestamp, $schedule, $hook, $args = array(),
|
|
95 |
* by this method also.
|
96 |
*
|
97 |
* @param string $hook The hook that the job will trigger.
|
98 |
-
* @param array
|
99 |
* @param string $group The group the job is assigned to.
|
100 |
*
|
101 |
* @return string|null The scheduled action ID if a scheduled action was found, or null if no matching action found.
|
@@ -104,27 +104,30 @@ function as_unschedule_action( $hook, $args = array(), $group = '' ) {
|
|
104 |
if ( ! ActionScheduler::is_initialized( __FUNCTION__ ) ) {
|
105 |
return 0;
|
106 |
}
|
107 |
-
$params = array(
|
|
|
|
|
|
|
|
|
|
|
|
|
108 |
if ( is_array( $args ) ) {
|
109 |
$params['args'] = $args;
|
110 |
}
|
111 |
-
if ( ! empty( $group ) ) {
|
112 |
-
$params['group'] = $group;
|
113 |
-
}
|
114 |
-
$job_id = ActionScheduler::store()->find_action( $hook, $params );
|
115 |
|
116 |
-
|
117 |
-
|
|
|
118 |
}
|
119 |
|
120 |
-
return $
|
121 |
}
|
122 |
|
123 |
/**
|
124 |
* Cancel all occurrences of a scheduled action.
|
125 |
*
|
126 |
* @param string $hook The hook that the job will trigger.
|
127 |
-
* @param array
|
128 |
* @param string $group The group the job is assigned to.
|
129 |
*/
|
130 |
function as_unschedule_all_actions( $hook, $args = array(), $group = '' ) {
|
@@ -156,7 +159,7 @@ function as_unschedule_all_actions( $hook, $args = array(), $group = '' ) {
|
|
156 |
* boolean false will be the return value.
|
157 |
*
|
158 |
* @param string $hook
|
159 |
-
* @param array
|
160 |
* @param string $group
|
161 |
*
|
162 |
* @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.
|
@@ -165,52 +168,93 @@ function as_next_scheduled_action( $hook, $args = null, $group = '' ) {
|
|
165 |
if ( ! ActionScheduler::is_initialized( __FUNCTION__ ) ) {
|
166 |
return false;
|
167 |
}
|
168 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
169 |
if ( is_array( $args ) ) {
|
170 |
$params['args'] = $args;
|
171 |
}
|
172 |
-
if ( ! empty( $group ) ) {
|
173 |
-
$params['group'] = $group;
|
174 |
-
}
|
175 |
|
176 |
$params['status'] = ActionScheduler_Store::STATUS_RUNNING;
|
177 |
-
$
|
178 |
-
if (
|
179 |
return true;
|
180 |
}
|
181 |
|
182 |
$params['status'] = ActionScheduler_Store::STATUS_PENDING;
|
183 |
-
$
|
184 |
-
if (
|
185 |
return false;
|
186 |
}
|
187 |
-
|
188 |
-
$
|
|
|
189 |
if ( $scheduled_date ) {
|
190 |
return (int) $scheduled_date->format( 'U' );
|
191 |
} elseif ( null === $scheduled_date ) { // pending async action with NullSchedule
|
192 |
return true;
|
193 |
}
|
|
|
194 |
return false;
|
195 |
}
|
196 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
197 |
/**
|
198 |
* Find scheduled actions
|
199 |
*
|
200 |
-
* @param array
|
201 |
-
*
|
202 |
-
*
|
203 |
-
*
|
204 |
-
*
|
205 |
-
*
|
206 |
-
*
|
207 |
-
*
|
208 |
-
*
|
209 |
-
*
|
210 |
-
*
|
211 |
-
*
|
212 |
-
*
|
213 |
-
*
|
214 |
*
|
215 |
* @param string $return_format OBJECT, ARRAY_A, or ids.
|
216 |
*
|
@@ -221,9 +265,9 @@ function as_get_scheduled_actions( $args = array(), $return_format = OBJECT ) {
|
|
221 |
return array();
|
222 |
}
|
223 |
$store = ActionScheduler::store();
|
224 |
-
foreach ( array(
|
225 |
-
if ( isset(
|
226 |
-
$args[
|
227 |
}
|
228 |
}
|
229 |
$ids = $store->query_actions( $args );
|
@@ -234,12 +278,12 @@ function as_get_scheduled_actions( $args = array(), $return_format = OBJECT ) {
|
|
234 |
|
235 |
$actions = array();
|
236 |
foreach ( $ids as $action_id ) {
|
237 |
-
$actions[
|
238 |
}
|
239 |
|
240 |
if ( $return_format == ARRAY_A ) {
|
241 |
foreach ( $actions as $action_id => $action_object ) {
|
242 |
-
$actions[
|
243 |
}
|
244 |
}
|
245 |
|
@@ -258,7 +302,7 @@ function as_get_scheduled_actions( $args = array(), $return_format = OBJECT ) {
|
|
258 |
* timezone when instantiating datetimes rather than leaving it up to
|
259 |
* the PHP default.
|
260 |
*
|
261 |
-
* @param mixed
|
262 |
* @param string $timezone A timezone identifier, like UTC or Europe/Lisbon. The list of valid identifiers is available http://php.net/manual/en/timezones.php.
|
263 |
*
|
264 |
* @return ActionScheduler_DateTime
|
22 |
/**
|
23 |
* Schedule an action to run one time
|
24 |
*
|
25 |
+
* @param int $timestamp When the job will run.
|
26 |
* @param string $hook The hook to trigger.
|
27 |
+
* @param array $args Arguments to pass when the hook triggers.
|
28 |
* @param string $group The group to assign this job to.
|
29 |
*
|
30 |
* @return int The action ID.
|
39 |
/**
|
40 |
* Schedule a recurring action
|
41 |
*
|
42 |
+
* @param int $timestamp When the first instance of the job will run.
|
43 |
+
* @param int $interval_in_seconds How long to wait between runs.
|
44 |
* @param string $hook The hook to trigger.
|
45 |
+
* @param array $args Arguments to pass when the hook triggers.
|
46 |
* @param string $group The group to assign this job to.
|
47 |
*
|
48 |
* @return int The action ID.
|
57 |
/**
|
58 |
* Schedule an action that recurs on a cron-like schedule.
|
59 |
*
|
60 |
+
* @param int $base_timestamp The first instance of the action will be scheduled
|
61 |
+
* to run at a time calculated after this timestamp matching the cron
|
62 |
+
* expression. This can be used to delay the first instance of the action.
|
63 |
* @param string $schedule A cron-link schedule string
|
64 |
* @see http://en.wikipedia.org/wiki/Cron
|
65 |
* * * * * * *
|
72 |
* | +-------------------- hour (0 - 23)
|
73 |
* +------------------------- min (0 - 59)
|
74 |
* @param string $hook The hook to trigger.
|
75 |
+
* @param array $args Arguments to pass when the hook triggers.
|
76 |
* @param string $group The group to assign this job to.
|
77 |
*
|
78 |
* @return int The action ID.
|
95 |
* by this method also.
|
96 |
*
|
97 |
* @param string $hook The hook that the job will trigger.
|
98 |
+
* @param array $args Args that would have been passed to the job.
|
99 |
* @param string $group The group the job is assigned to.
|
100 |
*
|
101 |
* @return string|null The scheduled action ID if a scheduled action was found, or null if no matching action found.
|
104 |
if ( ! ActionScheduler::is_initialized( __FUNCTION__ ) ) {
|
105 |
return 0;
|
106 |
}
|
107 |
+
$params = array(
|
108 |
+
'hook' => $hook,
|
109 |
+
'status' => ActionScheduler_Store::STATUS_PENDING,
|
110 |
+
'orderby' => 'date',
|
111 |
+
'order' => 'ASC',
|
112 |
+
'group' => $group,
|
113 |
+
);
|
114 |
if ( is_array( $args ) ) {
|
115 |
$params['args'] = $args;
|
116 |
}
|
|
|
|
|
|
|
|
|
117 |
|
118 |
+
$action_id = ActionScheduler::store()->query_action( $params );
|
119 |
+
if ( $action_id ) {
|
120 |
+
ActionScheduler::store()->cancel_action( $action_id );
|
121 |
}
|
122 |
|
123 |
+
return $action_id;
|
124 |
}
|
125 |
|
126 |
/**
|
127 |
* Cancel all occurrences of a scheduled action.
|
128 |
*
|
129 |
* @param string $hook The hook that the job will trigger.
|
130 |
+
* @param array $args Args that would have been passed to the job.
|
131 |
* @param string $group The group the job is assigned to.
|
132 |
*/
|
133 |
function as_unschedule_all_actions( $hook, $args = array(), $group = '' ) {
|
159 |
* boolean false will be the return value.
|
160 |
*
|
161 |
* @param string $hook
|
162 |
+
* @param array $args
|
163 |
* @param string $group
|
164 |
*
|
165 |
* @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.
|
168 |
if ( ! ActionScheduler::is_initialized( __FUNCTION__ ) ) {
|
169 |
return false;
|
170 |
}
|
171 |
+
|
172 |
+
$params = array(
|
173 |
+
'hook' => $hook,
|
174 |
+
'orderby' => 'date',
|
175 |
+
'order' => 'ASC',
|
176 |
+
'group' => $group,
|
177 |
+
);
|
178 |
+
|
179 |
if ( is_array( $args ) ) {
|
180 |
$params['args'] = $args;
|
181 |
}
|
|
|
|
|
|
|
182 |
|
183 |
$params['status'] = ActionScheduler_Store::STATUS_RUNNING;
|
184 |
+
$action_id = ActionScheduler::store()->query_action( $params );
|
185 |
+
if ( $action_id ) {
|
186 |
return true;
|
187 |
}
|
188 |
|
189 |
$params['status'] = ActionScheduler_Store::STATUS_PENDING;
|
190 |
+
$action_id = ActionScheduler::store()->query_action( $params );
|
191 |
+
if ( null === $action_id ) {
|
192 |
return false;
|
193 |
}
|
194 |
+
|
195 |
+
$action = ActionScheduler::store()->fetch_action( $action_id );
|
196 |
+
$scheduled_date = $action->get_schedule()->get_date();
|
197 |
if ( $scheduled_date ) {
|
198 |
return (int) $scheduled_date->format( 'U' );
|
199 |
} elseif ( null === $scheduled_date ) { // pending async action with NullSchedule
|
200 |
return true;
|
201 |
}
|
202 |
+
|
203 |
return false;
|
204 |
}
|
205 |
|
206 |
+
/**
|
207 |
+
* Check if there is a scheduled action in the queue but more efficiently than as_next_scheduled_action().
|
208 |
+
*
|
209 |
+
* It's recommended to use this function when you need to know whether a specific action is currently scheduled
|
210 |
+
* (pending or in-progress).
|
211 |
+
*
|
212 |
+
* @since x.x.x
|
213 |
+
*
|
214 |
+
* @param string $hook The hook of the action.
|
215 |
+
* @param array $args Args that have been passed to the action. Null will matches any args.
|
216 |
+
* @param string $group The group the job is assigned to.
|
217 |
+
*
|
218 |
+
* @return bool True if a matching action is pending or in-progress, false otherwise.
|
219 |
+
*/
|
220 |
+
function as_has_scheduled_action( $hook, $args = null, $group = '' ) {
|
221 |
+
if ( ! ActionScheduler::is_initialized( __FUNCTION__ ) ) {
|
222 |
+
return false;
|
223 |
+
}
|
224 |
+
|
225 |
+
$query_args = array(
|
226 |
+
'hook' => $hook,
|
227 |
+
'status' => array( ActionScheduler_Store::STATUS_RUNNING, ActionScheduler_Store::STATUS_PENDING ),
|
228 |
+
'group' => $group,
|
229 |
+
'orderby' => 'none',
|
230 |
+
);
|
231 |
+
|
232 |
+
if ( null !== $args ) {
|
233 |
+
$query_args['args'] = $args;
|
234 |
+
}
|
235 |
+
|
236 |
+
$action_id = ActionScheduler::store()->query_action( $query_args );
|
237 |
+
|
238 |
+
return $action_id !== null;
|
239 |
+
}
|
240 |
+
|
241 |
/**
|
242 |
* Find scheduled actions
|
243 |
*
|
244 |
+
* @param array $args Possible arguments, with their default values:
|
245 |
+
* 'hook' => '' - the name of the action that will be triggered
|
246 |
+
* 'args' => NULL - the args array that will be passed with the action
|
247 |
+
* 'date' => NULL - the scheduled date of the action. Expects a DateTime object, a unix timestamp, or a string that can parsed with strtotime(). Used in UTC timezone.
|
248 |
+
* 'date_compare' => '<=' - operator for testing "date". accepted values are '!=', '>', '>=', '<', '<=', '='
|
249 |
+
* 'modified' => NULL - the date the action was last updated. Expects a DateTime object, a unix timestamp, or a string that can parsed with strtotime(). Used in UTC timezone.
|
250 |
+
* 'modified_compare' => '<=' - operator for testing "modified". accepted values are '!=', '>', '>=', '<', '<=', '='
|
251 |
+
* 'group' => '' - the group the action belongs to
|
252 |
+
* 'status' => '' - ActionScheduler_Store::STATUS_COMPLETE or ActionScheduler_Store::STATUS_PENDING
|
253 |
+
* 'claimed' => NULL - TRUE to find claimed actions, FALSE to find unclaimed actions, a string to find a specific claim ID
|
254 |
+
* 'per_page' => 5 - Number of results to return
|
255 |
+
* 'offset' => 0
|
256 |
+
* 'orderby' => 'date' - accepted values are 'hook', 'group', 'modified', 'date' or 'none'
|
257 |
+
* 'order' => 'ASC'
|
258 |
*
|
259 |
* @param string $return_format OBJECT, ARRAY_A, or ids.
|
260 |
*
|
265 |
return array();
|
266 |
}
|
267 |
$store = ActionScheduler::store();
|
268 |
+
foreach ( array('date', 'modified') as $key ) {
|
269 |
+
if ( isset($args[$key]) ) {
|
270 |
+
$args[$key] = as_get_datetime_object($args[$key]);
|
271 |
}
|
272 |
}
|
273 |
$ids = $store->query_actions( $args );
|
278 |
|
279 |
$actions = array();
|
280 |
foreach ( $ids as $action_id ) {
|
281 |
+
$actions[$action_id] = $store->fetch_action( $action_id );
|
282 |
}
|
283 |
|
284 |
if ( $return_format == ARRAY_A ) {
|
285 |
foreach ( $actions as $action_id => $action_object ) {
|
286 |
+
$actions[$action_id] = get_object_vars($action_object);
|
287 |
}
|
288 |
}
|
289 |
|
302 |
* timezone when instantiating datetimes rather than leaving it up to
|
303 |
* the PHP default.
|
304 |
*
|
305 |
+
* @param mixed $date_string A date/time string. Valid formats are explained in http://php.net/manual/en/datetime.formats.php.
|
306 |
* @param string $timezone A timezone identifier, like UTC or Europe/Lisbon. The list of valid identifiers is available http://php.net/manual/en/timezones.php.
|
307 |
*
|
308 |
* @return ActionScheduler_DateTime
|
lite/includes/libraries/action-scheduler/lib/cron-expression/CronExpression.php
CHANGED
@@ -13,295 +13,306 @@
|
|
13 |
* @author Michael Dowling <mtdowling@gmail.com>
|
14 |
* @link http://en.wikipedia.org/wiki/Cron
|
15 |
*/
|
16 |
-
class CronExpression
|
17 |
-
|
18 |
-
|
19 |
-
|
20 |
-
|
21 |
-
|
22 |
-
|
23 |
-
|
24 |
-
|
25 |
-
|
26 |
-
|
27 |
-
|
28 |
-
|
29 |
-
|
30 |
-
|
31 |
-
|
32 |
-
|
33 |
-
|
34 |
-
|
35 |
-
|
36 |
-
|
37 |
-
|
38 |
-
|
39 |
-
|
40 |
-
|
41 |
-
|
42 |
-
|
43 |
-
|
44 |
-
|
45 |
-
|
46 |
-
|
47 |
-
|
48 |
-
|
49 |
-
|
50 |
-
|
51 |
-
|
52 |
-
|
53 |
-
|
54 |
-
|
55 |
-
|
56 |
-
|
57 |
-
|
58 |
-
|
59 |
-
|
60 |
-
|
61 |
-
|
62 |
-
|
63 |
-
|
64 |
-
|
65 |
-
|
66 |
-
|
67 |
-
|
68 |
-
|
69 |
-
|
70 |
-
|
71 |
-
|
72 |
-
|
73 |
-
|
74 |
-
|
75 |
-
|
76 |
-
|
77 |
-
|
78 |
-
|
79 |
-
|
80 |
-
|
81 |
-
|
82 |
-
|
83 |
-
|
84 |
-
|
85 |
-
|
86 |
-
|
87 |
-
|
88 |
-
|
89 |
-
|
90 |
-
|
91 |
-
|
92 |
-
|
93 |
-
|
94 |
-
|
95 |
-
|
96 |
-
|
97 |
-
|
98 |
-
|
99 |
-
|
100 |
-
|
101 |
-
|
102 |
-
|
103 |
-
|
104 |
-
|
105 |
-
|
106 |
-
|
107 |
-
|
108 |
-
|
109 |
-
|
110 |
-
|
111 |
-
|
112 |
-
|
113 |
-
|
114 |
-
|
115 |
-
|
116 |
-
|
117 |
-
|
118 |
-
|
119 |
-
|
120 |
-
|
121 |
-
|
122 |
-
|
123 |
-
|
124 |
-
|
125 |
-
|
126 |
-
|
127 |
-
|
128 |
-
|
129 |
-
|
130 |
-
|
131 |
-
|
132 |
-
|
133 |
-
|
134 |
-
|
135 |
-
|
136 |
-
|
137 |
-
|
138 |
-
|
139 |
-
|
140 |
-
|
141 |
-
|
142 |
-
|
143 |
-
|
144 |
-
|
145 |
-
|
146 |
-
|
147 |
-
|
148 |
-
|
149 |
-
|
150 |
-
|
151 |
-
|
152 |
-
|
153 |
-
|
154 |
-
|
155 |
-
|
156 |
-
|
157 |
-
|
158 |
-
|
159 |
-
|
160 |
-
|
161 |
-
|
162 |
-
|
163 |
-
|
164 |
-
|
165 |
-
|
166 |
-
|
167 |
-
|
168 |
-
|
169 |
-
|
170 |
-
|
171 |
-
|
172 |
-
|
173 |
-
|
174 |
-
|
175 |
-
|
176 |
-
|
177 |
-
|
178 |
-
|
179 |
-
|
180 |
-
|
181 |
-
|
182 |
-
|
183 |
-
|
184 |
-
|
185 |
-
|
186 |
-
|
187 |
-
|
188 |
-
|
189 |
-
|
190 |
-
|
191 |
-
|
192 |
-
|
193 |
-
|
194 |
-
|
195 |
-
|
196 |
-
|
197 |
-
|
198 |
-
|
199 |
-
|
200 |
-
|
201 |
-
|
202 |
-
|
203 |
-
|
204 |
-
|
205 |
-
|
206 |
-
|
207 |
-
|
208 |
-
|
209 |
-
|
210 |
-
|
211 |
-
|
212 |
-
|
213 |
-
|
214 |
-
|
215 |
-
|
216 |
-
|
217 |
-
|
218 |
-
|
219 |
-
|
220 |
-
|
221 |
-
|
222 |
-
|
223 |
-
|
224 |
-
|
225 |
-
|
226 |
-
|
227 |
-
|
228 |
-
|
229 |
-
|
230 |
-
|
231 |
-
|
232 |
-
|
233 |
-
|
234 |
-
|
235 |
-
|
236 |
-
|
237 |
-
|
238 |
-
|
239 |
-
|
240 |
-
|
241 |
-
|
242 |
-
|
243 |
-
|
244 |
-
|
245 |
-
|
246 |
-
|
247 |
-
|
248 |
-
|
249 |
-
|
250 |
-
|
251 |
-
|
252 |
-
|
253 |
-
|
254 |
-
|
255 |
-
|
256 |
-
|
257 |
-
|
258 |
-
|
259 |
-
|
260 |
-
|
261 |
-
|
262 |
-
|
263 |
-
|
264 |
-
|
265 |
-
|
266 |
-
|
267 |
-
|
268 |
-
|
269 |
-
|
270 |
-
|
271 |
-
|
272 |
-
|
273 |
-
|
274 |
-
|
275 |
-
|
276 |
-
|
277 |
-
|
278 |
-
|
279 |
-
|
280 |
-
|
281 |
-
|
282 |
-
|
283 |
-
|
284 |
-
|
285 |
-
|
286 |
-
|
287 |
-
|
288 |
-
|
289 |
-
|
290 |
-
|
291 |
-
|
292 |
-
|
293 |
-
|
294 |
-
|
295 |
-
|
296 |
-
|
297 |
-
|
298 |
-
|
299 |
-
|
300 |
-
|
301 |
-
|
302 |
-
|
303 |
-
|
304 |
-
|
305 |
-
|
306 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
307 |
}
|
13 |
* @author Michael Dowling <mtdowling@gmail.com>
|
14 |
* @link http://en.wikipedia.org/wiki/Cron
|
15 |
*/
|
16 |
+
class CronExpression
|
17 |
+
{
|
18 |
+
const MINUTE = 0;
|
19 |
+
const HOUR = 1;
|
20 |
+
const DAY = 2;
|
21 |
+
const MONTH = 3;
|
22 |
+
const WEEKDAY = 4;
|
23 |
+
const YEAR = 5;
|
24 |
+
|
25 |
+
/**
|
26 |
+
* @var array CRON expression parts
|
27 |
+
*/
|
28 |
+
private $cronParts;
|
29 |
+
|
30 |
+
/**
|
31 |
+
* @var CronExpression_FieldFactory CRON field factory
|
32 |
+
*/
|
33 |
+
private $fieldFactory;
|
34 |
+
|
35 |
+
/**
|
36 |
+
* @var array Order in which to test of cron parts
|
37 |
+
*/
|
38 |
+
private static $order = array(self::YEAR, self::MONTH, self::DAY, self::WEEKDAY, self::HOUR, self::MINUTE);
|
39 |
+
|
40 |
+
/**
|
41 |
+
* Factory method to create a new CronExpression.
|
42 |
+
*
|
43 |
+
* @param string $expression The CRON expression to create. There are
|
44 |
+
* several special predefined values which can be used to substitute the
|
45 |
+
* CRON expression:
|
46 |
+
*
|
47 |
+
* @yearly, @annually) - Run once a year, midnight, Jan. 1 - 0 0 1 1 *
|
48 |
+
* @monthly - Run once a month, midnight, first of month - 0 0 1 * *
|
49 |
+
* @weekly - Run once a week, midnight on Sun - 0 0 * * 0
|
50 |
+
* @daily - Run once a day, midnight - 0 0 * * *
|
51 |
+
* @hourly - Run once an hour, first minute - 0 * * * *
|
52 |
+
*
|
53 |
+
*@param CronExpression_FieldFactory $fieldFactory (optional) Field factory to use
|
54 |
+
*
|
55 |
+
* @return CronExpression
|
56 |
+
*/
|
57 |
+
public static function factory($expression, CronExpression_FieldFactory $fieldFactory = null)
|
58 |
+
{
|
59 |
+
$mappings = array(
|
60 |
+
'@yearly' => '0 0 1 1 *',
|
61 |
+
'@annually' => '0 0 1 1 *',
|
62 |
+
'@monthly' => '0 0 1 * *',
|
63 |
+
'@weekly' => '0 0 * * 0',
|
64 |
+
'@daily' => '0 0 * * *',
|
65 |
+
'@hourly' => '0 * * * *'
|
66 |
+
);
|
67 |
+
|
68 |
+
if (isset($mappings[$expression])) {
|
69 |
+
$expression = $mappings[$expression];
|
70 |
+
}
|
71 |
+
|
72 |
+
return new self($expression, $fieldFactory ? $fieldFactory : new CronExpression_FieldFactory());
|
73 |
+
}
|
74 |
+
|
75 |
+
/**
|
76 |
+
* Parse a CRON expression
|
77 |
+
*
|
78 |
+
* @param string $expression CRON expression (e.g. '8 * * * *')
|
79 |
+
* @param CronExpression_FieldFactory $fieldFactory Factory to create cron fields
|
80 |
+
*/
|
81 |
+
public function __construct($expression, CronExpression_FieldFactory $fieldFactory)
|
82 |
+
{
|
83 |
+
$this->fieldFactory = $fieldFactory;
|
84 |
+
$this->setExpression($expression);
|
85 |
+
}
|
86 |
+
|
87 |
+
/**
|
88 |
+
* Set or change the CRON expression
|
89 |
+
*
|
90 |
+
* @param string $value CRON expression (e.g. 8 * * * *)
|
91 |
+
*
|
92 |
+
* @return CronExpression
|
93 |
+
* @throws InvalidArgumentException if not a valid CRON expression
|
94 |
+
*/
|
95 |
+
public function setExpression($value)
|
96 |
+
{
|
97 |
+
$this->cronParts = preg_split('/\s/', $value, -1, PREG_SPLIT_NO_EMPTY);
|
98 |
+
if (count($this->cronParts) < 5) {
|
99 |
+
throw new InvalidArgumentException(
|
100 |
+
$value . ' is not a valid CRON expression'
|
101 |
+
);
|
102 |
+
}
|
103 |
+
|
104 |
+
foreach ($this->cronParts as $position => $part) {
|
105 |
+
$this->setPart($position, $part);
|
106 |
+
}
|
107 |
+
|
108 |
+
return $this;
|
109 |
+
}
|
110 |
+
|
111 |
+
/**
|
112 |
+
* Set part of the CRON expression
|
113 |
+
*
|
114 |
+
* @param int $position The position of the CRON expression to set
|
115 |
+
* @param string $value The value to set
|
116 |
+
*
|
117 |
+
* @return CronExpression
|
118 |
+
* @throws InvalidArgumentException if the value is not valid for the part
|
119 |
+
*/
|
120 |
+
public function setPart($position, $value)
|
121 |
+
{
|
122 |
+
if (!$this->fieldFactory->getField($position)->validate($value)) {
|
123 |
+
throw new InvalidArgumentException(
|
124 |
+
'Invalid CRON field value ' . $value . ' as position ' . $position
|
125 |
+
);
|
126 |
+
}
|
127 |
+
|
128 |
+
$this->cronParts[$position] = $value;
|
129 |
+
|
130 |
+
return $this;
|
131 |
+
}
|
132 |
+
|
133 |
+
/**
|
134 |
+
* Get a next run date relative to the current date or a specific date
|
135 |
+
*
|
136 |
+
* @param string|DateTime $currentTime (optional) Relative calculation date
|
137 |
+
* @param int $nth (optional) Number of matches to skip before returning a
|
138 |
+
* matching next run date. 0, the default, will return the current
|
139 |
+
* date and time if the next run date falls on the current date and
|
140 |
+
* time. Setting this value to 1 will skip the first match and go to
|
141 |
+
* the second match. Setting this value to 2 will skip the first 2
|
142 |
+
* matches and so on.
|
143 |
+
* @param bool $allowCurrentDate (optional) Set to TRUE to return the
|
144 |
+
* current date if it matches the cron expression
|
145 |
+
*
|
146 |
+
* @return DateTime
|
147 |
+
* @throws RuntimeException on too many iterations
|
148 |
+
*/
|
149 |
+
public function getNextRunDate($currentTime = 'now', $nth = 0, $allowCurrentDate = false)
|
150 |
+
{
|
151 |
+
return $this->getRunDate($currentTime, $nth, false, $allowCurrentDate);
|
152 |
+
}
|
153 |
+
|
154 |
+
/**
|
155 |
+
* Get a previous run date relative to the current date or a specific date
|
156 |
+
*
|
157 |
+
* @param string|DateTime $currentTime (optional) Relative calculation date
|
158 |
+
* @param int $nth (optional) Number of matches to skip before returning
|
159 |
+
* @param bool $allowCurrentDate (optional) Set to TRUE to return the
|
160 |
+
* current date if it matches the cron expression
|
161 |
+
*
|
162 |
+
* @return DateTime
|
163 |
+
* @throws RuntimeException on too many iterations
|
164 |
+
* @see CronExpression::getNextRunDate
|
165 |
+
*/
|
166 |
+
public function getPreviousRunDate($currentTime = 'now', $nth = 0, $allowCurrentDate = false)
|
167 |
+
{
|
168 |
+
return $this->getRunDate($currentTime, $nth, true, $allowCurrentDate);
|
169 |
+
}
|
170 |
+
|
171 |
+
/**
|
172 |
+
* Get multiple run dates starting at the current date or a specific date
|
173 |
+
*
|
174 |
+
* @param int $total Set the total number of dates to calculate
|
175 |
+
* @param string|DateTime $currentTime (optional) Relative calculation date
|
176 |
+
* @param bool $invert (optional) Set to TRUE to retrieve previous dates
|
177 |
+
* @param bool $allowCurrentDate (optional) Set to TRUE to return the
|
178 |
+
* current date if it matches the cron expression
|
179 |
+
*
|
180 |
+
* @return array Returns an array of run dates
|
181 |
+
*/
|
182 |
+
public function getMultipleRunDates($total, $currentTime = 'now', $invert = false, $allowCurrentDate = false)
|
183 |
+
{
|
184 |
+
$matches = array();
|
185 |
+
for ($i = 0; $i < max(0, $total); $i++) {
|
186 |
+
$matches[] = $this->getRunDate($currentTime, $i, $invert, $allowCurrentDate);
|
187 |
+
}
|
188 |
+
|
189 |
+
return $matches;
|
190 |
+
}
|
191 |
+
|
192 |
+
/**
|
193 |
+
* Get all or part of the CRON expression
|
194 |
+
*
|
195 |
+
* @param string $part (optional) Specify the part to retrieve or NULL to
|
196 |
+
* get the full cron schedule string.
|
197 |
+
*
|
198 |
+
* @return string|null Returns the CRON expression, a part of the
|
199 |
+
* CRON expression, or NULL if the part was specified but not found
|
200 |
+
*/
|
201 |
+
public function getExpression($part = null)
|
202 |
+
{
|
203 |
+
if (null === $part) {
|
204 |
+
return implode(' ', $this->cronParts);
|
205 |
+
} elseif (array_key_exists($part, $this->cronParts)) {
|
206 |
+
return $this->cronParts[$part];
|
207 |
+
}
|
208 |
+
|
209 |
+
return null;
|
210 |
+
}
|
211 |
+
|
212 |
+
/**
|
213 |
+
* Helper method to output the full expression.
|
214 |
+
*
|
215 |
+
* @return string Full CRON expression
|
216 |
+
*/
|
217 |
+
public function __toString()
|
218 |
+
{
|
219 |
+
return $this->getExpression();
|
220 |
+
}
|
221 |
+
|
222 |
+
/**
|
223 |
+
* Determine if the cron is due to run based on the current date or a
|
224 |
+
* specific date. This method assumes that the current number of
|
225 |
+
* seconds are irrelevant, and should be called once per minute.
|
226 |
+
*
|
227 |
+
* @param string|DateTime $currentTime (optional) Relative calculation date
|
228 |
+
*
|
229 |
+
* @return bool Returns TRUE if the cron is due to run or FALSE if not
|
230 |
+
*/
|
231 |
+
public function isDue($currentTime = 'now')
|
232 |
+
{
|
233 |
+
if ('now' === $currentTime) {
|
234 |
+
$currentDate = date('Y-m-d H:i');
|
235 |
+
$currentTime = strtotime($currentDate);
|
236 |
+
} elseif ($currentTime instanceof DateTime) {
|
237 |
+
$currentDate = $currentTime->format('Y-m-d H:i');
|
238 |
+
$currentTime = strtotime($currentDate);
|
239 |
+
} else {
|
240 |
+
$currentTime = new DateTime($currentTime);
|
241 |
+
$currentTime->setTime($currentTime->format('H'), $currentTime->format('i'), 0);
|
242 |
+
$currentDate = $currentTime->format('Y-m-d H:i');
|
243 |
+
$currentTime = (int)($currentTime->getTimestamp());
|
244 |
+
}
|
245 |
+
|
246 |
+
return $this->getNextRunDate($currentDate, 0, true)->getTimestamp() == $currentTime;
|
247 |
+
}
|
248 |
+
|
249 |
+
/**
|
250 |
+
* Get the next or previous run date of the expression relative to a date
|
251 |
+
*
|
252 |
+
* @param string|DateTime $currentTime (optional) Relative calculation date
|
253 |
+
* @param int $nth (optional) Number of matches to skip before returning
|
254 |
+
* @param bool $invert (optional) Set to TRUE to go backwards in time
|
255 |
+
* @param bool $allowCurrentDate (optional) Set to TRUE to return the
|
256 |
+
* current date if it matches the cron expression
|
257 |
+
*
|
258 |
+
* @return DateTime
|
259 |
+
* @throws RuntimeException on too many iterations
|
260 |
+
*/
|
261 |
+
protected function getRunDate($currentTime = null, $nth = 0, $invert = false, $allowCurrentDate = false)
|
262 |
+
{
|
263 |
+
if ($currentTime instanceof DateTime) {
|
264 |
+
$currentDate = $currentTime;
|
265 |
+
} else {
|
266 |
+
$currentDate = new DateTime($currentTime ? $currentTime : 'now');
|
267 |
+
$currentDate->setTimezone(new DateTimeZone(date_default_timezone_get()));
|
268 |
+
}
|
269 |
+
|
270 |
+
$currentDate->setTime($currentDate->format('H'), $currentDate->format('i'), 0);
|
271 |
+
$nextRun = clone $currentDate;
|
272 |
+
$nth = (int) $nth;
|
273 |
+
|
274 |
+
// Set a hard limit to bail on an impossible date
|
275 |
+
for ($i = 0; $i < 1000; $i++) {
|
276 |
+
|
277 |
+
foreach (self::$order as $position) {
|
278 |
+
$part = $this->getExpression($position);
|
279 |
+
if (null === $part) {
|
280 |
+
continue;
|
281 |
+
}
|
282 |
+
|
283 |
+
$satisfied = false;
|
284 |
+
// Get the field object used to validate this part
|
285 |
+
$field = $this->fieldFactory->getField($position);
|
286 |
+
// Check if this is singular or a list
|
287 |
+
if (strpos($part, ',') === false) {
|
288 |
+
$satisfied = $field->isSatisfiedBy($nextRun, $part);
|
289 |
+
} else {
|
290 |
+
foreach (array_map('trim', explode(',', $part)) as $listPart) {
|
291 |
+
if ($field->isSatisfiedBy($nextRun, $listPart)) {
|
292 |
+
$satisfied = true;
|
293 |
+
break;
|
294 |
+
}
|
295 |
+
}
|
296 |
+
}
|
297 |
+
|
298 |
+
// If the field is not satisfied, then start over
|
299 |
+
if (!$satisfied) {
|
300 |
+
$field->increment($nextRun, $invert);
|
301 |
+
continue 2;
|
302 |
+
}
|
303 |
+
}
|
304 |
+
|
305 |
+
// Skip this match if needed
|
306 |
+
if ((!$allowCurrentDate && $nextRun == $currentDate) || --$nth > -1) {
|
307 |
+
$this->fieldFactory->getField(0)->increment($nextRun, $invert);
|
308 |
+
continue;
|
309 |
+
}
|
310 |
+
|
311 |
+
return $nextRun;
|
312 |
+
}
|
313 |
+
|
314 |
+
// @codeCoverageIgnoreStart
|
315 |
+
throw new RuntimeException('Impossible CRON expression');
|
316 |
+
// @codeCoverageIgnoreEnd
|
317 |
+
}
|
318 |
}
|
lite/includes/libraries/action-scheduler/lib/cron-expression/CronExpression_AbstractField.php
CHANGED
@@ -5,91 +5,96 @@
|
|
5 |
*
|
6 |
* @author Michael Dowling <mtdowling@gmail.com>
|
7 |
*/
|
8 |
-
abstract class CronExpression_AbstractField implements CronExpression_FieldInterface
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
9 |
|
10 |
-
|
11 |
-
|
12 |
-
*
|
13 |
-
* @param string $dateValue Date value to check
|
14 |
-
* @param string $value Value to test
|
15 |
-
*
|
16 |
-
* @return bool
|
17 |
-
*/
|
18 |
-
public function isSatisfied( $dateValue, $value ) {
|
19 |
-
if ( $this->isIncrementsOfRanges( $value ) ) {
|
20 |
-
return $this->isInIncrementsOfRanges( $dateValue, $value );
|
21 |
-
} elseif ( $this->isRange( $value ) ) {
|
22 |
-
return $this->isInRange( $dateValue, $value );
|
23 |
-
}
|
24 |
|
25 |
-
|
26 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
27 |
|
28 |
-
|
29 |
-
|
30 |
-
|
31 |
-
|
32 |
-
|
33 |
-
|
34 |
-
|
35 |
-
|
36 |
-
|
37 |
-
|
|
|
38 |
|
39 |
-
|
40 |
-
|
41 |
-
|
42 |
-
|
43 |
-
|
44 |
-
|
45 |
-
|
46 |
-
|
47 |
-
|
48 |
-
|
|
|
49 |
|
50 |
-
|
51 |
-
|
52 |
-
*
|
53 |
-
* @param string $dateValue Set date value
|
54 |
-
* @param string $value Value to test
|
55 |
-
*
|
56 |
-
* @return bool
|
57 |
-
*/
|
58 |
-
public function isInRange( $dateValue, $value ) {
|
59 |
-
$parts = array_map( 'trim', explode( '-', $value, 2 ) );
|
60 |
|
61 |
-
|
62 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
63 |
|
64 |
-
|
65 |
-
|
66 |
-
|
67 |
-
|
68 |
-
|
69 |
-
|
70 |
-
|
71 |
-
*/
|
72 |
-
public function isInIncrementsOfRanges( $dateValue, $value ) {
|
73 |
-
$parts = array_map( 'trim', explode( '/', $value, 2 ) );
|
74 |
-
$stepSize = isset( $parts[1] ) ? $parts[1] : 0;
|
75 |
-
if ( $parts[0] == '*' || $parts[0] === '0' ) {
|
76 |
-
return (int) $dateValue % $stepSize == 0;
|
77 |
-
}
|
78 |
|
79 |
-
|
80 |
-
|
81 |
-
|
82 |
-
|
83 |
-
|
84 |
-
return false;
|
85 |
-
}
|
86 |
|
87 |
-
|
88 |
-
|
89 |
-
return true;
|
90 |
-
}
|
91 |
-
}
|
92 |
-
|
93 |
-
return false;
|
94 |
-
}
|
95 |
}
|
5 |
*
|
6 |
* @author Michael Dowling <mtdowling@gmail.com>
|
7 |
*/
|
8 |
+
abstract class CronExpression_AbstractField implements CronExpression_FieldInterface
|
9 |
+
{
|
10 |
+
/**
|
11 |
+
* Check to see if a field is satisfied by a value
|
12 |
+
*
|
13 |
+
* @param string $dateValue Date value to check
|
14 |
+
* @param string $value Value to test
|
15 |
+
*
|
16 |
+
* @return bool
|
17 |
+
*/
|
18 |
+
public function isSatisfied($dateValue, $value)
|
19 |
+
{
|
20 |
+
if ($this->isIncrementsOfRanges($value)) {
|
21 |
+
return $this->isInIncrementsOfRanges($dateValue, $value);
|
22 |
+
} elseif ($this->isRange($value)) {
|
23 |
+
return $this->isInRange($dateValue, $value);
|
24 |
+
}
|
25 |
|
26 |
+
return $value == '*' || $dateValue == $value;
|
27 |
+
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
28 |
|
29 |
+
/**
|
30 |
+
* Check if a value is a range
|
31 |
+
*
|
32 |
+
* @param string $value Value to test
|
33 |
+
*
|
34 |
+
* @return bool
|
35 |
+
*/
|
36 |
+
public function isRange($value)
|
37 |
+
{
|
38 |
+
return strpos($value, '-') !== false;
|
39 |
+
}
|
40 |
|
41 |
+
/**
|
42 |
+
* Check if a value is an increments of ranges
|
43 |
+
*
|
44 |
+
* @param string $value Value to test
|
45 |
+
*
|
46 |
+
* @return bool
|
47 |
+
*/
|
48 |
+
public function isIncrementsOfRanges($value)
|
49 |
+
{
|
50 |
+
return strpos($value, '/') !== false;
|
51 |
+
}
|
52 |
|
53 |
+
/**
|
54 |
+
* Test if a value is within a range
|
55 |
+
*
|
56 |
+
* @param string $dateValue Set date value
|
57 |
+
* @param string $value Value to test
|
58 |
+
*
|
59 |
+
* @return bool
|
60 |
+
*/
|
61 |
+
public function isInRange($dateValue, $value)
|
62 |
+
{
|
63 |
+
$parts = array_map('trim', explode('-', $value, 2));
|
64 |
|
65 |
+
return $dateValue >= $parts[0] && $dateValue <= $parts[1];
|
66 |
+
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
67 |
|
68 |
+
/**
|
69 |
+
* Test if a value is within an increments of ranges (offset[-to]/step size)
|
70 |
+
*
|
71 |
+
* @param string $dateValue Set date value
|
72 |
+
* @param string $value Value to test
|
73 |
+
*
|
74 |
+
* @return bool
|
75 |
+
*/
|
76 |
+
public function isInIncrementsOfRanges($dateValue, $value)
|
77 |
+
{
|
78 |
+
$parts = array_map('trim', explode('/', $value, 2));
|
79 |
+
$stepSize = isset($parts[1]) ? $parts[1] : 0;
|
80 |
+
if ($parts[0] == '*' || $parts[0] === '0') {
|
81 |
+
return (int) $dateValue % $stepSize == 0;
|
82 |
+
}
|
83 |
|
84 |
+
$range = explode('-', $parts[0], 2);
|
85 |
+
$offset = $range[0];
|
86 |
+
$to = isset($range[1]) ? $range[1] : $dateValue;
|
87 |
+
// Ensure that the date value is within the range
|
88 |
+
if ($dateValue < $offset || $dateValue > $to) {
|
89 |
+
return false;
|
90 |
+
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
91 |
|
92 |
+
for ($i = $offset; $i <= $to; $i+= $stepSize) {
|
93 |
+
if ($i == $dateValue) {
|
94 |
+
return true;
|
95 |
+
}
|
96 |
+
}
|
|
|
|
|
97 |
|
98 |
+
return false;
|
99 |
+
}
|
|
|
|
|
|
|
|
|
|
|
|
|
100 |
}
|
lite/includes/libraries/action-scheduler/lib/cron-expression/CronExpression_DayOfMonthField.php
CHANGED
@@ -18,89 +18,93 @@
|
|
18 |
*
|
19 |
* @author Michael Dowling <mtdowling@gmail.com>
|
20 |
*/
|
21 |
-
class CronExpression_DayOfMonthField extends CronExpression_AbstractField
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
22 |
|
23 |
-
|
24 |
-
|
25 |
-
|
26 |
-
* @param int $currentYear Current year
|
27 |
-
* @param int $currentMonth Current month
|
28 |
-
* @param int $targetDay Target day of the month
|
29 |
-
*
|
30 |
-
* @return DateTime Returns the nearest date
|
31 |
-
*/
|
32 |
-
private static function getNearestWeekday( $currentYear, $currentMonth, $targetDay ) {
|
33 |
-
$tday = str_pad( $targetDay, 2, '0', STR_PAD_LEFT );
|
34 |
-
$target = new DateTime( "$currentYear-$currentMonth-$tday" );
|
35 |
-
$currentWeekday = (int) $target->format( 'N' );
|
36 |
|
37 |
-
|
38 |
-
return $target;
|
39 |
-
}
|
40 |
|
41 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
42 |
|
43 |
-
|
44 |
-
|
45 |
-
|
46 |
-
|
47 |
-
|
48 |
-
|
49 |
-
|
50 |
-
|
51 |
-
|
52 |
-
}
|
53 |
|
54 |
-
|
55 |
-
* {@inheritdoc}
|
56 |
-
*/
|
57 |
-
public function isSatisfiedBy( DateTime $date, $value ) {
|
58 |
-
// ? states that the field value is to be skipped
|
59 |
-
if ( $value == '?' ) {
|
60 |
-
return true;
|
61 |
-
}
|
62 |
|
63 |
-
|
|
|
|
|
|
|
64 |
|
65 |
-
|
66 |
-
|
67 |
-
|
68 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
69 |
|
70 |
-
|
71 |
-
|
72 |
-
// Parse the target day
|
73 |
-
$targetDay = substr( $value, 0, strpos( $value, 'W' ) );
|
74 |
-
// Find out if the current day is the nearest day of the week
|
75 |
-
return $date->format( 'j' ) == self::getNearestWeekday(
|
76 |
-
$date->format( 'Y' ),
|
77 |
-
$date->format( 'm' ),
|
78 |
-
$targetDay
|
79 |
-
)->format( 'j' );
|
80 |
-
}
|
81 |
|
82 |
-
|
83 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
84 |
|
85 |
-
|
86 |
-
|
87 |
-
*/
|
88 |
-
public function increment( DateTime $date, $invert = false ) {
|
89 |
-
if ( $invert ) {
|
90 |
-
$date->modify( 'previous day' );
|
91 |
-
$date->setTime( 23, 59 );
|
92 |
-
} else {
|
93 |
-
$date->modify( 'next day' );
|
94 |
-
$date->setTime( 0, 0 );
|
95 |
-
}
|
96 |
|
97 |
-
|
98 |
-
|
99 |
-
|
100 |
-
|
101 |
-
|
102 |
-
|
103 |
-
|
104 |
-
return (bool) preg_match( '/[\*,\/\-\?LW0-9A-Za-z]+/', $value );
|
105 |
-
}
|
106 |
}
|
18 |
*
|
19 |
* @author Michael Dowling <mtdowling@gmail.com>
|
20 |
*/
|
21 |
+
class CronExpression_DayOfMonthField extends CronExpression_AbstractField
|
22 |
+
{
|
23 |
+
/**
|
24 |
+
* Get the nearest day of the week for a given day in a month
|
25 |
+
*
|
26 |
+
* @param int $currentYear Current year
|
27 |
+
* @param int $currentMonth Current month
|
28 |
+
* @param int $targetDay Target day of the month
|
29 |
+
*
|
30 |
+
* @return DateTime Returns the nearest date
|
31 |
+
*/
|
32 |
+
private static function getNearestWeekday($currentYear, $currentMonth, $targetDay)
|
33 |
+
{
|
34 |
+
$tday = str_pad($targetDay, 2, '0', STR_PAD_LEFT);
|
35 |
+
$target = new DateTime("$currentYear-$currentMonth-$tday");
|
36 |
+
$currentWeekday = (int) $target->format('N');
|
37 |
|
38 |
+
if ($currentWeekday < 6) {
|
39 |
+
return $target;
|
40 |
+
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
41 |
|
42 |
+
$lastDayOfMonth = $target->format('t');
|
|
|
|
|
43 |
|
44 |
+
foreach (array(-1, 1, -2, 2) as $i) {
|
45 |
+
$adjusted = $targetDay + $i;
|
46 |
+
if ($adjusted > 0 && $adjusted <= $lastDayOfMonth) {
|
47 |
+
$target->setDate($currentYear, $currentMonth, $adjusted);
|
48 |
+
if ($target->format('N') < 6 && $target->format('m') == $currentMonth) {
|
49 |
+
return $target;
|
50 |
+
}
|
51 |
+
}
|
52 |
+
}
|
53 |
+
}
|
54 |
|
55 |
+
/**
|
56 |
+
* {@inheritdoc}
|
57 |
+
*/
|
58 |
+
public function isSatisfiedBy(DateTime $date, $value)
|
59 |
+
{
|
60 |
+
// ? states that the field value is to be skipped
|
61 |
+
if ($value == '?') {
|
62 |
+
return true;
|
63 |
+
}
|
|
|
64 |
|
65 |
+
$fieldValue = $date->format('d');
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
66 |
|
67 |
+
// Check to see if this is the last day of the month
|
68 |
+
if ($value == 'L') {
|
69 |
+
return $fieldValue == $date->format('t');
|
70 |
+
}
|
71 |
|
72 |
+
// Check to see if this is the nearest weekday to a particular value
|
73 |
+
if (strpos($value, 'W')) {
|
74 |
+
// Parse the target day
|
75 |
+
$targetDay = substr($value, 0, strpos($value, 'W'));
|
76 |
+
// Find out if the current day is the nearest day of the week
|
77 |
+
return $date->format('j') == self::getNearestWeekday(
|
78 |
+
$date->format('Y'),
|
79 |
+
$date->format('m'),
|
80 |
+
$targetDay
|
81 |
+
)->format('j');
|
82 |
+
}
|
83 |
|
84 |
+
return $this->isSatisfied($date->format('d'), $value);
|
85 |
+
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
86 |
|
87 |
+
/**
|
88 |
+
* {@inheritdoc}
|
89 |
+
*/
|
90 |
+
public function increment(DateTime $date, $invert = false)
|
91 |
+
{
|
92 |
+
if ($invert) {
|
93 |
+
$date->modify('previous day');
|
94 |
+
$date->setTime(23, 59);
|
95 |
+
} else {
|
96 |
+
$date->modify('next day');
|
97 |
+
$date->setTime(0, 0);
|
98 |
+
}
|
99 |
|
100 |
+
return $this;
|
101 |
+
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
102 |
|
103 |
+
/**
|
104 |
+
* {@inheritdoc}
|
105 |
+
*/
|
106 |
+
public function validate($value)
|
107 |
+
{
|
108 |
+
return (bool) preg_match('/[\*,\/\-\?LW0-9A-Za-z]+/', $value);
|
109 |
+
}
|
|
|
|
|
110 |
}
|
lite/includes/libraries/action-scheduler/lib/cron-expression/CronExpression_DayOfWeekField.php
CHANGED
@@ -15,107 +15,110 @@
|
|
15 |
*
|
16 |
* @author Michael Dowling <mtdowling@gmail.com>
|
17 |
*/
|
18 |
-
class CronExpression_DayOfWeekField extends CronExpression_AbstractField
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
19 |
|
20 |
-
|
21 |
-
|
22 |
-
|
23 |
-
|
24 |
-
|
25 |
-
|
26 |
-
}
|
27 |
|
28 |
-
|
29 |
-
|
30 |
-
|
31 |
-
range( 0, 6 ),
|
32 |
-
$value
|
33 |
-
);
|
34 |
|
35 |
-
|
36 |
-
|
37 |
-
|
|
|
|
|
|
|
|
|
|
|
38 |
|
39 |
-
|
40 |
-
|
41 |
-
$weekday = str_replace( '7', '0', substr( $value, 0, strpos( $value, 'L' ) ) );
|
42 |
-
$tdate = clone $date;
|
43 |
-
$tdate->setDate( $currentYear, $currentMonth, $lastDayOfMonth );
|
44 |
-
while ( $tdate->format( 'w' ) != $weekday ) {
|
45 |
-
$tdate->setDate( $currentYear, $currentMonth, --$lastDayOfMonth );
|
46 |
-
}
|
47 |
|
48 |
-
|
49 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
50 |
|
51 |
-
|
52 |
-
|
53 |
-
|
54 |
-
|
55 |
-
|
56 |
-
|
57 |
-
|
58 |
-
|
59 |
-
|
60 |
-
|
61 |
-
|
62 |
-
|
63 |
-
return false;
|
64 |
-
}
|
65 |
|
66 |
-
|
67 |
-
|
68 |
-
$dayCount = 0;
|
69 |
-
$currentDay = 1;
|
70 |
-
while ( $currentDay < $lastDayOfMonth + 1 ) {
|
71 |
-
if ( $tdate->format( 'N' ) == $weekday ) {
|
72 |
-
if ( ++$dayCount >= $nth ) {
|
73 |
-
break;
|
74 |
-
}
|
75 |
-
}
|
76 |
-
$tdate->setDate( $currentYear, $currentMonth, ++$currentDay );
|
77 |
-
}
|
78 |
|
79 |
-
|
80 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
81 |
|
82 |
-
|
83 |
-
|
84 |
-
|
85 |
-
if ( $parts[0] == '7' ) {
|
86 |
-
$parts[0] = '0';
|
87 |
-
} elseif ( $parts[1] == '0' ) {
|
88 |
-
$parts[1] = '7';
|
89 |
-
}
|
90 |
-
$value = implode( '-', $parts );
|
91 |
-
}
|
92 |
|
93 |
-
|
94 |
-
|
95 |
-
$fieldValue = $date->format( $format );
|
96 |
|
97 |
-
|
98 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
99 |
|
100 |
-
|
101 |
-
|
102 |
-
*/
|
103 |
-
public function increment( DateTime $date, $invert = false ) {
|
104 |
-
if ( $invert ) {
|
105 |
-
$date->modify( '-1 day' );
|
106 |
-
$date->setTime( 23, 59, 0 );
|
107 |
-
} else {
|
108 |
-
$date->modify( '+1 day' );
|
109 |
-
$date->setTime( 0, 0, 0 );
|
110 |
-
}
|
111 |
|
112 |
-
|
113 |
-
|
114 |
-
|
115 |
-
|
116 |
-
|
117 |
-
|
118 |
-
|
119 |
-
return (bool) preg_match( '/[\*,\/\-0-9A-Z]+/', $value );
|
120 |
-
}
|
121 |
}
|
15 |
*
|
16 |
* @author Michael Dowling <mtdowling@gmail.com>
|
17 |
*/
|
18 |
+
class CronExpression_DayOfWeekField extends CronExpression_AbstractField
|
19 |
+
{
|
20 |
+
/**
|
21 |
+
* {@inheritdoc}
|
22 |
+
*/
|
23 |
+
public function isSatisfiedBy(DateTime $date, $value)
|
24 |
+
{
|
25 |
+
if ($value == '?') {
|
26 |
+
return true;
|
27 |
+
}
|
28 |
|
29 |
+
// Convert text day of the week values to integers
|
30 |
+
$value = str_ireplace(
|
31 |
+
array('SUN', 'MON', 'TUE', 'WED', 'THU', 'FRI', 'SAT'),
|
32 |
+
range(0, 6),
|
33 |
+
$value
|
34 |
+
);
|
|
|
35 |
|
36 |
+
$currentYear = $date->format('Y');
|
37 |
+
$currentMonth = $date->format('m');
|
38 |
+
$lastDayOfMonth = $date->format('t');
|
|
|
|
|
|
|
39 |
|
40 |
+
// Find out if this is the last specific weekday of the month
|
41 |
+
if (strpos($value, 'L')) {
|
42 |
+
$weekday = str_replace('7', '0', substr($value, 0, strpos($value, 'L')));
|
43 |
+
$tdate = clone $date;
|
44 |
+
$tdate->setDate($currentYear, $currentMonth, $lastDayOfMonth);
|
45 |
+
while ($tdate->format('w') != $weekday) {
|
46 |
+
$tdate->setDate($currentYear, $currentMonth, --$lastDayOfMonth);
|
47 |
+
}
|
48 |
|
49 |
+
return $date->format('j') == $lastDayOfMonth;
|
50 |
+
}
|
|
|
|
|
|
|
|
|
|
|
|
|
51 |
|
52 |
+
// Handle # hash tokens
|
53 |
+
if (strpos($value, '#')) {
|
54 |
+
list($weekday, $nth) = explode('#', $value);
|
55 |
+
// Validate the hash fields
|
56 |
+
if ($weekday < 1 || $weekday > 5) {
|
57 |
+
throw new InvalidArgumentException("Weekday must be a value between 1 and 5. {$weekday} given");
|
58 |
+
}
|
59 |
+
if ($nth > 5) {
|
60 |
+
throw new InvalidArgumentException('There are never more than 5 of a given weekday in a month');
|
61 |
+
}
|
62 |
+
// The current weekday must match the targeted weekday to proceed
|
63 |
+
if ($date->format('N') != $weekday) {
|
64 |
+
return false;
|
65 |
+
}
|
66 |
|
67 |
+
$tdate = clone $date;
|
68 |
+
$tdate->setDate($currentYear, $currentMonth, 1);
|
69 |
+
$dayCount = 0;
|
70 |
+
$currentDay = 1;
|
71 |
+
while ($currentDay < $lastDayOfMonth + 1) {
|
72 |
+
if ($tdate->format('N') == $weekday) {
|
73 |
+
if (++$dayCount >= $nth) {
|
74 |
+
break;
|
75 |
+
}
|
76 |
+
}
|
77 |
+
$tdate->setDate($currentYear, $currentMonth, ++$currentDay);
|
78 |
+
}
|
|
|
|
|
79 |
|
80 |
+
return $date->format('j') == $currentDay;
|
81 |
+
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
82 |
|
83 |
+
// Handle day of the week values
|
84 |
+
if (strpos($value, '-')) {
|
85 |
+
$parts = explode('-', $value);
|
86 |
+
if ($parts[0] == '7') {
|
87 |
+
$parts[0] = '0';
|
88 |
+
} elseif ($parts[1] == '0') {
|
89 |
+
$parts[1] = '7';
|
90 |
+
}
|
91 |
+
$value = implode('-', $parts);
|
92 |
+
}
|
93 |
|
94 |
+
// Test to see which Sunday to use -- 0 == 7 == Sunday
|
95 |
+
$format = in_array(7, str_split($value)) ? 'N' : 'w';
|
96 |
+
$fieldValue = $date->format($format);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
97 |
|
98 |
+
return $this->isSatisfied($fieldValue, $value);
|
99 |
+
}
|
|
|
100 |
|
101 |
+
/**
|
102 |
+
* {@inheritdoc}
|
103 |
+
*/
|
104 |
+
public function increment(DateTime $date, $invert = false)
|
105 |
+
{
|
106 |
+
if ($invert) {
|
107 |
+
$date->modify('-1 day');
|
108 |
+
$date->setTime(23, 59, 0);
|
109 |
+
} else {
|
110 |
+
$date->modify('+1 day');
|
111 |
+
$date->setTime(0, 0, 0);
|
112 |
+
}
|
113 |
|
114 |
+
return $this;
|
115 |
+
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
116 |
|
117 |
+
/**
|
118 |
+
* {@inheritdoc}
|
119 |
+
*/
|
120 |
+
public function validate($value)
|
121 |
+
{
|
122 |
+
return (bool) preg_match('/[\*,\/\-0-9A-Z]+/', $value);
|
123 |
+
}
|
|
|
|
|
124 |
}
|
lite/includes/libraries/action-scheduler/lib/cron-expression/CronExpression_FieldFactory.php
CHANGED
@@ -6,49 +6,50 @@
|
|
6 |
* @author Michael Dowling <mtdowling@gmail.com>
|
7 |
* @link http://en.wikipedia.org/wiki/Cron
|
8 |
*/
|
9 |
-
class CronExpression_FieldFactory
|
|
|
|
|
|
|
|
|
|
|
10 |
|
11 |
-
|
12 |
-
|
13 |
-
|
14 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
15 |
|
16 |
-
|
17 |
-
|
18 |
-
*
|
19 |
-
* @param int $position CRON expression position value to retrieve
|
20 |
-
*
|
21 |
-
* @return CronExpression_FieldInterface
|
22 |
-
* @throws InvalidArgumentException if a position is not valid
|
23 |
-
*/
|
24 |
-
public function getField( $position ) {
|
25 |
-
if ( ! isset( $this->fields[ $position ] ) ) {
|
26 |
-
switch ( $position ) {
|
27 |
-
case 0:
|
28 |
-
$this->fields[ $position ] = new CronExpression_MinutesField();
|
29 |
-
break;
|
30 |
-
case 1:
|
31 |
-
$this->fields[ $position ] = new CronExpression_HoursField();
|
32 |
-
break;
|
33 |
-
case 2:
|
34 |
-
$this->fields[ $position ] = new CronExpression_DayOfMonthField();
|
35 |
-
break;
|
36 |
-
case 3:
|
37 |
-
$this->fields[ $position ] = new CronExpression_MonthField();
|
38 |
-
break;
|
39 |
-
case 4:
|
40 |
-
$this->fields[ $position ] = new CronExpression_DayOfWeekField();
|
41 |
-
break;
|
42 |
-
case 5:
|
43 |
-
$this->fields[ $position ] = new CronExpression_YearField();
|
44 |
-
break;
|
45 |
-
default:
|
46 |
-
throw new InvalidArgumentException(
|
47 |
-
$position . ' is not a valid position'
|
48 |
-
);
|
49 |
-
}
|
50 |
-
}
|
51 |
-
|
52 |
-
return $this->fields[ $position ];
|
53 |
-
}
|
54 |
}
|
6 |
* @author Michael Dowling <mtdowling@gmail.com>
|
7 |
* @link http://en.wikipedia.org/wiki/Cron
|
8 |
*/
|
9 |
+
class CronExpression_FieldFactory
|
10 |
+
{
|
11 |
+
/**
|
12 |
+
* @var array Cache of instantiated fields
|
13 |
+
*/
|
14 |
+
private $fields = array();
|
15 |
|
16 |
+
/**
|
17 |
+
* Get an instance of a field object for a cron expression position
|
18 |
+
*
|
19 |
+
* @param int $position CRON expression position value to retrieve
|
20 |
+
*
|
21 |
+
* @return CronExpression_FieldInterface
|
22 |
+
* @throws InvalidArgumentException if a position is not valid
|
23 |
+
*/
|
24 |
+
public function getField($position)
|
25 |
+
{
|
26 |
+
if (!isset($this->fields[$position])) {
|
27 |
+
switch ($position) {
|
28 |
+
case 0:
|
29 |
+
$this->fields[$position] = new CronExpression_MinutesField();
|
30 |
+
break;
|
31 |
+
case 1:
|
32 |
+
$this->fields[$position] = new CronExpression_HoursField();
|
33 |
+
break;
|
34 |
+
case 2:
|
35 |
+
$this->fields[$position] = new CronExpression_DayOfMonthField();
|
36 |
+
break;
|
37 |
+
case 3:
|
38 |
+
$this->fields[$position] = new CronExpression_MonthField();
|
39 |
+
break;
|
40 |
+
case 4:
|
41 |
+
$this->fields[$position] = new CronExpression_DayOfWeekField();
|
42 |
+
break;
|
43 |
+
case 5:
|
44 |
+
$this->fields[$position] = new CronExpression_YearField();
|
45 |
+
break;
|
46 |
+
default:
|
47 |
+
throw new InvalidArgumentException(
|
48 |
+
$position . ' is not a valid position'
|
49 |
+
);
|
50 |
+
}
|
51 |
+
}
|
52 |
|
53 |
+
return $this->fields[$position];
|
54 |
+
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
55 |
}
|
lite/includes/libraries/action-scheduler/lib/cron-expression/CronExpression_FieldInterface.php
CHANGED
@@ -5,35 +5,35 @@
|
|
5 |
*
|
6 |
* @author Michael Dowling <mtdowling@gmail.com>
|
7 |
*/
|
8 |
-
interface CronExpression_FieldInterface
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
9 |
|
10 |
-
|
11 |
-
|
12 |
-
|
13 |
-
|
14 |
-
|
15 |
-
|
16 |
-
|
17 |
-
|
18 |
-
|
|
|
19 |
|
20 |
-
|
21 |
-
|
22 |
-
|
23 |
-
|
24 |
-
|
25 |
-
|
26 |
-
|
27 |
-
|
28 |
-
*/
|
29 |
-
public function increment( DateTime $date, $invert = false);
|
30 |
-
|
31 |
-
/**
|
32 |
-
* Validates a CRON expression for a given field
|
33 |
-
*
|
34 |
-
* @param string $value CRON expression value to validate
|
35 |
-
*
|
36 |
-
* @return bool Returns TRUE if valid, FALSE otherwise
|
37 |
-
*/
|
38 |
-
public function validate( $value);
|
39 |
}
|
5 |
*
|
6 |
* @author Michael Dowling <mtdowling@gmail.com>
|
7 |
*/
|
8 |
+
interface CronExpression_FieldInterface
|
9 |
+
{
|
10 |
+
/**
|
11 |
+
* Check if the respective value of a DateTime field satisfies a CRON exp
|
12 |
+
*
|
13 |
+
* @param DateTime $date DateTime object to check
|
14 |
+
* @param string $value CRON expression to test against
|
15 |
+
*
|
16 |
+
* @return bool Returns TRUE if satisfied, FALSE otherwise
|
17 |
+
*/
|
18 |
+
public function isSatisfiedBy(DateTime $date, $value);
|
19 |
|
20 |
+
/**
|
21 |
+
* When a CRON expression is not satisfied, this method is used to increment
|
22 |
+
* or decrement a DateTime object by the unit of the cron field
|
23 |
+
*
|
24 |
+
* @param DateTime $date DateTime object to change
|
25 |
+
* @param bool $invert (optional) Set to TRUE to decrement
|
26 |
+
*
|
27 |
+
* @return CronExpression_FieldInterface
|
28 |
+
*/
|
29 |
+
public function increment(DateTime $date, $invert = false);
|
30 |
|
31 |
+
/**
|
32 |
+
* Validates a CRON expression for a given field
|
33 |
+
*
|
34 |
+
* @param string $value CRON expression value to validate
|
35 |
+
*
|
36 |
+
* @return bool Returns TRUE if valid, FALSE otherwise
|
37 |
+
*/
|
38 |
+
public function validate($value);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
39 |
}
|
lite/includes/libraries/action-scheduler/lib/cron-expression/CronExpression_HoursField.php
CHANGED
@@ -5,40 +5,43 @@
|
|
5 |
*
|
6 |
* @author Michael Dowling <mtdowling@gmail.com>
|
7 |
*/
|
8 |
-
class CronExpression_HoursField extends CronExpression_AbstractField
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
9 |
|
10 |
-
|
11 |
-
|
12 |
-
|
13 |
-
|
14 |
-
|
15 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
16 |
|
17 |
-
|
18 |
-
|
19 |
-
*/
|
20 |
-
public function increment( DateTime $date, $invert = false ) {
|
21 |
-
// Change timezone to UTC temporarily. This will
|
22 |
-
// allow us to go back or forwards and hour even
|
23 |
-
// if DST will be changed between the hours.
|
24 |
-
$timezone = $date->getTimezone();
|
25 |
-
$date->setTimezone( new DateTimeZone( 'UTC' ) );
|
26 |
-
if ( $invert ) {
|
27 |
-
$date->modify( '-1 hour' );
|
28 |
-
$date->setTime( $date->format( 'H' ), 59 );
|
29 |
-
} else {
|
30 |
-
$date->modify( '+1 hour' );
|
31 |
-
$date->setTime( $date->format( 'H' ), 0 );
|
32 |
-
}
|
33 |
-
$date->setTimezone( $timezone );
|
34 |
|
35 |
-
|
36 |
-
|
37 |
-
|
38 |
-
|
39 |
-
|
40 |
-
|
41 |
-
|
42 |
-
return (bool) preg_match( '/[\*,\/\-0-9]+/', $value );
|
43 |
-
}
|
44 |
}
|
5 |
*
|
6 |
* @author Michael Dowling <mtdowling@gmail.com>
|
7 |
*/
|
8 |
+
class CronExpression_HoursField extends CronExpression_AbstractField
|
9 |
+
{
|
10 |
+
/**
|
11 |
+
* {@inheritdoc}
|
12 |
+
*/
|
13 |
+
public function isSatisfiedBy(DateTime $date, $value)
|
14 |
+
{
|
15 |
+
return $this->isSatisfied($date->format('H'), $value);
|
16 |
+
}
|
17 |
|
18 |
+
/**
|
19 |
+
* {@inheritdoc}
|
20 |
+
*/
|
21 |
+
public function increment(DateTime $date, $invert = false)
|
22 |
+
{
|
23 |
+
// Change timezone to UTC temporarily. This will
|
24 |
+
// allow us to go back or forwards and hour even
|
25 |
+
// if DST will be changed between the hours.
|
26 |
+
$timezone = $date->getTimezone();
|
27 |
+
$date->setTimezone(new DateTimeZone('UTC'));
|
28 |
+
if ($invert) {
|
29 |
+
$date->modify('-1 hour');
|
30 |
+
$date->setTime($date->format('H'), 59);
|
31 |
+
} else {
|
32 |
+
$date->modify('+1 hour');
|
33 |
+
$date->setTime($date->format('H'), 0);
|
34 |
+
}
|
35 |
+
$date->setTimezone($timezone);
|
36 |
|
37 |
+
return $this;
|
38 |
+
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
39 |
|
40 |
+
/**
|
41 |
+
* {@inheritdoc}
|
42 |
+
*/
|
43 |
+
public function validate($value)
|
44 |
+
{
|
45 |
+
return (bool) preg_match('/[\*,\/\-0-9]+/', $value);
|
46 |
+
}
|
|
|
|
|
47 |
}
|
lite/includes/libraries/action-scheduler/lib/cron-expression/CronExpression_MinutesField.php
CHANGED
@@ -5,32 +5,35 @@
|
|
5 |
*
|
6 |
* @author Michael Dowling <mtdowling@gmail.com>
|
7 |
*/
|
8 |
-
class CronExpression_MinutesField extends CronExpression_AbstractField
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
9 |
|
10 |
-
|
11 |
-
|
12 |
-
|
13 |
-
|
14 |
-
|
15 |
-
|
|
|
|
|
|
|
|
|
16 |
|
17 |
-
|
18 |
-
|
19 |
-
*/
|
20 |
-
public function increment( DateTime $date, $invert = false ) {
|
21 |
-
if ( $invert ) {
|
22 |
-
$date->modify( '-1 minute' );
|
23 |
-
} else {
|
24 |
-
$date->modify( '+1 minute' );
|
25 |
-
}
|
26 |
|
27 |
-
|
28 |
-
|
29 |
-
|
30 |
-
|
31 |
-
|
32 |
-
|
33 |
-
|
34 |
-
return (bool) preg_match( '/[\*,\/\-0-9]+/', $value );
|
35 |
-
}
|
36 |
}
|
5 |
*
|
6 |
* @author Michael Dowling <mtdowling@gmail.com>
|
7 |
*/
|
8 |
+
class CronExpression_MinutesField extends CronExpression_AbstractField
|
9 |
+
{
|
10 |
+
/**
|
11 |
+
* {@inheritdoc}
|
12 |
+
*/
|
13 |
+
public function isSatisfiedBy(DateTime $date, $value)
|
14 |
+
{
|
15 |
+
return $this->isSatisfied($date->format('i'), $value);
|
16 |
+
}
|
17 |
|
18 |
+
/**
|
19 |
+
* {@inheritdoc}
|
20 |
+
*/
|
21 |
+
public function increment(DateTime $date, $invert = false)
|
22 |
+
{
|
23 |
+
if ($invert) {
|
24 |
+
$date->modify('-1 minute');
|
25 |
+
} else {
|
26 |
+
$date->modify('+1 minute');
|
27 |
+
}
|
28 |
|
29 |
+
return $this;
|
30 |
+
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
31 |
|
32 |
+
/**
|
33 |
+
* {@inheritdoc}
|
34 |
+
*/
|
35 |
+
public function validate($value)
|
36 |
+
{
|
37 |
+
return (bool) preg_match('/[\*,\/\-0-9]+/', $value);
|
38 |
+
}
|
|
|
|
|
39 |
}
|
lite/includes/libraries/action-scheduler/lib/cron-expression/CronExpression_MonthField.php
CHANGED
@@ -5,58 +5,51 @@
|
|
5 |
*
|
6 |
* @author Michael Dowling <mtdowling@gmail.com>
|
7 |
*/
|
8 |
-
class CronExpression_MonthField extends CronExpression_AbstractField
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
9 |
|
10 |
-
|
11 |
-
|
12 |
-
*/
|
13 |
-
public function isSatisfiedBy( DateTime $date, $value ) {
|
14 |
-
// Convert text month values to integers
|
15 |
-
$value = str_ireplace(
|
16 |
-
array(
|
17 |
-
'JAN',
|
18 |
-
'FEB',
|
19 |
-
'MAR',
|
20 |
-
'APR',
|
21 |
-
'MAY',
|
22 |
-
'JUN',
|
23 |
-
'JUL',
|
24 |
-
'AUG',
|
25 |
-
'SEP',
|
26 |
-
'OCT',
|
27 |
-
'NOV',
|
28 |
-
'DEC',
|
29 |
-
),
|
30 |
-
range( 1, 12 ),
|
31 |
-
$value
|
32 |
-
);
|
33 |
|
34 |
-
|
35 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
36 |
|
37 |
-
|
38 |
-
|
39 |
-
*/
|
40 |
-
public function increment( DateTime $date, $invert = false ) {
|
41 |
-
if ( $invert ) {
|
42 |
-
// $date->modify('last day of previous month'); // remove for php 5.2 compat
|
43 |
-
$date->modify( 'previous month' );
|
44 |
-
$date->modify( $date->format( 'Y-m-t' ) );
|
45 |
-
$date->setTime( 23, 59 );
|
46 |
-
} else {
|
47 |
-
// $date->modify('first day of next month'); // remove for php 5.2 compat
|
48 |
-
$date->modify( 'next month' );
|
49 |
-
$date->modify( $date->format( 'Y-m-01' ) );
|
50 |
-
$date->setTime( 0, 0 );
|
51 |
-
}
|
52 |
|
53 |
-
|
54 |
-
|
55 |
-
|
56 |
-
|
57 |
-
|
58 |
-
|
59 |
-
|
60 |
-
return (bool) preg_match( '/[\*,\/\-0-9A-Z]+/', $value );
|
61 |
-
}
|
62 |
}
|
5 |
*
|
6 |
* @author Michael Dowling <mtdowling@gmail.com>
|
7 |
*/
|
8 |
+
class CronExpression_MonthField extends CronExpression_AbstractField
|
9 |
+
{
|
10 |
+
/**
|
11 |
+
* {@inheritdoc}
|
12 |
+
*/
|
13 |
+
public function isSatisfiedBy(DateTime $date, $value)
|
14 |
+
{
|
15 |
+
// Convert text month values to integers
|
16 |
+
$value = str_ireplace(
|
17 |
+
array(
|
18 |
+
'JAN', 'FEB', 'MAR', 'APR', 'MAY', 'JUN',
|
19 |
+
'JUL', 'AUG', 'SEP', 'OCT', 'NOV', 'DEC'
|
20 |
+
),
|
21 |
+
range(1, 12),
|
22 |
+
$value
|
23 |
+
);
|
24 |
|
25 |
+
return $this->isSatisfied($date->format('m'), $value);
|
26 |
+
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
27 |
|
28 |
+
/**
|
29 |
+
* {@inheritdoc}
|
30 |
+
*/
|
31 |
+
public function increment(DateTime $date, $invert = false)
|
32 |
+
{
|
33 |
+
if ($invert) {
|
34 |
+
// $date->modify('last day of previous month'); // remove for php 5.2 compat
|
35 |
+
$date->modify('previous month');
|
36 |
+
$date->modify($date->format('Y-m-t'));
|
37 |
+
$date->setTime(23, 59);
|
38 |
+
} else {
|
39 |
+
//$date->modify('first day of next month'); // remove for php 5.2 compat
|
40 |
+
$date->modify('next month');
|
41 |
+
$date->modify($date->format('Y-m-01'));
|
42 |
+
$date->setTime(0, 0);
|
43 |
+
}
|
44 |
|
45 |
+
return $this;
|
46 |
+
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
47 |
|
48 |
+
/**
|
49 |
+
* {@inheritdoc}
|
50 |
+
*/
|
51 |
+
public function validate($value)
|
52 |
+
{
|
53 |
+
return (bool) preg_match('/[\*,\/\-0-9A-Z]+/', $value);
|
54 |
+
}
|
|
|
|
|
55 |
}
|
lite/includes/libraries/action-scheduler/lib/cron-expression/CronExpression_YearField.php
CHANGED
@@ -5,36 +5,39 @@
|
|
5 |
*
|
6 |
* @author Michael Dowling <mtdowling@gmail.com>
|
7 |
*/
|
8 |
-
class CronExpression_YearField extends CronExpression_AbstractField
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
9 |
|
10 |
-
|
11 |
-
|
12 |
-
|
13 |
-
|
14 |
-
|
15 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
16 |
|
17 |
-
|
18 |
-
|
19 |
-
*/
|
20 |
-
public function increment( DateTime $date, $invert = false ) {
|
21 |
-
if ( $invert ) {
|
22 |
-
$date->modify( '-1 year' );
|
23 |
-
$date->setDate( $date->format( 'Y' ), 12, 31 );
|
24 |
-
$date->setTime( 23, 59, 0 );
|
25 |
-
} else {
|
26 |
-
$date->modify( '+1 year' );
|
27 |
-
$date->setDate( $date->format( 'Y' ), 1, 1 );
|
28 |
-
$date->setTime( 0, 0, 0 );
|
29 |
-
}
|
30 |
|
31 |
-
|
32 |
-
|
33 |
-
|
34 |
-
|
35 |
-
|
36 |
-
|
37 |
-
|
38 |
-
return (bool) preg_match( '/[\*,\/\-0-9]+/', $value );
|
39 |
-
}
|
40 |
}
|
5 |
*
|
6 |
* @author Michael Dowling <mtdowling@gmail.com>
|
7 |
*/
|
8 |
+
class CronExpression_YearField extends CronExpression_AbstractField
|
9 |
+
{
|
10 |
+
/**
|
11 |
+
* {@inheritdoc}
|
12 |
+
*/
|
13 |
+
public function isSatisfiedBy(DateTime $date, $value)
|
14 |
+
{
|
15 |
+
return $this->isSatisfied($date->format('Y'), $value);
|
16 |
+
}
|
17 |
|
18 |
+
/**
|
19 |
+
* {@inheritdoc}
|
20 |
+
*/
|
21 |
+
public function increment(DateTime $date, $invert = false)
|
22 |
+
{
|
23 |
+
if ($invert) {
|
24 |
+
$date->modify('-1 year');
|
25 |
+
$date->setDate($date->format('Y'), 12, 31);
|
26 |
+
$date->setTime(23, 59, 0);
|
27 |
+
} else {
|
28 |
+
$date->modify('+1 year');
|
29 |
+
$date->setDate($date->format('Y'), 1, 1);
|
30 |
+
$date->setTime(0, 0, 0);
|
31 |
+
}
|
32 |
|
33 |
+
return $this;
|
34 |
+
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
35 |
|
36 |
+
/**
|
37 |
+
* {@inheritdoc}
|
38 |
+
*/
|
39 |
+
public function validate($value)
|
40 |
+
{
|
41 |
+
return (bool) preg_match('/[\*,\/\-0-9]+/', $value);
|
42 |
+
}
|
|
|
|
|
43 |
}
|
lite/includes/libraries/action-scheduler/readme.txt
ADDED
@@ -0,0 +1,76 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
=== Action Scheduler ===
|
2 |
+
Contributors: Automattic, wpmuguru, claudiosanches, peterfabian1000, vedjain, jamosova, obliviousharmony, konamiman, sadowski, royho, barryhughes-1
|
3 |
+
Tags: scheduler, cron
|
4 |
+
Requires at least: 5.2
|
5 |
+
Tested up to: 5.7
|
6 |
+
Stable tag: 3.3.0
|
7 |
+
License: GPLv3
|
8 |
+
Requires PHP: 5.6
|
9 |
+
|
10 |
+
Action Scheduler - Job Queue for WordPress
|
11 |
+
|
12 |
+
== Description ==
|
13 |
+
|
14 |
+
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.
|
15 |
+
|
16 |
+
Action Scheduler works by triggering an action 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.
|
17 |
+
|
18 |
+
Think of it like an extension to `do_action()` which adds the ability to delay and repeat a hook.
|
19 |
+
|
20 |
+
## Battle-Tested Background Processing
|
21 |
+
|
22 |
+
Every month, Action Scheduler processes millions of payments for [Subscriptions](https://woocommerce.com/products/woocommerce-subscriptions/), webhooks for [WooCommerce](https://wordpress.org/plugins/woocommerce/), as well as emails and other events for a range of other plugins.
|
23 |
+
|
24 |
+
It's been seen on live sites processing queues in excess of 50,000 jobs and doing resource intensive operations, like processing payments and creating orders, at a sustained rate of over 10,000 / hour without negatively impacting normal site operations.
|
25 |
+
|
26 |
+
This is all on infrastructure and WordPress sites outside the control of the plugin author.
|
27 |
+
|
28 |
+
If your plugin needs background processing, especially of large sets of tasks, Action Scheduler can help.
|
29 |
+
|
30 |
+
## Learn More
|
31 |
+
|
32 |
+
To learn more about how to Action Scheduler works, and how to use it in your plugin, check out the docs on [ActionScheduler.org](https://actionscheduler.org).
|
33 |
+
|
34 |
+
There you will find:
|
35 |
+
|
36 |
+
* [Usage guide](https://actionscheduler.org/usage/): instructions on installing and using Action Scheduler
|
37 |
+
* [WP CLI guide](https://actionscheduler.org/wp-cli/): instructions on running Action Scheduler at scale via WP CLI
|
38 |
+
* [API Reference](https://actionscheduler.org/api/): complete reference guide for all API functions
|
39 |
+
* [Administration Guide](https://actionscheduler.org/admin/): guide to managing scheduled actions via the administration screen
|
40 |
+
* [Guide to Background Processing at Scale](https://actionscheduler.org/perf/): instructions for running Action Scheduler at scale via the default WP Cron queue runner
|
41 |
+
|
42 |
+
## Credits
|
43 |
+
|
44 |
+
Action Scheduler is developed and maintained by [Automattic](http://automattic.com/) with significant early development completed by [Flightless](https://flightless.us/).
|
45 |
+
|
46 |
+
Collaboration is cool. We'd love to work with you to improve Action Scheduler. [Pull Requests](https://github.com/woocommerce/action-scheduler/pulls) welcome.
|
47 |
+
|
48 |
+
== Changelog ==
|
49 |
+
|
50 |
+
= 3.3.0 - 2021-09-15 =
|
51 |
+
* Enhancement - Adds as_has_scheduled_action() to provide a performant way to test for existing actions. #645
|
52 |
+
* Fix - Improves compatibility with environments where NO_ZERO_DATE is enabled. #519
|
53 |
+
* Fix - Adds safety checks to guard against errors when our database tables cannot be created. #645
|
54 |
+
* Dev - Now supports queries that use multiple statuses. #649
|
55 |
+
* Dev - Minimum requirements for WordPress and PHP bumped (to 5.2 and 5.6 respectively). #723
|
56 |
+
|
57 |
+
= 3.2.1 - 2021-06-21 =
|
58 |
+
* Fix - Add extra safety/account for different versions of AS and different loading patterns. #714
|
59 |
+
* Fix - Handle hidden columns (Tools → Scheduled Actions) | #600.
|
60 |
+
|
61 |
+
= 3.2.0 - 2021-06-03 =
|
62 |
+
* Fix - Add "no ordering" option to as_next_scheduled_action().
|
63 |
+
* Fix - Add secondary scheduled date checks when claiming actions (DBStore) | #634.
|
64 |
+
* Fix - Add secondary scheduled date checks when claiming actions (wpPostStore) | #634.
|
65 |
+
* Fix - Adds a new index to the action table, reducing the potential for deadlocks (props: @glagonikas).
|
66 |
+
* Fix - Fix unit tests infrastructure and adapt tests to PHP 8.
|
67 |
+
* Fix - Identify in-use data store.
|
68 |
+
* Fix - Improve test_migration_is_scheduled.
|
69 |
+
* Fix - PHP notice on list table.
|
70 |
+
* Fix - Speed up clean up and batch selects.
|
71 |
+
* Fix - Update pending dependencies.
|
72 |
+
* Fix - [PHP 8.0] Only pass action arg values through to do_action_ref_array().
|
73 |
+
* Fix - [PHP 8] Set the PHP version to 7.1 in composer.json for PHP 8 compatibility.
|
74 |
+
* Fix - add is_initialized() to docs.
|
75 |
+
* Fix - fix file permissions.
|
76 |
+
* Fix - fixes #664 by replacing __ with esc_html__.
|
lite/languages/email-subscribers.pot
CHANGED
@@ -2,14 +2,14 @@
|
|
2 |
# This file is distributed under the same license as the Email Subscribers & Newsletters plugin.
|
3 |
msgid ""
|
4 |
msgstr ""
|
5 |
-
"Project-Id-Version: Email Subscribers & Newsletters 4.9.
|
6 |
"Report-Msgid-Bugs-To: https://wordpress.org/support/plugin/email-subscribers\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: 2021-
|
13 |
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
14 |
"X-Generator: WP-CLI 2.4.0\n"
|
15 |
"X-Domain: email-subscribers\n"
|
2 |
# This file is distributed under the same license as the Email Subscribers & Newsletters plugin.
|
3 |
msgid ""
|
4 |
msgstr ""
|
5 |
+
"Project-Id-Version: Email Subscribers & Newsletters 4.9.1\n"
|
6 |
"Report-Msgid-Bugs-To: https://wordpress.org/support/plugin/email-subscribers\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: 2021-11-02T07:00:07+01:00\n"
|
13 |
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
14 |
"X-Generator: WP-CLI 2.4.0\n"
|
15 |
"X-Domain: email-subscribers\n"
|
lite/public/partials/class-es-shortcode.php
CHANGED
@@ -308,7 +308,7 @@ class ES_Shortcode {
|
|
308 |
<input type="hidden" name="esfpx_es_email_page" value="<?php echo esc_attr( $current_page ); ?>"/>
|
309 |
<input type="hidden" name="esfpx_es_email_page_url" value="<?php echo esc_url( $current_page_url ); ?>"/>
|
310 |
<input type="hidden" name="esfpx_status" value="Unconfirmed"/>
|
311 |
-
<input type="hidden" name="esfpx_es-subscribe" id="es-subscribe" value="<?php echo esc_attr( $nonce ); ?>"/>
|
312 |
<label style="<?php echo esc_attr( $hp_style ); ?>"><input type="email" name="esfpx_es_hp_email" class="es_required_field" tabindex="-1" autocomplete="-1" value=""/></label>
|
313 |
<?php
|
314 |
|
308 |
<input type="hidden" name="esfpx_es_email_page" value="<?php echo esc_attr( $current_page ); ?>"/>
|
309 |
<input type="hidden" name="esfpx_es_email_page_url" value="<?php echo esc_url( $current_page_url ); ?>"/>
|
310 |
<input type="hidden" name="esfpx_status" value="Unconfirmed"/>
|
311 |
+
<input type="hidden" name="esfpx_es-subscribe" id="es-subscribe-<?php echo esc_attr( $unique_id ); ?>" value="<?php echo esc_attr( $nonce ); ?>"/>
|
312 |
<label style="<?php echo esc_attr( $hp_style ); ?>"><input type="email" name="esfpx_es_hp_email" class="es_required_field" tabindex="-1" autocomplete="-1" value=""/></label>
|
313 |
<?php
|
314 |
|
readme.txt
CHANGED
@@ -6,7 +6,7 @@ Tags: email marketing, subscription, autoresponder, post notification, welcome e
|
|
6 |
Requires at least: 3.9
|
7 |
Tested up to: 5.8.1
|
8 |
Requires PHP: 5.6
|
9 |
-
Stable tag: 4.9.
|
10 |
License: GPLv3
|
11 |
License URI: http://www.gnu.org/licenses
|
12 |
|
@@ -310,12 +310,20 @@ Refer [here](https://www.icegram.com/documentation/es-faq/).
|
|
310 |
|
311 |
== Upgrade Notice ==
|
312 |
|
313 |
-
= 4.9.
|
314 |
|
315 |
-
* New:
|
|
|
|
|
316 |
|
317 |
== Changelog ==
|
318 |
|
|
|
|
|
|
|
|
|
|
|
|
|
319 |
**4.9.0 (26.10.2021)**
|
320 |
|
321 |
* New: Automatic bounce handling for list **[PRO]**
|
6 |
Requires at least: 3.9
|
7 |
Tested up to: 5.8.1
|
8 |
Requires PHP: 5.6
|
9 |
+
Stable tag: 4.9.1
|
10 |
License: GPLv3
|
11 |
License URI: http://www.gnu.org/licenses
|
12 |
|
310 |
|
311 |
== Upgrade Notice ==
|
312 |
|
313 |
+
= 4.9.1 =
|
314 |
|
315 |
+
* New: Added {{POSTIMAGE-URL}} keyword for Post Notification
|
316 |
+
* Update: Action Scheduler Library to 3.3.0
|
317 |
+
* Fix: Amazon SES batch sending issue **[PRO]**
|
318 |
|
319 |
== Changelog ==
|
320 |
|
321 |
+
**4.9.1 (02.11.2021)**
|
322 |
+
|
323 |
+
* New: Added {{POSTIMAGE-URL}} keyword for Post Notification
|
324 |
+
* Update: Action Scheduler Library to 3.3.0
|
325 |
+
* Fix: Amazon SES batch sending issue **[PRO]**
|
326 |
+
|
327 |
**4.9.0 (26.10.2021)**
|
328 |
|
329 |
* New: Automatic bounce handling for list **[PRO]**
|