@@ -4,1072 +4,1072 @@ |
||
4 | 4 | * Class ActionScheduler_wpPostStore |
5 | 5 | */ |
6 | 6 | class ActionScheduler_wpPostStore extends ActionScheduler_Store { |
7 | - const POST_TYPE = 'scheduled-action'; |
|
8 | - const GROUP_TAXONOMY = 'action-group'; |
|
9 | - const SCHEDULE_META_KEY = '_action_manager_schedule'; |
|
10 | - 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 ); |
|
41 | - $post_array = $this->create_post_array( $action, $scheduled_date ); |
|
42 | - $post_id = $this->save_post_array( $post_array ); |
|
43 | - $this->save_post_schedule( $post_id, $action->get_schedule() ); |
|
44 | - $this->save_action_group( $post_id, $action->get_group() ); |
|
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 ), |
|
69 | - ); |
|
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 ); |
|
83 | - |
|
84 | - $has_kses = false !== has_filter( 'content_save_pre', 'wp_filter_post_kses' ); |
|
85 | - |
|
86 | - if ( $has_kses ) { |
|
87 | - // Prevent KSES from corrupting JSON in post_content. |
|
88 | - kses_remove_filters(); |
|
89 | - } |
|
90 | - |
|
91 | - $post_id = wp_insert_post( $post_array ); |
|
92 | - |
|
93 | - if ( $has_kses ) { |
|
94 | - kses_init_filters(); |
|
95 | - } |
|
96 | - |
|
97 | - remove_filter( 'wp_insert_post_data', array( $this, 'filter_insert_post_data' ), 10 ); |
|
98 | - remove_filter( 'pre_wp_unique_post_slug', array( $this, 'set_unique_post_slug' ), 10 ); |
|
99 | - |
|
100 | - if ( is_wp_error( $post_id ) || empty( $post_id ) ) { |
|
101 | - throw new RuntimeException( __( 'Unable to save action.', 'action-scheduler' ) ); |
|
102 | - } |
|
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 | - } |
|
120 | - return $postdata; |
|
121 | - } |
|
122 | - |
|
123 | - /** |
|
124 | - * Create a (probably unique) post name for scheduled actions in a more performant manner than wp_unique_post_slug(). |
|
125 | - * |
|
126 | - * When an action's post status is transitioned to something other than 'draft', 'pending' or 'auto-draft, like 'publish' |
|
127 | - * or 'failed' or 'trash', WordPress will find a unique slug (stored in post_name column) using the wp_unique_post_slug() |
|
128 | - * function. This is done to ensure URL uniqueness. The approach taken by wp_unique_post_slug() is to iterate over existing |
|
129 | - * post_name values that match, and append a number 1 greater than the largest. This makes sense when manually creating a |
|
130 | - * post from the Edit Post screen. It becomes a bottleneck when automatically processing thousands of actions, with a |
|
131 | - * database containing thousands of related post_name values. |
|
132 | - * |
|
133 | - * WordPress 5.1 introduces the 'pre_wp_unique_post_slug' filter for plugins to address this issue. |
|
134 | - * |
|
135 | - * We can short-circuit WordPress's wp_unique_post_slug() approach using the 'pre_wp_unique_post_slug' filter. This |
|
136 | - * method is available to be used as a callback on that filter. It provides a more scalable approach to generating a |
|
137 | - * post_name/slug that is probably unique. Because Action Scheduler never actually uses the post_name field, or an |
|
138 | - * action's slug, being probably unique is good enough. |
|
139 | - * |
|
140 | - * For more backstory on this issue, see: |
|
141 | - * - https://github.com/woocommerce/action-scheduler/issues/44 and |
|
142 | - * - https://core.trac.wordpress.org/ticket/21112 |
|
143 | - * |
|
144 | - * @param string $override_slug Short-circuit return value. |
|
145 | - * @param string $slug The desired slug (post_name). |
|
146 | - * @param int $post_ID Post ID. |
|
147 | - * @param string $post_status The post status. |
|
148 | - * @param string $post_type Post type. |
|
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 ); |
|
180 | - } else { |
|
181 | - wp_set_object_terms( $post_id, array( $group ), 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 | - |
|
197 | - try { |
|
198 | - $action = $this->make_action_from_post( $post ); |
|
199 | - } catch ( ActionScheduler_InvalidActionException $exception ) { |
|
200 | - do_action( 'action_scheduler_failed_fetch_action', $post->ID, $exception ); |
|
201 | - return $this->get_null_action(); |
|
202 | - } |
|
203 | - |
|
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; |
|
216 | - } |
|
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 | - |
|
238 | - $args = json_decode( $post->post_content, true ); |
|
239 | - $this->validate_args( $args, $post->ID ); |
|
240 | - |
|
241 | - $schedule = get_post_meta( $post->ID, self::SCHEDULE_META_KEY, true ); |
|
242 | - $this->validate_schedule( $schedule, $post->ID ); |
|
243 | - |
|
244 | - $group = wp_get_object_terms( $post->ID, self::GROUP_TAXONOMY, array( 'fields' => 'names' ) ); |
|
245 | - $group = empty( $group ) ? '' : reset( $group ); |
|
246 | - |
|
247 | - return ActionScheduler::factory()->get_stored_action( $this->get_action_status_by_post_status( $post->post_status ), $hook, $args, $schedule, $group ); |
|
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 ) { |
|
259 | - |
|
260 | - switch ( $post_status ) { |
|
261 | - case 'publish': |
|
262 | - $action_status = self::STATUS_COMPLETE; |
|
263 | - break; |
|
264 | - case 'trash': |
|
265 | - $action_status = self::STATUS_CANCELED; |
|
266 | - break; |
|
267 | - default: |
|
268 | - if ( ! array_key_exists( $post_status, $this->get_status_labels() ) ) { |
|
269 | - throw new InvalidArgumentException( sprintf( 'Invalid post status: "%s". No matching action status available.', $post_status ) ); |
|
270 | - } |
|
271 | - $action_status = $post_status; |
|
272 | - break; |
|
273 | - } |
|
274 | - |
|
275 | - return $action_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 ) { |
|
287 | - |
|
288 | - switch ( $action_status ) { |
|
289 | - case self::STATUS_COMPLETE: |
|
290 | - $post_status = 'publish'; |
|
291 | - break; |
|
292 | - case self::STATUS_CANCELED: |
|
293 | - $post_status = 'trash'; |
|
294 | - break; |
|
295 | - default: |
|
296 | - if ( ! array_key_exists( $action_status, $this->get_status_labels() ) ) { |
|
297 | - throw new InvalidArgumentException( sprintf( 'Invalid action status: "%s".', $action_status ) ); |
|
298 | - } |
|
299 | - $post_status = $action_status; |
|
300 | - break; |
|
301 | - } |
|
302 | - |
|
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 | - |
|
321 | - $query = wp_parse_args( |
|
322 | - $query, |
|
323 | - array( |
|
324 | - 'hook' => '', |
|
325 | - 'args' => null, |
|
326 | - 'date' => null, |
|
327 | - 'date_compare' => '<=', |
|
328 | - 'modified' => null, |
|
329 | - 'modified_compare' => '<=', |
|
330 | - 'group' => '', |
|
331 | - 'status' => '', |
|
332 | - 'claimed' => null, |
|
333 | - 'per_page' => 5, |
|
334 | - 'offset' => 0, |
|
335 | - 'orderby' => 'date', |
|
336 | - 'order' => 'ASC', |
|
337 | - 'search' => '', |
|
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"; |
|
349 | - $sql_params = array(); |
|
350 | - if ( empty( $query['group'] ) && 'group' === $query['orderby'] ) { |
|
351 | - $sql .= " LEFT JOIN {$wpdb->term_relationships} tr ON tr.object_id=p.ID"; |
|
352 | - $sql .= " LEFT JOIN {$wpdb->term_taxonomy} tt ON tr.term_taxonomy_id=tt.term_taxonomy_id"; |
|
353 | - $sql .= " LEFT JOIN {$wpdb->terms} t ON tt.term_id=t.term_id"; |
|
354 | - } elseif ( ! empty( $query['group'] ) ) { |
|
355 | - $sql .= " INNER JOIN {$wpdb->term_relationships} tr ON tr.object_id=p.ID"; |
|
356 | - $sql .= " INNER JOIN {$wpdb->term_taxonomy} tt ON tr.term_taxonomy_id=tt.term_taxonomy_id"; |
|
357 | - $sql .= " INNER JOIN {$wpdb->terms} t ON tt.term_id=t.term_id"; |
|
358 | - $sql .= ' AND t.slug=%s'; |
|
359 | - $sql_params[] = $query['group']; |
|
360 | - } |
|
361 | - $sql .= ' WHERE post_type=%s'; |
|
362 | - $sql_params[] = self::POST_TYPE; |
|
363 | - if ( $query['hook'] ) { |
|
364 | - $sql .= ' AND p.post_title=%s'; |
|
365 | - $sql_params[] = $query['hook']; |
|
366 | - } |
|
367 | - if ( $query['args'] !== null ) { |
|
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 ) { |
|
380 | - $date = clone $query['date']; |
|
381 | - $date->setTimezone( new DateTimeZone( 'UTC' ) ); |
|
382 | - $date_string = $date->format( 'Y-m-d H:i:s' ); |
|
383 | - $comparator = $this->validate_sql_comparator( $query['date_compare'] ); |
|
384 | - $sql .= " AND p.post_date_gmt $comparator %s"; |
|
385 | - $sql_params[] = $date_string; |
|
386 | - } |
|
387 | - |
|
388 | - if ( $query['modified'] instanceof DateTime ) { |
|
389 | - $modified = clone $query['modified']; |
|
390 | - $modified->setTimezone( new DateTimeZone( 'UTC' ) ); |
|
391 | - $date_string = $modified->format( 'Y-m-d H:i:s' ); |
|
392 | - $comparator = $this->validate_sql_comparator( $query['modified_compare'] ); |
|
393 | - $sql .= " AND p.post_modified_gmt $comparator %s"; |
|
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 ( $query['claimed'] !== null ) { |
|
402 | - $sql .= ' AND p.post_password = %s'; |
|
403 | - $sql_params[] = $query['claimed']; |
|
404 | - } |
|
405 | - |
|
406 | - if ( ! empty( $query['search'] ) ) { |
|
407 | - $sql .= ' AND (p.post_title LIKE %s OR p.post_content LIKE %s OR p.post_password LIKE %s)'; |
|
408 | - for ( $i = 0; $i < 3; $i++ ) { |
|
409 | - $sql_params[] = sprintf( '%%%s%%', $query['search'] ); |
|
410 | - } |
|
411 | - } |
|
412 | - |
|
413 | - if ( 'select' === $select_or_count ) { |
|
414 | - switch ( $query['orderby'] ) { |
|
415 | - case 'hook': |
|
416 | - $orderby = 'p.post_title'; |
|
417 | - break; |
|
418 | - case 'group': |
|
419 | - $orderby = 't.name'; |
|
420 | - break; |
|
421 | - case 'status': |
|
422 | - $orderby = 'p.post_status'; |
|
423 | - break; |
|
424 | - case 'modified': |
|
425 | - $orderby = 'p.post_modified'; |
|
426 | - break; |
|
427 | - case 'claim_id': |
|
428 | - $orderby = 'p.post_password'; |
|
429 | - break; |
|
430 | - case 'schedule': |
|
431 | - case 'date': |
|
432 | - default: |
|
433 | - $orderby = 'p.post_date_gmt'; |
|
434 | - break; |
|
435 | - } |
|
436 | - if ( 'ASC' === strtoupper( $query['order'] ) ) { |
|
437 | - $order = 'ASC'; |
|
438 | - } else { |
|
439 | - $order = 'DESC'; |
|
440 | - } |
|
441 | - $sql .= " ORDER BY $orderby $order"; |
|
442 | - if ( $query['per_page'] > 0 ) { |
|
443 | - $sql .= ' LIMIT %d, %d'; |
|
444 | - $sql_params[] = $query['offset']; |
|
445 | - $sql_params[] = $query['per_page']; |
|
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 3.3.0 $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 | - /** |
|
478 | - * Get a count of all actions in the store, grouped by status |
|
479 | - * |
|
480 | - * @return array |
|
481 | - */ |
|
482 | - public function action_counts() { |
|
483 | - |
|
484 | - $action_counts_by_status = array(); |
|
485 | - $action_stati_and_labels = $this->get_status_labels(); |
|
486 | - $posts_count_by_status = (array) wp_count_posts( self::POST_TYPE, 'readable' ); |
|
487 | - |
|
488 | - foreach ( $posts_count_by_status as $post_status_name => $count ) { |
|
489 | - |
|
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 ) ) { |
|
497 | - $action_counts_by_status[ $action_status_name ] = $count; |
|
498 | - } |
|
499 | - } |
|
500 | - |
|
501 | - return $action_counts_by_status; |
|
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 ); |
|
518 | - add_filter( 'pre_wp_unique_post_slug', array( $this, 'set_unique_post_slug' ), 10, 5 ); |
|
519 | - wp_trash_post( $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 ); |
|
537 | - |
|
538 | - wp_delete_post( $action_id, true ); |
|
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 ) { |
|
548 | - $next = $this->get_date_gmt( $action_id ); |
|
549 | - return ActionScheduler_TimezoneHelper::set_local_timezone( $next ); |
|
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 ); |
|
570 | - } |
|
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. |
|
580 | - * |
|
581 | - * @return ActionScheduler_ActionClaim |
|
582 | - * @throws RuntimeException When there is an error staking a claim. |
|
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. |
|
636 | - $date = null === $before_date ? as_get_datetime_object() : clone $before_date; |
|
637 | - $limit_ids = ! empty( $group ); |
|
638 | - $ids = $limit_ids ? $this->get_actions_by_group( $group, $limit, $date ) : array(); |
|
639 | - |
|
640 | - // If limiting by IDs and no posts found, then return early since we have nothing to update. |
|
641 | - if ( $limit_ids && 0 === count( $ids ) ) { |
|
642 | - return 0; |
|
643 | - } |
|
644 | - |
|
645 | - /** |
|
646 | - * Global wpdb object. |
|
647 | - * |
|
648 | - * @var wpdb $wpdb |
|
649 | - */ |
|
650 | - global $wpdb; |
|
651 | - |
|
652 | - /* |
|
7 | + const POST_TYPE = 'scheduled-action'; |
|
8 | + const GROUP_TAXONOMY = 'action-group'; |
|
9 | + const SCHEDULE_META_KEY = '_action_manager_schedule'; |
|
10 | + const DEPENDENCIES_MET = 'as-post-store-dependencies-met'; |
|
11 | + |
|
12 | + /** |
|
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 ); |
|
41 | + $post_array = $this->create_post_array( $action, $scheduled_date ); |
|
42 | + $post_id = $this->save_post_array( $post_array ); |
|
43 | + $this->save_post_schedule( $post_id, $action->get_schedule() ); |
|
44 | + $this->save_action_group( $post_id, $action->get_group() ); |
|
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 ), |
|
69 | + ); |
|
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 ); |
|
83 | + |
|
84 | + $has_kses = false !== has_filter( 'content_save_pre', 'wp_filter_post_kses' ); |
|
85 | + |
|
86 | + if ( $has_kses ) { |
|
87 | + // Prevent KSES from corrupting JSON in post_content. |
|
88 | + kses_remove_filters(); |
|
89 | + } |
|
90 | + |
|
91 | + $post_id = wp_insert_post( $post_array ); |
|
92 | + |
|
93 | + if ( $has_kses ) { |
|
94 | + kses_init_filters(); |
|
95 | + } |
|
96 | + |
|
97 | + remove_filter( 'wp_insert_post_data', array( $this, 'filter_insert_post_data' ), 10 ); |
|
98 | + remove_filter( 'pre_wp_unique_post_slug', array( $this, 'set_unique_post_slug' ), 10 ); |
|
99 | + |
|
100 | + if ( is_wp_error( $post_id ) || empty( $post_id ) ) { |
|
101 | + throw new RuntimeException( __( 'Unable to save action.', 'action-scheduler' ) ); |
|
102 | + } |
|
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 | + } |
|
120 | + return $postdata; |
|
121 | + } |
|
122 | + |
|
123 | + /** |
|
124 | + * Create a (probably unique) post name for scheduled actions in a more performant manner than wp_unique_post_slug(). |
|
125 | + * |
|
126 | + * When an action's post status is transitioned to something other than 'draft', 'pending' or 'auto-draft, like 'publish' |
|
127 | + * or 'failed' or 'trash', WordPress will find a unique slug (stored in post_name column) using the wp_unique_post_slug() |
|
128 | + * function. This is done to ensure URL uniqueness. The approach taken by wp_unique_post_slug() is to iterate over existing |
|
129 | + * post_name values that match, and append a number 1 greater than the largest. This makes sense when manually creating a |
|
130 | + * post from the Edit Post screen. It becomes a bottleneck when automatically processing thousands of actions, with a |
|
131 | + * database containing thousands of related post_name values. |
|
132 | + * |
|
133 | + * WordPress 5.1 introduces the 'pre_wp_unique_post_slug' filter for plugins to address this issue. |
|
134 | + * |
|
135 | + * We can short-circuit WordPress's wp_unique_post_slug() approach using the 'pre_wp_unique_post_slug' filter. This |
|
136 | + * method is available to be used as a callback on that filter. It provides a more scalable approach to generating a |
|
137 | + * post_name/slug that is probably unique. Because Action Scheduler never actually uses the post_name field, or an |
|
138 | + * action's slug, being probably unique is good enough. |
|
139 | + * |
|
140 | + * For more backstory on this issue, see: |
|
141 | + * - https://github.com/woocommerce/action-scheduler/issues/44 and |
|
142 | + * - https://core.trac.wordpress.org/ticket/21112 |
|
143 | + * |
|
144 | + * @param string $override_slug Short-circuit return value. |
|
145 | + * @param string $slug The desired slug (post_name). |
|
146 | + * @param int $post_ID Post ID. |
|
147 | + * @param string $post_status The post status. |
|
148 | + * @param string $post_type Post type. |
|
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 ); |
|
180 | + } else { |
|
181 | + wp_set_object_terms( $post_id, array( $group ), 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 | + |
|
197 | + try { |
|
198 | + $action = $this->make_action_from_post( $post ); |
|
199 | + } catch ( ActionScheduler_InvalidActionException $exception ) { |
|
200 | + do_action( 'action_scheduler_failed_fetch_action', $post->ID, $exception ); |
|
201 | + return $this->get_null_action(); |
|
202 | + } |
|
203 | + |
|
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; |
|
216 | + } |
|
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 | + |
|
238 | + $args = json_decode( $post->post_content, true ); |
|
239 | + $this->validate_args( $args, $post->ID ); |
|
240 | + |
|
241 | + $schedule = get_post_meta( $post->ID, self::SCHEDULE_META_KEY, true ); |
|
242 | + $this->validate_schedule( $schedule, $post->ID ); |
|
243 | + |
|
244 | + $group = wp_get_object_terms( $post->ID, self::GROUP_TAXONOMY, array( 'fields' => 'names' ) ); |
|
245 | + $group = empty( $group ) ? '' : reset( $group ); |
|
246 | + |
|
247 | + return ActionScheduler::factory()->get_stored_action( $this->get_action_status_by_post_status( $post->post_status ), $hook, $args, $schedule, $group ); |
|
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 ) { |
|
259 | + |
|
260 | + switch ( $post_status ) { |
|
261 | + case 'publish': |
|
262 | + $action_status = self::STATUS_COMPLETE; |
|
263 | + break; |
|
264 | + case 'trash': |
|
265 | + $action_status = self::STATUS_CANCELED; |
|
266 | + break; |
|
267 | + default: |
|
268 | + if ( ! array_key_exists( $post_status, $this->get_status_labels() ) ) { |
|
269 | + throw new InvalidArgumentException( sprintf( 'Invalid post status: "%s". No matching action status available.', $post_status ) ); |
|
270 | + } |
|
271 | + $action_status = $post_status; |
|
272 | + break; |
|
273 | + } |
|
274 | + |
|
275 | + return $action_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 ) { |
|
287 | + |
|
288 | + switch ( $action_status ) { |
|
289 | + case self::STATUS_COMPLETE: |
|
290 | + $post_status = 'publish'; |
|
291 | + break; |
|
292 | + case self::STATUS_CANCELED: |
|
293 | + $post_status = 'trash'; |
|
294 | + break; |
|
295 | + default: |
|
296 | + if ( ! array_key_exists( $action_status, $this->get_status_labels() ) ) { |
|
297 | + throw new InvalidArgumentException( sprintf( 'Invalid action status: "%s".', $action_status ) ); |
|
298 | + } |
|
299 | + $post_status = $action_status; |
|
300 | + break; |
|
301 | + } |
|
302 | + |
|
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 | + |
|
321 | + $query = wp_parse_args( |
|
322 | + $query, |
|
323 | + array( |
|
324 | + 'hook' => '', |
|
325 | + 'args' => null, |
|
326 | + 'date' => null, |
|
327 | + 'date_compare' => '<=', |
|
328 | + 'modified' => null, |
|
329 | + 'modified_compare' => '<=', |
|
330 | + 'group' => '', |
|
331 | + 'status' => '', |
|
332 | + 'claimed' => null, |
|
333 | + 'per_page' => 5, |
|
334 | + 'offset' => 0, |
|
335 | + 'orderby' => 'date', |
|
336 | + 'order' => 'ASC', |
|
337 | + 'search' => '', |
|
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"; |
|
349 | + $sql_params = array(); |
|
350 | + if ( empty( $query['group'] ) && 'group' === $query['orderby'] ) { |
|
351 | + $sql .= " LEFT JOIN {$wpdb->term_relationships} tr ON tr.object_id=p.ID"; |
|
352 | + $sql .= " LEFT JOIN {$wpdb->term_taxonomy} tt ON tr.term_taxonomy_id=tt.term_taxonomy_id"; |
|
353 | + $sql .= " LEFT JOIN {$wpdb->terms} t ON tt.term_id=t.term_id"; |
|
354 | + } elseif ( ! empty( $query['group'] ) ) { |
|
355 | + $sql .= " INNER JOIN {$wpdb->term_relationships} tr ON tr.object_id=p.ID"; |
|
356 | + $sql .= " INNER JOIN {$wpdb->term_taxonomy} tt ON tr.term_taxonomy_id=tt.term_taxonomy_id"; |
|
357 | + $sql .= " INNER JOIN {$wpdb->terms} t ON tt.term_id=t.term_id"; |
|
358 | + $sql .= ' AND t.slug=%s'; |
|
359 | + $sql_params[] = $query['group']; |
|
360 | + } |
|
361 | + $sql .= ' WHERE post_type=%s'; |
|
362 | + $sql_params[] = self::POST_TYPE; |
|
363 | + if ( $query['hook'] ) { |
|
364 | + $sql .= ' AND p.post_title=%s'; |
|
365 | + $sql_params[] = $query['hook']; |
|
366 | + } |
|
367 | + if ( $query['args'] !== null ) { |
|
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 ) { |
|
380 | + $date = clone $query['date']; |
|
381 | + $date->setTimezone( new DateTimeZone( 'UTC' ) ); |
|
382 | + $date_string = $date->format( 'Y-m-d H:i:s' ); |
|
383 | + $comparator = $this->validate_sql_comparator( $query['date_compare'] ); |
|
384 | + $sql .= " AND p.post_date_gmt $comparator %s"; |
|
385 | + $sql_params[] = $date_string; |
|
386 | + } |
|
387 | + |
|
388 | + if ( $query['modified'] instanceof DateTime ) { |
|
389 | + $modified = clone $query['modified']; |
|
390 | + $modified->setTimezone( new DateTimeZone( 'UTC' ) ); |
|
391 | + $date_string = $modified->format( 'Y-m-d H:i:s' ); |
|
392 | + $comparator = $this->validate_sql_comparator( $query['modified_compare'] ); |
|
393 | + $sql .= " AND p.post_modified_gmt $comparator %s"; |
|
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 ( $query['claimed'] !== null ) { |
|
402 | + $sql .= ' AND p.post_password = %s'; |
|
403 | + $sql_params[] = $query['claimed']; |
|
404 | + } |
|
405 | + |
|
406 | + if ( ! empty( $query['search'] ) ) { |
|
407 | + $sql .= ' AND (p.post_title LIKE %s OR p.post_content LIKE %s OR p.post_password LIKE %s)'; |
|
408 | + for ( $i = 0; $i < 3; $i++ ) { |
|
409 | + $sql_params[] = sprintf( '%%%s%%', $query['search'] ); |
|
410 | + } |
|
411 | + } |
|
412 | + |
|
413 | + if ( 'select' === $select_or_count ) { |
|
414 | + switch ( $query['orderby'] ) { |
|
415 | + case 'hook': |
|
416 | + $orderby = 'p.post_title'; |
|
417 | + break; |
|
418 | + case 'group': |
|
419 | + $orderby = 't.name'; |
|
420 | + break; |
|
421 | + case 'status': |
|
422 | + $orderby = 'p.post_status'; |
|
423 | + break; |
|
424 | + case 'modified': |
|
425 | + $orderby = 'p.post_modified'; |
|
426 | + break; |
|
427 | + case 'claim_id': |
|
428 | + $orderby = 'p.post_password'; |
|
429 | + break; |
|
430 | + case 'schedule': |
|
431 | + case 'date': |
|
432 | + default: |
|
433 | + $orderby = 'p.post_date_gmt'; |
|
434 | + break; |
|
435 | + } |
|
436 | + if ( 'ASC' === strtoupper( $query['order'] ) ) { |
|
437 | + $order = 'ASC'; |
|
438 | + } else { |
|
439 | + $order = 'DESC'; |
|
440 | + } |
|
441 | + $sql .= " ORDER BY $orderby $order"; |
|
442 | + if ( $query['per_page'] > 0 ) { |
|
443 | + $sql .= ' LIMIT %d, %d'; |
|
444 | + $sql_params[] = $query['offset']; |
|
445 | + $sql_params[] = $query['per_page']; |
|
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 3.3.0 $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 | + /** |
|
478 | + * Get a count of all actions in the store, grouped by status |
|
479 | + * |
|
480 | + * @return array |
|
481 | + */ |
|
482 | + public function action_counts() { |
|
483 | + |
|
484 | + $action_counts_by_status = array(); |
|
485 | + $action_stati_and_labels = $this->get_status_labels(); |
|
486 | + $posts_count_by_status = (array) wp_count_posts( self::POST_TYPE, 'readable' ); |
|
487 | + |
|
488 | + foreach ( $posts_count_by_status as $post_status_name => $count ) { |
|
489 | + |
|
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 ) ) { |
|
497 | + $action_counts_by_status[ $action_status_name ] = $count; |
|
498 | + } |
|
499 | + } |
|
500 | + |
|
501 | + return $action_counts_by_status; |
|
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 ); |
|
518 | + add_filter( 'pre_wp_unique_post_slug', array( $this, 'set_unique_post_slug' ), 10, 5 ); |
|
519 | + wp_trash_post( $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 ); |
|
537 | + |
|
538 | + wp_delete_post( $action_id, true ); |
|
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 ) { |
|
548 | + $next = $this->get_date_gmt( $action_id ); |
|
549 | + return ActionScheduler_TimezoneHelper::set_local_timezone( $next ); |
|
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 ); |
|
570 | + } |
|
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. |
|
580 | + * |
|
581 | + * @return ActionScheduler_ActionClaim |
|
582 | + * @throws RuntimeException When there is an error staking a claim. |
|
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. |
|
636 | + $date = null === $before_date ? as_get_datetime_object() : clone $before_date; |
|
637 | + $limit_ids = ! empty( $group ); |
|
638 | + $ids = $limit_ids ? $this->get_actions_by_group( $group, $limit, $date ) : array(); |
|
639 | + |
|
640 | + // If limiting by IDs and no posts found, then return early since we have nothing to update. |
|
641 | + if ( $limit_ids && 0 === count( $ids ) ) { |
|
642 | + return 0; |
|
643 | + } |
|
644 | + |
|
645 | + /** |
|
646 | + * Global wpdb object. |
|
647 | + * |
|
648 | + * @var wpdb $wpdb |
|
649 | + */ |
|
650 | + global $wpdb; |
|
651 | + |
|
652 | + /* |
|
653 | 653 | * Build up custom query to update the affected posts. Parameters are built as a separate array |
654 | 654 | * to make it easier to identify where they are in the query. |
655 | 655 | * |
656 | 656 | * We can't use $wpdb->update() here because of the "ID IN ..." clause. |
657 | 657 | */ |
658 | - $update = "UPDATE {$wpdb->posts} SET post_password = %s, post_modified_gmt = %s, post_modified = %s"; |
|
659 | - $params = array( |
|
660 | - $claim_id, |
|
661 | - current_time( 'mysql', true ), |
|
662 | - current_time( 'mysql' ), |
|
663 | - ); |
|
664 | - |
|
665 | - // Build initial WHERE clause. |
|
666 | - $where = "WHERE post_type = %s AND post_status = %s AND post_password = ''"; |
|
667 | - $params[] = self::POST_TYPE; |
|
668 | - $params[] = ActionScheduler_Store::STATUS_PENDING; |
|
669 | - |
|
670 | - if ( ! empty( $hooks ) ) { |
|
671 | - $placeholders = array_fill( 0, count( $hooks ), '%s' ); |
|
672 | - $where .= ' AND post_title IN (' . join( ', ', $placeholders ) . ')'; |
|
673 | - $params = array_merge( $params, array_values( $hooks ) ); |
|
674 | - } |
|
675 | - |
|
676 | - /* |
|
658 | + $update = "UPDATE {$wpdb->posts} SET post_password = %s, post_modified_gmt = %s, post_modified = %s"; |
|
659 | + $params = array( |
|
660 | + $claim_id, |
|
661 | + current_time( 'mysql', true ), |
|
662 | + current_time( 'mysql' ), |
|
663 | + ); |
|
664 | + |
|
665 | + // Build initial WHERE clause. |
|
666 | + $where = "WHERE post_type = %s AND post_status = %s AND post_password = ''"; |
|
667 | + $params[] = self::POST_TYPE; |
|
668 | + $params[] = ActionScheduler_Store::STATUS_PENDING; |
|
669 | + |
|
670 | + if ( ! empty( $hooks ) ) { |
|
671 | + $placeholders = array_fill( 0, count( $hooks ), '%s' ); |
|
672 | + $where .= ' AND post_title IN (' . join( ', ', $placeholders ) . ')'; |
|
673 | + $params = array_merge( $params, array_values( $hooks ) ); |
|
674 | + } |
|
675 | + |
|
676 | + /* |
|
677 | 677 | * Add the IDs to the WHERE clause. IDs not escaped because they came directly from a prior DB query. |
678 | 678 | * |
679 | 679 | * If we're not limiting by IDs, then include the post_date_gmt clause. |
680 | 680 | */ |
681 | - if ( $limit_ids ) { |
|
682 | - $where .= ' AND ID IN (' . join( ',', $ids ) . ')'; |
|
683 | - } else { |
|
684 | - $where .= ' AND post_date_gmt <= %s'; |
|
685 | - $params[] = $date->format( 'Y-m-d H:i:s' ); |
|
686 | - } |
|
687 | - |
|
688 | - // Add the ORDER BY clause and,ms limit. |
|
689 | - $order = 'ORDER BY menu_order ASC, post_date_gmt ASC, ID ASC LIMIT %d'; |
|
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 | - |
|
699 | - return (int) $rows_affected; |
|
700 | - } |
|
701 | - |
|
702 | - /** |
|
703 | - * Get IDs of actions within a certain group and up to a certain date/time. |
|
704 | - * |
|
705 | - * @param string $group The group to use in finding actions. |
|
706 | - * @param int $limit The number of actions to retrieve. |
|
707 | - * @param DateTime $date DateTime object representing cutoff time for actions. Actions retrieved will be |
|
708 | - * up to and including this DateTime. |
|
709 | - * |
|
710 | - * @return array IDs of actions in the appropriate group and before the appropriate time. |
|
711 | - * @throws InvalidArgumentException When the group does not exist. |
|
712 | - */ |
|
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 | - |
|
720 | - // Set up a query for post IDs to use later. |
|
721 | - $query = new WP_Query(); |
|
722 | - $query_args = array( |
|
723 | - 'fields' => 'ids', |
|
724 | - 'post_type' => self::POST_TYPE, |
|
725 | - 'post_status' => ActionScheduler_Store::STATUS_PENDING, |
|
726 | - 'has_password' => false, |
|
727 | - 'posts_per_page' => $limit * 3, |
|
728 | - 'suppress_filters' => true, |
|
729 | - 'no_found_rows' => true, |
|
730 | - 'orderby' => array( |
|
731 | - 'menu_order' => 'ASC', |
|
732 | - 'date' => 'ASC', |
|
733 | - 'ID' => 'ASC', |
|
734 | - ), |
|
735 | - 'date_query' => array( |
|
736 | - 'column' => 'post_date_gmt', |
|
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', |
|
744 | - 'terms' => $group, |
|
745 | - 'include_children' => false, |
|
746 | - ), |
|
747 | - ), |
|
748 | - ); |
|
749 | - |
|
750 | - return $query->query( $query_args ); |
|
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 | - } |
|
880 | - } |
|
881 | - |
|
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 ) { |
|
889 | - return $this->get_post_column( $action_id, 'post_password' ); |
|
890 | - } |
|
891 | - |
|
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 ); |
|
977 | - add_filter( 'pre_wp_unique_post_slug', array( $this, 'set_unique_post_slug' ), 10, 5 ); |
|
978 | - $result = wp_update_post( |
|
979 | - array( |
|
980 | - 'ID' => $action_id, |
|
981 | - 'post_status' => 'publish', |
|
982 | - ), |
|
983 | - true |
|
984 | - ); |
|
985 | - remove_filter( 'wp_insert_post_data', array( $this, 'filter_insert_post_data' ), 10 ); |
|
986 | - remove_filter( 'pre_wp_unique_post_slug', array( $this, 'set_unique_post_slug' ), 10 ); |
|
987 | - if ( is_wp_error( $result ) ) { |
|
988 | - throw new RuntimeException( $result->get_error_message() ); |
|
989 | - } |
|
990 | - |
|
991 | - /** |
|
992 | - * Fires after a scheduled action has been completed. |
|
993 | - * |
|
994 | - * @since 3.4.2 |
|
995 | - * |
|
996 | - * @param int $action_id Action ID. |
|
997 | - */ |
|
998 | - do_action( 'action_scheduler_completed_action', $action_id ); |
|
999 | - } |
|
1000 | - |
|
1001 | - /** |
|
1002 | - * Mark action as migrated when there is an error deleting the action. |
|
1003 | - * |
|
1004 | - * @param int $action_id Action ID. |
|
1005 | - */ |
|
1006 | - public function mark_migrated( $action_id ) { |
|
1007 | - wp_update_post( |
|
1008 | - array( |
|
1009 | - 'ID' => $action_id, |
|
1010 | - 'post_status' => 'migrated', |
|
1011 | - ) |
|
1012 | - ); |
|
1013 | - } |
|
1014 | - |
|
1015 | - /** |
|
1016 | - * Determine whether the post store can be migrated. |
|
1017 | - * |
|
1018 | - * @param [type] $setting - Setting value. |
|
1019 | - * @return bool |
|
1020 | - */ |
|
1021 | - public function migration_dependencies_met( $setting ) { |
|
1022 | - global $wpdb; |
|
1023 | - |
|
1024 | - $dependencies_met = get_transient( self::DEPENDENCIES_MET ); |
|
1025 | - if ( empty( $dependencies_met ) ) { |
|
1026 | - $maximum_args_length = apply_filters( 'action_scheduler_maximum_args_length', 191 ); |
|
1027 | - $found_action = $wpdb->get_var( // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching |
|
1028 | - $wpdb->prepare( |
|
1029 | - "SELECT ID FROM {$wpdb->posts} WHERE post_type = %s AND CHAR_LENGTH(post_content) > %d LIMIT 1", |
|
1030 | - $maximum_args_length, |
|
1031 | - self::POST_TYPE |
|
1032 | - ) |
|
1033 | - ); |
|
1034 | - $dependencies_met = $found_action ? 'no' : 'yes'; |
|
1035 | - set_transient( self::DEPENDENCIES_MET, $dependencies_met, DAY_IN_SECONDS ); |
|
1036 | - } |
|
1037 | - |
|
1038 | - return 'yes' === $dependencies_met ? $setting : false; |
|
1039 | - } |
|
1040 | - |
|
1041 | - /** |
|
1042 | - * InnoDB indexes have a maximum size of 767 bytes by default, which is only 191 characters with utf8mb4. |
|
1043 | - * |
|
1044 | - * Previously, AS wasn't concerned about args length, as we used the (unindex) post_content column. However, |
|
1045 | - * as we prepare to move to custom tables, and can use an indexed VARCHAR column instead, we want to warn |
|
1046 | - * developers of this impending requirement. |
|
1047 | - * |
|
1048 | - * @param ActionScheduler_Action $action Action object. |
|
1049 | - */ |
|
1050 | - protected function validate_action( ActionScheduler_Action $action ) { |
|
1051 | - try { |
|
1052 | - parent::validate_action( $action ); |
|
1053 | - } catch ( Exception $e ) { |
|
1054 | - /* translators: %s is the error message */ |
|
1055 | - $message = sprintf( __( '%s Support for strings longer than this will be removed in a future version.', 'action-scheduler' ), $e->getMessage() ); |
|
1056 | - _doing_it_wrong( 'ActionScheduler_Action::$args', esc_html( $message ), '2.1.0' ); |
|
1057 | - } |
|
1058 | - } |
|
1059 | - |
|
1060 | - /** |
|
1061 | - * (@codeCoverageIgnore) |
|
1062 | - */ |
|
1063 | - public function init() { |
|
1064 | - add_filter( 'action_scheduler_migration_dependencies_met', array( $this, 'migration_dependencies_met' ) ); |
|
1065 | - |
|
1066 | - $post_type_registrar = new ActionScheduler_wpPostStore_PostTypeRegistrar(); |
|
1067 | - $post_type_registrar->register(); |
|
1068 | - |
|
1069 | - $post_status_registrar = new ActionScheduler_wpPostStore_PostStatusRegistrar(); |
|
1070 | - $post_status_registrar->register(); |
|
1071 | - |
|
1072 | - $taxonomy_registrar = new ActionScheduler_wpPostStore_TaxonomyRegistrar(); |
|
1073 | - $taxonomy_registrar->register(); |
|
1074 | - } |
|
681 | + if ( $limit_ids ) { |
|
682 | + $where .= ' AND ID IN (' . join( ',', $ids ) . ')'; |
|
683 | + } else { |
|
684 | + $where .= ' AND post_date_gmt <= %s'; |
|
685 | + $params[] = $date->format( 'Y-m-d H:i:s' ); |
|
686 | + } |
|
687 | + |
|
688 | + // Add the ORDER BY clause and,ms limit. |
|
689 | + $order = 'ORDER BY menu_order ASC, post_date_gmt ASC, ID ASC LIMIT %d'; |
|
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 | + |
|
699 | + return (int) $rows_affected; |
|
700 | + } |
|
701 | + |
|
702 | + /** |
|
703 | + * Get IDs of actions within a certain group and up to a certain date/time. |
|
704 | + * |
|
705 | + * @param string $group The group to use in finding actions. |
|
706 | + * @param int $limit The number of actions to retrieve. |
|
707 | + * @param DateTime $date DateTime object representing cutoff time for actions. Actions retrieved will be |
|
708 | + * up to and including this DateTime. |
|
709 | + * |
|
710 | + * @return array IDs of actions in the appropriate group and before the appropriate time. |
|
711 | + * @throws InvalidArgumentException When the group does not exist. |
|
712 | + */ |
|
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 | + |
|
720 | + // Set up a query for post IDs to use later. |
|
721 | + $query = new WP_Query(); |
|
722 | + $query_args = array( |
|
723 | + 'fields' => 'ids', |
|
724 | + 'post_type' => self::POST_TYPE, |
|
725 | + 'post_status' => ActionScheduler_Store::STATUS_PENDING, |
|
726 | + 'has_password' => false, |
|
727 | + 'posts_per_page' => $limit * 3, |
|
728 | + 'suppress_filters' => true, |
|
729 | + 'no_found_rows' => true, |
|
730 | + 'orderby' => array( |
|
731 | + 'menu_order' => 'ASC', |
|
732 | + 'date' => 'ASC', |
|
733 | + 'ID' => 'ASC', |
|
734 | + ), |
|
735 | + 'date_query' => array( |
|
736 | + 'column' => 'post_date_gmt', |
|
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', |
|
744 | + 'terms' => $group, |
|
745 | + 'include_children' => false, |
|
746 | + ), |
|
747 | + ), |
|
748 | + ); |
|
749 | + |
|
750 | + return $query->query( $query_args ); |
|
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 | + } |
|
880 | + } |
|
881 | + |
|
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 ) { |
|
889 | + return $this->get_post_column( $action_id, 'post_password' ); |
|
890 | + } |
|
891 | + |
|
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 ); |
|
977 | + add_filter( 'pre_wp_unique_post_slug', array( $this, 'set_unique_post_slug' ), 10, 5 ); |
|
978 | + $result = wp_update_post( |
|
979 | + array( |
|
980 | + 'ID' => $action_id, |
|
981 | + 'post_status' => 'publish', |
|
982 | + ), |
|
983 | + true |
|
984 | + ); |
|
985 | + remove_filter( 'wp_insert_post_data', array( $this, 'filter_insert_post_data' ), 10 ); |
|
986 | + remove_filter( 'pre_wp_unique_post_slug', array( $this, 'set_unique_post_slug' ), 10 ); |
|
987 | + if ( is_wp_error( $result ) ) { |
|
988 | + throw new RuntimeException( $result->get_error_message() ); |
|
989 | + } |
|
990 | + |
|
991 | + /** |
|
992 | + * Fires after a scheduled action has been completed. |
|
993 | + * |
|
994 | + * @since 3.4.2 |
|
995 | + * |
|
996 | + * @param int $action_id Action ID. |
|
997 | + */ |
|
998 | + do_action( 'action_scheduler_completed_action', $action_id ); |
|
999 | + } |
|
1000 | + |
|
1001 | + /** |
|
1002 | + * Mark action as migrated when there is an error deleting the action. |
|
1003 | + * |
|
1004 | + * @param int $action_id Action ID. |
|
1005 | + */ |
|
1006 | + public function mark_migrated( $action_id ) { |
|
1007 | + wp_update_post( |
|
1008 | + array( |
|
1009 | + 'ID' => $action_id, |
|
1010 | + 'post_status' => 'migrated', |
|
1011 | + ) |
|
1012 | + ); |
|
1013 | + } |
|
1014 | + |
|
1015 | + /** |
|
1016 | + * Determine whether the post store can be migrated. |
|
1017 | + * |
|
1018 | + * @param [type] $setting - Setting value. |
|
1019 | + * @return bool |
|
1020 | + */ |
|
1021 | + public function migration_dependencies_met( $setting ) { |
|
1022 | + global $wpdb; |
|
1023 | + |
|
1024 | + $dependencies_met = get_transient( self::DEPENDENCIES_MET ); |
|
1025 | + if ( empty( $dependencies_met ) ) { |
|
1026 | + $maximum_args_length = apply_filters( 'action_scheduler_maximum_args_length', 191 ); |
|
1027 | + $found_action = $wpdb->get_var( // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching |
|
1028 | + $wpdb->prepare( |
|
1029 | + "SELECT ID FROM {$wpdb->posts} WHERE post_type = %s AND CHAR_LENGTH(post_content) > %d LIMIT 1", |
|
1030 | + $maximum_args_length, |
|
1031 | + self::POST_TYPE |
|
1032 | + ) |
|
1033 | + ); |
|
1034 | + $dependencies_met = $found_action ? 'no' : 'yes'; |
|
1035 | + set_transient( self::DEPENDENCIES_MET, $dependencies_met, DAY_IN_SECONDS ); |
|
1036 | + } |
|
1037 | + |
|
1038 | + return 'yes' === $dependencies_met ? $setting : false; |
|
1039 | + } |
|
1040 | + |
|
1041 | + /** |
|
1042 | + * InnoDB indexes have a maximum size of 767 bytes by default, which is only 191 characters with utf8mb4. |
|
1043 | + * |
|
1044 | + * Previously, AS wasn't concerned about args length, as we used the (unindex) post_content column. However, |
|
1045 | + * as we prepare to move to custom tables, and can use an indexed VARCHAR column instead, we want to warn |
|
1046 | + * developers of this impending requirement. |
|
1047 | + * |
|
1048 | + * @param ActionScheduler_Action $action Action object. |
|
1049 | + */ |
|
1050 | + protected function validate_action( ActionScheduler_Action $action ) { |
|
1051 | + try { |
|
1052 | + parent::validate_action( $action ); |
|
1053 | + } catch ( Exception $e ) { |
|
1054 | + /* translators: %s is the error message */ |
|
1055 | + $message = sprintf( __( '%s Support for strings longer than this will be removed in a future version.', 'action-scheduler' ), $e->getMessage() ); |
|
1056 | + _doing_it_wrong( 'ActionScheduler_Action::$args', esc_html( $message ), '2.1.0' ); |
|
1057 | + } |
|
1058 | + } |
|
1059 | + |
|
1060 | + /** |
|
1061 | + * (@codeCoverageIgnore) |
|
1062 | + */ |
|
1063 | + public function init() { |
|
1064 | + add_filter( 'action_scheduler_migration_dependencies_met', array( $this, 'migration_dependencies_met' ) ); |
|
1065 | + |
|
1066 | + $post_type_registrar = new ActionScheduler_wpPostStore_PostTypeRegistrar(); |
|
1067 | + $post_type_registrar->register(); |
|
1068 | + |
|
1069 | + $post_status_registrar = new ActionScheduler_wpPostStore_PostStatusRegistrar(); |
|
1070 | + $post_status_registrar->register(); |
|
1071 | + |
|
1072 | + $taxonomy_registrar = new ActionScheduler_wpPostStore_TaxonomyRegistrar(); |
|
1073 | + $taxonomy_registrar->register(); |
|
1074 | + } |
|
1075 | 1075 | } |
@@ -35,18 +35,18 @@ discard block |
||
35 | 35 | * @throws RuntimeException Throws an exception if the action could not be saved. |
36 | 36 | * @return int |
37 | 37 | */ |
38 | - public function save_action( ActionScheduler_Action $action, DateTime $scheduled_date = null ) { |
|
38 | + public function save_action(ActionScheduler_Action $action, DateTime $scheduled_date = null) { |
|
39 | 39 | try { |
40 | - $this->validate_action( $action ); |
|
41 | - $post_array = $this->create_post_array( $action, $scheduled_date ); |
|
42 | - $post_id = $this->save_post_array( $post_array ); |
|
43 | - $this->save_post_schedule( $post_id, $action->get_schedule() ); |
|
44 | - $this->save_action_group( $post_id, $action->get_group() ); |
|
45 | - do_action( 'action_scheduler_stored_action', $post_id ); |
|
40 | + $this->validate_action($action); |
|
41 | + $post_array = $this->create_post_array($action, $scheduled_date); |
|
42 | + $post_id = $this->save_post_array($post_array); |
|
43 | + $this->save_post_schedule($post_id, $action->get_schedule()); |
|
44 | + $this->save_action_group($post_id, $action->get_group()); |
|
45 | + do_action('action_scheduler_stored_action', $post_id); |
|
46 | 46 | return $post_id; |
47 | - } catch ( Exception $e ) { |
|
47 | + } catch (Exception $e) { |
|
48 | 48 | /* translators: %s: action error message */ |
49 | - throw new RuntimeException( sprintf( __( 'Error saving action: %s', 'action-scheduler' ), $e->getMessage() ), 0 ); |
|
49 | + throw new RuntimeException(sprintf(__('Error saving action: %s', 'action-scheduler'), $e->getMessage()), 0); |
|
50 | 50 | } |
51 | 51 | } |
52 | 52 | |
@@ -58,14 +58,14 @@ discard block |
||
58 | 58 | * |
59 | 59 | * @return array Returns an array of post data. |
60 | 60 | */ |
61 | - protected function create_post_array( ActionScheduler_Action $action, DateTime $scheduled_date = null ) { |
|
61 | + protected function create_post_array(ActionScheduler_Action $action, DateTime $scheduled_date = null) { |
|
62 | 62 | $post = array( |
63 | 63 | 'post_type' => self::POST_TYPE, |
64 | 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 ), |
|
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), |
|
69 | 69 | ); |
70 | 70 | return $post; |
71 | 71 | } |
@@ -77,28 +77,28 @@ discard block |
||
77 | 77 | * @return int Returns the post ID. |
78 | 78 | * @throws RuntimeException Throws an exception if the action could not be saved. |
79 | 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 ); |
|
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); |
|
83 | 83 | |
84 | - $has_kses = false !== has_filter( 'content_save_pre', 'wp_filter_post_kses' ); |
|
84 | + $has_kses = false !== has_filter('content_save_pre', 'wp_filter_post_kses'); |
|
85 | 85 | |
86 | - if ( $has_kses ) { |
|
86 | + if ($has_kses) { |
|
87 | 87 | // Prevent KSES from corrupting JSON in post_content. |
88 | 88 | kses_remove_filters(); |
89 | 89 | } |
90 | 90 | |
91 | - $post_id = wp_insert_post( $post_array ); |
|
91 | + $post_id = wp_insert_post($post_array); |
|
92 | 92 | |
93 | - if ( $has_kses ) { |
|
93 | + if ($has_kses) { |
|
94 | 94 | kses_init_filters(); |
95 | 95 | } |
96 | 96 | |
97 | - remove_filter( 'wp_insert_post_data', array( $this, 'filter_insert_post_data' ), 10 ); |
|
98 | - remove_filter( 'pre_wp_unique_post_slug', array( $this, 'set_unique_post_slug' ), 10 ); |
|
97 | + remove_filter('wp_insert_post_data', array($this, 'filter_insert_post_data'), 10); |
|
98 | + remove_filter('pre_wp_unique_post_slug', array($this, 'set_unique_post_slug'), 10); |
|
99 | 99 | |
100 | - if ( is_wp_error( $post_id ) || empty( $post_id ) ) { |
|
101 | - throw new RuntimeException( __( 'Unable to save action.', 'action-scheduler' ) ); |
|
100 | + if (is_wp_error($post_id) || empty($post_id)) { |
|
101 | + throw new RuntimeException(__('Unable to save action.', 'action-scheduler')); |
|
102 | 102 | } |
103 | 103 | return $post_id; |
104 | 104 | } |
@@ -110,10 +110,10 @@ discard block |
||
110 | 110 | * |
111 | 111 | * @return array |
112 | 112 | */ |
113 | - public function filter_insert_post_data( $postdata ) { |
|
114 | - if ( self::POST_TYPE === $postdata['post_type'] ) { |
|
113 | + public function filter_insert_post_data($postdata) { |
|
114 | + if (self::POST_TYPE === $postdata['post_type']) { |
|
115 | 115 | $postdata['post_author'] = 0; |
116 | - if ( 'future' === $postdata['post_status'] ) { |
|
116 | + if ('future' === $postdata['post_status']) { |
|
117 | 117 | $postdata['post_status'] = 'publish'; |
118 | 118 | } |
119 | 119 | } |
@@ -148,9 +148,9 @@ discard block |
||
148 | 148 | * @param string $post_type Post type. |
149 | 149 | * @return string |
150 | 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 ); |
|
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 | 154 | } |
155 | 155 | return $override_slug; |
156 | 156 | } |
@@ -163,8 +163,8 @@ discard block |
||
163 | 163 | * |
164 | 164 | * @return void |
165 | 165 | */ |
166 | - protected function save_post_schedule( $post_id, $schedule ) { |
|
167 | - update_post_meta( $post_id, self::SCHEDULE_META_KEY, $schedule ); |
|
166 | + protected function save_post_schedule($post_id, $schedule) { |
|
167 | + update_post_meta($post_id, self::SCHEDULE_META_KEY, $schedule); |
|
168 | 168 | } |
169 | 169 | |
170 | 170 | /** |
@@ -174,11 +174,11 @@ discard block |
||
174 | 174 | * @param string $group Group to save. |
175 | 175 | * @return void |
176 | 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 ); |
|
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); |
|
180 | 180 | } else { |
181 | - wp_set_object_terms( $post_id, array( $group ), self::GROUP_TAXONOMY, false ); |
|
181 | + wp_set_object_terms($post_id, array($group), self::GROUP_TAXONOMY, false); |
|
182 | 182 | } |
183 | 183 | } |
184 | 184 | |
@@ -188,16 +188,16 @@ discard block |
||
188 | 188 | * @param int $action_id Action ID. |
189 | 189 | * @return object |
190 | 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 ) { |
|
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 | 194 | return $this->get_null_action(); |
195 | 195 | } |
196 | 196 | |
197 | 197 | try { |
198 | - $action = $this->make_action_from_post( $post ); |
|
199 | - } catch ( ActionScheduler_InvalidActionException $exception ) { |
|
200 | - do_action( 'action_scheduler_failed_fetch_action', $post->ID, $exception ); |
|
198 | + $action = $this->make_action_from_post($post); |
|
199 | + } catch (ActionScheduler_InvalidActionException $exception) { |
|
200 | + do_action('action_scheduler_failed_fetch_action', $post->ID, $exception); |
|
201 | 201 | return $this->get_null_action(); |
202 | 202 | } |
203 | 203 | |
@@ -210,11 +210,11 @@ discard block |
||
210 | 210 | * @param string $action_id - Action ID. |
211 | 211 | * @return WP_Post|null |
212 | 212 | */ |
213 | - protected function get_post( $action_id ) { |
|
214 | - if ( empty( $action_id ) ) { |
|
213 | + protected function get_post($action_id) { |
|
214 | + if (empty($action_id)) { |
|
215 | 215 | return null; |
216 | 216 | } |
217 | - return get_post( $action_id ); |
|
217 | + return get_post($action_id); |
|
218 | 218 | } |
219 | 219 | |
220 | 220 | /** |
@@ -232,19 +232,19 @@ discard block |
||
232 | 232 | * @param WP_Post $post Post object. |
233 | 233 | * @return WP_Post |
234 | 234 | */ |
235 | - protected function make_action_from_post( $post ) { |
|
235 | + protected function make_action_from_post($post) { |
|
236 | 236 | $hook = $post->post_title; |
237 | 237 | |
238 | - $args = json_decode( $post->post_content, true ); |
|
239 | - $this->validate_args( $args, $post->ID ); |
|
238 | + $args = json_decode($post->post_content, true); |
|
239 | + $this->validate_args($args, $post->ID); |
|
240 | 240 | |
241 | - $schedule = get_post_meta( $post->ID, self::SCHEDULE_META_KEY, true ); |
|
242 | - $this->validate_schedule( $schedule, $post->ID ); |
|
241 | + $schedule = get_post_meta($post->ID, self::SCHEDULE_META_KEY, true); |
|
242 | + $this->validate_schedule($schedule, $post->ID); |
|
243 | 243 | |
244 | - $group = wp_get_object_terms( $post->ID, self::GROUP_TAXONOMY, array( 'fields' => 'names' ) ); |
|
245 | - $group = empty( $group ) ? '' : reset( $group ); |
|
244 | + $group = wp_get_object_terms($post->ID, self::GROUP_TAXONOMY, array('fields' => 'names')); |
|
245 | + $group = empty($group) ? '' : reset($group); |
|
246 | 246 | |
247 | - return ActionScheduler::factory()->get_stored_action( $this->get_action_status_by_post_status( $post->post_status ), $hook, $args, $schedule, $group ); |
|
247 | + return ActionScheduler::factory()->get_stored_action($this->get_action_status_by_post_status($post->post_status), $hook, $args, $schedule, $group); |
|
248 | 248 | } |
249 | 249 | |
250 | 250 | /** |
@@ -255,9 +255,9 @@ discard block |
||
255 | 255 | * @throws InvalidArgumentException Throw InvalidArgumentException if $post_status not in known status fields returned by $this->get_status_labels(). |
256 | 256 | * @return string |
257 | 257 | */ |
258 | - protected function get_action_status_by_post_status( $post_status ) { |
|
258 | + protected function get_action_status_by_post_status($post_status) { |
|
259 | 259 | |
260 | - switch ( $post_status ) { |
|
260 | + switch ($post_status) { |
|
261 | 261 | case 'publish': |
262 | 262 | $action_status = self::STATUS_COMPLETE; |
263 | 263 | break; |
@@ -265,8 +265,8 @@ discard block |
||
265 | 265 | $action_status = self::STATUS_CANCELED; |
266 | 266 | break; |
267 | 267 | default: |
268 | - if ( ! array_key_exists( $post_status, $this->get_status_labels() ) ) { |
|
269 | - throw new InvalidArgumentException( sprintf( 'Invalid post status: "%s". No matching action status available.', $post_status ) ); |
|
268 | + if ( ! array_key_exists($post_status, $this->get_status_labels())) { |
|
269 | + throw new InvalidArgumentException(sprintf('Invalid post status: "%s". No matching action status available.', $post_status)); |
|
270 | 270 | } |
271 | 271 | $action_status = $post_status; |
272 | 272 | break; |
@@ -283,9 +283,9 @@ discard block |
||
283 | 283 | * @throws InvalidArgumentException Throws InvalidArgumentException if $post_status not in known status fields returned by $this->get_status_labels(). |
284 | 284 | * @return string |
285 | 285 | */ |
286 | - protected function get_post_status_by_action_status( $action_status ) { |
|
286 | + protected function get_post_status_by_action_status($action_status) { |
|
287 | 287 | |
288 | - switch ( $action_status ) { |
|
288 | + switch ($action_status) { |
|
289 | 289 | case self::STATUS_COMPLETE: |
290 | 290 | $post_status = 'publish'; |
291 | 291 | break; |
@@ -293,8 +293,8 @@ discard block |
||
293 | 293 | $post_status = 'trash'; |
294 | 294 | break; |
295 | 295 | default: |
296 | - if ( ! array_key_exists( $action_status, $this->get_status_labels() ) ) { |
|
297 | - throw new InvalidArgumentException( sprintf( 'Invalid action status: "%s".', $action_status ) ); |
|
296 | + if ( ! array_key_exists($action_status, $this->get_status_labels())) { |
|
297 | + throw new InvalidArgumentException(sprintf('Invalid action status: "%s".', $action_status)); |
|
298 | 298 | } |
299 | 299 | $post_status = $action_status; |
300 | 300 | break; |
@@ -312,10 +312,10 @@ discard block |
||
312 | 312 | * @throws InvalidArgumentException - Throw InvalidArgumentException if $select_or_count not count or select. |
313 | 313 | * @return string SQL statement. The returned SQL is already properly escaped. |
314 | 314 | */ |
315 | - protected function get_query_actions_sql( array $query, $select_or_count = 'select' ) { |
|
315 | + protected function get_query_actions_sql(array $query, $select_or_count = 'select') { |
|
316 | 316 | |
317 | - if ( ! in_array( $select_or_count, array( 'select', 'count' ), true ) ) { |
|
318 | - throw new InvalidArgumentException( __( 'Invalid schedule. Cannot save action.', 'action-scheduler' ) ); |
|
317 | + if ( ! in_array($select_or_count, array('select', 'count'), true)) { |
|
318 | + throw new InvalidArgumentException(__('Invalid schedule. Cannot save action.', 'action-scheduler')); |
|
319 | 319 | } |
320 | 320 | |
321 | 321 | $query = wp_parse_args( |
@@ -344,14 +344,14 @@ discard block |
||
344 | 344 | * @var wpdb $wpdb |
345 | 345 | */ |
346 | 346 | global $wpdb; |
347 | - $sql = ( 'count' === $select_or_count ) ? 'SELECT count(p.ID)' : 'SELECT p.ID '; |
|
347 | + $sql = ('count' === $select_or_count) ? 'SELECT count(p.ID)' : 'SELECT p.ID '; |
|
348 | 348 | $sql .= "FROM {$wpdb->posts} p"; |
349 | 349 | $sql_params = array(); |
350 | - if ( empty( $query['group'] ) && 'group' === $query['orderby'] ) { |
|
350 | + if (empty($query['group']) && 'group' === $query['orderby']) { |
|
351 | 351 | $sql .= " LEFT JOIN {$wpdb->term_relationships} tr ON tr.object_id=p.ID"; |
352 | 352 | $sql .= " LEFT JOIN {$wpdb->term_taxonomy} tt ON tr.term_taxonomy_id=tt.term_taxonomy_id"; |
353 | 353 | $sql .= " LEFT JOIN {$wpdb->terms} t ON tt.term_id=t.term_id"; |
354 | - } elseif ( ! empty( $query['group'] ) ) { |
|
354 | + } elseif ( ! empty($query['group'])) { |
|
355 | 355 | $sql .= " INNER JOIN {$wpdb->term_relationships} tr ON tr.object_id=p.ID"; |
356 | 356 | $sql .= " INNER JOIN {$wpdb->term_taxonomy} tt ON tr.term_taxonomy_id=tt.term_taxonomy_id"; |
357 | 357 | $sql .= " INNER JOIN {$wpdb->terms} t ON tt.term_id=t.term_id"; |
@@ -360,58 +360,58 @@ discard block |
||
360 | 360 | } |
361 | 361 | $sql .= ' WHERE post_type=%s'; |
362 | 362 | $sql_params[] = self::POST_TYPE; |
363 | - if ( $query['hook'] ) { |
|
363 | + if ($query['hook']) { |
|
364 | 364 | $sql .= ' AND p.post_title=%s'; |
365 | 365 | $sql_params[] = $query['hook']; |
366 | 366 | } |
367 | - if ( $query['args'] !== null ) { |
|
367 | + if ($query['args'] !== null) { |
|
368 | 368 | $sql .= ' AND p.post_content=%s'; |
369 | - $sql_params[] = wp_json_encode( $query['args'] ); |
|
369 | + $sql_params[] = wp_json_encode($query['args']); |
|
370 | 370 | } |
371 | 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 ) ); |
|
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 | 377 | } |
378 | 378 | |
379 | - if ( $query['date'] instanceof DateTime ) { |
|
379 | + if ($query['date'] instanceof DateTime) { |
|
380 | 380 | $date = clone $query['date']; |
381 | - $date->setTimezone( new DateTimeZone( 'UTC' ) ); |
|
382 | - $date_string = $date->format( 'Y-m-d H:i:s' ); |
|
383 | - $comparator = $this->validate_sql_comparator( $query['date_compare'] ); |
|
381 | + $date->setTimezone(new DateTimeZone('UTC')); |
|
382 | + $date_string = $date->format('Y-m-d H:i:s'); |
|
383 | + $comparator = $this->validate_sql_comparator($query['date_compare']); |
|
384 | 384 | $sql .= " AND p.post_date_gmt $comparator %s"; |
385 | 385 | $sql_params[] = $date_string; |
386 | 386 | } |
387 | 387 | |
388 | - if ( $query['modified'] instanceof DateTime ) { |
|
388 | + if ($query['modified'] instanceof DateTime) { |
|
389 | 389 | $modified = clone $query['modified']; |
390 | - $modified->setTimezone( new DateTimeZone( 'UTC' ) ); |
|
391 | - $date_string = $modified->format( 'Y-m-d H:i:s' ); |
|
392 | - $comparator = $this->validate_sql_comparator( $query['modified_compare'] ); |
|
390 | + $modified->setTimezone(new DateTimeZone('UTC')); |
|
391 | + $date_string = $modified->format('Y-m-d H:i:s'); |
|
392 | + $comparator = $this->validate_sql_comparator($query['modified_compare']); |
|
393 | 393 | $sql .= " AND p.post_modified_gmt $comparator %s"; |
394 | 394 | $sql_params[] = $date_string; |
395 | 395 | } |
396 | 396 | |
397 | - if ( true === $query['claimed'] ) { |
|
397 | + if (true === $query['claimed']) { |
|
398 | 398 | $sql .= " AND p.post_password != ''"; |
399 | - } elseif ( false === $query['claimed'] ) { |
|
399 | + } elseif (false === $query['claimed']) { |
|
400 | 400 | $sql .= " AND p.post_password = ''"; |
401 | - } elseif ( $query['claimed'] !== null ) { |
|
401 | + } elseif ($query['claimed'] !== null) { |
|
402 | 402 | $sql .= ' AND p.post_password = %s'; |
403 | 403 | $sql_params[] = $query['claimed']; |
404 | 404 | } |
405 | 405 | |
406 | - if ( ! empty( $query['search'] ) ) { |
|
406 | + if ( ! empty($query['search'])) { |
|
407 | 407 | $sql .= ' AND (p.post_title LIKE %s OR p.post_content LIKE %s OR p.post_password LIKE %s)'; |
408 | - for ( $i = 0; $i < 3; $i++ ) { |
|
409 | - $sql_params[] = sprintf( '%%%s%%', $query['search'] ); |
|
408 | + for ($i = 0; $i < 3; $i++) { |
|
409 | + $sql_params[] = sprintf('%%%s%%', $query['search']); |
|
410 | 410 | } |
411 | 411 | } |
412 | 412 | |
413 | - if ( 'select' === $select_or_count ) { |
|
414 | - switch ( $query['orderby'] ) { |
|
413 | + if ('select' === $select_or_count) { |
|
414 | + switch ($query['orderby']) { |
|
415 | 415 | case 'hook': |
416 | 416 | $orderby = 'p.post_title'; |
417 | 417 | break; |
@@ -433,20 +433,20 @@ discard block |
||
433 | 433 | $orderby = 'p.post_date_gmt'; |
434 | 434 | break; |
435 | 435 | } |
436 | - if ( 'ASC' === strtoupper( $query['order'] ) ) { |
|
436 | + if ('ASC' === strtoupper($query['order'])) { |
|
437 | 437 | $order = 'ASC'; |
438 | 438 | } else { |
439 | 439 | $order = 'DESC'; |
440 | 440 | } |
441 | 441 | $sql .= " ORDER BY $orderby $order"; |
442 | - if ( $query['per_page'] > 0 ) { |
|
442 | + if ($query['per_page'] > 0) { |
|
443 | 443 | $sql .= ' LIMIT %d, %d'; |
444 | 444 | $sql_params[] = $query['offset']; |
445 | 445 | $sql_params[] = $query['per_page']; |
446 | 446 | } |
447 | 447 | } |
448 | 448 | |
449 | - return $wpdb->prepare( $sql, $sql_params ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared |
|
449 | + return $wpdb->prepare($sql, $sql_params); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared |
|
450 | 450 | } |
451 | 451 | |
452 | 452 | /** |
@@ -461,7 +461,7 @@ discard block |
||
461 | 461 | * |
462 | 462 | * @return string|array|null The IDs of actions matching the query. Null on failure. |
463 | 463 | */ |
464 | - public function query_actions( $query = array(), $query_type = 'select' ) { |
|
464 | + public function query_actions($query = array(), $query_type = 'select') { |
|
465 | 465 | /** |
466 | 466 | * Global $wpdb object. |
467 | 467 | * |
@@ -469,9 +469,9 @@ discard block |
||
469 | 469 | */ |
470 | 470 | global $wpdb; |
471 | 471 | |
472 | - $sql = $this->get_query_actions_sql( $query, $query_type ); |
|
472 | + $sql = $this->get_query_actions_sql($query, $query_type); |
|
473 | 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 |
|
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 | 475 | } |
476 | 476 | |
477 | 477 | /** |
@@ -483,18 +483,18 @@ discard block |
||
483 | 483 | |
484 | 484 | $action_counts_by_status = array(); |
485 | 485 | $action_stati_and_labels = $this->get_status_labels(); |
486 | - $posts_count_by_status = (array) wp_count_posts( self::POST_TYPE, 'readable' ); |
|
486 | + $posts_count_by_status = (array) wp_count_posts(self::POST_TYPE, 'readable'); |
|
487 | 487 | |
488 | - foreach ( $posts_count_by_status as $post_status_name => $count ) { |
|
488 | + foreach ($posts_count_by_status as $post_status_name => $count) { |
|
489 | 489 | |
490 | 490 | try { |
491 | - $action_status_name = $this->get_action_status_by_post_status( $post_status_name ); |
|
492 | - } catch ( Exception $e ) { |
|
491 | + $action_status_name = $this->get_action_status_by_post_status($post_status_name); |
|
492 | + } catch (Exception $e) { |
|
493 | 493 | // Ignore any post statuses that aren't for actions. |
494 | 494 | continue; |
495 | 495 | } |
496 | - if ( array_key_exists( $action_status_name, $action_stati_and_labels ) ) { |
|
497 | - $action_counts_by_status[ $action_status_name ] = $count; |
|
496 | + if (array_key_exists($action_status_name, $action_stati_and_labels)) { |
|
497 | + $action_counts_by_status[$action_status_name] = $count; |
|
498 | 498 | } |
499 | 499 | } |
500 | 500 | |
@@ -508,16 +508,16 @@ discard block |
||
508 | 508 | * |
509 | 509 | * @throws InvalidArgumentException If $action_id is not identified. |
510 | 510 | */ |
511 | - public function cancel_action( $action_id ) { |
|
512 | - $post = get_post( $action_id ); |
|
513 | - if ( empty( $post ) || ( self::POST_TYPE !== $post->post_type ) ) { |
|
511 | + public function cancel_action($action_id) { |
|
512 | + $post = get_post($action_id); |
|
513 | + if (empty($post) || (self::POST_TYPE !== $post->post_type)) { |
|
514 | 514 | /* translators: %s is the action ID */ |
515 | - throw new InvalidArgumentException( sprintf( __( 'Unidentified action %s', 'action-scheduler' ), $action_id ) ); |
|
515 | + throw new InvalidArgumentException(sprintf(__('Unidentified action %s', 'action-scheduler'), $action_id)); |
|
516 | 516 | } |
517 | - do_action( 'action_scheduler_canceled_action', $action_id ); |
|
518 | - add_filter( 'pre_wp_unique_post_slug', array( $this, 'set_unique_post_slug' ), 10, 5 ); |
|
519 | - wp_trash_post( $action_id ); |
|
520 | - remove_filter( 'pre_wp_unique_post_slug', array( $this, 'set_unique_post_slug' ), 10 ); |
|
517 | + do_action('action_scheduler_canceled_action', $action_id); |
|
518 | + add_filter('pre_wp_unique_post_slug', array($this, 'set_unique_post_slug'), 10, 5); |
|
519 | + wp_trash_post($action_id); |
|
520 | + remove_filter('pre_wp_unique_post_slug', array($this, 'set_unique_post_slug'), 10); |
|
521 | 521 | } |
522 | 522 | |
523 | 523 | /** |
@@ -527,15 +527,15 @@ discard block |
||
527 | 527 | * @return void |
528 | 528 | * @throws InvalidArgumentException If action is not identified. |
529 | 529 | */ |
530 | - public function delete_action( $action_id ) { |
|
531 | - $post = get_post( $action_id ); |
|
532 | - if ( empty( $post ) || ( self::POST_TYPE !== $post->post_type ) ) { |
|
530 | + public function delete_action($action_id) { |
|
531 | + $post = get_post($action_id); |
|
532 | + if (empty($post) || (self::POST_TYPE !== $post->post_type)) { |
|
533 | 533 | /* translators: %s is the action ID */ |
534 | - throw new InvalidArgumentException( sprintf( __( 'Unidentified action %s', 'action-scheduler' ), $action_id ) ); |
|
534 | + throw new InvalidArgumentException(sprintf(__('Unidentified action %s', 'action-scheduler'), $action_id)); |
|
535 | 535 | } |
536 | - do_action( 'action_scheduler_deleted_action', $action_id ); |
|
536 | + do_action('action_scheduler_deleted_action', $action_id); |
|
537 | 537 | |
538 | - wp_delete_post( $action_id, true ); |
|
538 | + wp_delete_post($action_id, true); |
|
539 | 539 | } |
540 | 540 | |
541 | 541 | /** |
@@ -544,9 +544,9 @@ discard block |
||
544 | 544 | * @param int $action_id Action ID. |
545 | 545 | * @return ActionScheduler_DateTime The date the action is schedule to run, or the date that it ran. |
546 | 546 | */ |
547 | - public function get_date( $action_id ) { |
|
548 | - $next = $this->get_date_gmt( $action_id ); |
|
549 | - return ActionScheduler_TimezoneHelper::set_local_timezone( $next ); |
|
547 | + public function get_date($action_id) { |
|
548 | + $next = $this->get_date_gmt($action_id); |
|
549 | + return ActionScheduler_TimezoneHelper::set_local_timezone($next); |
|
550 | 550 | } |
551 | 551 | |
552 | 552 | /** |
@@ -557,16 +557,16 @@ discard block |
||
557 | 557 | * @throws InvalidArgumentException If $action_id is not identified. |
558 | 558 | * @return ActionScheduler_DateTime The date the action is schedule to run, or the date that it ran. |
559 | 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 ) ) { |
|
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 | 563 | /* translators: %s is the action ID */ |
564 | - throw new InvalidArgumentException( sprintf( __( 'Unidentified action %s', 'action-scheduler' ), $action_id ) ); |
|
564 | + throw new InvalidArgumentException(sprintf(__('Unidentified action %s', 'action-scheduler'), $action_id)); |
|
565 | 565 | } |
566 | - if ( 'publish' === $post->post_status ) { |
|
567 | - return as_get_datetime_object( $post->post_modified_gmt ); |
|
566 | + if ('publish' === $post->post_status) { |
|
567 | + return as_get_datetime_object($post->post_modified_gmt); |
|
568 | 568 | } else { |
569 | - return as_get_datetime_object( $post->post_date_gmt ); |
|
569 | + return as_get_datetime_object($post->post_date_gmt); |
|
570 | 570 | } |
571 | 571 | } |
572 | 572 | |
@@ -582,14 +582,14 @@ discard block |
||
582 | 582 | * @throws RuntimeException When there is an error staking a claim. |
583 | 583 | * @throws InvalidArgumentException When the given group is not valid. |
584 | 584 | */ |
585 | - public function stake_claim( $max_actions = 10, DateTime $before_date = null, $hooks = array(), $group = '' ) { |
|
585 | + public function stake_claim($max_actions = 10, DateTime $before_date = null, $hooks = array(), $group = '') { |
|
586 | 586 | $this->claim_before_date = $before_date; |
587 | 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 ); |
|
588 | + $this->claim_actions($claim_id, $max_actions, $before_date, $hooks, $group); |
|
589 | + $action_ids = $this->find_actions_by_claim_id($claim_id); |
|
590 | 590 | $this->claim_before_date = null; |
591 | 591 | |
592 | - return new ActionScheduler_ActionClaim( $claim_id, $action_ids ); |
|
592 | + return new ActionScheduler_ActionClaim($claim_id, $action_ids); |
|
593 | 593 | } |
594 | 594 | |
595 | 595 | /** |
@@ -604,7 +604,7 @@ discard block |
||
604 | 604 | return $wpdb->get_var( |
605 | 605 | $wpdb->prepare( |
606 | 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 ) |
|
607 | + array(self::POST_TYPE) |
|
608 | 608 | ) |
609 | 609 | ); |
610 | 610 | } |
@@ -615,8 +615,8 @@ discard block |
||
615 | 615 | * @return string |
616 | 616 | */ |
617 | 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. |
|
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 | 620 | } |
621 | 621 | |
622 | 622 | /** |
@@ -631,14 +631,14 @@ discard block |
||
631 | 631 | * @return int The number of actions that were claimed. |
632 | 632 | * @throws RuntimeException When there is a database error. |
633 | 633 | */ |
634 | - protected function claim_actions( $claim_id, $limit, DateTime $before_date = null, $hooks = array(), $group = '' ) { |
|
634 | + protected function claim_actions($claim_id, $limit, DateTime $before_date = null, $hooks = array(), $group = '') { |
|
635 | 635 | // Set up initial variables. |
636 | 636 | $date = null === $before_date ? as_get_datetime_object() : clone $before_date; |
637 | - $limit_ids = ! empty( $group ); |
|
638 | - $ids = $limit_ids ? $this->get_actions_by_group( $group, $limit, $date ) : array(); |
|
637 | + $limit_ids = ! empty($group); |
|
638 | + $ids = $limit_ids ? $this->get_actions_by_group($group, $limit, $date) : array(); |
|
639 | 639 | |
640 | 640 | // If limiting by IDs and no posts found, then return early since we have nothing to update. |
641 | - if ( $limit_ids && 0 === count( $ids ) ) { |
|
641 | + if ($limit_ids && 0 === count($ids)) { |
|
642 | 642 | return 0; |
643 | 643 | } |
644 | 644 | |
@@ -658,8 +658,8 @@ discard block |
||
658 | 658 | $update = "UPDATE {$wpdb->posts} SET post_password = %s, post_modified_gmt = %s, post_modified = %s"; |
659 | 659 | $params = array( |
660 | 660 | $claim_id, |
661 | - current_time( 'mysql', true ), |
|
662 | - current_time( 'mysql' ), |
|
661 | + current_time('mysql', true), |
|
662 | + current_time('mysql'), |
|
663 | 663 | ); |
664 | 664 | |
665 | 665 | // Build initial WHERE clause. |
@@ -667,10 +667,10 @@ discard block |
||
667 | 667 | $params[] = self::POST_TYPE; |
668 | 668 | $params[] = ActionScheduler_Store::STATUS_PENDING; |
669 | 669 | |
670 | - if ( ! empty( $hooks ) ) { |
|
671 | - $placeholders = array_fill( 0, count( $hooks ), '%s' ); |
|
672 | - $where .= ' AND post_title IN (' . join( ', ', $placeholders ) . ')'; |
|
673 | - $params = array_merge( $params, array_values( $hooks ) ); |
|
670 | + if ( ! empty($hooks)) { |
|
671 | + $placeholders = array_fill(0, count($hooks), '%s'); |
|
672 | + $where .= ' AND post_title IN ('.join(', ', $placeholders).')'; |
|
673 | + $params = array_merge($params, array_values($hooks)); |
|
674 | 674 | } |
675 | 675 | |
676 | 676 | /* |
@@ -678,11 +678,11 @@ discard block |
||
678 | 678 | * |
679 | 679 | * If we're not limiting by IDs, then include the post_date_gmt clause. |
680 | 680 | */ |
681 | - if ( $limit_ids ) { |
|
682 | - $where .= ' AND ID IN (' . join( ',', $ids ) . ')'; |
|
681 | + if ($limit_ids) { |
|
682 | + $where .= ' AND ID IN ('.join(',', $ids).')'; |
|
683 | 683 | } else { |
684 | 684 | $where .= ' AND post_date_gmt <= %s'; |
685 | - $params[] = $date->format( 'Y-m-d H:i:s' ); |
|
685 | + $params[] = $date->format('Y-m-d H:i:s'); |
|
686 | 686 | } |
687 | 687 | |
688 | 688 | // Add the ORDER BY clause and,ms limit. |
@@ -690,10 +690,10 @@ discard block |
||
690 | 690 | $params[] = $limit; |
691 | 691 | |
692 | 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 |
|
693 | + $rows_affected = $wpdb->query($wpdb->prepare("{$update} {$where} {$order}", $params)); // phpcs:ignore // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.PreparedSQLPlaceholders.UnfinishedPrepare |
|
694 | 694 | |
695 | - if ( false === $rows_affected ) { |
|
696 | - throw new RuntimeException( __( 'Unable to claim actions. Database error.', 'action-scheduler' ) ); |
|
695 | + if (false === $rows_affected) { |
|
696 | + throw new RuntimeException(__('Unable to claim actions. Database error.', 'action-scheduler')); |
|
697 | 697 | } |
698 | 698 | |
699 | 699 | return (int) $rows_affected; |
@@ -710,11 +710,11 @@ discard block |
||
710 | 710 | * @return array IDs of actions in the appropriate group and before the appropriate time. |
711 | 711 | * @throws InvalidArgumentException When the group does not exist. |
712 | 712 | */ |
713 | - protected function get_actions_by_group( $group, $limit, DateTime $date ) { |
|
713 | + protected function get_actions_by_group($group, $limit, DateTime $date) { |
|
714 | 714 | // Ensure the group exists before continuing. |
715 | - if ( ! term_exists( $group, self::GROUP_TAXONOMY ) ) { |
|
715 | + if ( ! term_exists($group, self::GROUP_TAXONOMY)) { |
|
716 | 716 | /* translators: %s is the group name */ |
717 | - throw new InvalidArgumentException( sprintf( __( 'The group "%s" does not exist.', 'action-scheduler' ), $group ) ); |
|
717 | + throw new InvalidArgumentException(sprintf(__('The group "%s" does not exist.', 'action-scheduler'), $group)); |
|
718 | 718 | } |
719 | 719 | |
720 | 720 | // Set up a query for post IDs to use later. |
@@ -734,7 +734,7 @@ discard block |
||
734 | 734 | ), |
735 | 735 | 'date_query' => array( |
736 | 736 | 'column' => 'post_date_gmt', |
737 | - 'before' => $date->format( 'Y-m-d H:i' ), |
|
737 | + 'before' => $date->format('Y-m-d H:i'), |
|
738 | 738 | 'inclusive' => true, |
739 | 739 | ), |
740 | 740 | 'tax_query' => array( // phpcs:ignore WordPress.DB.SlowDBQuery |
@@ -747,7 +747,7 @@ discard block |
||
747 | 747 | ), |
748 | 748 | ); |
749 | 749 | |
750 | - return $query->query( $query_args ); |
|
750 | + return $query->query($query_args); |
|
751 | 751 | } |
752 | 752 | |
753 | 753 | /** |
@@ -756,7 +756,7 @@ discard block |
||
756 | 756 | * @param string $claim_id Claim ID. |
757 | 757 | * @return array |
758 | 758 | */ |
759 | - public function find_actions_by_claim_id( $claim_id ) { |
|
759 | + public function find_actions_by_claim_id($claim_id) { |
|
760 | 760 | /** |
761 | 761 | * Global wpdb object. |
762 | 762 | * |
@@ -765,8 +765,8 @@ discard block |
||
765 | 765 | global $wpdb; |
766 | 766 | |
767 | 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' ); |
|
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 | 770 | |
771 | 771 | // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching |
772 | 772 | $results = $wpdb->get_results( |
@@ -781,9 +781,9 @@ discard block |
||
781 | 781 | |
782 | 782 | // Verify that the scheduled date for each action is within the expected bounds (in some unusual |
783 | 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 ); |
|
784 | + foreach ($results as $claimed_action) { |
|
785 | + if ($claimed_action->post_date_gmt <= $cut_off) { |
|
786 | + $action_ids[] = absint($claimed_action->ID); |
|
787 | 787 | } |
788 | 788 | } |
789 | 789 | |
@@ -797,12 +797,12 @@ discard block |
||
797 | 797 | * @return void |
798 | 798 | * @throws RuntimeException When the claim is not unlocked. |
799 | 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 ) ) { |
|
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 | 803 | return; // nothing to do. |
804 | 804 | } |
805 | - $action_id_string = implode( ',', array_map( 'intval', $action_ids ) ); |
|
805 | + $action_id_string = implode(',', array_map('intval', $action_ids)); |
|
806 | 806 | /** |
807 | 807 | * Global wpdb object. |
808 | 808 | * |
@@ -819,9 +819,9 @@ discard block |
||
819 | 819 | ) |
820 | 820 | ) |
821 | 821 | ); |
822 | - if ( false === $result ) { |
|
822 | + if (false === $result) { |
|
823 | 823 | /* translators: %s: claim ID */ |
824 | - throw new RuntimeException( sprintf( __( 'Unable to unlock claim %s. Database error.', 'action-scheduler' ), $claim->get_id() ) ); |
|
824 | + throw new RuntimeException(sprintf(__('Unable to unlock claim %s. Database error.', 'action-scheduler'), $claim->get_id())); |
|
825 | 825 | } |
826 | 826 | } |
827 | 827 | |
@@ -831,7 +831,7 @@ discard block |
||
831 | 831 | * @param string $action_id Action ID. |
832 | 832 | * @throws RuntimeException When unable to unlock claim on action ID. |
833 | 833 | */ |
834 | - public function unclaim_action( $action_id ) { |
|
834 | + public function unclaim_action($action_id) { |
|
835 | 835 | /** |
836 | 836 | * Global wpdb object. |
837 | 837 | * |
@@ -847,9 +847,9 @@ discard block |
||
847 | 847 | self::POST_TYPE |
848 | 848 | ) |
849 | 849 | ); |
850 | - if ( false === $result ) { |
|
850 | + if (false === $result) { |
|
851 | 851 | /* translators: %s: action ID */ |
852 | - throw new RuntimeException( sprintf( __( 'Unable to unlock claim on action %s. Database error.', 'action-scheduler' ), $action_id ) ); |
|
852 | + throw new RuntimeException(sprintf(__('Unable to unlock claim on action %s. Database error.', 'action-scheduler'), $action_id)); |
|
853 | 853 | } |
854 | 854 | } |
855 | 855 | |
@@ -861,7 +861,7 @@ discard block |
||
861 | 861 | * @return void |
862 | 862 | * @throws RuntimeException When unable to mark failure on action ID. |
863 | 863 | */ |
864 | - public function mark_failure( $action_id ) { |
|
864 | + public function mark_failure($action_id) { |
|
865 | 865 | /** |
866 | 866 | * Global wpdb object. |
867 | 867 | * |
@@ -871,11 +871,11 @@ discard block |
||
871 | 871 | |
872 | 872 | // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching |
873 | 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 ) |
|
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 | 875 | ); |
876 | - if ( false === $result ) { |
|
876 | + if (false === $result) { |
|
877 | 877 | /* translators: %s: action ID */ |
878 | - throw new RuntimeException( sprintf( __( 'Unable to mark failure on action %s. Database error.', 'action-scheduler' ), $action_id ) ); |
|
878 | + throw new RuntimeException(sprintf(__('Unable to mark failure on action %s. Database error.', 'action-scheduler'), $action_id)); |
|
879 | 879 | } |
880 | 880 | } |
881 | 881 | |
@@ -885,8 +885,8 @@ discard block |
||
885 | 885 | * @param int $action_id Action ID. |
886 | 886 | * @return mixed |
887 | 887 | */ |
888 | - public function get_claim_id( $action_id ) { |
|
889 | - return $this->get_post_column( $action_id, 'post_password' ); |
|
888 | + public function get_claim_id($action_id) { |
|
889 | + return $this->get_post_column($action_id, 'post_password'); |
|
890 | 890 | } |
891 | 891 | |
892 | 892 | /** |
@@ -897,14 +897,14 @@ discard block |
||
897 | 897 | * @return mixed |
898 | 898 | * @throws InvalidArgumentException When the action ID is invalid. |
899 | 899 | */ |
900 | - public function get_status( $action_id ) { |
|
901 | - $status = $this->get_post_column( $action_id, 'post_status' ); |
|
900 | + public function get_status($action_id) { |
|
901 | + $status = $this->get_post_column($action_id, 'post_status'); |
|
902 | 902 | |
903 | - if ( null === $status ) { |
|
904 | - throw new InvalidArgumentException( __( 'Invalid action ID. No status found.', 'action-scheduler' ) ); |
|
903 | + if (null === $status) { |
|
904 | + throw new InvalidArgumentException(__('Invalid action ID. No status found.', 'action-scheduler')); |
|
905 | 905 | } |
906 | 906 | |
907 | - return $this->get_action_status_by_post_status( $status ); |
|
907 | + return $this->get_action_status_by_post_status($status); |
|
908 | 908 | } |
909 | 909 | |
910 | 910 | /** |
@@ -915,7 +915,7 @@ discard block |
||
915 | 915 | * |
916 | 916 | * @return string|null |
917 | 917 | */ |
918 | - private function get_post_column( $action_id, $column_name ) { |
|
918 | + private function get_post_column($action_id, $column_name) { |
|
919 | 919 | /** |
920 | 920 | * Global wpdb object. |
921 | 921 | * |
@@ -938,7 +938,7 @@ discard block |
||
938 | 938 | * |
939 | 939 | * @param string $action_id Action ID. |
940 | 940 | */ |
941 | - public function log_execution( $action_id ) { |
|
941 | + public function log_execution($action_id) { |
|
942 | 942 | /** |
943 | 943 | * Global wpdb object. |
944 | 944 | * |
@@ -951,8 +951,8 @@ discard block |
||
951 | 951 | $wpdb->prepare( |
952 | 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 | 953 | self::STATUS_RUNNING, |
954 | - current_time( 'mysql', true ), |
|
955 | - current_time( 'mysql' ), |
|
954 | + current_time('mysql', true), |
|
955 | + current_time('mysql'), |
|
956 | 956 | $action_id, |
957 | 957 | self::POST_TYPE |
958 | 958 | ) |
@@ -967,14 +967,14 @@ discard block |
||
967 | 967 | * @throws InvalidArgumentException When the action ID is invalid. |
968 | 968 | * @throws RuntimeException When there was an error executing the action. |
969 | 969 | */ |
970 | - public function mark_complete( $action_id ) { |
|
971 | - $post = get_post( $action_id ); |
|
972 | - if ( empty( $post ) || ( self::POST_TYPE !== $post->post_type ) ) { |
|
970 | + public function mark_complete($action_id) { |
|
971 | + $post = get_post($action_id); |
|
972 | + if (empty($post) || (self::POST_TYPE !== $post->post_type)) { |
|
973 | 973 | /* translators: %s is the action ID */ |
974 | - throw new InvalidArgumentException( sprintf( __( 'Unidentified action %s', 'action-scheduler' ), $action_id ) ); |
|
974 | + throw new InvalidArgumentException(sprintf(__('Unidentified action %s', 'action-scheduler'), $action_id)); |
|
975 | 975 | } |
976 | - add_filter( 'wp_insert_post_data', array( $this, 'filter_insert_post_data' ), 10, 1 ); |
|
977 | - add_filter( 'pre_wp_unique_post_slug', array( $this, 'set_unique_post_slug' ), 10, 5 ); |
|
976 | + add_filter('wp_insert_post_data', array($this, 'filter_insert_post_data'), 10, 1); |
|
977 | + add_filter('pre_wp_unique_post_slug', array($this, 'set_unique_post_slug'), 10, 5); |
|
978 | 978 | $result = wp_update_post( |
979 | 979 | array( |
980 | 980 | 'ID' => $action_id, |
@@ -982,10 +982,10 @@ discard block |
||
982 | 982 | ), |
983 | 983 | true |
984 | 984 | ); |
985 | - remove_filter( 'wp_insert_post_data', array( $this, 'filter_insert_post_data' ), 10 ); |
|
986 | - remove_filter( 'pre_wp_unique_post_slug', array( $this, 'set_unique_post_slug' ), 10 ); |
|
987 | - if ( is_wp_error( $result ) ) { |
|
988 | - throw new RuntimeException( $result->get_error_message() ); |
|
985 | + remove_filter('wp_insert_post_data', array($this, 'filter_insert_post_data'), 10); |
|
986 | + remove_filter('pre_wp_unique_post_slug', array($this, 'set_unique_post_slug'), 10); |
|
987 | + if (is_wp_error($result)) { |
|
988 | + throw new RuntimeException($result->get_error_message()); |
|
989 | 989 | } |
990 | 990 | |
991 | 991 | /** |
@@ -995,7 +995,7 @@ discard block |
||
995 | 995 | * |
996 | 996 | * @param int $action_id Action ID. |
997 | 997 | */ |
998 | - do_action( 'action_scheduler_completed_action', $action_id ); |
|
998 | + do_action('action_scheduler_completed_action', $action_id); |
|
999 | 999 | } |
1000 | 1000 | |
1001 | 1001 | /** |
@@ -1003,7 +1003,7 @@ discard block |
||
1003 | 1003 | * |
1004 | 1004 | * @param int $action_id Action ID. |
1005 | 1005 | */ |
1006 | - public function mark_migrated( $action_id ) { |
|
1006 | + public function mark_migrated($action_id) { |
|
1007 | 1007 | wp_update_post( |
1008 | 1008 | array( |
1009 | 1009 | 'ID' => $action_id, |
@@ -1018,12 +1018,12 @@ discard block |
||
1018 | 1018 | * @param [type] $setting - Setting value. |
1019 | 1019 | * @return bool |
1020 | 1020 | */ |
1021 | - public function migration_dependencies_met( $setting ) { |
|
1021 | + public function migration_dependencies_met($setting) { |
|
1022 | 1022 | global $wpdb; |
1023 | 1023 | |
1024 | - $dependencies_met = get_transient( self::DEPENDENCIES_MET ); |
|
1025 | - if ( empty( $dependencies_met ) ) { |
|
1026 | - $maximum_args_length = apply_filters( 'action_scheduler_maximum_args_length', 191 ); |
|
1024 | + $dependencies_met = get_transient(self::DEPENDENCIES_MET); |
|
1025 | + if (empty($dependencies_met)) { |
|
1026 | + $maximum_args_length = apply_filters('action_scheduler_maximum_args_length', 191); |
|
1027 | 1027 | $found_action = $wpdb->get_var( // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching |
1028 | 1028 | $wpdb->prepare( |
1029 | 1029 | "SELECT ID FROM {$wpdb->posts} WHERE post_type = %s AND CHAR_LENGTH(post_content) > %d LIMIT 1", |
@@ -1031,8 +1031,8 @@ discard block |
||
1031 | 1031 | self::POST_TYPE |
1032 | 1032 | ) |
1033 | 1033 | ); |
1034 | - $dependencies_met = $found_action ? 'no' : 'yes'; |
|
1035 | - set_transient( self::DEPENDENCIES_MET, $dependencies_met, DAY_IN_SECONDS ); |
|
1034 | + $dependencies_met = $found_action ? 'no' : 'yes'; |
|
1035 | + set_transient(self::DEPENDENCIES_MET, $dependencies_met, DAY_IN_SECONDS); |
|
1036 | 1036 | } |
1037 | 1037 | |
1038 | 1038 | return 'yes' === $dependencies_met ? $setting : false; |
@@ -1047,13 +1047,13 @@ discard block |
||
1047 | 1047 | * |
1048 | 1048 | * @param ActionScheduler_Action $action Action object. |
1049 | 1049 | */ |
1050 | - protected function validate_action( ActionScheduler_Action $action ) { |
|
1050 | + protected function validate_action(ActionScheduler_Action $action) { |
|
1051 | 1051 | try { |
1052 | - parent::validate_action( $action ); |
|
1053 | - } catch ( Exception $e ) { |
|
1052 | + parent::validate_action($action); |
|
1053 | + } catch (Exception $e) { |
|
1054 | 1054 | /* translators: %s is the error message */ |
1055 | - $message = sprintf( __( '%s Support for strings longer than this will be removed in a future version.', 'action-scheduler' ), $e->getMessage() ); |
|
1056 | - _doing_it_wrong( 'ActionScheduler_Action::$args', esc_html( $message ), '2.1.0' ); |
|
1055 | + $message = sprintf(__('%s Support for strings longer than this will be removed in a future version.', 'action-scheduler'), $e->getMessage()); |
|
1056 | + _doing_it_wrong('ActionScheduler_Action::$args', esc_html($message), '2.1.0'); |
|
1057 | 1057 | } |
1058 | 1058 | } |
1059 | 1059 | |
@@ -1061,7 +1061,7 @@ discard block |
||
1061 | 1061 | * (@codeCoverageIgnore) |
1062 | 1062 | */ |
1063 | 1063 | public function init() { |
1064 | - add_filter( 'action_scheduler_migration_dependencies_met', array( $this, 'migration_dependencies_met' ) ); |
|
1064 | + add_filter('action_scheduler_migration_dependencies_met', array($this, 'migration_dependencies_met')); |
|
1065 | 1065 | |
1066 | 1066 | $post_type_registrar = new ActionScheduler_wpPostStore_PostTypeRegistrar(); |
1067 | 1067 | $post_type_registrar->register(); |
@@ -13,415 +13,415 @@ |
||
13 | 13 | * @since 3.0.0 |
14 | 14 | */ |
15 | 15 | class ActionScheduler_HybridStore extends Store { |
16 | - const DEMARKATION_OPTION = 'action_scheduler_hybrid_store_demarkation'; |
|
17 | - |
|
18 | - private $primary_store; |
|
19 | - private $secondary_store; |
|
20 | - private $migration_runner; |
|
21 | - |
|
22 | - /** |
|
23 | - * @var int The dividing line between IDs of actions created |
|
24 | - * by the primary and secondary stores. |
|
25 | - * |
|
26 | - * Methods that accept an action ID will compare the ID against |
|
27 | - * this to determine which store will contain that ID. In almost |
|
28 | - * all cases, the ID should come from the primary store, but if |
|
29 | - * client code is bypassing the API functions and fetching IDs |
|
30 | - * from elsewhere, then there is a chance that an unmigrated ID |
|
31 | - * might be requested. |
|
32 | - */ |
|
33 | - private $demarkation_id = 0; |
|
34 | - |
|
35 | - /** |
|
36 | - * ActionScheduler_HybridStore constructor. |
|
37 | - * |
|
38 | - * @param Config $config Migration config object. |
|
39 | - */ |
|
40 | - public function __construct( Config $config = null ) { |
|
41 | - $this->demarkation_id = (int) get_option( self::DEMARKATION_OPTION, 0 ); |
|
42 | - if ( empty( $config ) ) { |
|
43 | - $config = Controller::instance()->get_migration_config_object(); |
|
44 | - } |
|
45 | - $this->primary_store = $config->get_destination_store(); |
|
46 | - $this->secondary_store = $config->get_source_store(); |
|
47 | - $this->migration_runner = new Runner( $config ); |
|
48 | - } |
|
49 | - |
|
50 | - /** |
|
51 | - * Initialize the table data store tables. |
|
52 | - * |
|
53 | - * @codeCoverageIgnore |
|
54 | - */ |
|
55 | - public function init() { |
|
56 | - add_action( 'action_scheduler/created_table', array( $this, 'set_autoincrement' ), 10, 2 ); |
|
57 | - $this->primary_store->init(); |
|
58 | - $this->secondary_store->init(); |
|
59 | - remove_action( 'action_scheduler/created_table', array( $this, 'set_autoincrement' ), 10 ); |
|
60 | - } |
|
61 | - |
|
62 | - /** |
|
63 | - * When the actions table is created, set its autoincrement |
|
64 | - * value to be one higher than the posts table to ensure that |
|
65 | - * there are no ID collisions. |
|
66 | - * |
|
67 | - * @param string $table_name |
|
68 | - * @param string $table_suffix |
|
69 | - * |
|
70 | - * @return void |
|
71 | - * @codeCoverageIgnore |
|
72 | - */ |
|
73 | - public function set_autoincrement( $table_name, $table_suffix ) { |
|
74 | - if ( ActionScheduler_StoreSchema::ACTIONS_TABLE === $table_suffix ) { |
|
75 | - if ( empty( $this->demarkation_id ) ) { |
|
76 | - $this->demarkation_id = $this->set_demarkation_id(); |
|
77 | - } |
|
78 | - /** @var \wpdb $wpdb */ |
|
79 | - global $wpdb; |
|
80 | - /** |
|
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' ); |
|
85 | - $null_action = new ActionScheduler_NullAction(); |
|
86 | - $date_gmt = $this->get_scheduled_date_string( $null_action, $default_date ); |
|
87 | - $date_local = $this->get_scheduled_date_string_local( $null_action, $default_date ); |
|
88 | - |
|
89 | - $row_count = $wpdb->insert( |
|
90 | - $wpdb->{ActionScheduler_StoreSchema::ACTIONS_TABLE}, |
|
91 | - array( |
|
92 | - 'action_id' => $this->demarkation_id, |
|
93 | - 'hook' => '', |
|
94 | - 'status' => '', |
|
95 | - 'scheduled_date_gmt' => $date_gmt, |
|
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 | - array( 'action_id' => $this->demarkation_id ) |
|
105 | - ); |
|
106 | - } |
|
107 | - } |
|
108 | - } |
|
109 | - |
|
110 | - /** |
|
111 | - * Store the demarkation id in WP options. |
|
112 | - * |
|
113 | - * @param int $id The ID to set as the demarkation point between the two stores |
|
114 | - * Leave null to use the next ID from the WP posts table. |
|
115 | - * |
|
116 | - * @return int The new ID. |
|
117 | - * |
|
118 | - * @codeCoverageIgnore |
|
119 | - */ |
|
120 | - private function set_demarkation_id( $id = null ) { |
|
121 | - if ( empty( $id ) ) { |
|
122 | - /** @var \wpdb $wpdb */ |
|
123 | - global $wpdb; |
|
124 | - $id = (int) $wpdb->get_var( "SELECT MAX(ID) FROM $wpdb->posts" ); |
|
125 | - $id ++; |
|
126 | - } |
|
127 | - update_option( self::DEMARKATION_OPTION, $id ); |
|
128 | - |
|
129 | - return $id; |
|
130 | - } |
|
131 | - |
|
132 | - /** |
|
133 | - * Find the first matching action from the secondary store. |
|
134 | - * If it exists, migrate it to the primary store immediately. |
|
135 | - * After it migrates, the secondary store will logically contain |
|
136 | - * the next matching action, so return the result thence. |
|
137 | - * |
|
138 | - * @param string $hook |
|
139 | - * @param array $params |
|
140 | - * |
|
141 | - * @return string |
|
142 | - */ |
|
143 | - public function find_action( $hook, $params = array() ) { |
|
144 | - $found_unmigrated_action = $this->secondary_store->find_action( $hook, $params ); |
|
145 | - if ( ! empty( $found_unmigrated_action ) ) { |
|
146 | - $this->migrate( array( $found_unmigrated_action ) ); |
|
147 | - } |
|
148 | - |
|
149 | - return $this->primary_store->find_action( $hook, $params ); |
|
150 | - } |
|
151 | - |
|
152 | - /** |
|
153 | - * Find actions matching the query in the secondary source first. |
|
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 = array(), $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 ); |
|
166 | - } |
|
167 | - |
|
168 | - return $this->primary_store->query_actions( $query, $query_type ); |
|
169 | - } |
|
170 | - |
|
171 | - /** |
|
172 | - * Get a count of all actions in the store, grouped by status |
|
173 | - * |
|
174 | - * @return array Set of 'status' => int $count pairs for statuses with 1 or more actions of that status. |
|
175 | - */ |
|
176 | - public function action_counts() { |
|
177 | - $unmigrated_actions_count = $this->secondary_store->action_counts(); |
|
178 | - $migrated_actions_count = $this->primary_store->action_counts(); |
|
179 | - $actions_count_by_status = array(); |
|
180 | - |
|
181 | - foreach ( $this->get_status_labels() as $status_key => $status_label ) { |
|
182 | - |
|
183 | - $count = 0; |
|
184 | - |
|
185 | - if ( isset( $unmigrated_actions_count[ $status_key ] ) ) { |
|
186 | - $count += $unmigrated_actions_count[ $status_key ]; |
|
187 | - } |
|
188 | - |
|
189 | - if ( isset( $migrated_actions_count[ $status_key ] ) ) { |
|
190 | - $count += $migrated_actions_count[ $status_key ]; |
|
191 | - } |
|
192 | - |
|
193 | - $actions_count_by_status[ $status_key ] = $count; |
|
194 | - } |
|
195 | - |
|
196 | - $actions_count_by_status = array_filter( $actions_count_by_status ); |
|
197 | - |
|
198 | - return $actions_count_by_status; |
|
199 | - } |
|
200 | - |
|
201 | - /** |
|
202 | - * If any actions would have been claimed by the secondary store, |
|
203 | - * migrate them immediately, then ask the primary store for the |
|
204 | - * canonical claim. |
|
205 | - * |
|
206 | - * @param int $max_actions |
|
207 | - * @param DateTime|null $before_date |
|
208 | - * |
|
209 | - * @return ActionScheduler_ActionClaim |
|
210 | - */ |
|
211 | - public function stake_claim( $max_actions = 10, DateTime $before_date = null, $hooks = array(), $group = '' ) { |
|
212 | - $claim = $this->secondary_store->stake_claim( $max_actions, $before_date, $hooks, $group ); |
|
213 | - |
|
214 | - $claimed_actions = $claim->get_actions(); |
|
215 | - if ( ! empty( $claimed_actions ) ) { |
|
216 | - $this->migrate( $claimed_actions ); |
|
217 | - } |
|
218 | - |
|
219 | - $this->secondary_store->release_claim( $claim ); |
|
220 | - |
|
221 | - return $this->primary_store->stake_claim( $max_actions, $before_date, $hooks, $group ); |
|
222 | - } |
|
223 | - |
|
224 | - /** |
|
225 | - * Migrate a list of actions to the table data store. |
|
226 | - * |
|
227 | - * @param array $action_ids List of action IDs. |
|
228 | - */ |
|
229 | - private function migrate( $action_ids ) { |
|
230 | - $this->migration_runner->migrate_actions( $action_ids ); |
|
231 | - } |
|
232 | - |
|
233 | - /** |
|
234 | - * Save an action to the primary store. |
|
235 | - * |
|
236 | - * @param ActionScheduler_Action $action Action object to be saved. |
|
237 | - * @param DateTime $date Optional. Schedule date. Default null. |
|
238 | - * |
|
239 | - * @return int The action ID |
|
240 | - */ |
|
241 | - public function save_action( ActionScheduler_Action $action, DateTime $date = null ) { |
|
242 | - return $this->primary_store->save_action( $action, $date ); |
|
243 | - } |
|
244 | - |
|
245 | - /** |
|
246 | - * Retrieve an existing action whether migrated or not. |
|
247 | - * |
|
248 | - * @param int $action_id Action ID. |
|
249 | - */ |
|
250 | - public function fetch_action( $action_id ) { |
|
251 | - $store = $this->get_store_from_action_id( $action_id, true ); |
|
252 | - if ( $store ) { |
|
253 | - return $store->fetch_action( $action_id ); |
|
254 | - } else { |
|
255 | - return new ActionScheduler_NullAction(); |
|
256 | - } |
|
257 | - } |
|
258 | - |
|
259 | - /** |
|
260 | - * Cancel an existing action whether migrated or not. |
|
261 | - * |
|
262 | - * @param int $action_id Action ID. |
|
263 | - */ |
|
264 | - public function cancel_action( $action_id ) { |
|
265 | - $store = $this->get_store_from_action_id( $action_id ); |
|
266 | - if ( $store ) { |
|
267 | - $store->cancel_action( $action_id ); |
|
268 | - } |
|
269 | - } |
|
270 | - |
|
271 | - /** |
|
272 | - * Delete an existing action whether migrated or not. |
|
273 | - * |
|
274 | - * @param int $action_id Action ID. |
|
275 | - */ |
|
276 | - public function delete_action( $action_id ) { |
|
277 | - $store = $this->get_store_from_action_id( $action_id ); |
|
278 | - if ( $store ) { |
|
279 | - $store->delete_action( $action_id ); |
|
280 | - } |
|
281 | - } |
|
282 | - |
|
283 | - /** |
|
284 | - * Get the schedule date an existing action whether migrated or not. |
|
285 | - * |
|
286 | - * @param int $action_id Action ID. |
|
287 | - */ |
|
288 | - public function get_date( $action_id ) { |
|
289 | - $store = $this->get_store_from_action_id( $action_id ); |
|
290 | - if ( $store ) { |
|
291 | - return $store->get_date( $action_id ); |
|
292 | - } else { |
|
293 | - return null; |
|
294 | - } |
|
295 | - } |
|
296 | - |
|
297 | - /** |
|
298 | - * Mark an existing action as failed whether migrated or not. |
|
299 | - * |
|
300 | - * @param int $action_id Action ID. |
|
301 | - */ |
|
302 | - public function mark_failure( $action_id ) { |
|
303 | - $store = $this->get_store_from_action_id( $action_id ); |
|
304 | - if ( $store ) { |
|
305 | - $store->mark_failure( $action_id ); |
|
306 | - } |
|
307 | - } |
|
308 | - |
|
309 | - /** |
|
310 | - * Log the execution of an existing action whether migrated or not. |
|
311 | - * |
|
312 | - * @param int $action_id Action ID. |
|
313 | - */ |
|
314 | - public function log_execution( $action_id ) { |
|
315 | - $store = $this->get_store_from_action_id( $action_id ); |
|
316 | - if ( $store ) { |
|
317 | - $store->log_execution( $action_id ); |
|
318 | - } |
|
319 | - } |
|
320 | - |
|
321 | - /** |
|
322 | - * Mark an existing action complete whether migrated or not. |
|
323 | - * |
|
324 | - * @param int $action_id Action ID. |
|
325 | - */ |
|
326 | - public function mark_complete( $action_id ) { |
|
327 | - $store = $this->get_store_from_action_id( $action_id ); |
|
328 | - if ( $store ) { |
|
329 | - $store->mark_complete( $action_id ); |
|
330 | - } |
|
331 | - } |
|
332 | - |
|
333 | - /** |
|
334 | - * Get an existing action status whether migrated or not. |
|
335 | - * |
|
336 | - * @param int $action_id Action ID. |
|
337 | - */ |
|
338 | - public function get_status( $action_id ) { |
|
339 | - $store = $this->get_store_from_action_id( $action_id ); |
|
340 | - if ( $store ) { |
|
341 | - return $store->get_status( $action_id ); |
|
342 | - } |
|
343 | - return null; |
|
344 | - } |
|
345 | - |
|
346 | - /** |
|
347 | - * Return which store an action is stored in. |
|
348 | - * |
|
349 | - * @param int $action_id ID of the action. |
|
350 | - * @param bool $primary_first Optional flag indicating search the primary store first. |
|
351 | - * @return ActionScheduler_Store |
|
352 | - */ |
|
353 | - protected function get_store_from_action_id( $action_id, $primary_first = false ) { |
|
354 | - if ( $primary_first ) { |
|
355 | - $stores = array( |
|
356 | - $this->primary_store, |
|
357 | - $this->secondary_store, |
|
358 | - ); |
|
359 | - } elseif ( $action_id < $this->demarkation_id ) { |
|
360 | - $stores = array( |
|
361 | - $this->secondary_store, |
|
362 | - $this->primary_store, |
|
363 | - ); |
|
364 | - } else { |
|
365 | - $stores = array( |
|
366 | - $this->primary_store, |
|
367 | - ); |
|
368 | - } |
|
369 | - |
|
370 | - foreach ( $stores as $store ) { |
|
371 | - $action = $store->fetch_action( $action_id ); |
|
372 | - if ( ! is_a( $action, 'ActionScheduler_NullAction' ) ) { |
|
373 | - return $store; |
|
374 | - } |
|
375 | - } |
|
376 | - return null; |
|
377 | - } |
|
378 | - |
|
379 | - /* |
|
16 | + const DEMARKATION_OPTION = 'action_scheduler_hybrid_store_demarkation'; |
|
17 | + |
|
18 | + private $primary_store; |
|
19 | + private $secondary_store; |
|
20 | + private $migration_runner; |
|
21 | + |
|
22 | + /** |
|
23 | + * @var int The dividing line between IDs of actions created |
|
24 | + * by the primary and secondary stores. |
|
25 | + * |
|
26 | + * Methods that accept an action ID will compare the ID against |
|
27 | + * this to determine which store will contain that ID. In almost |
|
28 | + * all cases, the ID should come from the primary store, but if |
|
29 | + * client code is bypassing the API functions and fetching IDs |
|
30 | + * from elsewhere, then there is a chance that an unmigrated ID |
|
31 | + * might be requested. |
|
32 | + */ |
|
33 | + private $demarkation_id = 0; |
|
34 | + |
|
35 | + /** |
|
36 | + * ActionScheduler_HybridStore constructor. |
|
37 | + * |
|
38 | + * @param Config $config Migration config object. |
|
39 | + */ |
|
40 | + public function __construct( Config $config = null ) { |
|
41 | + $this->demarkation_id = (int) get_option( self::DEMARKATION_OPTION, 0 ); |
|
42 | + if ( empty( $config ) ) { |
|
43 | + $config = Controller::instance()->get_migration_config_object(); |
|
44 | + } |
|
45 | + $this->primary_store = $config->get_destination_store(); |
|
46 | + $this->secondary_store = $config->get_source_store(); |
|
47 | + $this->migration_runner = new Runner( $config ); |
|
48 | + } |
|
49 | + |
|
50 | + /** |
|
51 | + * Initialize the table data store tables. |
|
52 | + * |
|
53 | + * @codeCoverageIgnore |
|
54 | + */ |
|
55 | + public function init() { |
|
56 | + add_action( 'action_scheduler/created_table', array( $this, 'set_autoincrement' ), 10, 2 ); |
|
57 | + $this->primary_store->init(); |
|
58 | + $this->secondary_store->init(); |
|
59 | + remove_action( 'action_scheduler/created_table', array( $this, 'set_autoincrement' ), 10 ); |
|
60 | + } |
|
61 | + |
|
62 | + /** |
|
63 | + * When the actions table is created, set its autoincrement |
|
64 | + * value to be one higher than the posts table to ensure that |
|
65 | + * there are no ID collisions. |
|
66 | + * |
|
67 | + * @param string $table_name |
|
68 | + * @param string $table_suffix |
|
69 | + * |
|
70 | + * @return void |
|
71 | + * @codeCoverageIgnore |
|
72 | + */ |
|
73 | + public function set_autoincrement( $table_name, $table_suffix ) { |
|
74 | + if ( ActionScheduler_StoreSchema::ACTIONS_TABLE === $table_suffix ) { |
|
75 | + if ( empty( $this->demarkation_id ) ) { |
|
76 | + $this->demarkation_id = $this->set_demarkation_id(); |
|
77 | + } |
|
78 | + /** @var \wpdb $wpdb */ |
|
79 | + global $wpdb; |
|
80 | + /** |
|
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' ); |
|
85 | + $null_action = new ActionScheduler_NullAction(); |
|
86 | + $date_gmt = $this->get_scheduled_date_string( $null_action, $default_date ); |
|
87 | + $date_local = $this->get_scheduled_date_string_local( $null_action, $default_date ); |
|
88 | + |
|
89 | + $row_count = $wpdb->insert( |
|
90 | + $wpdb->{ActionScheduler_StoreSchema::ACTIONS_TABLE}, |
|
91 | + array( |
|
92 | + 'action_id' => $this->demarkation_id, |
|
93 | + 'hook' => '', |
|
94 | + 'status' => '', |
|
95 | + 'scheduled_date_gmt' => $date_gmt, |
|
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 | + array( 'action_id' => $this->demarkation_id ) |
|
105 | + ); |
|
106 | + } |
|
107 | + } |
|
108 | + } |
|
109 | + |
|
110 | + /** |
|
111 | + * Store the demarkation id in WP options. |
|
112 | + * |
|
113 | + * @param int $id The ID to set as the demarkation point between the two stores |
|
114 | + * Leave null to use the next ID from the WP posts table. |
|
115 | + * |
|
116 | + * @return int The new ID. |
|
117 | + * |
|
118 | + * @codeCoverageIgnore |
|
119 | + */ |
|
120 | + private function set_demarkation_id( $id = null ) { |
|
121 | + if ( empty( $id ) ) { |
|
122 | + /** @var \wpdb $wpdb */ |
|
123 | + global $wpdb; |
|
124 | + $id = (int) $wpdb->get_var( "SELECT MAX(ID) FROM $wpdb->posts" ); |
|
125 | + $id ++; |
|
126 | + } |
|
127 | + update_option( self::DEMARKATION_OPTION, $id ); |
|
128 | + |
|
129 | + return $id; |
|
130 | + } |
|
131 | + |
|
132 | + /** |
|
133 | + * Find the first matching action from the secondary store. |
|
134 | + * If it exists, migrate it to the primary store immediately. |
|
135 | + * After it migrates, the secondary store will logically contain |
|
136 | + * the next matching action, so return the result thence. |
|
137 | + * |
|
138 | + * @param string $hook |
|
139 | + * @param array $params |
|
140 | + * |
|
141 | + * @return string |
|
142 | + */ |
|
143 | + public function find_action( $hook, $params = array() ) { |
|
144 | + $found_unmigrated_action = $this->secondary_store->find_action( $hook, $params ); |
|
145 | + if ( ! empty( $found_unmigrated_action ) ) { |
|
146 | + $this->migrate( array( $found_unmigrated_action ) ); |
|
147 | + } |
|
148 | + |
|
149 | + return $this->primary_store->find_action( $hook, $params ); |
|
150 | + } |
|
151 | + |
|
152 | + /** |
|
153 | + * Find actions matching the query in the secondary source first. |
|
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 = array(), $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 ); |
|
166 | + } |
|
167 | + |
|
168 | + return $this->primary_store->query_actions( $query, $query_type ); |
|
169 | + } |
|
170 | + |
|
171 | + /** |
|
172 | + * Get a count of all actions in the store, grouped by status |
|
173 | + * |
|
174 | + * @return array Set of 'status' => int $count pairs for statuses with 1 or more actions of that status. |
|
175 | + */ |
|
176 | + public function action_counts() { |
|
177 | + $unmigrated_actions_count = $this->secondary_store->action_counts(); |
|
178 | + $migrated_actions_count = $this->primary_store->action_counts(); |
|
179 | + $actions_count_by_status = array(); |
|
180 | + |
|
181 | + foreach ( $this->get_status_labels() as $status_key => $status_label ) { |
|
182 | + |
|
183 | + $count = 0; |
|
184 | + |
|
185 | + if ( isset( $unmigrated_actions_count[ $status_key ] ) ) { |
|
186 | + $count += $unmigrated_actions_count[ $status_key ]; |
|
187 | + } |
|
188 | + |
|
189 | + if ( isset( $migrated_actions_count[ $status_key ] ) ) { |
|
190 | + $count += $migrated_actions_count[ $status_key ]; |
|
191 | + } |
|
192 | + |
|
193 | + $actions_count_by_status[ $status_key ] = $count; |
|
194 | + } |
|
195 | + |
|
196 | + $actions_count_by_status = array_filter( $actions_count_by_status ); |
|
197 | + |
|
198 | + return $actions_count_by_status; |
|
199 | + } |
|
200 | + |
|
201 | + /** |
|
202 | + * If any actions would have been claimed by the secondary store, |
|
203 | + * migrate them immediately, then ask the primary store for the |
|
204 | + * canonical claim. |
|
205 | + * |
|
206 | + * @param int $max_actions |
|
207 | + * @param DateTime|null $before_date |
|
208 | + * |
|
209 | + * @return ActionScheduler_ActionClaim |
|
210 | + */ |
|
211 | + public function stake_claim( $max_actions = 10, DateTime $before_date = null, $hooks = array(), $group = '' ) { |
|
212 | + $claim = $this->secondary_store->stake_claim( $max_actions, $before_date, $hooks, $group ); |
|
213 | + |
|
214 | + $claimed_actions = $claim->get_actions(); |
|
215 | + if ( ! empty( $claimed_actions ) ) { |
|
216 | + $this->migrate( $claimed_actions ); |
|
217 | + } |
|
218 | + |
|
219 | + $this->secondary_store->release_claim( $claim ); |
|
220 | + |
|
221 | + return $this->primary_store->stake_claim( $max_actions, $before_date, $hooks, $group ); |
|
222 | + } |
|
223 | + |
|
224 | + /** |
|
225 | + * Migrate a list of actions to the table data store. |
|
226 | + * |
|
227 | + * @param array $action_ids List of action IDs. |
|
228 | + */ |
|
229 | + private function migrate( $action_ids ) { |
|
230 | + $this->migration_runner->migrate_actions( $action_ids ); |
|
231 | + } |
|
232 | + |
|
233 | + /** |
|
234 | + * Save an action to the primary store. |
|
235 | + * |
|
236 | + * @param ActionScheduler_Action $action Action object to be saved. |
|
237 | + * @param DateTime $date Optional. Schedule date. Default null. |
|
238 | + * |
|
239 | + * @return int The action ID |
|
240 | + */ |
|
241 | + public function save_action( ActionScheduler_Action $action, DateTime $date = null ) { |
|
242 | + return $this->primary_store->save_action( $action, $date ); |
|
243 | + } |
|
244 | + |
|
245 | + /** |
|
246 | + * Retrieve an existing action whether migrated or not. |
|
247 | + * |
|
248 | + * @param int $action_id Action ID. |
|
249 | + */ |
|
250 | + public function fetch_action( $action_id ) { |
|
251 | + $store = $this->get_store_from_action_id( $action_id, true ); |
|
252 | + if ( $store ) { |
|
253 | + return $store->fetch_action( $action_id ); |
|
254 | + } else { |
|
255 | + return new ActionScheduler_NullAction(); |
|
256 | + } |
|
257 | + } |
|
258 | + |
|
259 | + /** |
|
260 | + * Cancel an existing action whether migrated or not. |
|
261 | + * |
|
262 | + * @param int $action_id Action ID. |
|
263 | + */ |
|
264 | + public function cancel_action( $action_id ) { |
|
265 | + $store = $this->get_store_from_action_id( $action_id ); |
|
266 | + if ( $store ) { |
|
267 | + $store->cancel_action( $action_id ); |
|
268 | + } |
|
269 | + } |
|
270 | + |
|
271 | + /** |
|
272 | + * Delete an existing action whether migrated or not. |
|
273 | + * |
|
274 | + * @param int $action_id Action ID. |
|
275 | + */ |
|
276 | + public function delete_action( $action_id ) { |
|
277 | + $store = $this->get_store_from_action_id( $action_id ); |
|
278 | + if ( $store ) { |
|
279 | + $store->delete_action( $action_id ); |
|
280 | + } |
|
281 | + } |
|
282 | + |
|
283 | + /** |
|
284 | + * Get the schedule date an existing action whether migrated or not. |
|
285 | + * |
|
286 | + * @param int $action_id Action ID. |
|
287 | + */ |
|
288 | + public function get_date( $action_id ) { |
|
289 | + $store = $this->get_store_from_action_id( $action_id ); |
|
290 | + if ( $store ) { |
|
291 | + return $store->get_date( $action_id ); |
|
292 | + } else { |
|
293 | + return null; |
|
294 | + } |
|
295 | + } |
|
296 | + |
|
297 | + /** |
|
298 | + * Mark an existing action as failed whether migrated or not. |
|
299 | + * |
|
300 | + * @param int $action_id Action ID. |
|
301 | + */ |
|
302 | + public function mark_failure( $action_id ) { |
|
303 | + $store = $this->get_store_from_action_id( $action_id ); |
|
304 | + if ( $store ) { |
|
305 | + $store->mark_failure( $action_id ); |
|
306 | + } |
|
307 | + } |
|
308 | + |
|
309 | + /** |
|
310 | + * Log the execution of an existing action whether migrated or not. |
|
311 | + * |
|
312 | + * @param int $action_id Action ID. |
|
313 | + */ |
|
314 | + public function log_execution( $action_id ) { |
|
315 | + $store = $this->get_store_from_action_id( $action_id ); |
|
316 | + if ( $store ) { |
|
317 | + $store->log_execution( $action_id ); |
|
318 | + } |
|
319 | + } |
|
320 | + |
|
321 | + /** |
|
322 | + * Mark an existing action complete whether migrated or not. |
|
323 | + * |
|
324 | + * @param int $action_id Action ID. |
|
325 | + */ |
|
326 | + public function mark_complete( $action_id ) { |
|
327 | + $store = $this->get_store_from_action_id( $action_id ); |
|
328 | + if ( $store ) { |
|
329 | + $store->mark_complete( $action_id ); |
|
330 | + } |
|
331 | + } |
|
332 | + |
|
333 | + /** |
|
334 | + * Get an existing action status whether migrated or not. |
|
335 | + * |
|
336 | + * @param int $action_id Action ID. |
|
337 | + */ |
|
338 | + public function get_status( $action_id ) { |
|
339 | + $store = $this->get_store_from_action_id( $action_id ); |
|
340 | + if ( $store ) { |
|
341 | + return $store->get_status( $action_id ); |
|
342 | + } |
|
343 | + return null; |
|
344 | + } |
|
345 | + |
|
346 | + /** |
|
347 | + * Return which store an action is stored in. |
|
348 | + * |
|
349 | + * @param int $action_id ID of the action. |
|
350 | + * @param bool $primary_first Optional flag indicating search the primary store first. |
|
351 | + * @return ActionScheduler_Store |
|
352 | + */ |
|
353 | + protected function get_store_from_action_id( $action_id, $primary_first = false ) { |
|
354 | + if ( $primary_first ) { |
|
355 | + $stores = array( |
|
356 | + $this->primary_store, |
|
357 | + $this->secondary_store, |
|
358 | + ); |
|
359 | + } elseif ( $action_id < $this->demarkation_id ) { |
|
360 | + $stores = array( |
|
361 | + $this->secondary_store, |
|
362 | + $this->primary_store, |
|
363 | + ); |
|
364 | + } else { |
|
365 | + $stores = array( |
|
366 | + $this->primary_store, |
|
367 | + ); |
|
368 | + } |
|
369 | + |
|
370 | + foreach ( $stores as $store ) { |
|
371 | + $action = $store->fetch_action( $action_id ); |
|
372 | + if ( ! is_a( $action, 'ActionScheduler_NullAction' ) ) { |
|
373 | + return $store; |
|
374 | + } |
|
375 | + } |
|
376 | + return null; |
|
377 | + } |
|
378 | + |
|
379 | + /* |
|
380 | 380 | * * * * * * * * * * * * * * * * * * * * * * * * * * |
381 | 381 | * All claim-related functions should operate solely |
382 | 382 | * on the primary store. |
383 | 383 | * * * * * * * * * * * * * * * * * * * * * * * * * * */ |
384 | 384 | |
385 | - /** |
|
386 | - * Get the claim count from the table data store. |
|
387 | - */ |
|
388 | - public function get_claim_count() { |
|
389 | - return $this->primary_store->get_claim_count(); |
|
390 | - } |
|
391 | - |
|
392 | - /** |
|
393 | - * Retrieve the claim ID for an action from the table data store. |
|
394 | - * |
|
395 | - * @param int $action_id Action ID. |
|
396 | - */ |
|
397 | - public function get_claim_id( $action_id ) { |
|
398 | - return $this->primary_store->get_claim_id( $action_id ); |
|
399 | - } |
|
400 | - |
|
401 | - /** |
|
402 | - * Release a claim in the table data store. |
|
403 | - * |
|
404 | - * @param ActionScheduler_ActionClaim $claim Claim object. |
|
405 | - */ |
|
406 | - public function release_claim( ActionScheduler_ActionClaim $claim ) { |
|
407 | - $this->primary_store->release_claim( $claim ); |
|
408 | - } |
|
409 | - |
|
410 | - /** |
|
411 | - * Release claims on an action in the table data store. |
|
412 | - * |
|
413 | - * @param int $action_id Action ID. |
|
414 | - */ |
|
415 | - public function unclaim_action( $action_id ) { |
|
416 | - $this->primary_store->unclaim_action( $action_id ); |
|
417 | - } |
|
418 | - |
|
419 | - /** |
|
420 | - * Retrieve a list of action IDs by claim. |
|
421 | - * |
|
422 | - * @param int $claim_id Claim ID. |
|
423 | - */ |
|
424 | - public function find_actions_by_claim_id( $claim_id ) { |
|
425 | - return $this->primary_store->find_actions_by_claim_id( $claim_id ); |
|
426 | - } |
|
385 | + /** |
|
386 | + * Get the claim count from the table data store. |
|
387 | + */ |
|
388 | + public function get_claim_count() { |
|
389 | + return $this->primary_store->get_claim_count(); |
|
390 | + } |
|
391 | + |
|
392 | + /** |
|
393 | + * Retrieve the claim ID for an action from the table data store. |
|
394 | + * |
|
395 | + * @param int $action_id Action ID. |
|
396 | + */ |
|
397 | + public function get_claim_id( $action_id ) { |
|
398 | + return $this->primary_store->get_claim_id( $action_id ); |
|
399 | + } |
|
400 | + |
|
401 | + /** |
|
402 | + * Release a claim in the table data store. |
|
403 | + * |
|
404 | + * @param ActionScheduler_ActionClaim $claim Claim object. |
|
405 | + */ |
|
406 | + public function release_claim( ActionScheduler_ActionClaim $claim ) { |
|
407 | + $this->primary_store->release_claim( $claim ); |
|
408 | + } |
|
409 | + |
|
410 | + /** |
|
411 | + * Release claims on an action in the table data store. |
|
412 | + * |
|
413 | + * @param int $action_id Action ID. |
|
414 | + */ |
|
415 | + public function unclaim_action( $action_id ) { |
|
416 | + $this->primary_store->unclaim_action( $action_id ); |
|
417 | + } |
|
418 | + |
|
419 | + /** |
|
420 | + * Retrieve a list of action IDs by claim. |
|
421 | + * |
|
422 | + * @param int $claim_id Claim ID. |
|
423 | + */ |
|
424 | + public function find_actions_by_claim_id( $claim_id ) { |
|
425 | + return $this->primary_store->find_actions_by_claim_id( $claim_id ); |
|
426 | + } |
|
427 | 427 | } |
@@ -37,14 +37,14 @@ discard block |
||
37 | 37 | * |
38 | 38 | * @param Config $config Migration config object. |
39 | 39 | */ |
40 | - public function __construct( Config $config = null ) { |
|
41 | - $this->demarkation_id = (int) get_option( self::DEMARKATION_OPTION, 0 ); |
|
42 | - if ( empty( $config ) ) { |
|
40 | + public function __construct(Config $config = null) { |
|
41 | + $this->demarkation_id = (int) get_option(self::DEMARKATION_OPTION, 0); |
|
42 | + if (empty($config)) { |
|
43 | 43 | $config = Controller::instance()->get_migration_config_object(); |
44 | 44 | } |
45 | 45 | $this->primary_store = $config->get_destination_store(); |
46 | 46 | $this->secondary_store = $config->get_source_store(); |
47 | - $this->migration_runner = new Runner( $config ); |
|
47 | + $this->migration_runner = new Runner($config); |
|
48 | 48 | } |
49 | 49 | |
50 | 50 | /** |
@@ -53,10 +53,10 @@ discard block |
||
53 | 53 | * @codeCoverageIgnore |
54 | 54 | */ |
55 | 55 | public function init() { |
56 | - add_action( 'action_scheduler/created_table', array( $this, 'set_autoincrement' ), 10, 2 ); |
|
56 | + add_action('action_scheduler/created_table', array($this, 'set_autoincrement'), 10, 2); |
|
57 | 57 | $this->primary_store->init(); |
58 | 58 | $this->secondary_store->init(); |
59 | - remove_action( 'action_scheduler/created_table', array( $this, 'set_autoincrement' ), 10 ); |
|
59 | + remove_action('action_scheduler/created_table', array($this, 'set_autoincrement'), 10); |
|
60 | 60 | } |
61 | 61 | |
62 | 62 | /** |
@@ -70,9 +70,9 @@ discard block |
||
70 | 70 | * @return void |
71 | 71 | * @codeCoverageIgnore |
72 | 72 | */ |
73 | - public function set_autoincrement( $table_name, $table_suffix ) { |
|
74 | - if ( ActionScheduler_StoreSchema::ACTIONS_TABLE === $table_suffix ) { |
|
75 | - if ( empty( $this->demarkation_id ) ) { |
|
73 | + public function set_autoincrement($table_name, $table_suffix) { |
|
74 | + if (ActionScheduler_StoreSchema::ACTIONS_TABLE === $table_suffix) { |
|
75 | + if (empty($this->demarkation_id)) { |
|
76 | 76 | $this->demarkation_id = $this->set_demarkation_id(); |
77 | 77 | } |
78 | 78 | /** @var \wpdb $wpdb */ |
@@ -81,10 +81,10 @@ discard block |
||
81 | 81 | * A default date of '0000-00-00 00:00:00' is invalid in MySQL 5.7 when configured with |
82 | 82 | * sql_mode including both STRICT_TRANS_TABLES and NO_ZERO_DATE. |
83 | 83 | */ |
84 | - $default_date = new DateTime( 'tomorrow' ); |
|
84 | + $default_date = new DateTime('tomorrow'); |
|
85 | 85 | $null_action = new ActionScheduler_NullAction(); |
86 | - $date_gmt = $this->get_scheduled_date_string( $null_action, $default_date ); |
|
87 | - $date_local = $this->get_scheduled_date_string_local( $null_action, $default_date ); |
|
86 | + $date_gmt = $this->get_scheduled_date_string($null_action, $default_date); |
|
87 | + $date_local = $this->get_scheduled_date_string_local($null_action, $default_date); |
|
88 | 88 | |
89 | 89 | $row_count = $wpdb->insert( |
90 | 90 | $wpdb->{ActionScheduler_StoreSchema::ACTIONS_TABLE}, |
@@ -98,10 +98,10 @@ discard block |
||
98 | 98 | 'last_attempt_local' => $date_local, |
99 | 99 | ) |
100 | 100 | ); |
101 | - if ( $row_count > 0 ) { |
|
101 | + if ($row_count > 0) { |
|
102 | 102 | $wpdb->delete( |
103 | 103 | $wpdb->{ActionScheduler_StoreSchema::ACTIONS_TABLE}, |
104 | - array( 'action_id' => $this->demarkation_id ) |
|
104 | + array('action_id' => $this->demarkation_id) |
|
105 | 105 | ); |
106 | 106 | } |
107 | 107 | } |
@@ -117,14 +117,14 @@ discard block |
||
117 | 117 | * |
118 | 118 | * @codeCoverageIgnore |
119 | 119 | */ |
120 | - private function set_demarkation_id( $id = null ) { |
|
121 | - if ( empty( $id ) ) { |
|
120 | + private function set_demarkation_id($id = null) { |
|
121 | + if (empty($id)) { |
|
122 | 122 | /** @var \wpdb $wpdb */ |
123 | 123 | global $wpdb; |
124 | - $id = (int) $wpdb->get_var( "SELECT MAX(ID) FROM $wpdb->posts" ); |
|
125 | - $id ++; |
|
124 | + $id = (int) $wpdb->get_var("SELECT MAX(ID) FROM $wpdb->posts"); |
|
125 | + $id++; |
|
126 | 126 | } |
127 | - update_option( self::DEMARKATION_OPTION, $id ); |
|
127 | + update_option(self::DEMARKATION_OPTION, $id); |
|
128 | 128 | |
129 | 129 | return $id; |
130 | 130 | } |
@@ -140,13 +140,13 @@ discard block |
||
140 | 140 | * |
141 | 141 | * @return string |
142 | 142 | */ |
143 | - public function find_action( $hook, $params = array() ) { |
|
144 | - $found_unmigrated_action = $this->secondary_store->find_action( $hook, $params ); |
|
145 | - if ( ! empty( $found_unmigrated_action ) ) { |
|
146 | - $this->migrate( array( $found_unmigrated_action ) ); |
|
143 | + public function find_action($hook, $params = array()) { |
|
144 | + $found_unmigrated_action = $this->secondary_store->find_action($hook, $params); |
|
145 | + if ( ! empty($found_unmigrated_action)) { |
|
146 | + $this->migrate(array($found_unmigrated_action)); |
|
147 | 147 | } |
148 | 148 | |
149 | - return $this->primary_store->find_action( $hook, $params ); |
|
149 | + return $this->primary_store->find_action($hook, $params); |
|
150 | 150 | } |
151 | 151 | |
152 | 152 | /** |
@@ -159,13 +159,13 @@ discard block |
||
159 | 159 | * |
160 | 160 | * @return int[] |
161 | 161 | */ |
162 | - public function query_actions( $query = array(), $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 ); |
|
162 | + public function query_actions($query = array(), $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); |
|
166 | 166 | } |
167 | 167 | |
168 | - return $this->primary_store->query_actions( $query, $query_type ); |
|
168 | + return $this->primary_store->query_actions($query, $query_type); |
|
169 | 169 | } |
170 | 170 | |
171 | 171 | /** |
@@ -178,22 +178,22 @@ discard block |
||
178 | 178 | $migrated_actions_count = $this->primary_store->action_counts(); |
179 | 179 | $actions_count_by_status = array(); |
180 | 180 | |
181 | - foreach ( $this->get_status_labels() as $status_key => $status_label ) { |
|
181 | + foreach ($this->get_status_labels() as $status_key => $status_label) { |
|
182 | 182 | |
183 | 183 | $count = 0; |
184 | 184 | |
185 | - if ( isset( $unmigrated_actions_count[ $status_key ] ) ) { |
|
186 | - $count += $unmigrated_actions_count[ $status_key ]; |
|
185 | + if (isset($unmigrated_actions_count[$status_key])) { |
|
186 | + $count += $unmigrated_actions_count[$status_key]; |
|
187 | 187 | } |
188 | 188 | |
189 | - if ( isset( $migrated_actions_count[ $status_key ] ) ) { |
|
190 | - $count += $migrated_actions_count[ $status_key ]; |
|
189 | + if (isset($migrated_actions_count[$status_key])) { |
|
190 | + $count += $migrated_actions_count[$status_key]; |
|
191 | 191 | } |
192 | 192 | |
193 | - $actions_count_by_status[ $status_key ] = $count; |
|
193 | + $actions_count_by_status[$status_key] = $count; |
|
194 | 194 | } |
195 | 195 | |
196 | - $actions_count_by_status = array_filter( $actions_count_by_status ); |
|
196 | + $actions_count_by_status = array_filter($actions_count_by_status); |
|
197 | 197 | |
198 | 198 | return $actions_count_by_status; |
199 | 199 | } |
@@ -208,17 +208,17 @@ discard block |
||
208 | 208 | * |
209 | 209 | * @return ActionScheduler_ActionClaim |
210 | 210 | */ |
211 | - public function stake_claim( $max_actions = 10, DateTime $before_date = null, $hooks = array(), $group = '' ) { |
|
212 | - $claim = $this->secondary_store->stake_claim( $max_actions, $before_date, $hooks, $group ); |
|
211 | + public function stake_claim($max_actions = 10, DateTime $before_date = null, $hooks = array(), $group = '') { |
|
212 | + $claim = $this->secondary_store->stake_claim($max_actions, $before_date, $hooks, $group); |
|
213 | 213 | |
214 | 214 | $claimed_actions = $claim->get_actions(); |
215 | - if ( ! empty( $claimed_actions ) ) { |
|
216 | - $this->migrate( $claimed_actions ); |
|
215 | + if ( ! empty($claimed_actions)) { |
|
216 | + $this->migrate($claimed_actions); |
|
217 | 217 | } |
218 | 218 | |
219 | - $this->secondary_store->release_claim( $claim ); |
|
219 | + $this->secondary_store->release_claim($claim); |
|
220 | 220 | |
221 | - return $this->primary_store->stake_claim( $max_actions, $before_date, $hooks, $group ); |
|
221 | + return $this->primary_store->stake_claim($max_actions, $before_date, $hooks, $group); |
|
222 | 222 | } |
223 | 223 | |
224 | 224 | /** |
@@ -226,8 +226,8 @@ discard block |
||
226 | 226 | * |
227 | 227 | * @param array $action_ids List of action IDs. |
228 | 228 | */ |
229 | - private function migrate( $action_ids ) { |
|
230 | - $this->migration_runner->migrate_actions( $action_ids ); |
|
229 | + private function migrate($action_ids) { |
|
230 | + $this->migration_runner->migrate_actions($action_ids); |
|
231 | 231 | } |
232 | 232 | |
233 | 233 | /** |
@@ -238,8 +238,8 @@ discard block |
||
238 | 238 | * |
239 | 239 | * @return int The action ID |
240 | 240 | */ |
241 | - public function save_action( ActionScheduler_Action $action, DateTime $date = null ) { |
|
242 | - return $this->primary_store->save_action( $action, $date ); |
|
241 | + public function save_action(ActionScheduler_Action $action, DateTime $date = null) { |
|
242 | + return $this->primary_store->save_action($action, $date); |
|
243 | 243 | } |
244 | 244 | |
245 | 245 | /** |
@@ -247,10 +247,10 @@ discard block |
||
247 | 247 | * |
248 | 248 | * @param int $action_id Action ID. |
249 | 249 | */ |
250 | - public function fetch_action( $action_id ) { |
|
251 | - $store = $this->get_store_from_action_id( $action_id, true ); |
|
252 | - if ( $store ) { |
|
253 | - return $store->fetch_action( $action_id ); |
|
250 | + public function fetch_action($action_id) { |
|
251 | + $store = $this->get_store_from_action_id($action_id, true); |
|
252 | + if ($store) { |
|
253 | + return $store->fetch_action($action_id); |
|
254 | 254 | } else { |
255 | 255 | return new ActionScheduler_NullAction(); |
256 | 256 | } |
@@ -261,10 +261,10 @@ discard block |
||
261 | 261 | * |
262 | 262 | * @param int $action_id Action ID. |
263 | 263 | */ |
264 | - public function cancel_action( $action_id ) { |
|
265 | - $store = $this->get_store_from_action_id( $action_id ); |
|
266 | - if ( $store ) { |
|
267 | - $store->cancel_action( $action_id ); |
|
264 | + public function cancel_action($action_id) { |
|
265 | + $store = $this->get_store_from_action_id($action_id); |
|
266 | + if ($store) { |
|
267 | + $store->cancel_action($action_id); |
|
268 | 268 | } |
269 | 269 | } |
270 | 270 | |
@@ -273,10 +273,10 @@ discard block |
||
273 | 273 | * |
274 | 274 | * @param int $action_id Action ID. |
275 | 275 | */ |
276 | - public function delete_action( $action_id ) { |
|
277 | - $store = $this->get_store_from_action_id( $action_id ); |
|
278 | - if ( $store ) { |
|
279 | - $store->delete_action( $action_id ); |
|
276 | + public function delete_action($action_id) { |
|
277 | + $store = $this->get_store_from_action_id($action_id); |
|
278 | + if ($store) { |
|
279 | + $store->delete_action($action_id); |
|
280 | 280 | } |
281 | 281 | } |
282 | 282 | |
@@ -285,10 +285,10 @@ discard block |
||
285 | 285 | * |
286 | 286 | * @param int $action_id Action ID. |
287 | 287 | */ |
288 | - public function get_date( $action_id ) { |
|
289 | - $store = $this->get_store_from_action_id( $action_id ); |
|
290 | - if ( $store ) { |
|
291 | - return $store->get_date( $action_id ); |
|
288 | + public function get_date($action_id) { |
|
289 | + $store = $this->get_store_from_action_id($action_id); |
|
290 | + if ($store) { |
|
291 | + return $store->get_date($action_id); |
|
292 | 292 | } else { |
293 | 293 | return null; |
294 | 294 | } |
@@ -299,10 +299,10 @@ discard block |
||
299 | 299 | * |
300 | 300 | * @param int $action_id Action ID. |
301 | 301 | */ |
302 | - public function mark_failure( $action_id ) { |
|
303 | - $store = $this->get_store_from_action_id( $action_id ); |
|
304 | - if ( $store ) { |
|
305 | - $store->mark_failure( $action_id ); |
|
302 | + public function mark_failure($action_id) { |
|
303 | + $store = $this->get_store_from_action_id($action_id); |
|
304 | + if ($store) { |
|
305 | + $store->mark_failure($action_id); |
|
306 | 306 | } |
307 | 307 | } |
308 | 308 | |
@@ -311,10 +311,10 @@ discard block |
||
311 | 311 | * |
312 | 312 | * @param int $action_id Action ID. |
313 | 313 | */ |
314 | - public function log_execution( $action_id ) { |
|
315 | - $store = $this->get_store_from_action_id( $action_id ); |
|
316 | - if ( $store ) { |
|
317 | - $store->log_execution( $action_id ); |
|
314 | + public function log_execution($action_id) { |
|
315 | + $store = $this->get_store_from_action_id($action_id); |
|
316 | + if ($store) { |
|
317 | + $store->log_execution($action_id); |
|
318 | 318 | } |
319 | 319 | } |
320 | 320 | |
@@ -323,10 +323,10 @@ discard block |
||
323 | 323 | * |
324 | 324 | * @param int $action_id Action ID. |
325 | 325 | */ |
326 | - public function mark_complete( $action_id ) { |
|
327 | - $store = $this->get_store_from_action_id( $action_id ); |
|
328 | - if ( $store ) { |
|
329 | - $store->mark_complete( $action_id ); |
|
326 | + public function mark_complete($action_id) { |
|
327 | + $store = $this->get_store_from_action_id($action_id); |
|
328 | + if ($store) { |
|
329 | + $store->mark_complete($action_id); |
|
330 | 330 | } |
331 | 331 | } |
332 | 332 | |
@@ -335,10 +335,10 @@ discard block |
||
335 | 335 | * |
336 | 336 | * @param int $action_id Action ID. |
337 | 337 | */ |
338 | - public function get_status( $action_id ) { |
|
339 | - $store = $this->get_store_from_action_id( $action_id ); |
|
340 | - if ( $store ) { |
|
341 | - return $store->get_status( $action_id ); |
|
338 | + public function get_status($action_id) { |
|
339 | + $store = $this->get_store_from_action_id($action_id); |
|
340 | + if ($store) { |
|
341 | + return $store->get_status($action_id); |
|
342 | 342 | } |
343 | 343 | return null; |
344 | 344 | } |
@@ -350,13 +350,13 @@ discard block |
||
350 | 350 | * @param bool $primary_first Optional flag indicating search the primary store first. |
351 | 351 | * @return ActionScheduler_Store |
352 | 352 | */ |
353 | - protected function get_store_from_action_id( $action_id, $primary_first = false ) { |
|
354 | - if ( $primary_first ) { |
|
353 | + protected function get_store_from_action_id($action_id, $primary_first = false) { |
|
354 | + if ($primary_first) { |
|
355 | 355 | $stores = array( |
356 | 356 | $this->primary_store, |
357 | 357 | $this->secondary_store, |
358 | 358 | ); |
359 | - } elseif ( $action_id < $this->demarkation_id ) { |
|
359 | + } elseif ($action_id < $this->demarkation_id) { |
|
360 | 360 | $stores = array( |
361 | 361 | $this->secondary_store, |
362 | 362 | $this->primary_store, |
@@ -367,9 +367,9 @@ discard block |
||
367 | 367 | ); |
368 | 368 | } |
369 | 369 | |
370 | - foreach ( $stores as $store ) { |
|
371 | - $action = $store->fetch_action( $action_id ); |
|
372 | - if ( ! is_a( $action, 'ActionScheduler_NullAction' ) ) { |
|
370 | + foreach ($stores as $store) { |
|
371 | + $action = $store->fetch_action($action_id); |
|
372 | + if ( ! is_a($action, 'ActionScheduler_NullAction')) { |
|
373 | 373 | return $store; |
374 | 374 | } |
375 | 375 | } |
@@ -394,8 +394,8 @@ discard block |
||
394 | 394 | * |
395 | 395 | * @param int $action_id Action ID. |
396 | 396 | */ |
397 | - public function get_claim_id( $action_id ) { |
|
398 | - return $this->primary_store->get_claim_id( $action_id ); |
|
397 | + public function get_claim_id($action_id) { |
|
398 | + return $this->primary_store->get_claim_id($action_id); |
|
399 | 399 | } |
400 | 400 | |
401 | 401 | /** |
@@ -403,8 +403,8 @@ discard block |
||
403 | 403 | * |
404 | 404 | * @param ActionScheduler_ActionClaim $claim Claim object. |
405 | 405 | */ |
406 | - public function release_claim( ActionScheduler_ActionClaim $claim ) { |
|
407 | - $this->primary_store->release_claim( $claim ); |
|
406 | + public function release_claim(ActionScheduler_ActionClaim $claim) { |
|
407 | + $this->primary_store->release_claim($claim); |
|
408 | 408 | } |
409 | 409 | |
410 | 410 | /** |
@@ -412,8 +412,8 @@ discard block |
||
412 | 412 | * |
413 | 413 | * @param int $action_id Action ID. |
414 | 414 | */ |
415 | - public function unclaim_action( $action_id ) { |
|
416 | - $this->primary_store->unclaim_action( $action_id ); |
|
415 | + public function unclaim_action($action_id) { |
|
416 | + $this->primary_store->unclaim_action($action_id); |
|
417 | 417 | } |
418 | 418 | |
419 | 419 | /** |
@@ -421,7 +421,7 @@ discard block |
||
421 | 421 | * |
422 | 422 | * @param int $claim_id Claim ID. |
423 | 423 | */ |
424 | - public function find_actions_by_claim_id( $claim_id ) { |
|
425 | - return $this->primary_store->find_actions_by_claim_id( $claim_id ); |
|
424 | + public function find_actions_by_claim_id($claim_id) { |
|
425 | + return $this->primary_store->find_actions_by_claim_id($claim_id); |
|
426 | 426 | } |
427 | 427 | } |
@@ -6,46 +6,46 @@ |
||
6 | 6 | * @codeCoverageIgnore |
7 | 7 | */ |
8 | 8 | class ActionScheduler_wpPostStore_PostTypeRegistrar { |
9 | - public function register() { |
|
10 | - register_post_type( ActionScheduler_wpPostStore::POST_TYPE, $this->post_type_args() ); |
|
11 | - } |
|
9 | + public function register() { |
|
10 | + register_post_type( ActionScheduler_wpPostStore::POST_TYPE, $this->post_type_args() ); |
|
11 | + } |
|
12 | 12 | |
13 | - /** |
|
14 | - * Build the args array for the post type definition |
|
15 | - * |
|
16 | - * @return array |
|
17 | - */ |
|
18 | - protected function post_type_args() { |
|
19 | - $args = array( |
|
20 | - 'label' => __( 'Scheduled Actions', 'action-scheduler' ), |
|
21 | - 'description' => __( 'Scheduled actions are hooks triggered on a cetain date and time.', 'action-scheduler' ), |
|
22 | - 'public' => false, |
|
23 | - 'map_meta_cap' => true, |
|
24 | - 'hierarchical' => false, |
|
25 | - 'supports' => array( 'title', 'editor', 'comments' ), |
|
26 | - 'rewrite' => false, |
|
27 | - 'query_var' => false, |
|
28 | - 'can_export' => true, |
|
29 | - 'ep_mask' => EP_NONE, |
|
30 | - 'labels' => array( |
|
31 | - 'name' => __( 'Scheduled Actions', 'action-scheduler' ), |
|
32 | - 'singular_name' => __( 'Scheduled Action', 'action-scheduler' ), |
|
33 | - 'menu_name' => _x( 'Scheduled Actions', 'Admin menu name', 'action-scheduler' ), |
|
34 | - 'add_new' => __( 'Add', 'action-scheduler' ), |
|
35 | - 'add_new_item' => __( 'Add New Scheduled Action', 'action-scheduler' ), |
|
36 | - 'edit' => __( 'Edit', 'action-scheduler' ), |
|
37 | - 'edit_item' => __( 'Edit Scheduled Action', 'action-scheduler' ), |
|
38 | - 'new_item' => __( 'New Scheduled Action', 'action-scheduler' ), |
|
39 | - 'view' => __( 'View Action', 'action-scheduler' ), |
|
40 | - 'view_item' => __( 'View Action', 'action-scheduler' ), |
|
41 | - 'search_items' => __( 'Search Scheduled Actions', 'action-scheduler' ), |
|
42 | - 'not_found' => __( 'No actions found', 'action-scheduler' ), |
|
43 | - 'not_found_in_trash' => __( 'No actions found in trash', 'action-scheduler' ), |
|
44 | - ), |
|
45 | - ); |
|
13 | + /** |
|
14 | + * Build the args array for the post type definition |
|
15 | + * |
|
16 | + * @return array |
|
17 | + */ |
|
18 | + protected function post_type_args() { |
|
19 | + $args = array( |
|
20 | + 'label' => __( 'Scheduled Actions', 'action-scheduler' ), |
|
21 | + 'description' => __( 'Scheduled actions are hooks triggered on a cetain date and time.', 'action-scheduler' ), |
|
22 | + 'public' => false, |
|
23 | + 'map_meta_cap' => true, |
|
24 | + 'hierarchical' => false, |
|
25 | + 'supports' => array( 'title', 'editor', 'comments' ), |
|
26 | + 'rewrite' => false, |
|
27 | + 'query_var' => false, |
|
28 | + 'can_export' => true, |
|
29 | + 'ep_mask' => EP_NONE, |
|
30 | + 'labels' => array( |
|
31 | + 'name' => __( 'Scheduled Actions', 'action-scheduler' ), |
|
32 | + 'singular_name' => __( 'Scheduled Action', 'action-scheduler' ), |
|
33 | + 'menu_name' => _x( 'Scheduled Actions', 'Admin menu name', 'action-scheduler' ), |
|
34 | + 'add_new' => __( 'Add', 'action-scheduler' ), |
|
35 | + 'add_new_item' => __( 'Add New Scheduled Action', 'action-scheduler' ), |
|
36 | + 'edit' => __( 'Edit', 'action-scheduler' ), |
|
37 | + 'edit_item' => __( 'Edit Scheduled Action', 'action-scheduler' ), |
|
38 | + 'new_item' => __( 'New Scheduled Action', 'action-scheduler' ), |
|
39 | + 'view' => __( 'View Action', 'action-scheduler' ), |
|
40 | + 'view_item' => __( 'View Action', 'action-scheduler' ), |
|
41 | + 'search_items' => __( 'Search Scheduled Actions', 'action-scheduler' ), |
|
42 | + 'not_found' => __( 'No actions found', 'action-scheduler' ), |
|
43 | + 'not_found_in_trash' => __( 'No actions found in trash', 'action-scheduler' ), |
|
44 | + ), |
|
45 | + ); |
|
46 | 46 | |
47 | - $args = apply_filters( 'action_scheduler_post_type_args', $args ); |
|
48 | - return $args; |
|
49 | - } |
|
47 | + $args = apply_filters( 'action_scheduler_post_type_args', $args ); |
|
48 | + return $args; |
|
49 | + } |
|
50 | 50 | } |
51 | 51 |
@@ -7,7 +7,7 @@ discard block |
||
7 | 7 | */ |
8 | 8 | class ActionScheduler_wpPostStore_PostTypeRegistrar { |
9 | 9 | public function register() { |
10 | - register_post_type( ActionScheduler_wpPostStore::POST_TYPE, $this->post_type_args() ); |
|
10 | + register_post_type(ActionScheduler_wpPostStore::POST_TYPE, $this->post_type_args()); |
|
11 | 11 | } |
12 | 12 | |
13 | 13 | /** |
@@ -17,34 +17,34 @@ discard block |
||
17 | 17 | */ |
18 | 18 | protected function post_type_args() { |
19 | 19 | $args = array( |
20 | - 'label' => __( 'Scheduled Actions', 'action-scheduler' ), |
|
21 | - 'description' => __( 'Scheduled actions are hooks triggered on a cetain date and time.', 'action-scheduler' ), |
|
20 | + 'label' => __('Scheduled Actions', 'action-scheduler'), |
|
21 | + 'description' => __('Scheduled actions are hooks triggered on a cetain date and time.', 'action-scheduler'), |
|
22 | 22 | 'public' => false, |
23 | 23 | 'map_meta_cap' => true, |
24 | 24 | 'hierarchical' => false, |
25 | - 'supports' => array( 'title', 'editor', 'comments' ), |
|
25 | + 'supports' => array('title', 'editor', 'comments'), |
|
26 | 26 | 'rewrite' => false, |
27 | 27 | 'query_var' => false, |
28 | 28 | 'can_export' => true, |
29 | 29 | 'ep_mask' => EP_NONE, |
30 | 30 | 'labels' => array( |
31 | - 'name' => __( 'Scheduled Actions', 'action-scheduler' ), |
|
32 | - 'singular_name' => __( 'Scheduled Action', 'action-scheduler' ), |
|
33 | - 'menu_name' => _x( 'Scheduled Actions', 'Admin menu name', 'action-scheduler' ), |
|
34 | - 'add_new' => __( 'Add', 'action-scheduler' ), |
|
35 | - 'add_new_item' => __( 'Add New Scheduled Action', 'action-scheduler' ), |
|
36 | - 'edit' => __( 'Edit', 'action-scheduler' ), |
|
37 | - 'edit_item' => __( 'Edit Scheduled Action', 'action-scheduler' ), |
|
38 | - 'new_item' => __( 'New Scheduled Action', 'action-scheduler' ), |
|
39 | - 'view' => __( 'View Action', 'action-scheduler' ), |
|
40 | - 'view_item' => __( 'View Action', 'action-scheduler' ), |
|
41 | - 'search_items' => __( 'Search Scheduled Actions', 'action-scheduler' ), |
|
42 | - 'not_found' => __( 'No actions found', 'action-scheduler' ), |
|
43 | - 'not_found_in_trash' => __( 'No actions found in trash', 'action-scheduler' ), |
|
31 | + 'name' => __('Scheduled Actions', 'action-scheduler'), |
|
32 | + 'singular_name' => __('Scheduled Action', 'action-scheduler'), |
|
33 | + 'menu_name' => _x('Scheduled Actions', 'Admin menu name', 'action-scheduler'), |
|
34 | + 'add_new' => __('Add', 'action-scheduler'), |
|
35 | + 'add_new_item' => __('Add New Scheduled Action', 'action-scheduler'), |
|
36 | + 'edit' => __('Edit', 'action-scheduler'), |
|
37 | + 'edit_item' => __('Edit Scheduled Action', 'action-scheduler'), |
|
38 | + 'new_item' => __('New Scheduled Action', 'action-scheduler'), |
|
39 | + 'view' => __('View Action', 'action-scheduler'), |
|
40 | + 'view_item' => __('View Action', 'action-scheduler'), |
|
41 | + 'search_items' => __('Search Scheduled Actions', 'action-scheduler'), |
|
42 | + 'not_found' => __('No actions found', 'action-scheduler'), |
|
43 | + 'not_found_in_trash' => __('No actions found in trash', 'action-scheduler'), |
|
44 | 44 | ), |
45 | 45 | ); |
46 | 46 | |
47 | - $args = apply_filters( 'action_scheduler_post_type_args', $args ); |
|
47 | + $args = apply_filters('action_scheduler_post_type_args', $args); |
|
48 | 48 | return $args; |
49 | 49 | } |
50 | 50 | } |
@@ -6,22 +6,22 @@ |
||
6 | 6 | * @codeCoverageIgnore |
7 | 7 | */ |
8 | 8 | class ActionScheduler_wpPostStore_TaxonomyRegistrar { |
9 | - public function register() { |
|
10 | - register_taxonomy( ActionScheduler_wpPostStore::GROUP_TAXONOMY, ActionScheduler_wpPostStore::POST_TYPE, $this->taxonomy_args() ); |
|
11 | - } |
|
9 | + public function register() { |
|
10 | + register_taxonomy( ActionScheduler_wpPostStore::GROUP_TAXONOMY, ActionScheduler_wpPostStore::POST_TYPE, $this->taxonomy_args() ); |
|
11 | + } |
|
12 | 12 | |
13 | - protected function taxonomy_args() { |
|
14 | - $args = array( |
|
15 | - 'label' => __( 'Action Group', 'action-scheduler' ), |
|
16 | - 'public' => false, |
|
17 | - 'hierarchical' => false, |
|
18 | - 'show_admin_column' => true, |
|
19 | - 'query_var' => false, |
|
20 | - 'rewrite' => false, |
|
21 | - ); |
|
13 | + protected function taxonomy_args() { |
|
14 | + $args = array( |
|
15 | + 'label' => __( 'Action Group', 'action-scheduler' ), |
|
16 | + 'public' => false, |
|
17 | + 'hierarchical' => false, |
|
18 | + 'show_admin_column' => true, |
|
19 | + 'query_var' => false, |
|
20 | + 'rewrite' => false, |
|
21 | + ); |
|
22 | 22 | |
23 | - $args = apply_filters( 'action_scheduler_taxonomy_args', $args ); |
|
24 | - return $args; |
|
25 | - } |
|
23 | + $args = apply_filters( 'action_scheduler_taxonomy_args', $args ); |
|
24 | + return $args; |
|
25 | + } |
|
26 | 26 | } |
27 | 27 |
@@ -7,12 +7,12 @@ discard block |
||
7 | 7 | */ |
8 | 8 | class ActionScheduler_wpPostStore_TaxonomyRegistrar { |
9 | 9 | public function register() { |
10 | - register_taxonomy( ActionScheduler_wpPostStore::GROUP_TAXONOMY, ActionScheduler_wpPostStore::POST_TYPE, $this->taxonomy_args() ); |
|
10 | + register_taxonomy(ActionScheduler_wpPostStore::GROUP_TAXONOMY, ActionScheduler_wpPostStore::POST_TYPE, $this->taxonomy_args()); |
|
11 | 11 | } |
12 | 12 | |
13 | 13 | protected function taxonomy_args() { |
14 | 14 | $args = array( |
15 | - 'label' => __( 'Action Group', 'action-scheduler' ), |
|
15 | + 'label' => __('Action Group', 'action-scheduler'), |
|
16 | 16 | 'public' => false, |
17 | 17 | 'hierarchical' => false, |
18 | 18 | 'show_admin_column' => true, |
@@ -20,7 +20,7 @@ discard block |
||
20 | 20 | 'rewrite' => false, |
21 | 21 | ); |
22 | 22 | |
23 | - $args = apply_filters( 'action_scheduler_taxonomy_args', $args ); |
|
23 | + $args = apply_filters('action_scheduler_taxonomy_args', $args); |
|
24 | 24 | return $args; |
25 | 25 | } |
26 | 26 | } |
@@ -4,52 +4,52 @@ |
||
4 | 4 | * Class ActionScheduler_FatalErrorMonitor |
5 | 5 | */ |
6 | 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; |
|
7 | + /** @var ActionScheduler_ActionClaim */ |
|
8 | + private $claim = null; |
|
9 | + /** @var ActionScheduler_Store */ |
|
10 | + private $store = null; |
|
11 | + private $action_id = 0; |
|
12 | 12 | |
13 | - public function __construct( ActionScheduler_Store $store ) { |
|
14 | - $this->store = $store; |
|
15 | - } |
|
13 | + public function __construct( ActionScheduler_Store $store ) { |
|
14 | + $this->store = $store; |
|
15 | + } |
|
16 | 16 | |
17 | - public function attach( ActionScheduler_ActionClaim $claim ) { |
|
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 | - } |
|
17 | + public function attach( ActionScheduler_ActionClaim $claim ) { |
|
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 | 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 | - } |
|
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 | 35 | |
36 | - public function track_current_action( $action_id ) { |
|
37 | - $this->action_id = $action_id; |
|
38 | - } |
|
36 | + public function track_current_action( $action_id ) { |
|
37 | + $this->action_id = $action_id; |
|
38 | + } |
|
39 | 39 | |
40 | - public function untrack_action() { |
|
41 | - $this->action_id = 0; |
|
42 | - } |
|
40 | + public function untrack_action() { |
|
41 | + $this->action_id = 0; |
|
42 | + } |
|
43 | 43 | |
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 | - } |
|
51 | - } |
|
52 | - $this->store->release_claim( $this->claim ); |
|
53 | - } |
|
54 | - } |
|
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 | + } |
|
51 | + } |
|
52 | + $this->store->release_claim( $this->claim ); |
|
53 | + } |
|
54 | + } |
|
55 | 55 | } |
@@ -10,30 +10,30 @@ discard block |
||
10 | 10 | private $store = null; |
11 | 11 | private $action_id = 0; |
12 | 12 | |
13 | - public function __construct( ActionScheduler_Store $store ) { |
|
13 | + public function __construct(ActionScheduler_Store $store) { |
|
14 | 14 | $this->store = $store; |
15 | 15 | } |
16 | 16 | |
17 | - public function attach( ActionScheduler_ActionClaim $claim ) { |
|
17 | + public function attach(ActionScheduler_ActionClaim $claim) { |
|
18 | 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 ); |
|
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 | 24 | } |
25 | 25 | |
26 | 26 | public function detach() { |
27 | 27 | $this->claim = null; |
28 | 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 ); |
|
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 | 34 | } |
35 | 35 | |
36 | - public function track_current_action( $action_id ) { |
|
36 | + public function track_current_action($action_id) { |
|
37 | 37 | $this->action_id = $action_id; |
38 | 38 | } |
39 | 39 | |
@@ -42,14 +42,14 @@ discard block |
||
42 | 42 | } |
43 | 43 | |
44 | 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 ); |
|
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 | 50 | } |
51 | 51 | } |
52 | - $this->store->release_claim( $this->claim ); |
|
52 | + $this->store->release_claim($this->claim); |
|
53 | 53 | } |
54 | 54 | } |
55 | 55 | } |
@@ -5,160 +5,160 @@ |
||
5 | 5 | */ |
6 | 6 | class ActionScheduler_QueueCleaner { |
7 | 7 | |
8 | - /** @var int */ |
|
9 | - protected $batch_size; |
|
10 | - |
|
11 | - /** @var ActionScheduler_Store */ |
|
12 | - private $store = null; |
|
13 | - |
|
14 | - /** |
|
15 | - * 31 days in seconds. |
|
16 | - * |
|
17 | - * @var int |
|
18 | - */ |
|
19 | - private $month_in_seconds = 2678400; |
|
20 | - |
|
21 | - /** |
|
22 | - * ActionScheduler_QueueCleaner constructor. |
|
23 | - * |
|
24 | - * @param ActionScheduler_Store $store The store instance. |
|
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, |
|
38 | - ActionScheduler_Store::STATUS_CANCELED, |
|
39 | - ); |
|
40 | - |
|
41 | - foreach ( $statuses_to_purge as $status ) { |
|
42 | - $actions_to_delete = $this->store->query_actions( |
|
43 | - array( |
|
44 | - 'status' => $status, |
|
45 | - 'modified' => $cutoff, |
|
46 | - 'modified_compare' => '<=', |
|
47 | - 'per_page' => $this->get_batch_size(), |
|
48 | - 'orderby' => 'none', |
|
49 | - ) |
|
50 | - ); |
|
51 | - |
|
52 | - foreach ( $actions_to_delete as $action_id ) { |
|
53 | - try { |
|
54 | - $this->store->delete_action( $action_id ); |
|
55 | - } catch ( Exception $e ) { |
|
56 | - |
|
57 | - /** |
|
58 | - * Notify 3rd party code of exceptions when deleting a completed action older than the retention period |
|
59 | - * |
|
60 | - * This hook provides a way for 3rd party code to log or otherwise handle exceptions relating to their |
|
61 | - * actions. |
|
62 | - * |
|
63 | - * @since 2.0.0 |
|
64 | - * |
|
65 | - * @param int $action_id The scheduled actions ID in the data store |
|
66 | - * @param Exception $e The exception thrown when attempting to delete the action from the data store |
|
67 | - * @param int $lifespan The retention period, in seconds, for old actions |
|
68 | - * @param int $count_of_actions_to_delete The number of old actions being deleted in this batch |
|
69 | - */ |
|
70 | - do_action( 'action_scheduler_failed_old_action_deletion', $action_id, $e, $lifespan, count( $actions_to_delete ) ); |
|
71 | - } |
|
72 | - } |
|
73 | - } |
|
74 | - } |
|
75 | - |
|
76 | - /** |
|
77 | - * Unclaim pending actions that have not been run within a given time limit. |
|
78 | - * |
|
79 | - * When called by ActionScheduler_Abstract_QueueRunner::run_cleanup(), the time limit passed |
|
80 | - * as a parameter is 10x the time limit used for queue processing. |
|
81 | - * |
|
82 | - * @param int $time_limit The number of seconds to allow a queue to run before unclaiming its pending actions. Default 300 (5 minutes). |
|
83 | - */ |
|
84 | - public function reset_timeouts( $time_limit = 300 ) { |
|
85 | - $timeout = apply_filters( 'action_scheduler_timeout_period', $time_limit ); |
|
86 | - if ( $timeout < 0 ) { |
|
87 | - return; |
|
88 | - } |
|
89 | - $cutoff = as_get_datetime_object( $timeout . ' seconds ago' ); |
|
90 | - $actions_to_reset = $this->store->query_actions( |
|
91 | - array( |
|
92 | - 'status' => ActionScheduler_Store::STATUS_PENDING, |
|
93 | - 'modified' => $cutoff, |
|
94 | - 'modified_compare' => '<=', |
|
95 | - 'claimed' => true, |
|
96 | - 'per_page' => $this->get_batch_size(), |
|
97 | - 'orderby' => 'none', |
|
98 | - ) |
|
99 | - ); |
|
100 | - |
|
101 | - foreach ( $actions_to_reset as $action_id ) { |
|
102 | - $this->store->unclaim_action( $action_id ); |
|
103 | - do_action( 'action_scheduler_reset_action', $action_id ); |
|
104 | - } |
|
105 | - } |
|
106 | - |
|
107 | - /** |
|
108 | - * Mark actions that have been running for more than a given time limit as failed, based on |
|
109 | - * the assumption some uncatachable and unloggable fatal error occurred during processing. |
|
110 | - * |
|
111 | - * When called by ActionScheduler_Abstract_QueueRunner::run_cleanup(), the time limit passed |
|
112 | - * as a parameter is 10x the time limit used for queue processing. |
|
113 | - * |
|
114 | - * @param int $time_limit The number of seconds to allow an action to run before it is considered to have failed. Default 300 (5 minutes). |
|
115 | - */ |
|
116 | - public function mark_failures( $time_limit = 300 ) { |
|
117 | - $timeout = apply_filters( 'action_scheduler_failure_period', $time_limit ); |
|
118 | - if ( $timeout < 0 ) { |
|
119 | - return; |
|
120 | - } |
|
121 | - $cutoff = as_get_datetime_object( $timeout . ' seconds ago' ); |
|
122 | - $actions_to_reset = $this->store->query_actions( |
|
123 | - array( |
|
124 | - 'status' => ActionScheduler_Store::STATUS_RUNNING, |
|
125 | - 'modified' => $cutoff, |
|
126 | - 'modified_compare' => '<=', |
|
127 | - 'per_page' => $this->get_batch_size(), |
|
128 | - 'orderby' => 'none', |
|
129 | - ) |
|
130 | - ); |
|
131 | - |
|
132 | - foreach ( $actions_to_reset as $action_id ) { |
|
133 | - $this->store->mark_failure( $action_id ); |
|
134 | - do_action( 'action_scheduler_failed_action', $action_id, $timeout ); |
|
135 | - } |
|
136 | - } |
|
137 | - |
|
138 | - /** |
|
139 | - * Do all of the cleaning actions. |
|
140 | - * |
|
141 | - * @param int $time_limit The number of seconds to use as the timeout and failure period. Default 300 (5 minutes). |
|
142 | - * @author Jeremy Pry |
|
143 | - */ |
|
144 | - public function clean( $time_limit = 300 ) { |
|
145 | - $this->delete_old_actions(); |
|
146 | - $this->reset_timeouts( $time_limit ); |
|
147 | - $this->mark_failures( $time_limit ); |
|
148 | - } |
|
149 | - |
|
150 | - /** |
|
151 | - * Get the batch size for cleaning the queue. |
|
152 | - * |
|
153 | - * @author Jeremy Pry |
|
154 | - * @return int |
|
155 | - */ |
|
156 | - protected function get_batch_size() { |
|
157 | - /** |
|
158 | - * Filter the batch size when cleaning the queue. |
|
159 | - * |
|
160 | - * @param int $batch_size The number of actions to clean in one batch. |
|
161 | - */ |
|
162 | - return absint( apply_filters( 'action_scheduler_cleanup_batch_size', $this->batch_size ) ); |
|
163 | - } |
|
8 | + /** @var int */ |
|
9 | + protected $batch_size; |
|
10 | + |
|
11 | + /** @var ActionScheduler_Store */ |
|
12 | + private $store = null; |
|
13 | + |
|
14 | + /** |
|
15 | + * 31 days in seconds. |
|
16 | + * |
|
17 | + * @var int |
|
18 | + */ |
|
19 | + private $month_in_seconds = 2678400; |
|
20 | + |
|
21 | + /** |
|
22 | + * ActionScheduler_QueueCleaner constructor. |
|
23 | + * |
|
24 | + * @param ActionScheduler_Store $store The store instance. |
|
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, |
|
38 | + ActionScheduler_Store::STATUS_CANCELED, |
|
39 | + ); |
|
40 | + |
|
41 | + foreach ( $statuses_to_purge as $status ) { |
|
42 | + $actions_to_delete = $this->store->query_actions( |
|
43 | + array( |
|
44 | + 'status' => $status, |
|
45 | + 'modified' => $cutoff, |
|
46 | + 'modified_compare' => '<=', |
|
47 | + 'per_page' => $this->get_batch_size(), |
|
48 | + 'orderby' => 'none', |
|
49 | + ) |
|
50 | + ); |
|
51 | + |
|
52 | + foreach ( $actions_to_delete as $action_id ) { |
|
53 | + try { |
|
54 | + $this->store->delete_action( $action_id ); |
|
55 | + } catch ( Exception $e ) { |
|
56 | + |
|
57 | + /** |
|
58 | + * Notify 3rd party code of exceptions when deleting a completed action older than the retention period |
|
59 | + * |
|
60 | + * This hook provides a way for 3rd party code to log or otherwise handle exceptions relating to their |
|
61 | + * actions. |
|
62 | + * |
|
63 | + * @since 2.0.0 |
|
64 | + * |
|
65 | + * @param int $action_id The scheduled actions ID in the data store |
|
66 | + * @param Exception $e The exception thrown when attempting to delete the action from the data store |
|
67 | + * @param int $lifespan The retention period, in seconds, for old actions |
|
68 | + * @param int $count_of_actions_to_delete The number of old actions being deleted in this batch |
|
69 | + */ |
|
70 | + do_action( 'action_scheduler_failed_old_action_deletion', $action_id, $e, $lifespan, count( $actions_to_delete ) ); |
|
71 | + } |
|
72 | + } |
|
73 | + } |
|
74 | + } |
|
75 | + |
|
76 | + /** |
|
77 | + * Unclaim pending actions that have not been run within a given time limit. |
|
78 | + * |
|
79 | + * When called by ActionScheduler_Abstract_QueueRunner::run_cleanup(), the time limit passed |
|
80 | + * as a parameter is 10x the time limit used for queue processing. |
|
81 | + * |
|
82 | + * @param int $time_limit The number of seconds to allow a queue to run before unclaiming its pending actions. Default 300 (5 minutes). |
|
83 | + */ |
|
84 | + public function reset_timeouts( $time_limit = 300 ) { |
|
85 | + $timeout = apply_filters( 'action_scheduler_timeout_period', $time_limit ); |
|
86 | + if ( $timeout < 0 ) { |
|
87 | + return; |
|
88 | + } |
|
89 | + $cutoff = as_get_datetime_object( $timeout . ' seconds ago' ); |
|
90 | + $actions_to_reset = $this->store->query_actions( |
|
91 | + array( |
|
92 | + 'status' => ActionScheduler_Store::STATUS_PENDING, |
|
93 | + 'modified' => $cutoff, |
|
94 | + 'modified_compare' => '<=', |
|
95 | + 'claimed' => true, |
|
96 | + 'per_page' => $this->get_batch_size(), |
|
97 | + 'orderby' => 'none', |
|
98 | + ) |
|
99 | + ); |
|
100 | + |
|
101 | + foreach ( $actions_to_reset as $action_id ) { |
|
102 | + $this->store->unclaim_action( $action_id ); |
|
103 | + do_action( 'action_scheduler_reset_action', $action_id ); |
|
104 | + } |
|
105 | + } |
|
106 | + |
|
107 | + /** |
|
108 | + * Mark actions that have been running for more than a given time limit as failed, based on |
|
109 | + * the assumption some uncatachable and unloggable fatal error occurred during processing. |
|
110 | + * |
|
111 | + * When called by ActionScheduler_Abstract_QueueRunner::run_cleanup(), the time limit passed |
|
112 | + * as a parameter is 10x the time limit used for queue processing. |
|
113 | + * |
|
114 | + * @param int $time_limit The number of seconds to allow an action to run before it is considered to have failed. Default 300 (5 minutes). |
|
115 | + */ |
|
116 | + public function mark_failures( $time_limit = 300 ) { |
|
117 | + $timeout = apply_filters( 'action_scheduler_failure_period', $time_limit ); |
|
118 | + if ( $timeout < 0 ) { |
|
119 | + return; |
|
120 | + } |
|
121 | + $cutoff = as_get_datetime_object( $timeout . ' seconds ago' ); |
|
122 | + $actions_to_reset = $this->store->query_actions( |
|
123 | + array( |
|
124 | + 'status' => ActionScheduler_Store::STATUS_RUNNING, |
|
125 | + 'modified' => $cutoff, |
|
126 | + 'modified_compare' => '<=', |
|
127 | + 'per_page' => $this->get_batch_size(), |
|
128 | + 'orderby' => 'none', |
|
129 | + ) |
|
130 | + ); |
|
131 | + |
|
132 | + foreach ( $actions_to_reset as $action_id ) { |
|
133 | + $this->store->mark_failure( $action_id ); |
|
134 | + do_action( 'action_scheduler_failed_action', $action_id, $timeout ); |
|
135 | + } |
|
136 | + } |
|
137 | + |
|
138 | + /** |
|
139 | + * Do all of the cleaning actions. |
|
140 | + * |
|
141 | + * @param int $time_limit The number of seconds to use as the timeout and failure period. Default 300 (5 minutes). |
|
142 | + * @author Jeremy Pry |
|
143 | + */ |
|
144 | + public function clean( $time_limit = 300 ) { |
|
145 | + $this->delete_old_actions(); |
|
146 | + $this->reset_timeouts( $time_limit ); |
|
147 | + $this->mark_failures( $time_limit ); |
|
148 | + } |
|
149 | + |
|
150 | + /** |
|
151 | + * Get the batch size for cleaning the queue. |
|
152 | + * |
|
153 | + * @author Jeremy Pry |
|
154 | + * @return int |
|
155 | + */ |
|
156 | + protected function get_batch_size() { |
|
157 | + /** |
|
158 | + * Filter the batch size when cleaning the queue. |
|
159 | + * |
|
160 | + * @param int $batch_size The number of actions to clean in one batch. |
|
161 | + */ |
|
162 | + return absint( apply_filters( 'action_scheduler_cleanup_batch_size', $this->batch_size ) ); |
|
163 | + } |
|
164 | 164 | } |
@@ -24,21 +24,21 @@ discard block |
||
24 | 24 | * @param ActionScheduler_Store $store The store instance. |
25 | 25 | * @param int $batch_size The batch size. |
26 | 26 | */ |
27 | - public function __construct( ActionScheduler_Store $store = null, $batch_size = 20 ) { |
|
27 | + public function __construct(ActionScheduler_Store $store = null, $batch_size = 20) { |
|
28 | 28 | $this->store = $store ? $store : ActionScheduler_Store::instance(); |
29 | 29 | $this->batch_size = $batch_size; |
30 | 30 | } |
31 | 31 | |
32 | 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' ); |
|
33 | + $lifespan = apply_filters('action_scheduler_retention_period', $this->month_in_seconds); |
|
34 | + $cutoff = as_get_datetime_object($lifespan.' seconds ago'); |
|
35 | 35 | |
36 | 36 | $statuses_to_purge = array( |
37 | 37 | ActionScheduler_Store::STATUS_COMPLETE, |
38 | 38 | ActionScheduler_Store::STATUS_CANCELED, |
39 | 39 | ); |
40 | 40 | |
41 | - foreach ( $statuses_to_purge as $status ) { |
|
41 | + foreach ($statuses_to_purge as $status) { |
|
42 | 42 | $actions_to_delete = $this->store->query_actions( |
43 | 43 | array( |
44 | 44 | 'status' => $status, |
@@ -49,10 +49,10 @@ discard block |
||
49 | 49 | ) |
50 | 50 | ); |
51 | 51 | |
52 | - foreach ( $actions_to_delete as $action_id ) { |
|
52 | + foreach ($actions_to_delete as $action_id) { |
|
53 | 53 | try { |
54 | - $this->store->delete_action( $action_id ); |
|
55 | - } catch ( Exception $e ) { |
|
54 | + $this->store->delete_action($action_id); |
|
55 | + } catch (Exception $e) { |
|
56 | 56 | |
57 | 57 | /** |
58 | 58 | * Notify 3rd party code of exceptions when deleting a completed action older than the retention period |
@@ -67,7 +67,7 @@ discard block |
||
67 | 67 | * @param int $lifespan The retention period, in seconds, for old actions |
68 | 68 | * @param int $count_of_actions_to_delete The number of old actions being deleted in this batch |
69 | 69 | */ |
70 | - do_action( 'action_scheduler_failed_old_action_deletion', $action_id, $e, $lifespan, count( $actions_to_delete ) ); |
|
70 | + do_action('action_scheduler_failed_old_action_deletion', $action_id, $e, $lifespan, count($actions_to_delete)); |
|
71 | 71 | } |
72 | 72 | } |
73 | 73 | } |
@@ -81,12 +81,12 @@ discard block |
||
81 | 81 | * |
82 | 82 | * @param int $time_limit The number of seconds to allow a queue to run before unclaiming its pending actions. Default 300 (5 minutes). |
83 | 83 | */ |
84 | - public function reset_timeouts( $time_limit = 300 ) { |
|
85 | - $timeout = apply_filters( 'action_scheduler_timeout_period', $time_limit ); |
|
86 | - if ( $timeout < 0 ) { |
|
84 | + public function reset_timeouts($time_limit = 300) { |
|
85 | + $timeout = apply_filters('action_scheduler_timeout_period', $time_limit); |
|
86 | + if ($timeout < 0) { |
|
87 | 87 | return; |
88 | 88 | } |
89 | - $cutoff = as_get_datetime_object( $timeout . ' seconds ago' ); |
|
89 | + $cutoff = as_get_datetime_object($timeout.' seconds ago'); |
|
90 | 90 | $actions_to_reset = $this->store->query_actions( |
91 | 91 | array( |
92 | 92 | 'status' => ActionScheduler_Store::STATUS_PENDING, |
@@ -98,9 +98,9 @@ discard block |
||
98 | 98 | ) |
99 | 99 | ); |
100 | 100 | |
101 | - foreach ( $actions_to_reset as $action_id ) { |
|
102 | - $this->store->unclaim_action( $action_id ); |
|
103 | - do_action( 'action_scheduler_reset_action', $action_id ); |
|
101 | + foreach ($actions_to_reset as $action_id) { |
|
102 | + $this->store->unclaim_action($action_id); |
|
103 | + do_action('action_scheduler_reset_action', $action_id); |
|
104 | 104 | } |
105 | 105 | } |
106 | 106 | |
@@ -113,12 +113,12 @@ discard block |
||
113 | 113 | * |
114 | 114 | * @param int $time_limit The number of seconds to allow an action to run before it is considered to have failed. Default 300 (5 minutes). |
115 | 115 | */ |
116 | - public function mark_failures( $time_limit = 300 ) { |
|
117 | - $timeout = apply_filters( 'action_scheduler_failure_period', $time_limit ); |
|
118 | - if ( $timeout < 0 ) { |
|
116 | + public function mark_failures($time_limit = 300) { |
|
117 | + $timeout = apply_filters('action_scheduler_failure_period', $time_limit); |
|
118 | + if ($timeout < 0) { |
|
119 | 119 | return; |
120 | 120 | } |
121 | - $cutoff = as_get_datetime_object( $timeout . ' seconds ago' ); |
|
121 | + $cutoff = as_get_datetime_object($timeout.' seconds ago'); |
|
122 | 122 | $actions_to_reset = $this->store->query_actions( |
123 | 123 | array( |
124 | 124 | 'status' => ActionScheduler_Store::STATUS_RUNNING, |
@@ -129,9 +129,9 @@ discard block |
||
129 | 129 | ) |
130 | 130 | ); |
131 | 131 | |
132 | - foreach ( $actions_to_reset as $action_id ) { |
|
133 | - $this->store->mark_failure( $action_id ); |
|
134 | - do_action( 'action_scheduler_failed_action', $action_id, $timeout ); |
|
132 | + foreach ($actions_to_reset as $action_id) { |
|
133 | + $this->store->mark_failure($action_id); |
|
134 | + do_action('action_scheduler_failed_action', $action_id, $timeout); |
|
135 | 135 | } |
136 | 136 | } |
137 | 137 | |
@@ -141,10 +141,10 @@ discard block |
||
141 | 141 | * @param int $time_limit The number of seconds to use as the timeout and failure period. Default 300 (5 minutes). |
142 | 142 | * @author Jeremy Pry |
143 | 143 | */ |
144 | - public function clean( $time_limit = 300 ) { |
|
144 | + public function clean($time_limit = 300) { |
|
145 | 145 | $this->delete_old_actions(); |
146 | - $this->reset_timeouts( $time_limit ); |
|
147 | - $this->mark_failures( $time_limit ); |
|
146 | + $this->reset_timeouts($time_limit); |
|
147 | + $this->mark_failures($time_limit); |
|
148 | 148 | } |
149 | 149 | |
150 | 150 | /** |
@@ -159,6 +159,6 @@ discard block |
||
159 | 159 | * |
160 | 160 | * @param int $batch_size The number of actions to clean in one batch. |
161 | 161 | */ |
162 | - return absint( apply_filters( 'action_scheduler_cleanup_batch_size', $this->batch_size ) ); |
|
162 | + return absint(apply_filters('action_scheduler_cleanup_batch_size', $this->batch_size)); |
|
163 | 163 | } |
164 | 164 | } |
@@ -7,242 +7,242 @@ |
||
7 | 7 | */ |
8 | 8 | class ActionScheduler_AdminView extends ActionScheduler_AdminView_Deprecated { |
9 | 9 | |
10 | - private static $admin_view = null; |
|
11 | - |
|
12 | - private static $screen_id = 'tools_page_action-scheduler'; |
|
13 | - |
|
14 | - /** @var ActionScheduler_ListTable */ |
|
15 | - protected $list_table; |
|
16 | - |
|
17 | - /** |
|
18 | - * @return ActionScheduler_AdminView |
|
19 | - * @codeCoverageIgnore |
|
20 | - */ |
|
21 | - public static function instance() { |
|
22 | - |
|
23 | - if ( empty( self::$admin_view ) ) { |
|
24 | - $class = apply_filters( 'action_scheduler_admin_view_class', 'ActionScheduler_AdminView' ); |
|
25 | - self::$admin_view = new $class(); |
|
26 | - } |
|
27 | - |
|
28 | - return self::$admin_view; |
|
29 | - } |
|
30 | - |
|
31 | - /** |
|
32 | - * @codeCoverageIgnore |
|
33 | - */ |
|
34 | - public function init() { |
|
35 | - if ( is_admin() && ( ! defined( 'DOING_AJAX' ) || false == DOING_AJAX ) ) { |
|
36 | - |
|
37 | - if ( class_exists( 'WooCommerce' ) ) { |
|
38 | - add_action( 'woocommerce_admin_status_content_action-scheduler', array( $this, 'render_admin_ui' ) ); |
|
39 | - add_action( 'woocommerce_system_status_report', array( $this, 'system_status_report' ) ); |
|
40 | - add_filter( 'woocommerce_admin_status_tabs', array( $this, 'register_system_status_tab' ) ); |
|
41 | - } |
|
42 | - |
|
43 | - add_action( 'admin_menu', array( $this, 'register_menu' ) ); |
|
44 | - add_action( 'admin_notices', array( $this, 'maybe_check_pastdue_actions' ) ); |
|
45 | - add_action( 'current_screen', array( $this, 'add_help_tabs' ) ); |
|
46 | - } |
|
47 | - } |
|
48 | - |
|
49 | - public function system_status_report() { |
|
50 | - $table = new ActionScheduler_wcSystemStatus( ActionScheduler::store() ); |
|
51 | - $table->render(); |
|
52 | - } |
|
53 | - |
|
54 | - /** |
|
55 | - * Registers action-scheduler into WooCommerce > System status. |
|
56 | - * |
|
57 | - * @param array $tabs An associative array of tab key => label. |
|
58 | - * @return array $tabs An associative array of tab key => label, including Action Scheduler's tabs |
|
59 | - */ |
|
60 | - public function register_system_status_tab( array $tabs ) { |
|
61 | - $tabs['action-scheduler'] = __( 'Scheduled Actions', 'action-scheduler' ); |
|
62 | - |
|
63 | - return $tabs; |
|
64 | - } |
|
65 | - |
|
66 | - /** |
|
67 | - * Include Action Scheduler's administration under the Tools menu. |
|
68 | - * |
|
69 | - * A menu under the Tools menu is important for backward compatibility (as that's |
|
70 | - * where it started), and also provides more convenient access than the WooCommerce |
|
71 | - * System Status page, and for sites where WooCommerce isn't active. |
|
72 | - */ |
|
73 | - public function register_menu() { |
|
74 | - $hook_suffix = add_submenu_page( |
|
75 | - 'tools.php', |
|
76 | - __( 'Scheduled Actions', 'action-scheduler' ), |
|
77 | - __( 'Scheduled Actions', 'action-scheduler' ), |
|
78 | - 'manage_options', |
|
79 | - 'action-scheduler', |
|
80 | - array( $this, 'render_admin_ui' ) |
|
81 | - ); |
|
82 | - add_action( 'load-' . $hook_suffix, array( $this, 'process_admin_ui' ) ); |
|
83 | - } |
|
84 | - |
|
85 | - /** |
|
86 | - * Triggers processing of any pending actions. |
|
87 | - */ |
|
88 | - public function process_admin_ui() { |
|
89 | - $this->get_list_table(); |
|
90 | - } |
|
91 | - |
|
92 | - /** |
|
93 | - * Renders the Admin UI |
|
94 | - */ |
|
95 | - public function render_admin_ui() { |
|
96 | - $table = $this->get_list_table(); |
|
97 | - $table->display_page(); |
|
98 | - } |
|
99 | - |
|
100 | - /** |
|
101 | - * Get the admin UI object and process any requested actions. |
|
102 | - * |
|
103 | - * @return ActionScheduler_ListTable |
|
104 | - */ |
|
105 | - protected function get_list_table() { |
|
106 | - if ( null === $this->list_table ) { |
|
107 | - $this->list_table = new ActionScheduler_ListTable( ActionScheduler::store(), ActionScheduler::logger(), ActionScheduler::runner() ); |
|
108 | - $this->list_table->process_actions(); |
|
109 | - } |
|
110 | - |
|
111 | - return $this->list_table; |
|
112 | - } |
|
113 | - |
|
114 | - /** |
|
115 | - * Action: admin_notices |
|
116 | - * |
|
117 | - * Maybe check past-due actions, and print notice. |
|
118 | - * |
|
119 | - * @uses $this->check_pastdue_actions() |
|
120 | - */ |
|
121 | - public function maybe_check_pastdue_actions() { |
|
122 | - |
|
123 | - // Filter to prevent checking actions (ex: inappropriate user). |
|
124 | - if ( ! apply_filters( 'action_scheduler_check_pastdue_actions', current_user_can( 'manage_options' ) ) ) { |
|
125 | - return; |
|
126 | - } |
|
127 | - |
|
128 | - // Get last check transient. |
|
129 | - $last_check = get_transient( 'action_scheduler_last_pastdue_actions_check' ); |
|
130 | - |
|
131 | - // If transient exists, we're within interval, so bail. |
|
132 | - if ( ! empty( $last_check ) ) { |
|
133 | - return; |
|
134 | - } |
|
135 | - |
|
136 | - // Perform the check. |
|
137 | - $this->check_pastdue_actions(); |
|
138 | - } |
|
139 | - |
|
140 | - /** |
|
141 | - * Check past-due actions, and print notice. |
|
142 | - * |
|
143 | - * @todo update $link_url to "Past-due" filter when released (see issue #510, PR #511) |
|
144 | - */ |
|
145 | - protected function check_pastdue_actions() { |
|
146 | - |
|
147 | - // Set thresholds. |
|
148 | - $threshold_seconds = (int) apply_filters( 'action_scheduler_pastdue_actions_seconds', DAY_IN_SECONDS ); |
|
149 | - $threshhold_min = (int) apply_filters( 'action_scheduler_pastdue_actions_min', 1 ); |
|
150 | - |
|
151 | - // Allow third-parties to preempt the default check logic. |
|
152 | - $check = apply_filters( 'action_scheduler_pastdue_actions_check_pre', null ); |
|
153 | - |
|
154 | - // Scheduled actions query arguments. |
|
155 | - $query_args = array( |
|
156 | - 'date' => as_get_datetime_object( time() - $threshold_seconds ), |
|
157 | - 'status' => ActionScheduler_Store::STATUS_PENDING, |
|
158 | - 'per_page' => $threshhold_min, |
|
159 | - ); |
|
160 | - |
|
161 | - // If no third-party preempted, run default check. |
|
162 | - if ( $check === null ) { |
|
163 | - $store = ActionScheduler_Store::instance(); |
|
164 | - $num_pastdue_actions = (int) $store->query_actions( $query_args, 'count' ); |
|
165 | - |
|
166 | - // Check if past-due actions count is greater than or equal to threshold. |
|
167 | - $check = ( $num_pastdue_actions >= $threshhold_min ); |
|
168 | - $check = (bool) apply_filters( 'action_scheduler_pastdue_actions_check', $check, $num_pastdue_actions, $threshold_seconds, $threshhold_min ); |
|
169 | - } |
|
170 | - |
|
171 | - // If check failed, set transient and abort. |
|
172 | - if ( ! boolval( $check ) ) { |
|
173 | - $interval = apply_filters( 'action_scheduler_pastdue_actions_check_interval', round( $threshold_seconds / 4 ), $threshold_seconds ); |
|
174 | - set_transient( 'action_scheduler_last_pastdue_actions_check', time(), $interval ); |
|
175 | - |
|
176 | - return; |
|
177 | - } |
|
178 | - |
|
179 | - $actions_url = add_query_arg( |
|
180 | - array( |
|
181 | - 'page' => 'action-scheduler', |
|
182 | - 'status' => 'past-due', |
|
183 | - 'order' => 'asc', |
|
184 | - ), |
|
185 | - admin_url( 'tools.php' ) |
|
186 | - ); |
|
187 | - |
|
188 | - // Print notice. |
|
189 | - echo '<div class="notice notice-warning"><p>'; |
|
190 | - printf( |
|
191 | - _n( |
|
192 | - // translators: 1) is the number of affected actions, 2) is a link to an admin screen. |
|
193 | - '<strong>Action Scheduler:</strong> %1$d <a href="%2$s">past-due action</a> found; something may be wrong. <a href="https://actionscheduler.org/faq/#my-site-has-past-due-actions-what-can-i-do" target="_blank">Read documentation »</a>', |
|
194 | - '<strong>Action Scheduler:</strong> %1$d <a href="%2$s">past-due actions</a> found; something may be wrong. <a href="https://actionscheduler.org/faq/#my-site-has-past-due-actions-what-can-i-do" target="_blank">Read documentation »</a>', |
|
195 | - $num_pastdue_actions, |
|
196 | - 'action-scheduler' |
|
197 | - ), |
|
198 | - $num_pastdue_actions, |
|
199 | - esc_attr( esc_url( $actions_url ) ) |
|
200 | - ); |
|
201 | - echo '</p></div>'; |
|
202 | - |
|
203 | - // Facilitate third-parties to evaluate and print notices. |
|
204 | - do_action( 'action_scheduler_pastdue_actions_extra_notices', $query_args ); |
|
205 | - } |
|
206 | - |
|
207 | - /** |
|
208 | - * Provide more information about the screen and its data in the help tab. |
|
209 | - */ |
|
210 | - public function add_help_tabs() { |
|
211 | - $screen = get_current_screen(); |
|
212 | - |
|
213 | - if ( ! $screen || self::$screen_id != $screen->id ) { |
|
214 | - return; |
|
215 | - } |
|
216 | - |
|
217 | - $as_version = ActionScheduler_Versions::instance()->latest_version(); |
|
218 | - $screen->add_help_tab( |
|
219 | - array( |
|
220 | - 'id' => 'action_scheduler_about', |
|
221 | - 'title' => __( 'About', 'action-scheduler' ), |
|
222 | - 'content' => |
|
223 | - '<h2>' . sprintf( __( 'About Action Scheduler %s', 'action-scheduler' ), $as_version ) . '</h2>' . |
|
224 | - '<p>' . |
|
225 | - __( 'Action Scheduler is a scalable, traceable job queue for background processing large sets of actions. Action Scheduler works by triggering an action hook to run at some time in the future. Scheduled actions can also be scheduled to run on a recurring schedule.', 'action-scheduler' ) . |
|
226 | - '</p>', |
|
227 | - ) |
|
228 | - ); |
|
229 | - |
|
230 | - $screen->add_help_tab( |
|
231 | - array( |
|
232 | - 'id' => 'action_scheduler_columns', |
|
233 | - 'title' => __( 'Columns', 'action-scheduler' ), |
|
234 | - 'content' => |
|
235 | - '<h2>' . __( 'Scheduled Action Columns', 'action-scheduler' ) . '</h2>' . |
|
236 | - '<ul>' . |
|
237 | - sprintf( '<li><strong>%1$s</strong>: %2$s</li>', __( 'Hook', 'action-scheduler' ), __( 'Name of the action hook that will be triggered.', 'action-scheduler' ) ) . |
|
238 | - sprintf( '<li><strong>%1$s</strong>: %2$s</li>', __( 'Status', 'action-scheduler' ), __( 'Action statuses are Pending, Complete, Canceled, Failed', 'action-scheduler' ) ) . |
|
239 | - sprintf( '<li><strong>%1$s</strong>: %2$s</li>', __( 'Arguments', 'action-scheduler' ), __( 'Optional data array passed to the action hook.', 'action-scheduler' ) ) . |
|
240 | - sprintf( '<li><strong>%1$s</strong>: %2$s</li>', __( 'Group', 'action-scheduler' ), __( 'Optional action group.', 'action-scheduler' ) ) . |
|
241 | - sprintf( '<li><strong>%1$s</strong>: %2$s</li>', __( 'Recurrence', 'action-scheduler' ), __( 'The action\'s schedule frequency.', 'action-scheduler' ) ) . |
|
242 | - sprintf( '<li><strong>%1$s</strong>: %2$s</li>', __( 'Scheduled', 'action-scheduler' ), __( 'The date/time the action is/was scheduled to run.', 'action-scheduler' ) ) . |
|
243 | - sprintf( '<li><strong>%1$s</strong>: %2$s</li>', __( 'Log', 'action-scheduler' ), __( 'Activity log for the action.', 'action-scheduler' ) ) . |
|
244 | - '</ul>', |
|
245 | - ) |
|
246 | - ); |
|
247 | - } |
|
10 | + private static $admin_view = null; |
|
11 | + |
|
12 | + private static $screen_id = 'tools_page_action-scheduler'; |
|
13 | + |
|
14 | + /** @var ActionScheduler_ListTable */ |
|
15 | + protected $list_table; |
|
16 | + |
|
17 | + /** |
|
18 | + * @return ActionScheduler_AdminView |
|
19 | + * @codeCoverageIgnore |
|
20 | + */ |
|
21 | + public static function instance() { |
|
22 | + |
|
23 | + if ( empty( self::$admin_view ) ) { |
|
24 | + $class = apply_filters( 'action_scheduler_admin_view_class', 'ActionScheduler_AdminView' ); |
|
25 | + self::$admin_view = new $class(); |
|
26 | + } |
|
27 | + |
|
28 | + return self::$admin_view; |
|
29 | + } |
|
30 | + |
|
31 | + /** |
|
32 | + * @codeCoverageIgnore |
|
33 | + */ |
|
34 | + public function init() { |
|
35 | + if ( is_admin() && ( ! defined( 'DOING_AJAX' ) || false == DOING_AJAX ) ) { |
|
36 | + |
|
37 | + if ( class_exists( 'WooCommerce' ) ) { |
|
38 | + add_action( 'woocommerce_admin_status_content_action-scheduler', array( $this, 'render_admin_ui' ) ); |
|
39 | + add_action( 'woocommerce_system_status_report', array( $this, 'system_status_report' ) ); |
|
40 | + add_filter( 'woocommerce_admin_status_tabs', array( $this, 'register_system_status_tab' ) ); |
|
41 | + } |
|
42 | + |
|
43 | + add_action( 'admin_menu', array( $this, 'register_menu' ) ); |
|
44 | + add_action( 'admin_notices', array( $this, 'maybe_check_pastdue_actions' ) ); |
|
45 | + add_action( 'current_screen', array( $this, 'add_help_tabs' ) ); |
|
46 | + } |
|
47 | + } |
|
48 | + |
|
49 | + public function system_status_report() { |
|
50 | + $table = new ActionScheduler_wcSystemStatus( ActionScheduler::store() ); |
|
51 | + $table->render(); |
|
52 | + } |
|
53 | + |
|
54 | + /** |
|
55 | + * Registers action-scheduler into WooCommerce > System status. |
|
56 | + * |
|
57 | + * @param array $tabs An associative array of tab key => label. |
|
58 | + * @return array $tabs An associative array of tab key => label, including Action Scheduler's tabs |
|
59 | + */ |
|
60 | + public function register_system_status_tab( array $tabs ) { |
|
61 | + $tabs['action-scheduler'] = __( 'Scheduled Actions', 'action-scheduler' ); |
|
62 | + |
|
63 | + return $tabs; |
|
64 | + } |
|
65 | + |
|
66 | + /** |
|
67 | + * Include Action Scheduler's administration under the Tools menu. |
|
68 | + * |
|
69 | + * A menu under the Tools menu is important for backward compatibility (as that's |
|
70 | + * where it started), and also provides more convenient access than the WooCommerce |
|
71 | + * System Status page, and for sites where WooCommerce isn't active. |
|
72 | + */ |
|
73 | + public function register_menu() { |
|
74 | + $hook_suffix = add_submenu_page( |
|
75 | + 'tools.php', |
|
76 | + __( 'Scheduled Actions', 'action-scheduler' ), |
|
77 | + __( 'Scheduled Actions', 'action-scheduler' ), |
|
78 | + 'manage_options', |
|
79 | + 'action-scheduler', |
|
80 | + array( $this, 'render_admin_ui' ) |
|
81 | + ); |
|
82 | + add_action( 'load-' . $hook_suffix, array( $this, 'process_admin_ui' ) ); |
|
83 | + } |
|
84 | + |
|
85 | + /** |
|
86 | + * Triggers processing of any pending actions. |
|
87 | + */ |
|
88 | + public function process_admin_ui() { |
|
89 | + $this->get_list_table(); |
|
90 | + } |
|
91 | + |
|
92 | + /** |
|
93 | + * Renders the Admin UI |
|
94 | + */ |
|
95 | + public function render_admin_ui() { |
|
96 | + $table = $this->get_list_table(); |
|
97 | + $table->display_page(); |
|
98 | + } |
|
99 | + |
|
100 | + /** |
|
101 | + * Get the admin UI object and process any requested actions. |
|
102 | + * |
|
103 | + * @return ActionScheduler_ListTable |
|
104 | + */ |
|
105 | + protected function get_list_table() { |
|
106 | + if ( null === $this->list_table ) { |
|
107 | + $this->list_table = new ActionScheduler_ListTable( ActionScheduler::store(), ActionScheduler::logger(), ActionScheduler::runner() ); |
|
108 | + $this->list_table->process_actions(); |
|
109 | + } |
|
110 | + |
|
111 | + return $this->list_table; |
|
112 | + } |
|
113 | + |
|
114 | + /** |
|
115 | + * Action: admin_notices |
|
116 | + * |
|
117 | + * Maybe check past-due actions, and print notice. |
|
118 | + * |
|
119 | + * @uses $this->check_pastdue_actions() |
|
120 | + */ |
|
121 | + public function maybe_check_pastdue_actions() { |
|
122 | + |
|
123 | + // Filter to prevent checking actions (ex: inappropriate user). |
|
124 | + if ( ! apply_filters( 'action_scheduler_check_pastdue_actions', current_user_can( 'manage_options' ) ) ) { |
|
125 | + return; |
|
126 | + } |
|
127 | + |
|
128 | + // Get last check transient. |
|
129 | + $last_check = get_transient( 'action_scheduler_last_pastdue_actions_check' ); |
|
130 | + |
|
131 | + // If transient exists, we're within interval, so bail. |
|
132 | + if ( ! empty( $last_check ) ) { |
|
133 | + return; |
|
134 | + } |
|
135 | + |
|
136 | + // Perform the check. |
|
137 | + $this->check_pastdue_actions(); |
|
138 | + } |
|
139 | + |
|
140 | + /** |
|
141 | + * Check past-due actions, and print notice. |
|
142 | + * |
|
143 | + * @todo update $link_url to "Past-due" filter when released (see issue #510, PR #511) |
|
144 | + */ |
|
145 | + protected function check_pastdue_actions() { |
|
146 | + |
|
147 | + // Set thresholds. |
|
148 | + $threshold_seconds = (int) apply_filters( 'action_scheduler_pastdue_actions_seconds', DAY_IN_SECONDS ); |
|
149 | + $threshhold_min = (int) apply_filters( 'action_scheduler_pastdue_actions_min', 1 ); |
|
150 | + |
|
151 | + // Allow third-parties to preempt the default check logic. |
|
152 | + $check = apply_filters( 'action_scheduler_pastdue_actions_check_pre', null ); |
|
153 | + |
|
154 | + // Scheduled actions query arguments. |
|
155 | + $query_args = array( |
|
156 | + 'date' => as_get_datetime_object( time() - $threshold_seconds ), |
|
157 | + 'status' => ActionScheduler_Store::STATUS_PENDING, |
|
158 | + 'per_page' => $threshhold_min, |
|
159 | + ); |
|
160 | + |
|
161 | + // If no third-party preempted, run default check. |
|
162 | + if ( $check === null ) { |
|
163 | + $store = ActionScheduler_Store::instance(); |
|
164 | + $num_pastdue_actions = (int) $store->query_actions( $query_args, 'count' ); |
|
165 | + |
|
166 | + // Check if past-due actions count is greater than or equal to threshold. |
|
167 | + $check = ( $num_pastdue_actions >= $threshhold_min ); |
|
168 | + $check = (bool) apply_filters( 'action_scheduler_pastdue_actions_check', $check, $num_pastdue_actions, $threshold_seconds, $threshhold_min ); |
|
169 | + } |
|
170 | + |
|
171 | + // If check failed, set transient and abort. |
|
172 | + if ( ! boolval( $check ) ) { |
|
173 | + $interval = apply_filters( 'action_scheduler_pastdue_actions_check_interval', round( $threshold_seconds / 4 ), $threshold_seconds ); |
|
174 | + set_transient( 'action_scheduler_last_pastdue_actions_check', time(), $interval ); |
|
175 | + |
|
176 | + return; |
|
177 | + } |
|
178 | + |
|
179 | + $actions_url = add_query_arg( |
|
180 | + array( |
|
181 | + 'page' => 'action-scheduler', |
|
182 | + 'status' => 'past-due', |
|
183 | + 'order' => 'asc', |
|
184 | + ), |
|
185 | + admin_url( 'tools.php' ) |
|
186 | + ); |
|
187 | + |
|
188 | + // Print notice. |
|
189 | + echo '<div class="notice notice-warning"><p>'; |
|
190 | + printf( |
|
191 | + _n( |
|
192 | + // translators: 1) is the number of affected actions, 2) is a link to an admin screen. |
|
193 | + '<strong>Action Scheduler:</strong> %1$d <a href="%2$s">past-due action</a> found; something may be wrong. <a href="https://actionscheduler.org/faq/#my-site-has-past-due-actions-what-can-i-do" target="_blank">Read documentation »</a>', |
|
194 | + '<strong>Action Scheduler:</strong> %1$d <a href="%2$s">past-due actions</a> found; something may be wrong. <a href="https://actionscheduler.org/faq/#my-site-has-past-due-actions-what-can-i-do" target="_blank">Read documentation »</a>', |
|
195 | + $num_pastdue_actions, |
|
196 | + 'action-scheduler' |
|
197 | + ), |
|
198 | + $num_pastdue_actions, |
|
199 | + esc_attr( esc_url( $actions_url ) ) |
|
200 | + ); |
|
201 | + echo '</p></div>'; |
|
202 | + |
|
203 | + // Facilitate third-parties to evaluate and print notices. |
|
204 | + do_action( 'action_scheduler_pastdue_actions_extra_notices', $query_args ); |
|
205 | + } |
|
206 | + |
|
207 | + /** |
|
208 | + * Provide more information about the screen and its data in the help tab. |
|
209 | + */ |
|
210 | + public function add_help_tabs() { |
|
211 | + $screen = get_current_screen(); |
|
212 | + |
|
213 | + if ( ! $screen || self::$screen_id != $screen->id ) { |
|
214 | + return; |
|
215 | + } |
|
216 | + |
|
217 | + $as_version = ActionScheduler_Versions::instance()->latest_version(); |
|
218 | + $screen->add_help_tab( |
|
219 | + array( |
|
220 | + 'id' => 'action_scheduler_about', |
|
221 | + 'title' => __( 'About', 'action-scheduler' ), |
|
222 | + 'content' => |
|
223 | + '<h2>' . sprintf( __( 'About Action Scheduler %s', 'action-scheduler' ), $as_version ) . '</h2>' . |
|
224 | + '<p>' . |
|
225 | + __( 'Action Scheduler is a scalable, traceable job queue for background processing large sets of actions. Action Scheduler works by triggering an action hook to run at some time in the future. Scheduled actions can also be scheduled to run on a recurring schedule.', 'action-scheduler' ) . |
|
226 | + '</p>', |
|
227 | + ) |
|
228 | + ); |
|
229 | + |
|
230 | + $screen->add_help_tab( |
|
231 | + array( |
|
232 | + 'id' => 'action_scheduler_columns', |
|
233 | + 'title' => __( 'Columns', 'action-scheduler' ), |
|
234 | + 'content' => |
|
235 | + '<h2>' . __( 'Scheduled Action Columns', 'action-scheduler' ) . '</h2>' . |
|
236 | + '<ul>' . |
|
237 | + sprintf( '<li><strong>%1$s</strong>: %2$s</li>', __( 'Hook', 'action-scheduler' ), __( 'Name of the action hook that will be triggered.', 'action-scheduler' ) ) . |
|
238 | + sprintf( '<li><strong>%1$s</strong>: %2$s</li>', __( 'Status', 'action-scheduler' ), __( 'Action statuses are Pending, Complete, Canceled, Failed', 'action-scheduler' ) ) . |
|
239 | + sprintf( '<li><strong>%1$s</strong>: %2$s</li>', __( 'Arguments', 'action-scheduler' ), __( 'Optional data array passed to the action hook.', 'action-scheduler' ) ) . |
|
240 | + sprintf( '<li><strong>%1$s</strong>: %2$s</li>', __( 'Group', 'action-scheduler' ), __( 'Optional action group.', 'action-scheduler' ) ) . |
|
241 | + sprintf( '<li><strong>%1$s</strong>: %2$s</li>', __( 'Recurrence', 'action-scheduler' ), __( 'The action\'s schedule frequency.', 'action-scheduler' ) ) . |
|
242 | + sprintf( '<li><strong>%1$s</strong>: %2$s</li>', __( 'Scheduled', 'action-scheduler' ), __( 'The date/time the action is/was scheduled to run.', 'action-scheduler' ) ) . |
|
243 | + sprintf( '<li><strong>%1$s</strong>: %2$s</li>', __( 'Log', 'action-scheduler' ), __( 'Activity log for the action.', 'action-scheduler' ) ) . |
|
244 | + '</ul>', |
|
245 | + ) |
|
246 | + ); |
|
247 | + } |
|
248 | 248 | } |
@@ -20,8 +20,8 @@ discard block |
||
20 | 20 | */ |
21 | 21 | public static function instance() { |
22 | 22 | |
23 | - if ( empty( self::$admin_view ) ) { |
|
24 | - $class = apply_filters( 'action_scheduler_admin_view_class', 'ActionScheduler_AdminView' ); |
|
23 | + if (empty(self::$admin_view)) { |
|
24 | + $class = apply_filters('action_scheduler_admin_view_class', 'ActionScheduler_AdminView'); |
|
25 | 25 | self::$admin_view = new $class(); |
26 | 26 | } |
27 | 27 | |
@@ -32,22 +32,22 @@ discard block |
||
32 | 32 | * @codeCoverageIgnore |
33 | 33 | */ |
34 | 34 | public function init() { |
35 | - if ( is_admin() && ( ! defined( 'DOING_AJAX' ) || false == DOING_AJAX ) ) { |
|
35 | + if (is_admin() && ( ! defined('DOING_AJAX') || false == DOING_AJAX)) { |
|
36 | 36 | |
37 | - if ( class_exists( 'WooCommerce' ) ) { |
|
38 | - add_action( 'woocommerce_admin_status_content_action-scheduler', array( $this, 'render_admin_ui' ) ); |
|
39 | - add_action( 'woocommerce_system_status_report', array( $this, 'system_status_report' ) ); |
|
40 | - add_filter( 'woocommerce_admin_status_tabs', array( $this, 'register_system_status_tab' ) ); |
|
37 | + if (class_exists('WooCommerce')) { |
|
38 | + add_action('woocommerce_admin_status_content_action-scheduler', array($this, 'render_admin_ui')); |
|
39 | + add_action('woocommerce_system_status_report', array($this, 'system_status_report')); |
|
40 | + add_filter('woocommerce_admin_status_tabs', array($this, 'register_system_status_tab')); |
|
41 | 41 | } |
42 | 42 | |
43 | - add_action( 'admin_menu', array( $this, 'register_menu' ) ); |
|
44 | - add_action( 'admin_notices', array( $this, 'maybe_check_pastdue_actions' ) ); |
|
45 | - add_action( 'current_screen', array( $this, 'add_help_tabs' ) ); |
|
43 | + add_action('admin_menu', array($this, 'register_menu')); |
|
44 | + add_action('admin_notices', array($this, 'maybe_check_pastdue_actions')); |
|
45 | + add_action('current_screen', array($this, 'add_help_tabs')); |
|
46 | 46 | } |
47 | 47 | } |
48 | 48 | |
49 | 49 | public function system_status_report() { |
50 | - $table = new ActionScheduler_wcSystemStatus( ActionScheduler::store() ); |
|
50 | + $table = new ActionScheduler_wcSystemStatus(ActionScheduler::store()); |
|
51 | 51 | $table->render(); |
52 | 52 | } |
53 | 53 | |
@@ -57,8 +57,8 @@ discard block |
||
57 | 57 | * @param array $tabs An associative array of tab key => label. |
58 | 58 | * @return array $tabs An associative array of tab key => label, including Action Scheduler's tabs |
59 | 59 | */ |
60 | - public function register_system_status_tab( array $tabs ) { |
|
61 | - $tabs['action-scheduler'] = __( 'Scheduled Actions', 'action-scheduler' ); |
|
60 | + public function register_system_status_tab(array $tabs) { |
|
61 | + $tabs['action-scheduler'] = __('Scheduled Actions', 'action-scheduler'); |
|
62 | 62 | |
63 | 63 | return $tabs; |
64 | 64 | } |
@@ -73,13 +73,13 @@ discard block |
||
73 | 73 | public function register_menu() { |
74 | 74 | $hook_suffix = add_submenu_page( |
75 | 75 | 'tools.php', |
76 | - __( 'Scheduled Actions', 'action-scheduler' ), |
|
77 | - __( 'Scheduled Actions', 'action-scheduler' ), |
|
76 | + __('Scheduled Actions', 'action-scheduler'), |
|
77 | + __('Scheduled Actions', 'action-scheduler'), |
|
78 | 78 | 'manage_options', |
79 | 79 | 'action-scheduler', |
80 | - array( $this, 'render_admin_ui' ) |
|
80 | + array($this, 'render_admin_ui') |
|
81 | 81 | ); |
82 | - add_action( 'load-' . $hook_suffix, array( $this, 'process_admin_ui' ) ); |
|
82 | + add_action('load-'.$hook_suffix, array($this, 'process_admin_ui')); |
|
83 | 83 | } |
84 | 84 | |
85 | 85 | /** |
@@ -103,8 +103,8 @@ discard block |
||
103 | 103 | * @return ActionScheduler_ListTable |
104 | 104 | */ |
105 | 105 | protected function get_list_table() { |
106 | - if ( null === $this->list_table ) { |
|
107 | - $this->list_table = new ActionScheduler_ListTable( ActionScheduler::store(), ActionScheduler::logger(), ActionScheduler::runner() ); |
|
106 | + if (null === $this->list_table) { |
|
107 | + $this->list_table = new ActionScheduler_ListTable(ActionScheduler::store(), ActionScheduler::logger(), ActionScheduler::runner()); |
|
108 | 108 | $this->list_table->process_actions(); |
109 | 109 | } |
110 | 110 | |
@@ -121,15 +121,15 @@ discard block |
||
121 | 121 | public function maybe_check_pastdue_actions() { |
122 | 122 | |
123 | 123 | // Filter to prevent checking actions (ex: inappropriate user). |
124 | - if ( ! apply_filters( 'action_scheduler_check_pastdue_actions', current_user_can( 'manage_options' ) ) ) { |
|
124 | + if ( ! apply_filters('action_scheduler_check_pastdue_actions', current_user_can('manage_options'))) { |
|
125 | 125 | return; |
126 | 126 | } |
127 | 127 | |
128 | 128 | // Get last check transient. |
129 | - $last_check = get_transient( 'action_scheduler_last_pastdue_actions_check' ); |
|
129 | + $last_check = get_transient('action_scheduler_last_pastdue_actions_check'); |
|
130 | 130 | |
131 | 131 | // If transient exists, we're within interval, so bail. |
132 | - if ( ! empty( $last_check ) ) { |
|
132 | + if ( ! empty($last_check)) { |
|
133 | 133 | return; |
134 | 134 | } |
135 | 135 | |
@@ -145,33 +145,33 @@ discard block |
||
145 | 145 | protected function check_pastdue_actions() { |
146 | 146 | |
147 | 147 | // Set thresholds. |
148 | - $threshold_seconds = (int) apply_filters( 'action_scheduler_pastdue_actions_seconds', DAY_IN_SECONDS ); |
|
149 | - $threshhold_min = (int) apply_filters( 'action_scheduler_pastdue_actions_min', 1 ); |
|
148 | + $threshold_seconds = (int) apply_filters('action_scheduler_pastdue_actions_seconds', DAY_IN_SECONDS); |
|
149 | + $threshhold_min = (int) apply_filters('action_scheduler_pastdue_actions_min', 1); |
|
150 | 150 | |
151 | 151 | // Allow third-parties to preempt the default check logic. |
152 | - $check = apply_filters( 'action_scheduler_pastdue_actions_check_pre', null ); |
|
152 | + $check = apply_filters('action_scheduler_pastdue_actions_check_pre', null); |
|
153 | 153 | |
154 | 154 | // Scheduled actions query arguments. |
155 | 155 | $query_args = array( |
156 | - 'date' => as_get_datetime_object( time() - $threshold_seconds ), |
|
156 | + 'date' => as_get_datetime_object(time() - $threshold_seconds), |
|
157 | 157 | 'status' => ActionScheduler_Store::STATUS_PENDING, |
158 | 158 | 'per_page' => $threshhold_min, |
159 | 159 | ); |
160 | 160 | |
161 | 161 | // If no third-party preempted, run default check. |
162 | - if ( $check === null ) { |
|
162 | + if ($check === null) { |
|
163 | 163 | $store = ActionScheduler_Store::instance(); |
164 | - $num_pastdue_actions = (int) $store->query_actions( $query_args, 'count' ); |
|
164 | + $num_pastdue_actions = (int) $store->query_actions($query_args, 'count'); |
|
165 | 165 | |
166 | 166 | // Check if past-due actions count is greater than or equal to threshold. |
167 | - $check = ( $num_pastdue_actions >= $threshhold_min ); |
|
168 | - $check = (bool) apply_filters( 'action_scheduler_pastdue_actions_check', $check, $num_pastdue_actions, $threshold_seconds, $threshhold_min ); |
|
167 | + $check = ($num_pastdue_actions >= $threshhold_min); |
|
168 | + $check = (bool) apply_filters('action_scheduler_pastdue_actions_check', $check, $num_pastdue_actions, $threshold_seconds, $threshhold_min); |
|
169 | 169 | } |
170 | 170 | |
171 | 171 | // If check failed, set transient and abort. |
172 | - if ( ! boolval( $check ) ) { |
|
173 | - $interval = apply_filters( 'action_scheduler_pastdue_actions_check_interval', round( $threshold_seconds / 4 ), $threshold_seconds ); |
|
174 | - set_transient( 'action_scheduler_last_pastdue_actions_check', time(), $interval ); |
|
172 | + if ( ! boolval($check)) { |
|
173 | + $interval = apply_filters('action_scheduler_pastdue_actions_check_interval', round($threshold_seconds / 4), $threshold_seconds); |
|
174 | + set_transient('action_scheduler_last_pastdue_actions_check', time(), $interval); |
|
175 | 175 | |
176 | 176 | return; |
177 | 177 | } |
@@ -182,7 +182,7 @@ discard block |
||
182 | 182 | 'status' => 'past-due', |
183 | 183 | 'order' => 'asc', |
184 | 184 | ), |
185 | - admin_url( 'tools.php' ) |
|
185 | + admin_url('tools.php') |
|
186 | 186 | ); |
187 | 187 | |
188 | 188 | // Print notice. |
@@ -196,12 +196,12 @@ discard block |
||
196 | 196 | 'action-scheduler' |
197 | 197 | ), |
198 | 198 | $num_pastdue_actions, |
199 | - esc_attr( esc_url( $actions_url ) ) |
|
199 | + esc_attr(esc_url($actions_url)) |
|
200 | 200 | ); |
201 | 201 | echo '</p></div>'; |
202 | 202 | |
203 | 203 | // Facilitate third-parties to evaluate and print notices. |
204 | - do_action( 'action_scheduler_pastdue_actions_extra_notices', $query_args ); |
|
204 | + do_action('action_scheduler_pastdue_actions_extra_notices', $query_args); |
|
205 | 205 | } |
206 | 206 | |
207 | 207 | /** |
@@ -210,7 +210,7 @@ discard block |
||
210 | 210 | public function add_help_tabs() { |
211 | 211 | $screen = get_current_screen(); |
212 | 212 | |
213 | - if ( ! $screen || self::$screen_id != $screen->id ) { |
|
213 | + if ( ! $screen || self::$screen_id != $screen->id) { |
|
214 | 214 | return; |
215 | 215 | } |
216 | 216 | |
@@ -218,11 +218,11 @@ discard block |
||
218 | 218 | $screen->add_help_tab( |
219 | 219 | array( |
220 | 220 | 'id' => 'action_scheduler_about', |
221 | - 'title' => __( 'About', 'action-scheduler' ), |
|
221 | + 'title' => __('About', 'action-scheduler'), |
|
222 | 222 | 'content' => |
223 | - '<h2>' . sprintf( __( 'About Action Scheduler %s', 'action-scheduler' ), $as_version ) . '</h2>' . |
|
224 | - '<p>' . |
|
225 | - __( 'Action Scheduler is a scalable, traceable job queue for background processing large sets of actions. Action Scheduler works by triggering an action hook to run at some time in the future. Scheduled actions can also be scheduled to run on a recurring schedule.', 'action-scheduler' ) . |
|
223 | + '<h2>'.sprintf(__('About Action Scheduler %s', 'action-scheduler'), $as_version).'</h2>'. |
|
224 | + '<p>'. |
|
225 | + __('Action Scheduler is a scalable, traceable job queue for background processing large sets of actions. Action Scheduler works by triggering an action hook to run at some time in the future. Scheduled actions can also be scheduled to run on a recurring schedule.', 'action-scheduler'). |
|
226 | 226 | '</p>', |
227 | 227 | ) |
228 | 228 | ); |
@@ -230,17 +230,17 @@ discard block |
||
230 | 230 | $screen->add_help_tab( |
231 | 231 | array( |
232 | 232 | 'id' => 'action_scheduler_columns', |
233 | - 'title' => __( 'Columns', 'action-scheduler' ), |
|
233 | + 'title' => __('Columns', 'action-scheduler'), |
|
234 | 234 | 'content' => |
235 | - '<h2>' . __( 'Scheduled Action Columns', 'action-scheduler' ) . '</h2>' . |
|
236 | - '<ul>' . |
|
237 | - sprintf( '<li><strong>%1$s</strong>: %2$s</li>', __( 'Hook', 'action-scheduler' ), __( 'Name of the action hook that will be triggered.', 'action-scheduler' ) ) . |
|
238 | - sprintf( '<li><strong>%1$s</strong>: %2$s</li>', __( 'Status', 'action-scheduler' ), __( 'Action statuses are Pending, Complete, Canceled, Failed', 'action-scheduler' ) ) . |
|
239 | - sprintf( '<li><strong>%1$s</strong>: %2$s</li>', __( 'Arguments', 'action-scheduler' ), __( 'Optional data array passed to the action hook.', 'action-scheduler' ) ) . |
|
240 | - sprintf( '<li><strong>%1$s</strong>: %2$s</li>', __( 'Group', 'action-scheduler' ), __( 'Optional action group.', 'action-scheduler' ) ) . |
|
241 | - sprintf( '<li><strong>%1$s</strong>: %2$s</li>', __( 'Recurrence', 'action-scheduler' ), __( 'The action\'s schedule frequency.', 'action-scheduler' ) ) . |
|
242 | - sprintf( '<li><strong>%1$s</strong>: %2$s</li>', __( 'Scheduled', 'action-scheduler' ), __( 'The date/time the action is/was scheduled to run.', 'action-scheduler' ) ) . |
|
243 | - sprintf( '<li><strong>%1$s</strong>: %2$s</li>', __( 'Log', 'action-scheduler' ), __( 'Activity log for the action.', 'action-scheduler' ) ) . |
|
235 | + '<h2>'.__('Scheduled Action Columns', 'action-scheduler').'</h2>'. |
|
236 | + '<ul>'. |
|
237 | + sprintf('<li><strong>%1$s</strong>: %2$s</li>', __('Hook', 'action-scheduler'), __('Name of the action hook that will be triggered.', 'action-scheduler')). |
|
238 | + sprintf('<li><strong>%1$s</strong>: %2$s</li>', __('Status', 'action-scheduler'), __('Action statuses are Pending, Complete, Canceled, Failed', 'action-scheduler')). |
|
239 | + sprintf('<li><strong>%1$s</strong>: %2$s</li>', __('Arguments', 'action-scheduler'), __('Optional data array passed to the action hook.', 'action-scheduler')). |
|
240 | + sprintf('<li><strong>%1$s</strong>: %2$s</li>', __('Group', 'action-scheduler'), __('Optional action group.', 'action-scheduler')). |
|
241 | + sprintf('<li><strong>%1$s</strong>: %2$s</li>', __('Recurrence', 'action-scheduler'), __('The action\'s schedule frequency.', 'action-scheduler')). |
|
242 | + sprintf('<li><strong>%1$s</strong>: %2$s</li>', __('Scheduled', 'action-scheduler'), __('The date/time the action is/was scheduled to run.', 'action-scheduler')). |
|
243 | + sprintf('<li><strong>%1$s</strong>: %2$s</li>', __('Log', 'action-scheduler'), __('Activity log for the action.', 'action-scheduler')). |
|
244 | 244 | '</ul>', |
245 | 245 | ) |
246 | 246 | ); |
@@ -20,87 +20,87 @@ |
||
20 | 20 | */ |
21 | 21 | class CronExpression_DayOfMonthField extends CronExpression_AbstractField { |
22 | 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 | - $tday = str_pad( $targetDay, 2, '0', STR_PAD_LEFT ); |
|
34 | - $target = new DateTime( "$currentYear-$currentMonth-$tday" ); |
|
35 | - $currentWeekday = (int) $target->format( 'N' ); |
|
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 | + $tday = str_pad( $targetDay, 2, '0', STR_PAD_LEFT ); |
|
34 | + $target = new DateTime( "$currentYear-$currentMonth-$tday" ); |
|
35 | + $currentWeekday = (int) $target->format( 'N' ); |
|
36 | 36 | |
37 | - if ( $currentWeekday < 6 ) { |
|
38 | - return $target; |
|
39 | - } |
|
37 | + if ( $currentWeekday < 6 ) { |
|
38 | + return $target; |
|
39 | + } |
|
40 | 40 | |
41 | - $lastDayOfMonth = $target->format( 't' ); |
|
41 | + $lastDayOfMonth = $target->format( 't' ); |
|
42 | 42 | |
43 | - foreach ( array( -1, 1, -2, 2 ) as $i ) { |
|
44 | - $adjusted = $targetDay + $i; |
|
45 | - if ( $adjusted > 0 && $adjusted <= $lastDayOfMonth ) { |
|
46 | - $target->setDate( $currentYear, $currentMonth, $adjusted ); |
|
47 | - if ( $target->format( 'N' ) < 6 && $target->format( 'm' ) == $currentMonth ) { |
|
48 | - return $target; |
|
49 | - } |
|
50 | - } |
|
51 | - } |
|
52 | - } |
|
43 | + foreach ( array( -1, 1, -2, 2 ) as $i ) { |
|
44 | + $adjusted = $targetDay + $i; |
|
45 | + if ( $adjusted > 0 && $adjusted <= $lastDayOfMonth ) { |
|
46 | + $target->setDate( $currentYear, $currentMonth, $adjusted ); |
|
47 | + if ( $target->format( 'N' ) < 6 && $target->format( 'm' ) == $currentMonth ) { |
|
48 | + return $target; |
|
49 | + } |
|
50 | + } |
|
51 | + } |
|
52 | + } |
|
53 | 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 | - } |
|
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 | 62 | |
63 | - $fieldValue = $date->format( 'd' ); |
|
63 | + $fieldValue = $date->format( 'd' ); |
|
64 | 64 | |
65 | - // Check to see if this is the last day of the month |
|
66 | - if ( $value == 'L' ) { |
|
67 | - return $fieldValue == $date->format( 't' ); |
|
68 | - } |
|
65 | + // Check to see if this is the last day of the month |
|
66 | + if ( $value == 'L' ) { |
|
67 | + return $fieldValue == $date->format( 't' ); |
|
68 | + } |
|
69 | 69 | |
70 | - // Check to see if this is the nearest weekday to a particular value |
|
71 | - if ( strpos( $value, 'W' ) ) { |
|
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 | - } |
|
70 | + // Check to see if this is the nearest weekday to a particular value |
|
71 | + if ( strpos( $value, 'W' ) ) { |
|
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 | 81 | |
82 | - return $this->isSatisfied( $date->format( 'd' ), $value ); |
|
83 | - } |
|
82 | + return $this->isSatisfied( $date->format( 'd' ), $value ); |
|
83 | + } |
|
84 | 84 | |
85 | - /** |
|
86 | - * {@inheritdoc} |
|
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 | - } |
|
85 | + /** |
|
86 | + * {@inheritdoc} |
|
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 | 96 | |
97 | - return $this; |
|
98 | - } |
|
97 | + return $this; |
|
98 | + } |
|
99 | 99 | |
100 | - /** |
|
101 | - * {@inheritdoc} |
|
102 | - */ |
|
103 | - public function validate( $value ) { |
|
104 | - return (bool) preg_match( '/[\*,\/\-\?LW0-9A-Za-z]+/', $value ); |
|
105 | - } |
|
100 | + /** |
|
101 | + * {@inheritdoc} |
|
102 | + */ |
|
103 | + public function validate( $value ) { |
|
104 | + return (bool) preg_match( '/[\*,\/\-\?LW0-9A-Za-z]+/', $value ); |
|
105 | + } |
|
106 | 106 | } |
@@ -29,22 +29,22 @@ discard block |
||
29 | 29 | * |
30 | 30 | * @return DateTime Returns the nearest date |
31 | 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' ); |
|
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 | 36 | |
37 | - if ( $currentWeekday < 6 ) { |
|
37 | + if ($currentWeekday < 6) { |
|
38 | 38 | return $target; |
39 | 39 | } |
40 | 40 | |
41 | - $lastDayOfMonth = $target->format( 't' ); |
|
41 | + $lastDayOfMonth = $target->format('t'); |
|
42 | 42 | |
43 | - foreach ( array( -1, 1, -2, 2 ) as $i ) { |
|
43 | + foreach (array( -1, 1, -2, 2 ) as $i) { |
|
44 | 44 | $adjusted = $targetDay + $i; |
45 | - if ( $adjusted > 0 && $adjusted <= $lastDayOfMonth ) { |
|
46 | - $target->setDate( $currentYear, $currentMonth, $adjusted ); |
|
47 | - if ( $target->format( 'N' ) < 6 && $target->format( 'm' ) == $currentMonth ) { |
|
45 | + if ($adjusted > 0 && $adjusted <= $lastDayOfMonth) { |
|
46 | + $target->setDate($currentYear, $currentMonth, $adjusted); |
|
47 | + if ($target->format('N') < 6 && $target->format('m') == $currentMonth) { |
|
48 | 48 | return $target; |
49 | 49 | } |
50 | 50 | } |
@@ -54,44 +54,44 @@ discard block |
||
54 | 54 | /** |
55 | 55 | * {@inheritdoc} |
56 | 56 | */ |
57 | - public function isSatisfiedBy( DateTime $date, $value ) { |
|
57 | + public function isSatisfiedBy(DateTime $date, $value) { |
|
58 | 58 | // ? states that the field value is to be skipped |
59 | - if ( $value == '?' ) { |
|
59 | + if ($value == '?') { |
|
60 | 60 | return true; |
61 | 61 | } |
62 | 62 | |
63 | - $fieldValue = $date->format( 'd' ); |
|
63 | + $fieldValue = $date->format('d'); |
|
64 | 64 | |
65 | 65 | // Check to see if this is the last day of the month |
66 | - if ( $value == 'L' ) { |
|
67 | - return $fieldValue == $date->format( 't' ); |
|
66 | + if ($value == 'L') { |
|
67 | + return $fieldValue == $date->format('t'); |
|
68 | 68 | } |
69 | 69 | |
70 | 70 | // Check to see if this is the nearest weekday to a particular value |
71 | - if ( strpos( $value, 'W' ) ) { |
|
71 | + if (strpos($value, 'W')) { |
|
72 | 72 | // Parse the target day |
73 | - $targetDay = substr( $value, 0, strpos( $value, 'W' ) ); |
|
73 | + $targetDay = substr($value, 0, strpos($value, 'W')); |
|
74 | 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' ), |
|
75 | + return $date->format('j') == self::getNearestWeekday( |
|
76 | + $date->format('Y'), |
|
77 | + $date->format('m'), |
|
78 | 78 | $targetDay |
79 | - )->format( 'j' ); |
|
79 | + )->format('j'); |
|
80 | 80 | } |
81 | 81 | |
82 | - return $this->isSatisfied( $date->format( 'd' ), $value ); |
|
82 | + return $this->isSatisfied($date->format('d'), $value); |
|
83 | 83 | } |
84 | 84 | |
85 | 85 | /** |
86 | 86 | * {@inheritdoc} |
87 | 87 | */ |
88 | - public function increment( DateTime $date, $invert = false ) { |
|
89 | - if ( $invert ) { |
|
90 | - $date->modify( 'previous day' ); |
|
91 | - $date->setTime( 23, 59 ); |
|
88 | + public function increment(DateTime $date, $invert = false) { |
|
89 | + if ($invert) { |
|
90 | + $date->modify('previous day'); |
|
91 | + $date->setTime(23, 59); |
|
92 | 92 | } else { |
93 | - $date->modify( 'next day' ); |
|
94 | - $date->setTime( 0, 0 ); |
|
93 | + $date->modify('next day'); |
|
94 | + $date->setTime(0, 0); |
|
95 | 95 | } |
96 | 96 | |
97 | 97 | return $this; |
@@ -100,7 +100,7 @@ discard block |
||
100 | 100 | /** |
101 | 101 | * {@inheritdoc} |
102 | 102 | */ |
103 | - public function validate( $value ) { |
|
104 | - return (bool) preg_match( '/[\*,\/\-\?LW0-9A-Za-z]+/', $value ); |
|
103 | + public function validate($value) { |
|
104 | + return (bool) preg_match('/[\*,\/\-\?LW0-9A-Za-z]+/', $value); |
|
105 | 105 | } |
106 | 106 | } |
@@ -7,34 +7,34 @@ |
||
7 | 7 | */ |
8 | 8 | class CronExpression_YearField extends CronExpression_AbstractField { |
9 | 9 | |
10 | - /** |
|
11 | - * {@inheritdoc} |
|
12 | - */ |
|
13 | - public function isSatisfiedBy( DateTime $date, $value ) { |
|
14 | - return $this->isSatisfied( $date->format( 'Y' ), $value ); |
|
15 | - } |
|
10 | + /** |
|
11 | + * {@inheritdoc} |
|
12 | + */ |
|
13 | + public function isSatisfiedBy( DateTime $date, $value ) { |
|
14 | + return $this->isSatisfied( $date->format( 'Y' ), $value ); |
|
15 | + } |
|
16 | 16 | |
17 | - /** |
|
18 | - * {@inheritdoc} |
|
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 | - } |
|
17 | + /** |
|
18 | + * {@inheritdoc} |
|
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 | 30 | |
31 | - return $this; |
|
32 | - } |
|
31 | + return $this; |
|
32 | + } |
|
33 | 33 | |
34 | - /** |
|
35 | - * {@inheritdoc} |
|
36 | - */ |
|
37 | - public function validate( $value ) { |
|
38 | - return (bool) preg_match( '/[\*,\/\-0-9]+/', $value ); |
|
39 | - } |
|
34 | + /** |
|
35 | + * {@inheritdoc} |
|
36 | + */ |
|
37 | + public function validate( $value ) { |
|
38 | + return (bool) preg_match( '/[\*,\/\-0-9]+/', $value ); |
|
39 | + } |
|
40 | 40 | } |
@@ -10,22 +10,22 @@ discard block |
||
10 | 10 | /** |
11 | 11 | * {@inheritdoc} |
12 | 12 | */ |
13 | - public function isSatisfiedBy( DateTime $date, $value ) { |
|
14 | - return $this->isSatisfied( $date->format( 'Y' ), $value ); |
|
13 | + public function isSatisfiedBy(DateTime $date, $value) { |
|
14 | + return $this->isSatisfied($date->format('Y'), $value); |
|
15 | 15 | } |
16 | 16 | |
17 | 17 | /** |
18 | 18 | * {@inheritdoc} |
19 | 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 ); |
|
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 | 25 | } else { |
26 | - $date->modify( '+1 year' ); |
|
27 | - $date->setDate( $date->format( 'Y' ), 1, 1 ); |
|
28 | - $date->setTime( 0, 0, 0 ); |
|
26 | + $date->modify('+1 year'); |
|
27 | + $date->setDate($date->format('Y'), 1, 1); |
|
28 | + $date->setTime(0, 0, 0); |
|
29 | 29 | } |
30 | 30 | |
31 | 31 | return $this; |
@@ -34,7 +34,7 @@ discard block |
||
34 | 34 | /** |
35 | 35 | * {@inheritdoc} |
36 | 36 | */ |
37 | - public function validate( $value ) { |
|
38 | - return (bool) preg_match( '/[\*,\/\-0-9]+/', $value ); |
|
37 | + public function validate($value) { |
|
38 | + return (bool) preg_match('/[\*,\/\-0-9]+/', $value); |
|
39 | 39 | } |
40 | 40 | } |