@@ -4,149 +4,149 @@ |
||
| 4 | 4 | * Class ActionScheduler_TimezoneHelper |
| 5 | 5 | */ |
| 6 | 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 |
|
| 11 | - * if no timezone string is available. |
|
| 12 | - * |
|
| 13 | - * @since 2.1.0 |
|
| 14 | - * |
|
| 15 | - * @param DateTime $date |
|
| 16 | - * @return ActionScheduler_DateTime |
|
| 17 | - */ |
|
| 18 | - public static function set_local_timezone( DateTime $date ) { |
|
| 19 | - |
|
| 20 | - // Accept a DateTime for easier backward compatibility, even though we require methods on ActionScheduler_DateTime |
|
| 21 | - if ( ! is_a( $date, 'ActionScheduler_DateTime' ) ) { |
|
| 22 | - $date = as_get_datetime_object( $date->format( 'U' ) ); |
|
| 23 | - } |
|
| 24 | - |
|
| 25 | - if ( get_option( 'timezone_string' ) ) { |
|
| 26 | - $date->setTimezone( new DateTimeZone( self::get_local_timezone_string() ) ); |
|
| 27 | - } else { |
|
| 28 | - $date->setUtcOffset( self::get_local_timezone_offset() ); |
|
| 29 | - } |
|
| 30 | - |
|
| 31 | - return $date; |
|
| 32 | - } |
|
| 33 | - |
|
| 34 | - /** |
|
| 35 | - * Helper to retrieve the timezone string for a site until a WP core method exists |
|
| 36 | - * (see https://core.trac.wordpress.org/ticket/24730). |
|
| 37 | - * |
|
| 38 | - * Adapted from wc_timezone_string() and https://secure.php.net/manual/en/function.timezone-name-from-abbr.php#89155. |
|
| 39 | - * |
|
| 40 | - * If no timezone string is set, and its not possible to match the UTC offset set for the site to a timezone |
|
| 41 | - * string, then an empty string will be returned, and the UTC offset should be used to set a DateTime's |
|
| 42 | - * timezone. |
|
| 43 | - * |
|
| 44 | - * @since 2.1.0 |
|
| 45 | - * @return string PHP timezone string for the site or empty if no timezone string is available. |
|
| 46 | - */ |
|
| 47 | - protected static function get_local_timezone_string( $reset = false ) { |
|
| 48 | - // If site timezone string exists, return it. |
|
| 49 | - $timezone = get_option( 'timezone_string' ); |
|
| 50 | - if ( $timezone ) { |
|
| 51 | - return $timezone; |
|
| 52 | - } |
|
| 53 | - |
|
| 54 | - // Get UTC offset, if it isn't set then return UTC. |
|
| 55 | - $utc_offset = intval( get_option( 'gmt_offset', 0 ) ); |
|
| 56 | - if ( 0 === $utc_offset ) { |
|
| 57 | - return 'UTC'; |
|
| 58 | - } |
|
| 59 | - |
|
| 60 | - // Adjust UTC offset from hours to seconds. |
|
| 61 | - $utc_offset *= 3600; |
|
| 62 | - |
|
| 63 | - // Attempt to guess the timezone string from the UTC offset. |
|
| 64 | - $timezone = timezone_name_from_abbr( '', $utc_offset ); |
|
| 65 | - if ( $timezone ) { |
|
| 66 | - return $timezone; |
|
| 67 | - } |
|
| 68 | - |
|
| 69 | - // Last try, guess timezone string manually. |
|
| 70 | - foreach ( timezone_abbreviations_list() as $abbr ) { |
|
| 71 | - foreach ( $abbr as $city ) { |
|
| 72 | - if ( (bool) date( 'I' ) === (bool) $city['dst'] && $city['timezone_id'] && intval( $city['offset'] ) === $utc_offset ) { |
|
| 73 | - return $city['timezone_id']; |
|
| 74 | - } |
|
| 75 | - } |
|
| 76 | - } |
|
| 77 | - |
|
| 78 | - // No timezone string |
|
| 79 | - return ''; |
|
| 80 | - } |
|
| 81 | - |
|
| 82 | - /** |
|
| 83 | - * Get timezone offset in seconds. |
|
| 84 | - * |
|
| 85 | - * @since 2.1.0 |
|
| 86 | - * @return float |
|
| 87 | - */ |
|
| 88 | - protected static function get_local_timezone_offset() { |
|
| 89 | - $timezone = get_option( 'timezone_string' ); |
|
| 90 | - |
|
| 91 | - if ( $timezone ) { |
|
| 92 | - $timezone_object = new DateTimeZone( $timezone ); |
|
| 93 | - return $timezone_object->getOffset( new DateTime( 'now' ) ); |
|
| 94 | - } else { |
|
| 95 | - return floatval( get_option( 'gmt_offset', 0 ) ) * HOUR_IN_SECONDS; |
|
| 96 | - } |
|
| 97 | - } |
|
| 98 | - |
|
| 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 ) { |
|
| 120 | - $tzstring = timezone_name_from_abbr( '', $gmt_offset, 0 ); |
|
| 121 | - } |
|
| 122 | - |
|
| 123 | - // Try mapping to the first abbreviation we can find. |
|
| 124 | - if ( false === $tzstring ) { |
|
| 125 | - $is_dst = date( 'I' ); |
|
| 126 | - foreach ( timezone_abbreviations_list() as $abbr ) { |
|
| 127 | - foreach ( $abbr as $city ) { |
|
| 128 | - if ( $city['dst'] == $is_dst && $city['offset'] == $gmt_offset ) { |
|
| 129 | - // If there's no valid timezone ID, keep looking. |
|
| 130 | - if ( null === $city['timezone_id'] ) { |
|
| 131 | - continue; |
|
| 132 | - } |
|
| 133 | - |
|
| 134 | - $tzstring = $city['timezone_id']; |
|
| 135 | - break 2; |
|
| 136 | - } |
|
| 137 | - } |
|
| 138 | - } |
|
| 139 | - } |
|
| 140 | - |
|
| 141 | - // If we still have no valid string, then fall back to UTC. |
|
| 142 | - if ( false === $tzstring ) { |
|
| 143 | - $tzstring = 'UTC'; |
|
| 144 | - } |
|
| 145 | - } |
|
| 146 | - } |
|
| 147 | - |
|
| 148 | - self::$local_timezone = new DateTimeZone($tzstring); |
|
| 149 | - } |
|
| 150 | - return self::$local_timezone; |
|
| 151 | - } |
|
| 7 | + private static $local_timezone = NULL; |
|
| 8 | + |
|
| 9 | + /** |
|
| 10 | + * Set a DateTime's timezone to the WordPress site's timezone, or a UTC offset |
|
| 11 | + * if no timezone string is available. |
|
| 12 | + * |
|
| 13 | + * @since 2.1.0 |
|
| 14 | + * |
|
| 15 | + * @param DateTime $date |
|
| 16 | + * @return ActionScheduler_DateTime |
|
| 17 | + */ |
|
| 18 | + public static function set_local_timezone( DateTime $date ) { |
|
| 19 | + |
|
| 20 | + // Accept a DateTime for easier backward compatibility, even though we require methods on ActionScheduler_DateTime |
|
| 21 | + if ( ! is_a( $date, 'ActionScheduler_DateTime' ) ) { |
|
| 22 | + $date = as_get_datetime_object( $date->format( 'U' ) ); |
|
| 23 | + } |
|
| 24 | + |
|
| 25 | + if ( get_option( 'timezone_string' ) ) { |
|
| 26 | + $date->setTimezone( new DateTimeZone( self::get_local_timezone_string() ) ); |
|
| 27 | + } else { |
|
| 28 | + $date->setUtcOffset( self::get_local_timezone_offset() ); |
|
| 29 | + } |
|
| 30 | + |
|
| 31 | + return $date; |
|
| 32 | + } |
|
| 33 | + |
|
| 34 | + /** |
|
| 35 | + * Helper to retrieve the timezone string for a site until a WP core method exists |
|
| 36 | + * (see https://core.trac.wordpress.org/ticket/24730). |
|
| 37 | + * |
|
| 38 | + * Adapted from wc_timezone_string() and https://secure.php.net/manual/en/function.timezone-name-from-abbr.php#89155. |
|
| 39 | + * |
|
| 40 | + * If no timezone string is set, and its not possible to match the UTC offset set for the site to a timezone |
|
| 41 | + * string, then an empty string will be returned, and the UTC offset should be used to set a DateTime's |
|
| 42 | + * timezone. |
|
| 43 | + * |
|
| 44 | + * @since 2.1.0 |
|
| 45 | + * @return string PHP timezone string for the site or empty if no timezone string is available. |
|
| 46 | + */ |
|
| 47 | + protected static function get_local_timezone_string( $reset = false ) { |
|
| 48 | + // If site timezone string exists, return it. |
|
| 49 | + $timezone = get_option( 'timezone_string' ); |
|
| 50 | + if ( $timezone ) { |
|
| 51 | + return $timezone; |
|
| 52 | + } |
|
| 53 | + |
|
| 54 | + // Get UTC offset, if it isn't set then return UTC. |
|
| 55 | + $utc_offset = intval( get_option( 'gmt_offset', 0 ) ); |
|
| 56 | + if ( 0 === $utc_offset ) { |
|
| 57 | + return 'UTC'; |
|
| 58 | + } |
|
| 59 | + |
|
| 60 | + // Adjust UTC offset from hours to seconds. |
|
| 61 | + $utc_offset *= 3600; |
|
| 62 | + |
|
| 63 | + // Attempt to guess the timezone string from the UTC offset. |
|
| 64 | + $timezone = timezone_name_from_abbr( '', $utc_offset ); |
|
| 65 | + if ( $timezone ) { |
|
| 66 | + return $timezone; |
|
| 67 | + } |
|
| 68 | + |
|
| 69 | + // Last try, guess timezone string manually. |
|
| 70 | + foreach ( timezone_abbreviations_list() as $abbr ) { |
|
| 71 | + foreach ( $abbr as $city ) { |
|
| 72 | + if ( (bool) date( 'I' ) === (bool) $city['dst'] && $city['timezone_id'] && intval( $city['offset'] ) === $utc_offset ) { |
|
| 73 | + return $city['timezone_id']; |
|
| 74 | + } |
|
| 75 | + } |
|
| 76 | + } |
|
| 77 | + |
|
| 78 | + // No timezone string |
|
| 79 | + return ''; |
|
| 80 | + } |
|
| 81 | + |
|
| 82 | + /** |
|
| 83 | + * Get timezone offset in seconds. |
|
| 84 | + * |
|
| 85 | + * @since 2.1.0 |
|
| 86 | + * @return float |
|
| 87 | + */ |
|
| 88 | + protected static function get_local_timezone_offset() { |
|
| 89 | + $timezone = get_option( 'timezone_string' ); |
|
| 90 | + |
|
| 91 | + if ( $timezone ) { |
|
| 92 | + $timezone_object = new DateTimeZone( $timezone ); |
|
| 93 | + return $timezone_object->getOffset( new DateTime( 'now' ) ); |
|
| 94 | + } else { |
|
| 95 | + return floatval( get_option( 'gmt_offset', 0 ) ) * HOUR_IN_SECONDS; |
|
| 96 | + } |
|
| 97 | + } |
|
| 98 | + |
|
| 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 ) { |
|
| 120 | + $tzstring = timezone_name_from_abbr( '', $gmt_offset, 0 ); |
|
| 121 | + } |
|
| 122 | + |
|
| 123 | + // Try mapping to the first abbreviation we can find. |
|
| 124 | + if ( false === $tzstring ) { |
|
| 125 | + $is_dst = date( 'I' ); |
|
| 126 | + foreach ( timezone_abbreviations_list() as $abbr ) { |
|
| 127 | + foreach ( $abbr as $city ) { |
|
| 128 | + if ( $city['dst'] == $is_dst && $city['offset'] == $gmt_offset ) { |
|
| 129 | + // If there's no valid timezone ID, keep looking. |
|
| 130 | + if ( null === $city['timezone_id'] ) { |
|
| 131 | + continue; |
|
| 132 | + } |
|
| 133 | + |
|
| 134 | + $tzstring = $city['timezone_id']; |
|
| 135 | + break 2; |
|
| 136 | + } |
|
| 137 | + } |
|
| 138 | + } |
|
| 139 | + } |
|
| 140 | + |
|
| 141 | + // If we still have no valid string, then fall back to UTC. |
|
| 142 | + if ( false === $tzstring ) { |
|
| 143 | + $tzstring = 'UTC'; |
|
| 144 | + } |
|
| 145 | + } |
|
| 146 | + } |
|
| 147 | + |
|
| 148 | + self::$local_timezone = new DateTimeZone($tzstring); |
|
| 149 | + } |
|
| 150 | + return self::$local_timezone; |
|
| 151 | + } |
|
| 152 | 152 | } |
@@ -5,236 +5,236 @@ |
||
| 5 | 5 | */ |
| 6 | 6 | abstract class ActionScheduler_Abstract_QueueRunner extends ActionScheduler_Abstract_QueueRunner_Deprecated { |
| 7 | 7 | |
| 8 | - /** @var ActionScheduler_QueueCleaner */ |
|
| 9 | - protected $cleaner; |
|
| 10 | - |
|
| 11 | - /** @var ActionScheduler_FatalErrorMonitor */ |
|
| 12 | - protected $monitor; |
|
| 13 | - |
|
| 14 | - /** @var ActionScheduler_Store */ |
|
| 15 | - protected $store; |
|
| 16 | - |
|
| 17 | - /** |
|
| 18 | - * The created time. |
|
| 19 | - * |
|
| 20 | - * Represents when the queue runner was constructed and used when calculating how long a PHP request has been running. |
|
| 21 | - * For this reason it should be as close as possible to the PHP request start time. |
|
| 22 | - * |
|
| 23 | - * @var int |
|
| 24 | - */ |
|
| 25 | - private $created_time; |
|
| 26 | - |
|
| 27 | - /** |
|
| 28 | - * ActionScheduler_Abstract_QueueRunner constructor. |
|
| 29 | - * |
|
| 30 | - * @param ActionScheduler_Store $store |
|
| 31 | - * @param ActionScheduler_FatalErrorMonitor $monitor |
|
| 32 | - * @param ActionScheduler_QueueCleaner $cleaner |
|
| 33 | - */ |
|
| 34 | - public function __construct( ActionScheduler_Store $store = null, ActionScheduler_FatalErrorMonitor $monitor = null, ActionScheduler_QueueCleaner $cleaner = null ) { |
|
| 35 | - |
|
| 36 | - $this->created_time = microtime( true ); |
|
| 37 | - |
|
| 38 | - $this->store = $store ? $store : ActionScheduler_Store::instance(); |
|
| 39 | - $this->monitor = $monitor ? $monitor : new ActionScheduler_FatalErrorMonitor( $this->store ); |
|
| 40 | - $this->cleaner = $cleaner ? $cleaner : new ActionScheduler_QueueCleaner( $this->store ); |
|
| 41 | - } |
|
| 42 | - |
|
| 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 | - */ |
|
| 50 | - public function process_action( $action_id, $context = '' ) { |
|
| 51 | - try { |
|
| 52 | - $valid_action = false; |
|
| 53 | - do_action( 'action_scheduler_before_execute', $action_id, $context ); |
|
| 54 | - |
|
| 55 | - if ( ActionScheduler_Store::STATUS_PENDING !== $this->store->get_status( $action_id ) ) { |
|
| 56 | - do_action( 'action_scheduler_execution_ignored', $action_id, $context ); |
|
| 57 | - return; |
|
| 58 | - } |
|
| 59 | - |
|
| 60 | - $valid_action = true; |
|
| 61 | - do_action( 'action_scheduler_begin_execute', $action_id, $context ); |
|
| 62 | - |
|
| 63 | - $action = $this->store->fetch_action( $action_id ); |
|
| 64 | - $this->store->log_execution( $action_id ); |
|
| 65 | - $action->execute(); |
|
| 66 | - do_action( 'action_scheduler_after_execute', $action_id, $action, $context ); |
|
| 67 | - $this->store->mark_complete( $action_id ); |
|
| 68 | - } catch ( Exception $e ) { |
|
| 69 | - if ( $valid_action ) { |
|
| 70 | - $this->store->mark_failure( $action_id ); |
|
| 71 | - do_action( 'action_scheduler_failed_execution', $action_id, $e, $context ); |
|
| 72 | - } else { |
|
| 73 | - do_action( 'action_scheduler_failed_validation', $action_id, $e, $context ); |
|
| 74 | - } |
|
| 75 | - } |
|
| 76 | - |
|
| 77 | - if ( isset( $action ) && is_a( $action, 'ActionScheduler_Action' ) && $action->get_schedule()->is_recurring() ) { |
|
| 78 | - $this->schedule_next_instance( $action, $action_id ); |
|
| 79 | - } |
|
| 80 | - } |
|
| 81 | - |
|
| 82 | - /** |
|
| 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 { |
|
| 90 | - ActionScheduler::factory()->repeat( $action ); |
|
| 91 | - } catch ( Exception $e ) { |
|
| 92 | - do_action( 'action_scheduler_failed_to_schedule_next_instance', $action_id, $e, $action ); |
|
| 93 | - } |
|
| 94 | - } |
|
| 95 | - |
|
| 96 | - /** |
|
| 97 | - * Run the queue cleaner. |
|
| 98 | - * |
|
| 99 | - * @author Jeremy Pry |
|
| 100 | - */ |
|
| 101 | - protected function run_cleanup() { |
|
| 102 | - $this->cleaner->clean( 10 * $this->get_time_limit() ); |
|
| 103 | - } |
|
| 104 | - |
|
| 105 | - /** |
|
| 106 | - * Get the number of concurrent batches a runner allows. |
|
| 107 | - * |
|
| 108 | - * @return int |
|
| 109 | - */ |
|
| 110 | - public function get_allowed_concurrent_batches() { |
|
| 111 | - return apply_filters( 'action_scheduler_queue_runner_concurrent_batches', 1 ); |
|
| 112 | - } |
|
| 113 | - |
|
| 114 | - /** |
|
| 115 | - * Check if the number of allowed concurrent batches is met or exceeded. |
|
| 116 | - * |
|
| 117 | - * @return bool |
|
| 118 | - */ |
|
| 119 | - public function has_maximum_concurrent_batches() { |
|
| 120 | - return $this->store->get_claim_count() >= $this->get_allowed_concurrent_batches(); |
|
| 121 | - } |
|
| 122 | - |
|
| 123 | - /** |
|
| 124 | - * Get the maximum number of seconds a batch can run for. |
|
| 125 | - * |
|
| 126 | - * @return int The number of seconds. |
|
| 127 | - */ |
|
| 128 | - protected function get_time_limit() { |
|
| 129 | - |
|
| 130 | - $time_limit = 30; |
|
| 131 | - |
|
| 132 | - // Apply deprecated filter from deprecated get_maximum_execution_time() method |
|
| 133 | - if ( has_filter( 'action_scheduler_maximum_execution_time' ) ) { |
|
| 134 | - _deprecated_function( 'action_scheduler_maximum_execution_time', '2.1.1', 'action_scheduler_queue_runner_time_limit' ); |
|
| 135 | - $time_limit = apply_filters( 'action_scheduler_maximum_execution_time', $time_limit ); |
|
| 136 | - } |
|
| 137 | - |
|
| 138 | - return absint( apply_filters( 'action_scheduler_queue_runner_time_limit', $time_limit ) ); |
|
| 139 | - } |
|
| 140 | - |
|
| 141 | - /** |
|
| 142 | - * Get the number of seconds the process has been running. |
|
| 143 | - * |
|
| 144 | - * @return int The number of seconds. |
|
| 145 | - */ |
|
| 146 | - protected function get_execution_time() { |
|
| 147 | - $execution_time = microtime( true ) - $this->created_time; |
|
| 148 | - |
|
| 149 | - // Get the CPU time if the hosting environment uses it rather than wall-clock time to calculate a process's execution time. |
|
| 150 | - if ( function_exists( 'getrusage' ) && apply_filters( 'action_scheduler_use_cpu_execution_time', defined( 'PANTHEON_ENVIRONMENT' ) ) ) { |
|
| 151 | - $resource_usages = getrusage(); |
|
| 152 | - |
|
| 153 | - if ( isset( $resource_usages['ru_stime.tv_usec'], $resource_usages['ru_stime.tv_usec'] ) ) { |
|
| 154 | - $execution_time = $resource_usages['ru_stime.tv_sec'] + ( $resource_usages['ru_stime.tv_usec'] / 1000000 ); |
|
| 155 | - } |
|
| 156 | - } |
|
| 157 | - |
|
| 158 | - return $execution_time; |
|
| 159 | - } |
|
| 160 | - |
|
| 161 | - /** |
|
| 162 | - * Check if the host's max execution time is (likely) to be exceeded if processing more actions. |
|
| 163 | - * |
|
| 164 | - * @param int $processed_actions The number of actions processed so far - used to determine the likelihood of exceeding the time limit if processing another action |
|
| 165 | - * @return bool |
|
| 166 | - */ |
|
| 167 | - protected function time_likely_to_be_exceeded( $processed_actions ) { |
|
| 168 | - |
|
| 169 | - $execution_time = $this->get_execution_time(); |
|
| 170 | - $max_execution_time = $this->get_time_limit(); |
|
| 171 | - $time_per_action = $execution_time / $processed_actions; |
|
| 172 | - $estimated_time = $execution_time + ( $time_per_action * 3 ); |
|
| 173 | - $likely_to_be_exceeded = $estimated_time > $max_execution_time; |
|
| 174 | - |
|
| 175 | - return apply_filters( 'action_scheduler_maximum_execution_time_likely_to_be_exceeded', $likely_to_be_exceeded, $this, $processed_actions, $execution_time, $max_execution_time ); |
|
| 176 | - } |
|
| 177 | - |
|
| 178 | - /** |
|
| 179 | - * Get memory limit |
|
| 180 | - * |
|
| 181 | - * Based on WP_Background_Process::get_memory_limit() |
|
| 182 | - * |
|
| 183 | - * @return int |
|
| 184 | - */ |
|
| 185 | - protected function get_memory_limit() { |
|
| 186 | - if ( function_exists( 'ini_get' ) ) { |
|
| 187 | - $memory_limit = ini_get( 'memory_limit' ); |
|
| 188 | - } else { |
|
| 189 | - $memory_limit = '128M'; // Sensible default, and minimum required by WooCommerce |
|
| 190 | - } |
|
| 191 | - |
|
| 192 | - if ( ! $memory_limit || -1 === $memory_limit || '-1' === $memory_limit ) { |
|
| 193 | - // Unlimited, set to 32GB. |
|
| 194 | - $memory_limit = '32G'; |
|
| 195 | - } |
|
| 196 | - |
|
| 197 | - return ActionScheduler_Compatibility::convert_hr_to_bytes( $memory_limit ); |
|
| 198 | - } |
|
| 199 | - |
|
| 200 | - /** |
|
| 201 | - * Memory exceeded |
|
| 202 | - * |
|
| 203 | - * Ensures the batch process never exceeds 90% of the maximum WordPress memory. |
|
| 204 | - * |
|
| 205 | - * Based on WP_Background_Process::memory_exceeded() |
|
| 206 | - * |
|
| 207 | - * @return bool |
|
| 208 | - */ |
|
| 209 | - protected function memory_exceeded() { |
|
| 210 | - |
|
| 211 | - $memory_limit = $this->get_memory_limit() * 0.90; |
|
| 212 | - $current_memory = memory_get_usage( true ); |
|
| 213 | - $memory_exceeded = $current_memory >= $memory_limit; |
|
| 214 | - |
|
| 215 | - return apply_filters( 'action_scheduler_memory_exceeded', $memory_exceeded, $this ); |
|
| 216 | - } |
|
| 217 | - |
|
| 218 | - /** |
|
| 219 | - * See if the batch limits have been exceeded, which is when memory usage is almost at |
|
| 220 | - * the maximum limit, or the time to process more actions will exceed the max time limit. |
|
| 221 | - * |
|
| 222 | - * Based on WC_Background_Process::batch_limits_exceeded() |
|
| 223 | - * |
|
| 224 | - * @param int $processed_actions The number of actions processed so far - used to determine the likelihood of exceeding the time limit if processing another action |
|
| 225 | - * @return bool |
|
| 226 | - */ |
|
| 227 | - protected function batch_limits_exceeded( $processed_actions ) { |
|
| 228 | - return $this->memory_exceeded() || $this->time_likely_to_be_exceeded( $processed_actions ); |
|
| 229 | - } |
|
| 230 | - |
|
| 231 | - /** |
|
| 232 | - * Process actions in the queue. |
|
| 233 | - * |
|
| 234 | - * @author Jeremy Pry |
|
| 235 | - * @param string $context Optional identifer for the context in which this action is being processed, e.g. 'WP CLI' or 'WP Cron' |
|
| 236 | - * Generally, this should be capitalised and not localised as it's a proper noun. |
|
| 237 | - * @return int The number of actions processed. |
|
| 238 | - */ |
|
| 239 | - abstract public function run( $context = '' ); |
|
| 8 | + /** @var ActionScheduler_QueueCleaner */ |
|
| 9 | + protected $cleaner; |
|
| 10 | + |
|
| 11 | + /** @var ActionScheduler_FatalErrorMonitor */ |
|
| 12 | + protected $monitor; |
|
| 13 | + |
|
| 14 | + /** @var ActionScheduler_Store */ |
|
| 15 | + protected $store; |
|
| 16 | + |
|
| 17 | + /** |
|
| 18 | + * The created time. |
|
| 19 | + * |
|
| 20 | + * Represents when the queue runner was constructed and used when calculating how long a PHP request has been running. |
|
| 21 | + * For this reason it should be as close as possible to the PHP request start time. |
|
| 22 | + * |
|
| 23 | + * @var int |
|
| 24 | + */ |
|
| 25 | + private $created_time; |
|
| 26 | + |
|
| 27 | + /** |
|
| 28 | + * ActionScheduler_Abstract_QueueRunner constructor. |
|
| 29 | + * |
|
| 30 | + * @param ActionScheduler_Store $store |
|
| 31 | + * @param ActionScheduler_FatalErrorMonitor $monitor |
|
| 32 | + * @param ActionScheduler_QueueCleaner $cleaner |
|
| 33 | + */ |
|
| 34 | + public function __construct( ActionScheduler_Store $store = null, ActionScheduler_FatalErrorMonitor $monitor = null, ActionScheduler_QueueCleaner $cleaner = null ) { |
|
| 35 | + |
|
| 36 | + $this->created_time = microtime( true ); |
|
| 37 | + |
|
| 38 | + $this->store = $store ? $store : ActionScheduler_Store::instance(); |
|
| 39 | + $this->monitor = $monitor ? $monitor : new ActionScheduler_FatalErrorMonitor( $this->store ); |
|
| 40 | + $this->cleaner = $cleaner ? $cleaner : new ActionScheduler_QueueCleaner( $this->store ); |
|
| 41 | + } |
|
| 42 | + |
|
| 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 | + */ |
|
| 50 | + public function process_action( $action_id, $context = '' ) { |
|
| 51 | + try { |
|
| 52 | + $valid_action = false; |
|
| 53 | + do_action( 'action_scheduler_before_execute', $action_id, $context ); |
|
| 54 | + |
|
| 55 | + if ( ActionScheduler_Store::STATUS_PENDING !== $this->store->get_status( $action_id ) ) { |
|
| 56 | + do_action( 'action_scheduler_execution_ignored', $action_id, $context ); |
|
| 57 | + return; |
|
| 58 | + } |
|
| 59 | + |
|
| 60 | + $valid_action = true; |
|
| 61 | + do_action( 'action_scheduler_begin_execute', $action_id, $context ); |
|
| 62 | + |
|
| 63 | + $action = $this->store->fetch_action( $action_id ); |
|
| 64 | + $this->store->log_execution( $action_id ); |
|
| 65 | + $action->execute(); |
|
| 66 | + do_action( 'action_scheduler_after_execute', $action_id, $action, $context ); |
|
| 67 | + $this->store->mark_complete( $action_id ); |
|
| 68 | + } catch ( Exception $e ) { |
|
| 69 | + if ( $valid_action ) { |
|
| 70 | + $this->store->mark_failure( $action_id ); |
|
| 71 | + do_action( 'action_scheduler_failed_execution', $action_id, $e, $context ); |
|
| 72 | + } else { |
|
| 73 | + do_action( 'action_scheduler_failed_validation', $action_id, $e, $context ); |
|
| 74 | + } |
|
| 75 | + } |
|
| 76 | + |
|
| 77 | + if ( isset( $action ) && is_a( $action, 'ActionScheduler_Action' ) && $action->get_schedule()->is_recurring() ) { |
|
| 78 | + $this->schedule_next_instance( $action, $action_id ); |
|
| 79 | + } |
|
| 80 | + } |
|
| 81 | + |
|
| 82 | + /** |
|
| 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 { |
|
| 90 | + ActionScheduler::factory()->repeat( $action ); |
|
| 91 | + } catch ( Exception $e ) { |
|
| 92 | + do_action( 'action_scheduler_failed_to_schedule_next_instance', $action_id, $e, $action ); |
|
| 93 | + } |
|
| 94 | + } |
|
| 95 | + |
|
| 96 | + /** |
|
| 97 | + * Run the queue cleaner. |
|
| 98 | + * |
|
| 99 | + * @author Jeremy Pry |
|
| 100 | + */ |
|
| 101 | + protected function run_cleanup() { |
|
| 102 | + $this->cleaner->clean( 10 * $this->get_time_limit() ); |
|
| 103 | + } |
|
| 104 | + |
|
| 105 | + /** |
|
| 106 | + * Get the number of concurrent batches a runner allows. |
|
| 107 | + * |
|
| 108 | + * @return int |
|
| 109 | + */ |
|
| 110 | + public function get_allowed_concurrent_batches() { |
|
| 111 | + return apply_filters( 'action_scheduler_queue_runner_concurrent_batches', 1 ); |
|
| 112 | + } |
|
| 113 | + |
|
| 114 | + /** |
|
| 115 | + * Check if the number of allowed concurrent batches is met or exceeded. |
|
| 116 | + * |
|
| 117 | + * @return bool |
|
| 118 | + */ |
|
| 119 | + public function has_maximum_concurrent_batches() { |
|
| 120 | + return $this->store->get_claim_count() >= $this->get_allowed_concurrent_batches(); |
|
| 121 | + } |
|
| 122 | + |
|
| 123 | + /** |
|
| 124 | + * Get the maximum number of seconds a batch can run for. |
|
| 125 | + * |
|
| 126 | + * @return int The number of seconds. |
|
| 127 | + */ |
|
| 128 | + protected function get_time_limit() { |
|
| 129 | + |
|
| 130 | + $time_limit = 30; |
|
| 131 | + |
|
| 132 | + // Apply deprecated filter from deprecated get_maximum_execution_time() method |
|
| 133 | + if ( has_filter( 'action_scheduler_maximum_execution_time' ) ) { |
|
| 134 | + _deprecated_function( 'action_scheduler_maximum_execution_time', '2.1.1', 'action_scheduler_queue_runner_time_limit' ); |
|
| 135 | + $time_limit = apply_filters( 'action_scheduler_maximum_execution_time', $time_limit ); |
|
| 136 | + } |
|
| 137 | + |
|
| 138 | + return absint( apply_filters( 'action_scheduler_queue_runner_time_limit', $time_limit ) ); |
|
| 139 | + } |
|
| 140 | + |
|
| 141 | + /** |
|
| 142 | + * Get the number of seconds the process has been running. |
|
| 143 | + * |
|
| 144 | + * @return int The number of seconds. |
|
| 145 | + */ |
|
| 146 | + protected function get_execution_time() { |
|
| 147 | + $execution_time = microtime( true ) - $this->created_time; |
|
| 148 | + |
|
| 149 | + // Get the CPU time if the hosting environment uses it rather than wall-clock time to calculate a process's execution time. |
|
| 150 | + if ( function_exists( 'getrusage' ) && apply_filters( 'action_scheduler_use_cpu_execution_time', defined( 'PANTHEON_ENVIRONMENT' ) ) ) { |
|
| 151 | + $resource_usages = getrusage(); |
|
| 152 | + |
|
| 153 | + if ( isset( $resource_usages['ru_stime.tv_usec'], $resource_usages['ru_stime.tv_usec'] ) ) { |
|
| 154 | + $execution_time = $resource_usages['ru_stime.tv_sec'] + ( $resource_usages['ru_stime.tv_usec'] / 1000000 ); |
|
| 155 | + } |
|
| 156 | + } |
|
| 157 | + |
|
| 158 | + return $execution_time; |
|
| 159 | + } |
|
| 160 | + |
|
| 161 | + /** |
|
| 162 | + * Check if the host's max execution time is (likely) to be exceeded if processing more actions. |
|
| 163 | + * |
|
| 164 | + * @param int $processed_actions The number of actions processed so far - used to determine the likelihood of exceeding the time limit if processing another action |
|
| 165 | + * @return bool |
|
| 166 | + */ |
|
| 167 | + protected function time_likely_to_be_exceeded( $processed_actions ) { |
|
| 168 | + |
|
| 169 | + $execution_time = $this->get_execution_time(); |
|
| 170 | + $max_execution_time = $this->get_time_limit(); |
|
| 171 | + $time_per_action = $execution_time / $processed_actions; |
|
| 172 | + $estimated_time = $execution_time + ( $time_per_action * 3 ); |
|
| 173 | + $likely_to_be_exceeded = $estimated_time > $max_execution_time; |
|
| 174 | + |
|
| 175 | + return apply_filters( 'action_scheduler_maximum_execution_time_likely_to_be_exceeded', $likely_to_be_exceeded, $this, $processed_actions, $execution_time, $max_execution_time ); |
|
| 176 | + } |
|
| 177 | + |
|
| 178 | + /** |
|
| 179 | + * Get memory limit |
|
| 180 | + * |
|
| 181 | + * Based on WP_Background_Process::get_memory_limit() |
|
| 182 | + * |
|
| 183 | + * @return int |
|
| 184 | + */ |
|
| 185 | + protected function get_memory_limit() { |
|
| 186 | + if ( function_exists( 'ini_get' ) ) { |
|
| 187 | + $memory_limit = ini_get( 'memory_limit' ); |
|
| 188 | + } else { |
|
| 189 | + $memory_limit = '128M'; // Sensible default, and minimum required by WooCommerce |
|
| 190 | + } |
|
| 191 | + |
|
| 192 | + if ( ! $memory_limit || -1 === $memory_limit || '-1' === $memory_limit ) { |
|
| 193 | + // Unlimited, set to 32GB. |
|
| 194 | + $memory_limit = '32G'; |
|
| 195 | + } |
|
| 196 | + |
|
| 197 | + return ActionScheduler_Compatibility::convert_hr_to_bytes( $memory_limit ); |
|
| 198 | + } |
|
| 199 | + |
|
| 200 | + /** |
|
| 201 | + * Memory exceeded |
|
| 202 | + * |
|
| 203 | + * Ensures the batch process never exceeds 90% of the maximum WordPress memory. |
|
| 204 | + * |
|
| 205 | + * Based on WP_Background_Process::memory_exceeded() |
|
| 206 | + * |
|
| 207 | + * @return bool |
|
| 208 | + */ |
|
| 209 | + protected function memory_exceeded() { |
|
| 210 | + |
|
| 211 | + $memory_limit = $this->get_memory_limit() * 0.90; |
|
| 212 | + $current_memory = memory_get_usage( true ); |
|
| 213 | + $memory_exceeded = $current_memory >= $memory_limit; |
|
| 214 | + |
|
| 215 | + return apply_filters( 'action_scheduler_memory_exceeded', $memory_exceeded, $this ); |
|
| 216 | + } |
|
| 217 | + |
|
| 218 | + /** |
|
| 219 | + * See if the batch limits have been exceeded, which is when memory usage is almost at |
|
| 220 | + * the maximum limit, or the time to process more actions will exceed the max time limit. |
|
| 221 | + * |
|
| 222 | + * Based on WC_Background_Process::batch_limits_exceeded() |
|
| 223 | + * |
|
| 224 | + * @param int $processed_actions The number of actions processed so far - used to determine the likelihood of exceeding the time limit if processing another action |
|
| 225 | + * @return bool |
|
| 226 | + */ |
|
| 227 | + protected function batch_limits_exceeded( $processed_actions ) { |
|
| 228 | + return $this->memory_exceeded() || $this->time_likely_to_be_exceeded( $processed_actions ); |
|
| 229 | + } |
|
| 230 | + |
|
| 231 | + /** |
|
| 232 | + * Process actions in the queue. |
|
| 233 | + * |
|
| 234 | + * @author Jeremy Pry |
|
| 235 | + * @param string $context Optional identifer for the context in which this action is being processed, e.g. 'WP CLI' or 'WP Cron' |
|
| 236 | + * Generally, this should be capitalised and not localised as it's a proper noun. |
|
| 237 | + * @return int The number of actions processed. |
|
| 238 | + */ |
|
| 239 | + abstract public function run( $context = '' ); |
|
| 240 | 240 | } |
@@ -7,109 +7,109 @@ |
||
| 7 | 7 | */ |
| 8 | 8 | class ActionScheduler_WPCommentCleaner { |
| 9 | 9 | |
| 10 | - /** |
|
| 11 | - * Post migration hook used to cleanup the WP comment table. |
|
| 12 | - * |
|
| 13 | - * @var string |
|
| 14 | - */ |
|
| 15 | - protected static $cleanup_hook = 'action_scheduler/cleanup_wp_comment_logs'; |
|
| 16 | - |
|
| 17 | - /** |
|
| 18 | - * An instance of the ActionScheduler_wpCommentLogger class to interact with the comments table. |
|
| 19 | - * |
|
| 20 | - * This instance should only be used as an interface. It should not be initialized. |
|
| 21 | - * |
|
| 22 | - * @var ActionScheduler_wpCommentLogger |
|
| 23 | - */ |
|
| 24 | - protected static $wp_comment_logger = null; |
|
| 25 | - |
|
| 26 | - /** |
|
| 27 | - * The key used to store the cached value of whether there are logs in the WP comment table. |
|
| 28 | - * |
|
| 29 | - * @var string |
|
| 30 | - */ |
|
| 31 | - protected static $has_logs_option_key = 'as_has_wp_comment_logs'; |
|
| 32 | - |
|
| 33 | - /** |
|
| 34 | - * Initialize the class and attach callbacks. |
|
| 35 | - */ |
|
| 36 | - public static function init() { |
|
| 37 | - if ( empty( self::$wp_comment_logger ) ) { |
|
| 38 | - self::$wp_comment_logger = new ActionScheduler_wpCommentLogger(); |
|
| 39 | - } |
|
| 40 | - |
|
| 41 | - add_action( self::$cleanup_hook, array( __CLASS__, 'delete_all_action_comments' ) ); |
|
| 42 | - |
|
| 43 | - // While there are orphaned logs left in the comments table, we need to attach the callbacks which filter comment counts. |
|
| 44 | - add_action( 'pre_get_comments', array( self::$wp_comment_logger, 'filter_comment_queries' ), 10, 1 ); |
|
| 45 | - add_action( 'wp_count_comments', array( self::$wp_comment_logger, 'filter_comment_count' ), 20, 2 ); // run after WC_Comments::wp_count_comments() to make sure we exclude order notes and action logs |
|
| 46 | - add_action( 'comment_feed_where', array( self::$wp_comment_logger, 'filter_comment_feed' ), 10, 2 ); |
|
| 47 | - |
|
| 48 | - // Action Scheduler may be displayed as a Tools screen or WooCommerce > Status administration screen |
|
| 49 | - add_action( 'load-tools_page_action-scheduler', array( __CLASS__, 'register_admin_notice' ) ); |
|
| 50 | - add_action( 'load-woocommerce_page_wc-status', array( __CLASS__, 'register_admin_notice' ) ); |
|
| 51 | - } |
|
| 52 | - |
|
| 53 | - /** |
|
| 54 | - * Determines if there are log entries in the wp comments table. |
|
| 55 | - * |
|
| 56 | - * Uses the flag set on migration completion set by @see self::maybe_schedule_cleanup(). |
|
| 57 | - * |
|
| 58 | - * @return boolean Whether there are scheduled action comments in the comments table. |
|
| 59 | - */ |
|
| 60 | - public static function has_logs() { |
|
| 61 | - return 'yes' === get_option( self::$has_logs_option_key ); |
|
| 62 | - } |
|
| 63 | - |
|
| 64 | - /** |
|
| 65 | - * Schedules the WP Post comment table cleanup to run in 6 months if it's not already scheduled. |
|
| 66 | - * Attached to the migration complete hook 'action_scheduler/migration_complete'. |
|
| 67 | - */ |
|
| 68 | - public static function maybe_schedule_cleanup() { |
|
| 69 | - if ( (bool) get_comments( array( 'type' => ActionScheduler_wpCommentLogger::TYPE, 'number' => 1, 'fields' => 'ids' ) ) ) { |
|
| 70 | - update_option( self::$has_logs_option_key, 'yes' ); |
|
| 71 | - |
|
| 72 | - if ( ! as_next_scheduled_action( self::$cleanup_hook ) ) { |
|
| 73 | - as_schedule_single_action( gmdate( 'U' ) + ( 6 * MONTH_IN_SECONDS ), self::$cleanup_hook ); |
|
| 74 | - } |
|
| 75 | - } |
|
| 76 | - } |
|
| 77 | - |
|
| 78 | - /** |
|
| 79 | - * Delete all action comments from the WP Comments table. |
|
| 80 | - */ |
|
| 81 | - public static function delete_all_action_comments() { |
|
| 82 | - global $wpdb; |
|
| 83 | - $wpdb->delete( $wpdb->comments, array( 'comment_type' => ActionScheduler_wpCommentLogger::TYPE, 'comment_agent' => ActionScheduler_wpCommentLogger::AGENT ) ); |
|
| 84 | - delete_option( self::$has_logs_option_key ); |
|
| 85 | - } |
|
| 86 | - |
|
| 87 | - /** |
|
| 88 | - * Registers admin notices about the orphaned action logs. |
|
| 89 | - */ |
|
| 90 | - public static function register_admin_notice() { |
|
| 91 | - add_action( 'admin_notices', array( __CLASS__, 'print_admin_notice' ) ); |
|
| 92 | - } |
|
| 10 | + /** |
|
| 11 | + * Post migration hook used to cleanup the WP comment table. |
|
| 12 | + * |
|
| 13 | + * @var string |
|
| 14 | + */ |
|
| 15 | + protected static $cleanup_hook = 'action_scheduler/cleanup_wp_comment_logs'; |
|
| 16 | + |
|
| 17 | + /** |
|
| 18 | + * An instance of the ActionScheduler_wpCommentLogger class to interact with the comments table. |
|
| 19 | + * |
|
| 20 | + * This instance should only be used as an interface. It should not be initialized. |
|
| 21 | + * |
|
| 22 | + * @var ActionScheduler_wpCommentLogger |
|
| 23 | + */ |
|
| 24 | + protected static $wp_comment_logger = null; |
|
| 25 | + |
|
| 26 | + /** |
|
| 27 | + * The key used to store the cached value of whether there are logs in the WP comment table. |
|
| 28 | + * |
|
| 29 | + * @var string |
|
| 30 | + */ |
|
| 31 | + protected static $has_logs_option_key = 'as_has_wp_comment_logs'; |
|
| 32 | + |
|
| 33 | + /** |
|
| 34 | + * Initialize the class and attach callbacks. |
|
| 35 | + */ |
|
| 36 | + public static function init() { |
|
| 37 | + if ( empty( self::$wp_comment_logger ) ) { |
|
| 38 | + self::$wp_comment_logger = new ActionScheduler_wpCommentLogger(); |
|
| 39 | + } |
|
| 40 | + |
|
| 41 | + add_action( self::$cleanup_hook, array( __CLASS__, 'delete_all_action_comments' ) ); |
|
| 42 | + |
|
| 43 | + // While there are orphaned logs left in the comments table, we need to attach the callbacks which filter comment counts. |
|
| 44 | + add_action( 'pre_get_comments', array( self::$wp_comment_logger, 'filter_comment_queries' ), 10, 1 ); |
|
| 45 | + add_action( 'wp_count_comments', array( self::$wp_comment_logger, 'filter_comment_count' ), 20, 2 ); // run after WC_Comments::wp_count_comments() to make sure we exclude order notes and action logs |
|
| 46 | + add_action( 'comment_feed_where', array( self::$wp_comment_logger, 'filter_comment_feed' ), 10, 2 ); |
|
| 47 | + |
|
| 48 | + // Action Scheduler may be displayed as a Tools screen or WooCommerce > Status administration screen |
|
| 49 | + add_action( 'load-tools_page_action-scheduler', array( __CLASS__, 'register_admin_notice' ) ); |
|
| 50 | + add_action( 'load-woocommerce_page_wc-status', array( __CLASS__, 'register_admin_notice' ) ); |
|
| 51 | + } |
|
| 52 | + |
|
| 53 | + /** |
|
| 54 | + * Determines if there are log entries in the wp comments table. |
|
| 55 | + * |
|
| 56 | + * Uses the flag set on migration completion set by @see self::maybe_schedule_cleanup(). |
|
| 57 | + * |
|
| 58 | + * @return boolean Whether there are scheduled action comments in the comments table. |
|
| 59 | + */ |
|
| 60 | + public static function has_logs() { |
|
| 61 | + return 'yes' === get_option( self::$has_logs_option_key ); |
|
| 62 | + } |
|
| 63 | + |
|
| 64 | + /** |
|
| 65 | + * Schedules the WP Post comment table cleanup to run in 6 months if it's not already scheduled. |
|
| 66 | + * Attached to the migration complete hook 'action_scheduler/migration_complete'. |
|
| 67 | + */ |
|
| 68 | + public static function maybe_schedule_cleanup() { |
|
| 69 | + if ( (bool) get_comments( array( 'type' => ActionScheduler_wpCommentLogger::TYPE, 'number' => 1, 'fields' => 'ids' ) ) ) { |
|
| 70 | + update_option( self::$has_logs_option_key, 'yes' ); |
|
| 71 | + |
|
| 72 | + if ( ! as_next_scheduled_action( self::$cleanup_hook ) ) { |
|
| 73 | + as_schedule_single_action( gmdate( 'U' ) + ( 6 * MONTH_IN_SECONDS ), self::$cleanup_hook ); |
|
| 74 | + } |
|
| 75 | + } |
|
| 76 | + } |
|
| 77 | + |
|
| 78 | + /** |
|
| 79 | + * Delete all action comments from the WP Comments table. |
|
| 80 | + */ |
|
| 81 | + public static function delete_all_action_comments() { |
|
| 82 | + global $wpdb; |
|
| 83 | + $wpdb->delete( $wpdb->comments, array( 'comment_type' => ActionScheduler_wpCommentLogger::TYPE, 'comment_agent' => ActionScheduler_wpCommentLogger::AGENT ) ); |
|
| 84 | + delete_option( self::$has_logs_option_key ); |
|
| 85 | + } |
|
| 86 | + |
|
| 87 | + /** |
|
| 88 | + * Registers admin notices about the orphaned action logs. |
|
| 89 | + */ |
|
| 90 | + public static function register_admin_notice() { |
|
| 91 | + add_action( 'admin_notices', array( __CLASS__, 'print_admin_notice' ) ); |
|
| 92 | + } |
|
| 93 | 93 | |
| 94 | - /** |
|
| 95 | - * Prints details about the orphaned action logs and includes information on where to learn more. |
|
| 96 | - */ |
|
| 97 | - public static function print_admin_notice() { |
|
| 98 | - $next_cleanup_message = ''; |
|
| 99 | - $next_scheduled_cleanup_hook = as_next_scheduled_action( self::$cleanup_hook ); |
|
| 100 | - |
|
| 101 | - if ( $next_scheduled_cleanup_hook ) { |
|
| 102 | - /* translators: %s: date interval */ |
|
| 103 | - $next_cleanup_message = sprintf( __( 'This data will be deleted in %s.', 'woocommerce' ), human_time_diff( gmdate( 'U' ), $next_scheduled_cleanup_hook ) ); |
|
| 104 | - } |
|
| 105 | - |
|
| 106 | - $notice = sprintf( |
|
| 107 | - /* translators: 1: next cleanup message 2: github issue URL */ |
|
| 108 | - __( 'Action Scheduler has migrated data to custom tables; however, orphaned log entries exist in the WordPress Comments table. %1$s <a href="%2$s">Learn more »</a>', 'woocommerce' ), |
|
| 109 | - $next_cleanup_message, |
|
| 110 | - 'https://github.com/woocommerce/action-scheduler/issues/368' |
|
| 111 | - ); |
|
| 112 | - |
|
| 113 | - echo '<div class="notice notice-warning"><p>' . wp_kses_post( $notice ) . '</p></div>'; |
|
| 114 | - } |
|
| 94 | + /** |
|
| 95 | + * Prints details about the orphaned action logs and includes information on where to learn more. |
|
| 96 | + */ |
|
| 97 | + public static function print_admin_notice() { |
|
| 98 | + $next_cleanup_message = ''; |
|
| 99 | + $next_scheduled_cleanup_hook = as_next_scheduled_action( self::$cleanup_hook ); |
|
| 100 | + |
|
| 101 | + if ( $next_scheduled_cleanup_hook ) { |
|
| 102 | + /* translators: %s: date interval */ |
|
| 103 | + $next_cleanup_message = sprintf( __( 'This data will be deleted in %s.', 'woocommerce' ), human_time_diff( gmdate( 'U' ), $next_scheduled_cleanup_hook ) ); |
|
| 104 | + } |
|
| 105 | + |
|
| 106 | + $notice = sprintf( |
|
| 107 | + /* translators: 1: next cleanup message 2: github issue URL */ |
|
| 108 | + __( 'Action Scheduler has migrated data to custom tables; however, orphaned log entries exist in the WordPress Comments table. %1$s <a href="%2$s">Learn more »</a>', 'woocommerce' ), |
|
| 109 | + $next_cleanup_message, |
|
| 110 | + 'https://github.com/woocommerce/action-scheduler/issues/368' |
|
| 111 | + ); |
|
| 112 | + |
|
| 113 | + echo '<div class="notice notice-warning"><p>' . wp_kses_post( $notice ) . '</p></div>'; |
|
| 114 | + } |
|
| 115 | 115 | } |
@@ -10,88 +10,88 @@ |
||
| 10 | 10 | */ |
| 11 | 11 | class ActionScheduler_AsyncRequest_QueueRunner extends WP_Async_Request { |
| 12 | 12 | |
| 13 | - /** |
|
| 14 | - * Data store for querying actions |
|
| 15 | - * |
|
| 16 | - * @var ActionScheduler_Store |
|
| 17 | - * @access protected |
|
| 18 | - */ |
|
| 19 | - protected $store; |
|
| 20 | - |
|
| 21 | - /** |
|
| 22 | - * Prefix for ajax hooks |
|
| 23 | - * |
|
| 24 | - * @var string |
|
| 25 | - * @access protected |
|
| 26 | - */ |
|
| 27 | - protected $prefix = 'as'; |
|
| 28 | - |
|
| 29 | - /** |
|
| 30 | - * Action for ajax hooks |
|
| 31 | - * |
|
| 32 | - * @var string |
|
| 33 | - * @access protected |
|
| 34 | - */ |
|
| 35 | - protected $action = 'async_request_queue_runner'; |
|
| 36 | - |
|
| 37 | - /** |
|
| 38 | - * Initiate new async request |
|
| 39 | - */ |
|
| 40 | - public function __construct( ActionScheduler_Store $store ) { |
|
| 41 | - parent::__construct(); |
|
| 42 | - $this->store = $store; |
|
| 43 | - } |
|
| 44 | - |
|
| 45 | - /** |
|
| 46 | - * Handle async requests |
|
| 47 | - * |
|
| 48 | - * Run a queue, and maybe dispatch another async request to run another queue |
|
| 49 | - * if there are still pending actions after completing a queue in this request. |
|
| 50 | - */ |
|
| 51 | - protected function handle() { |
|
| 52 | - do_action( 'action_scheduler_run_queue', 'Async Request' ); // run a queue in the same way as WP Cron, but declare the Async Request context |
|
| 53 | - |
|
| 54 | - $sleep_seconds = $this->get_sleep_seconds(); |
|
| 55 | - |
|
| 56 | - if ( $sleep_seconds ) { |
|
| 57 | - sleep( $sleep_seconds ); |
|
| 58 | - } |
|
| 59 | - |
|
| 60 | - $this->maybe_dispatch(); |
|
| 61 | - } |
|
| 62 | - |
|
| 63 | - /** |
|
| 64 | - * If the async request runner is needed and allowed to run, dispatch a request. |
|
| 65 | - */ |
|
| 66 | - public function maybe_dispatch() { |
|
| 67 | - if ( ! $this->allow() ) { |
|
| 68 | - return; |
|
| 69 | - } |
|
| 70 | - |
|
| 71 | - $this->dispatch(); |
|
| 72 | - ActionScheduler_QueueRunner::instance()->unhook_dispatch_async_request(); |
|
| 73 | - } |
|
| 74 | - |
|
| 75 | - /** |
|
| 76 | - * Only allow async requests when needed. |
|
| 77 | - * |
|
| 78 | - * Also allow 3rd party code to disable running actions via async requests. |
|
| 79 | - */ |
|
| 80 | - protected function allow() { |
|
| 81 | - |
|
| 82 | - if ( ! has_action( 'action_scheduler_run_queue' ) || ActionScheduler::runner()->has_maximum_concurrent_batches() || ! $this->store->has_pending_actions_due() ) { |
|
| 83 | - $allow = false; |
|
| 84 | - } else { |
|
| 85 | - $allow = true; |
|
| 86 | - } |
|
| 87 | - |
|
| 88 | - return apply_filters( 'action_scheduler_allow_async_request_runner', $allow ); |
|
| 89 | - } |
|
| 90 | - |
|
| 91 | - /** |
|
| 92 | - * Chaining async requests can crash MySQL. A brief sleep call in PHP prevents that. |
|
| 93 | - */ |
|
| 94 | - protected function get_sleep_seconds() { |
|
| 95 | - return apply_filters( 'action_scheduler_async_request_sleep_seconds', 5, $this ); |
|
| 96 | - } |
|
| 13 | + /** |
|
| 14 | + * Data store for querying actions |
|
| 15 | + * |
|
| 16 | + * @var ActionScheduler_Store |
|
| 17 | + * @access protected |
|
| 18 | + */ |
|
| 19 | + protected $store; |
|
| 20 | + |
|
| 21 | + /** |
|
| 22 | + * Prefix for ajax hooks |
|
| 23 | + * |
|
| 24 | + * @var string |
|
| 25 | + * @access protected |
|
| 26 | + */ |
|
| 27 | + protected $prefix = 'as'; |
|
| 28 | + |
|
| 29 | + /** |
|
| 30 | + * Action for ajax hooks |
|
| 31 | + * |
|
| 32 | + * @var string |
|
| 33 | + * @access protected |
|
| 34 | + */ |
|
| 35 | + protected $action = 'async_request_queue_runner'; |
|
| 36 | + |
|
| 37 | + /** |
|
| 38 | + * Initiate new async request |
|
| 39 | + */ |
|
| 40 | + public function __construct( ActionScheduler_Store $store ) { |
|
| 41 | + parent::__construct(); |
|
| 42 | + $this->store = $store; |
|
| 43 | + } |
|
| 44 | + |
|
| 45 | + /** |
|
| 46 | + * Handle async requests |
|
| 47 | + * |
|
| 48 | + * Run a queue, and maybe dispatch another async request to run another queue |
|
| 49 | + * if there are still pending actions after completing a queue in this request. |
|
| 50 | + */ |
|
| 51 | + protected function handle() { |
|
| 52 | + do_action( 'action_scheduler_run_queue', 'Async Request' ); // run a queue in the same way as WP Cron, but declare the Async Request context |
|
| 53 | + |
|
| 54 | + $sleep_seconds = $this->get_sleep_seconds(); |
|
| 55 | + |
|
| 56 | + if ( $sleep_seconds ) { |
|
| 57 | + sleep( $sleep_seconds ); |
|
| 58 | + } |
|
| 59 | + |
|
| 60 | + $this->maybe_dispatch(); |
|
| 61 | + } |
|
| 62 | + |
|
| 63 | + /** |
|
| 64 | + * If the async request runner is needed and allowed to run, dispatch a request. |
|
| 65 | + */ |
|
| 66 | + public function maybe_dispatch() { |
|
| 67 | + if ( ! $this->allow() ) { |
|
| 68 | + return; |
|
| 69 | + } |
|
| 70 | + |
|
| 71 | + $this->dispatch(); |
|
| 72 | + ActionScheduler_QueueRunner::instance()->unhook_dispatch_async_request(); |
|
| 73 | + } |
|
| 74 | + |
|
| 75 | + /** |
|
| 76 | + * Only allow async requests when needed. |
|
| 77 | + * |
|
| 78 | + * Also allow 3rd party code to disable running actions via async requests. |
|
| 79 | + */ |
|
| 80 | + protected function allow() { |
|
| 81 | + |
|
| 82 | + if ( ! has_action( 'action_scheduler_run_queue' ) || ActionScheduler::runner()->has_maximum_concurrent_batches() || ! $this->store->has_pending_actions_due() ) { |
|
| 83 | + $allow = false; |
|
| 84 | + } else { |
|
| 85 | + $allow = true; |
|
| 86 | + } |
|
| 87 | + |
|
| 88 | + return apply_filters( 'action_scheduler_allow_async_request_runner', $allow ); |
|
| 89 | + } |
|
| 90 | + |
|
| 91 | + /** |
|
| 92 | + * Chaining async requests can crash MySQL. A brief sleep call in PHP prevents that. |
|
| 93 | + */ |
|
| 94 | + protected function get_sleep_seconds() { |
|
| 95 | + return apply_filters( 'action_scheduler_async_request_sleep_seconds', 5, $this ); |
|
| 96 | + } |
|
| 97 | 97 | } |
@@ -5,63 +5,63 @@ |
||
| 5 | 5 | */ |
| 6 | 6 | class ActionScheduler_LogEntry { |
| 7 | 7 | |
| 8 | - /** |
|
| 9 | - * @var int $action_id |
|
| 10 | - */ |
|
| 11 | - protected $action_id = ''; |
|
| 8 | + /** |
|
| 9 | + * @var int $action_id |
|
| 10 | + */ |
|
| 11 | + protected $action_id = ''; |
|
| 12 | 12 | |
| 13 | - /** |
|
| 14 | - * @var string $message |
|
| 15 | - */ |
|
| 16 | - protected $message = ''; |
|
| 13 | + /** |
|
| 14 | + * @var string $message |
|
| 15 | + */ |
|
| 16 | + protected $message = ''; |
|
| 17 | 17 | |
| 18 | - /** |
|
| 19 | - * @var Datetime $date |
|
| 20 | - */ |
|
| 21 | - protected $date; |
|
| 18 | + /** |
|
| 19 | + * @var Datetime $date |
|
| 20 | + */ |
|
| 21 | + protected $date; |
|
| 22 | 22 | |
| 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 | - */ |
|
| 31 | - public function __construct( $action_id, $message, $date = null ) { |
|
| 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 | + */ |
|
| 31 | + public function __construct( $action_id, $message, $date = null ) { |
|
| 32 | 32 | |
| 33 | - /* |
|
| 33 | + /* |
|
| 34 | 34 | * ActionScheduler_wpCommentLogger::get_entry() previously passed a 3rd param of $comment->comment_type |
| 35 | 35 | * to ActionScheduler_LogEntry::__construct(), goodness knows why, and the Follow-up Emails plugin |
| 36 | 36 | * hard-codes loading its own version of ActionScheduler_wpCommentLogger with that out-dated method, |
| 37 | 37 | * goodness knows why, so we need to guard against that here instead of using a DateTime type declaration |
| 38 | 38 | * for the constructor's 3rd param of $date and causing a fatal error with older versions of FUE. |
| 39 | 39 | */ |
| 40 | - if ( null !== $date && ! is_a( $date, 'DateTime' ) ) { |
|
| 41 | - _doing_it_wrong( __METHOD__, 'The third parameter must be a valid DateTime instance, or null.', '2.0.0' ); |
|
| 42 | - $date = null; |
|
| 43 | - } |
|
| 40 | + if ( null !== $date && ! is_a( $date, 'DateTime' ) ) { |
|
| 41 | + _doing_it_wrong( __METHOD__, 'The third parameter must be a valid DateTime instance, or null.', '2.0.0' ); |
|
| 42 | + $date = null; |
|
| 43 | + } |
|
| 44 | 44 | |
| 45 | - $this->action_id = $action_id; |
|
| 46 | - $this->message = $message; |
|
| 47 | - $this->date = $date ? $date : new Datetime; |
|
| 48 | - } |
|
| 45 | + $this->action_id = $action_id; |
|
| 46 | + $this->message = $message; |
|
| 47 | + $this->date = $date ? $date : new Datetime; |
|
| 48 | + } |
|
| 49 | 49 | |
| 50 | - /** |
|
| 51 | - * Returns the date when this log entry was created |
|
| 52 | - * |
|
| 53 | - * @return Datetime |
|
| 54 | - */ |
|
| 55 | - public function get_date() { |
|
| 56 | - return $this->date; |
|
| 57 | - } |
|
| 50 | + /** |
|
| 51 | + * Returns the date when this log entry was created |
|
| 52 | + * |
|
| 53 | + * @return Datetime |
|
| 54 | + */ |
|
| 55 | + public function get_date() { |
|
| 56 | + return $this->date; |
|
| 57 | + } |
|
| 58 | 58 | |
| 59 | - public function get_action_id() { |
|
| 60 | - return $this->action_id; |
|
| 61 | - } |
|
| 59 | + public function get_action_id() { |
|
| 60 | + return $this->action_id; |
|
| 61 | + } |
|
| 62 | 62 | |
| 63 | - public function get_message() { |
|
| 64 | - return $this->message; |
|
| 65 | - } |
|
| 63 | + public function get_message() { |
|
| 64 | + return $this->message; |
|
| 65 | + } |
|
| 66 | 66 | } |
| 67 | 67 | |
@@ -7,73 +7,73 @@ |
||
| 7 | 7 | */ |
| 8 | 8 | class ActionScheduler_DateTime extends DateTime { |
| 9 | 9 | |
| 10 | - /** |
|
| 11 | - * UTC offset. |
|
| 12 | - * |
|
| 13 | - * Only used when a timezone is not set. When a timezone string is |
|
| 14 | - * used, this will be set to 0. |
|
| 15 | - * |
|
| 16 | - * @var int |
|
| 17 | - */ |
|
| 18 | - protected $utcOffset = 0; |
|
| 10 | + /** |
|
| 11 | + * UTC offset. |
|
| 12 | + * |
|
| 13 | + * Only used when a timezone is not set. When a timezone string is |
|
| 14 | + * used, this will be set to 0. |
|
| 15 | + * |
|
| 16 | + * @var int |
|
| 17 | + */ |
|
| 18 | + protected $utcOffset = 0; |
|
| 19 | 19 | |
| 20 | - /** |
|
| 21 | - * Get the unix timestamp of the current object. |
|
| 22 | - * |
|
| 23 | - * Missing in PHP 5.2 so just here so it can be supported consistently. |
|
| 24 | - * |
|
| 25 | - * @return int |
|
| 26 | - */ |
|
| 27 | - #[\ReturnTypeWillChange] |
|
| 28 | - public function getTimestamp() { |
|
| 29 | - return method_exists( 'DateTime', 'getTimestamp' ) ? parent::getTimestamp() : $this->format( 'U' ); |
|
| 30 | - } |
|
| 20 | + /** |
|
| 21 | + * Get the unix timestamp of the current object. |
|
| 22 | + * |
|
| 23 | + * Missing in PHP 5.2 so just here so it can be supported consistently. |
|
| 24 | + * |
|
| 25 | + * @return int |
|
| 26 | + */ |
|
| 27 | + #[\ReturnTypeWillChange] |
|
| 28 | + public function getTimestamp() { |
|
| 29 | + return method_exists( 'DateTime', 'getTimestamp' ) ? parent::getTimestamp() : $this->format( 'U' ); |
|
| 30 | + } |
|
| 31 | 31 | |
| 32 | - /** |
|
| 33 | - * Set the UTC offset. |
|
| 34 | - * |
|
| 35 | - * This represents a fixed offset instead of a timezone setting. |
|
| 36 | - * |
|
| 37 | - * @param $offset |
|
| 38 | - */ |
|
| 39 | - public function setUtcOffset( $offset ) { |
|
| 40 | - $this->utcOffset = intval( $offset ); |
|
| 41 | - } |
|
| 32 | + /** |
|
| 33 | + * Set the UTC offset. |
|
| 34 | + * |
|
| 35 | + * This represents a fixed offset instead of a timezone setting. |
|
| 36 | + * |
|
| 37 | + * @param $offset |
|
| 38 | + */ |
|
| 39 | + public function setUtcOffset( $offset ) { |
|
| 40 | + $this->utcOffset = intval( $offset ); |
|
| 41 | + } |
|
| 42 | 42 | |
| 43 | - /** |
|
| 44 | - * Returns the timezone offset. |
|
| 45 | - * |
|
| 46 | - * @return int |
|
| 47 | - * @link http://php.net/manual/en/datetime.getoffset.php |
|
| 48 | - */ |
|
| 49 | - #[\ReturnTypeWillChange] |
|
| 50 | - public function getOffset() { |
|
| 51 | - return $this->utcOffset ? $this->utcOffset : parent::getOffset(); |
|
| 52 | - } |
|
| 43 | + /** |
|
| 44 | + * Returns the timezone offset. |
|
| 45 | + * |
|
| 46 | + * @return int |
|
| 47 | + * @link http://php.net/manual/en/datetime.getoffset.php |
|
| 48 | + */ |
|
| 49 | + #[\ReturnTypeWillChange] |
|
| 50 | + public function getOffset() { |
|
| 51 | + return $this->utcOffset ? $this->utcOffset : parent::getOffset(); |
|
| 52 | + } |
|
| 53 | 53 | |
| 54 | - /** |
|
| 55 | - * Set the TimeZone associated with the DateTime |
|
| 56 | - * |
|
| 57 | - * @param DateTimeZone $timezone |
|
| 58 | - * |
|
| 59 | - * @return static |
|
| 60 | - * @link http://php.net/manual/en/datetime.settimezone.php |
|
| 61 | - */ |
|
| 62 | - #[\ReturnTypeWillChange] |
|
| 63 | - public function setTimezone( $timezone ) { |
|
| 64 | - $this->utcOffset = 0; |
|
| 65 | - parent::setTimezone( $timezone ); |
|
| 54 | + /** |
|
| 55 | + * Set the TimeZone associated with the DateTime |
|
| 56 | + * |
|
| 57 | + * @param DateTimeZone $timezone |
|
| 58 | + * |
|
| 59 | + * @return static |
|
| 60 | + * @link http://php.net/manual/en/datetime.settimezone.php |
|
| 61 | + */ |
|
| 62 | + #[\ReturnTypeWillChange] |
|
| 63 | + public function setTimezone( $timezone ) { |
|
| 64 | + $this->utcOffset = 0; |
|
| 65 | + parent::setTimezone( $timezone ); |
|
| 66 | 66 | |
| 67 | - return $this; |
|
| 68 | - } |
|
| 67 | + return $this; |
|
| 68 | + } |
|
| 69 | 69 | |
| 70 | - /** |
|
| 71 | - * Get the timestamp with the WordPress timezone offset added or subtracted. |
|
| 72 | - * |
|
| 73 | - * @since 3.0.0 |
|
| 74 | - * @return int |
|
| 75 | - */ |
|
| 76 | - public function getOffsetTimestamp() { |
|
| 77 | - return $this->getTimestamp() + $this->getOffset(); |
|
| 78 | - } |
|
| 70 | + /** |
|
| 71 | + * Get the timestamp with the WordPress timezone offset added or subtracted. |
|
| 72 | + * |
|
| 73 | + * @since 3.0.0 |
|
| 74 | + * @return int |
|
| 75 | + */ |
|
| 76 | + public function getOffsetTimestamp() { |
|
| 77 | + return $this->getTimestamp() + $this->getOffset(); |
|
| 78 | + } |
|
| 79 | 79 | } |
@@ -9,39 +9,39 @@ |
||
| 9 | 9 | */ |
| 10 | 10 | class ActionScheduler_InvalidActionException extends \InvalidArgumentException implements ActionScheduler_Exception { |
| 11 | 11 | |
| 12 | - /** |
|
| 13 | - * Create a new exception when the action's schedule cannot be fetched. |
|
| 14 | - * |
|
| 15 | - * @param string $action_id The action ID with bad args. |
|
| 16 | - * @return static |
|
| 17 | - */ |
|
| 18 | - public static function from_schedule( $action_id, $schedule ) { |
|
| 19 | - $message = sprintf( |
|
| 20 | - /* translators: 1: action ID 2: schedule */ |
|
| 21 | - __( 'Action [%1$s] has an invalid schedule: %2$s', 'woocommerce' ), |
|
| 22 | - $action_id, |
|
| 23 | - var_export( $schedule, true ) |
|
| 24 | - ); |
|
| 12 | + /** |
|
| 13 | + * Create a new exception when the action's schedule cannot be fetched. |
|
| 14 | + * |
|
| 15 | + * @param string $action_id The action ID with bad args. |
|
| 16 | + * @return static |
|
| 17 | + */ |
|
| 18 | + public static function from_schedule( $action_id, $schedule ) { |
|
| 19 | + $message = sprintf( |
|
| 20 | + /* translators: 1: action ID 2: schedule */ |
|
| 21 | + __( 'Action [%1$s] has an invalid schedule: %2$s', 'woocommerce' ), |
|
| 22 | + $action_id, |
|
| 23 | + var_export( $schedule, true ) |
|
| 24 | + ); |
|
| 25 | 25 | |
| 26 | - return new static( $message ); |
|
| 27 | - } |
|
| 26 | + return new static( $message ); |
|
| 27 | + } |
|
| 28 | 28 | |
| 29 | - /** |
|
| 30 | - * Create a new exception when the action's args cannot be decoded to an array. |
|
| 31 | - * |
|
| 32 | - * @author Jeremy Pry |
|
| 33 | - * |
|
| 34 | - * @param string $action_id The action ID with bad args. |
|
| 35 | - * @return static |
|
| 36 | - */ |
|
| 37 | - public static function from_decoding_args( $action_id, $args = array() ) { |
|
| 38 | - $message = sprintf( |
|
| 39 | - /* translators: 1: action ID 2: arguments */ |
|
| 40 | - __( 'Action [%1$s] has invalid arguments. It cannot be JSON decoded to an array. $args = %2$s', 'woocommerce' ), |
|
| 41 | - $action_id, |
|
| 42 | - var_export( $args, true ) |
|
| 43 | - ); |
|
| 29 | + /** |
|
| 30 | + * Create a new exception when the action's args cannot be decoded to an array. |
|
| 31 | + * |
|
| 32 | + * @author Jeremy Pry |
|
| 33 | + * |
|
| 34 | + * @param string $action_id The action ID with bad args. |
|
| 35 | + * @return static |
|
| 36 | + */ |
|
| 37 | + public static function from_decoding_args( $action_id, $args = array() ) { |
|
| 38 | + $message = sprintf( |
|
| 39 | + /* translators: 1: action ID 2: arguments */ |
|
| 40 | + __( 'Action [%1$s] has invalid arguments. It cannot be JSON decoded to an array. $args = %2$s', 'woocommerce' ), |
|
| 41 | + $action_id, |
|
| 42 | + var_export( $args, true ) |
|
| 43 | + ); |
|
| 44 | 44 | |
| 45 | - return new static( $message ); |
|
| 46 | - } |
|
| 45 | + return new static( $message ); |
|
| 46 | + } |
|
| 47 | 47 | } |
@@ -4,15 +4,15 @@ |
||
| 4 | 4 | * Class ActionScheduler_Schedule |
| 5 | 5 | */ |
| 6 | 6 | interface ActionScheduler_Schedule { |
| 7 | - /** |
|
| 8 | - * @param DateTime $after |
|
| 9 | - * @return DateTime|null |
|
| 10 | - */ |
|
| 11 | - public function next( DateTime $after = NULL ); |
|
| 7 | + /** |
|
| 8 | + * @param DateTime $after |
|
| 9 | + * @return DateTime|null |
|
| 10 | + */ |
|
| 11 | + public function next( DateTime $after = NULL ); |
|
| 12 | 12 | |
| 13 | - /** |
|
| 14 | - * @return bool |
|
| 15 | - */ |
|
| 16 | - public function is_recurring(); |
|
| 13 | + /** |
|
| 14 | + * @return bool |
|
| 15 | + */ |
|
| 16 | + public function is_recurring(); |
|
| 17 | 17 | } |
| 18 | - |
|
| 19 | 18 | \ No newline at end of file |
| 19 | + |
|
| 20 | 20 | \ No newline at end of file |
@@ -5,77 +5,77 @@ |
||
| 5 | 5 | */ |
| 6 | 6 | class ActionScheduler_IntervalSchedule extends ActionScheduler_Abstract_RecurringSchedule implements ActionScheduler_Schedule { |
| 7 | 7 | |
| 8 | - /** |
|
| 9 | - * Deprecated property @see $this->__wakeup() for details. |
|
| 10 | - **/ |
|
| 11 | - private $start_timestamp = NULL; |
|
| 8 | + /** |
|
| 9 | + * Deprecated property @see $this->__wakeup() for details. |
|
| 10 | + **/ |
|
| 11 | + private $start_timestamp = NULL; |
|
| 12 | 12 | |
| 13 | - /** |
|
| 14 | - * Deprecated property @see $this->__wakeup() for details. |
|
| 15 | - **/ |
|
| 16 | - private $interval_in_seconds = NULL; |
|
| 13 | + /** |
|
| 14 | + * Deprecated property @see $this->__wakeup() for details. |
|
| 15 | + **/ |
|
| 16 | + private $interval_in_seconds = NULL; |
|
| 17 | 17 | |
| 18 | - /** |
|
| 19 | - * Calculate when this schedule should start after a given date & time using |
|
| 20 | - * the number of seconds between recurrences. |
|
| 21 | - * |
|
| 22 | - * @param DateTime $after |
|
| 23 | - * @return DateTime |
|
| 24 | - */ |
|
| 25 | - protected function calculate_next( DateTime $after ) { |
|
| 26 | - $after->modify( '+' . (int) $this->get_recurrence() . ' seconds' ); |
|
| 27 | - return $after; |
|
| 28 | - } |
|
| 18 | + /** |
|
| 19 | + * Calculate when this schedule should start after a given date & time using |
|
| 20 | + * the number of seconds between recurrences. |
|
| 21 | + * |
|
| 22 | + * @param DateTime $after |
|
| 23 | + * @return DateTime |
|
| 24 | + */ |
|
| 25 | + protected function calculate_next( DateTime $after ) { |
|
| 26 | + $after->modify( '+' . (int) $this->get_recurrence() . ' seconds' ); |
|
| 27 | + return $after; |
|
| 28 | + } |
|
| 29 | 29 | |
| 30 | - /** |
|
| 31 | - * @return int |
|
| 32 | - */ |
|
| 33 | - public function interval_in_seconds() { |
|
| 34 | - _deprecated_function( __METHOD__, '3.0.0', '(int)ActionScheduler_Abstract_RecurringSchedule::get_recurrence()' ); |
|
| 35 | - return (int) $this->get_recurrence(); |
|
| 36 | - } |
|
| 30 | + /** |
|
| 31 | + * @return int |
|
| 32 | + */ |
|
| 33 | + public function interval_in_seconds() { |
|
| 34 | + _deprecated_function( __METHOD__, '3.0.0', '(int)ActionScheduler_Abstract_RecurringSchedule::get_recurrence()' ); |
|
| 35 | + return (int) $this->get_recurrence(); |
|
| 36 | + } |
|
| 37 | 37 | |
| 38 | - /** |
|
| 39 | - * Serialize interval schedules with data required prior to AS 3.0.0 |
|
| 40 | - * |
|
| 41 | - * Prior to Action Scheduler 3.0.0, reccuring schedules used different property names to |
|
| 42 | - * refer to equivalent data. For example, ActionScheduler_IntervalSchedule::start_timestamp |
|
| 43 | - * was the same as ActionScheduler_SimpleSchedule::timestamp. Action Scheduler 3.0.0 |
|
| 44 | - * aligned properties and property names for better inheritance. To guard against the |
|
| 45 | - * possibility of infinite loops if downgrading to Action Scheduler < 3.0.0, we need to |
|
| 46 | - * also store the data with the old property names so if it's unserialized in AS < 3.0, |
|
| 47 | - * the schedule doesn't end up with a null/false/0 recurrence. |
|
| 48 | - * |
|
| 49 | - * @return array |
|
| 50 | - */ |
|
| 51 | - public function __sleep() { |
|
| 38 | + /** |
|
| 39 | + * Serialize interval schedules with data required prior to AS 3.0.0 |
|
| 40 | + * |
|
| 41 | + * Prior to Action Scheduler 3.0.0, reccuring schedules used different property names to |
|
| 42 | + * refer to equivalent data. For example, ActionScheduler_IntervalSchedule::start_timestamp |
|
| 43 | + * was the same as ActionScheduler_SimpleSchedule::timestamp. Action Scheduler 3.0.0 |
|
| 44 | + * aligned properties and property names for better inheritance. To guard against the |
|
| 45 | + * possibility of infinite loops if downgrading to Action Scheduler < 3.0.0, we need to |
|
| 46 | + * also store the data with the old property names so if it's unserialized in AS < 3.0, |
|
| 47 | + * the schedule doesn't end up with a null/false/0 recurrence. |
|
| 48 | + * |
|
| 49 | + * @return array |
|
| 50 | + */ |
|
| 51 | + public function __sleep() { |
|
| 52 | 52 | |
| 53 | - $sleep_params = parent::__sleep(); |
|
| 53 | + $sleep_params = parent::__sleep(); |
|
| 54 | 54 | |
| 55 | - $this->start_timestamp = $this->scheduled_timestamp; |
|
| 56 | - $this->interval_in_seconds = $this->recurrence; |
|
| 55 | + $this->start_timestamp = $this->scheduled_timestamp; |
|
| 56 | + $this->interval_in_seconds = $this->recurrence; |
|
| 57 | 57 | |
| 58 | - return array_merge( $sleep_params, array( |
|
| 59 | - 'start_timestamp', |
|
| 60 | - 'interval_in_seconds' |
|
| 61 | - ) ); |
|
| 62 | - } |
|
| 58 | + return array_merge( $sleep_params, array( |
|
| 59 | + 'start_timestamp', |
|
| 60 | + 'interval_in_seconds' |
|
| 61 | + ) ); |
|
| 62 | + } |
|
| 63 | 63 | |
| 64 | - /** |
|
| 65 | - * Unserialize interval schedules serialized/stored prior to AS 3.0.0 |
|
| 66 | - * |
|
| 67 | - * For more background, @see ActionScheduler_Abstract_RecurringSchedule::__wakeup(). |
|
| 68 | - */ |
|
| 69 | - public function __wakeup() { |
|
| 70 | - if ( is_null( $this->scheduled_timestamp ) && ! is_null( $this->start_timestamp ) ) { |
|
| 71 | - $this->scheduled_timestamp = $this->start_timestamp; |
|
| 72 | - unset( $this->start_timestamp ); |
|
| 73 | - } |
|
| 64 | + /** |
|
| 65 | + * Unserialize interval schedules serialized/stored prior to AS 3.0.0 |
|
| 66 | + * |
|
| 67 | + * For more background, @see ActionScheduler_Abstract_RecurringSchedule::__wakeup(). |
|
| 68 | + */ |
|
| 69 | + public function __wakeup() { |
|
| 70 | + if ( is_null( $this->scheduled_timestamp ) && ! is_null( $this->start_timestamp ) ) { |
|
| 71 | + $this->scheduled_timestamp = $this->start_timestamp; |
|
| 72 | + unset( $this->start_timestamp ); |
|
| 73 | + } |
|
| 74 | 74 | |
| 75 | - if ( is_null( $this->recurrence ) && ! is_null( $this->interval_in_seconds ) ) { |
|
| 76 | - $this->recurrence = $this->interval_in_seconds; |
|
| 77 | - unset( $this->interval_in_seconds ); |
|
| 78 | - } |
|
| 79 | - parent::__wakeup(); |
|
| 80 | - } |
|
| 75 | + if ( is_null( $this->recurrence ) && ! is_null( $this->interval_in_seconds ) ) { |
|
| 76 | + $this->recurrence = $this->interval_in_seconds; |
|
| 77 | + unset( $this->interval_in_seconds ); |
|
| 78 | + } |
|
| 79 | + parent::__wakeup(); |
|
| 80 | + } |
|
| 81 | 81 | } |