Diff: STRATO-apps/wordpress_03/app/wp-includes/cron.php

Keine Baseline-Datei – Diff nur gegen leer.
Zur Liste
1 -
1 + <?php
2 + /**
3 + * WordPress Cron API
4 + *
5 + * @package WordPress
6 + */
7 +
8 + /**
9 + * Schedules an event to run only once.
10 + *
11 + * Schedules a hook which will be triggered by WordPress at the specified UTC time.
12 + * The action will trigger when someone visits your WordPress site if the scheduled
13 + * time has passed.
14 + *
15 + * Note that scheduling an event to occur within 10 minutes of an existing event
16 + * with the same action hook will be ignored unless you pass unique `$args` values
17 + * for each scheduled event.
18 + *
19 + * Use wp_next_scheduled() to prevent duplicate events.
20 + *
21 + * Use wp_schedule_event() to schedule a recurring event.
22 + *
23 + * @since 2.1.0
24 + * @since 5.1.0 Return value modified to boolean indicating success or failure,
25 + * {@see 'pre_schedule_event'} filter added to short-circuit the function.
26 + * @since 5.7.0 The `$wp_error` parameter was added.
27 + *
28 + * @link https://developer.wordpress.org/reference/functions/wp_schedule_single_event/
29 + *
30 + * @param int $timestamp Unix timestamp (UTC) for when to next run the event.
31 + * @param string $hook Action hook to execute when the event is run.
32 + * @param array $args Optional. Array containing arguments to pass to the
33 + * hook's callback function. Each value in the array
34 + * is passed to the callback as an individual parameter.
35 + * The array keys are ignored. Default empty array.
36 + * @param bool $wp_error Optional. Whether to return a WP_Error on failure. Default false.
37 + * @return bool|WP_Error True if event successfully scheduled. False or WP_Error on failure.
38 + */
39 + function wp_schedule_single_event( $timestamp, $hook, $args = array(), $wp_error = false ) {
40 + // Make sure timestamp is a positive integer.
41 + if ( ! is_numeric( $timestamp ) || $timestamp <= 0 ) {
42 + if ( $wp_error ) {
43 + return new WP_Error(
44 + 'invalid_timestamp',
45 + __( 'Event timestamp must be a valid Unix timestamp.' )
46 + );
47 + }
48 +
49 + return false;
50 + }
51 +
52 + $event = (object) array(
53 + 'hook' => $hook,
54 + 'timestamp' => $timestamp,
55 + 'schedule' => false,
56 + 'args' => $args,
57 + );
58 +
59 + /**
60 + * Filter to override scheduling an event.
61 + *
62 + * Returning a non-null value will short-circuit adding the event to the
63 + * cron array, causing the function to return the filtered value instead.
64 + *
65 + * Both single events and recurring events are passed through this filter;
66 + * single events have `$event->schedule` as false, whereas recurring events
67 + * have this set to a recurrence from wp_get_schedules(). Recurring
68 + * events also have the integer recurrence interval set as `$event->interval`.
69 + *
70 + * For plugins replacing wp-cron, it is recommended you check for an
71 + * identical event within ten minutes and apply the {@see 'schedule_event'}
72 + * filter to check if another plugin has disallowed the event before scheduling.
73 + *
74 + * Return true if the event was scheduled, false or a WP_Error if not.
75 + *
76 + * @since 5.1.0
77 + * @since 5.7.0 The `$wp_error` parameter was added, and a `WP_Error` object can now be returned.
78 + *
79 + * @param null|bool|WP_Error $result The value to return instead. Default null to continue adding the event.
80 + * @param object $event {
81 + * An object containing an event's data.
82 + *
83 + * @type string $hook Action hook to execute when the event is run.
84 + * @type int $timestamp Unix timestamp (UTC) for when to next run the event.
85 + * @type string|false $schedule How often the event should subsequently recur.
86 + * @type array $args Array containing each separate argument to pass to the hook's callback function.
87 + * @type int $interval Optional. The interval time in seconds for the schedule. Only present for recurring events.
88 + * }
89 + * @param bool $wp_error Whether to return a WP_Error on failure.
90 + */
91 + $pre = apply_filters( 'pre_schedule_event', null, $event, $wp_error );
92 +
93 + if ( null !== $pre ) {
94 + if ( $wp_error && false === $pre ) {
95 + return new WP_Error(
96 + 'pre_schedule_event_false',
97 + __( 'A plugin prevented the event from being scheduled.' )
98 + );
99 + }
100 +
101 + if ( ! $wp_error && is_wp_error( $pre ) ) {
102 + return false;
103 + }
104 +
105 + return $pre;
106 + }
107 +
108 + /*
109 + * Check for a duplicated event.
110 + *
111 + * Don't schedule an event if there's already an identical event
112 + * within 10 minutes.
113 + *
114 + * When scheduling events within ten minutes of the current time,
115 + * all past identical events are considered duplicates.
116 + *
117 + * When scheduling an event with a past timestamp (ie, before the
118 + * current time) all events scheduled within the next ten minutes
119 + * are considered duplicates.
120 + */
121 + $crons = _get_cron_array();
122 +
123 + $key = md5( serialize( $event->args ) );
124 + $duplicate = false;
125 +
126 + if ( $event->timestamp < time() + 10 * MINUTE_IN_SECONDS ) {
127 + $min_timestamp = 0;
128 + } else {
129 + $min_timestamp = $event->timestamp - 10 * MINUTE_IN_SECONDS;
130 + }
131 +
132 + if ( $event->timestamp < time() ) {
133 + $max_timestamp = time() + 10 * MINUTE_IN_SECONDS;
134 + } else {
135 + $max_timestamp = $event->timestamp + 10 * MINUTE_IN_SECONDS;
136 + }
137 +
138 + foreach ( $crons as $event_timestamp => $cron ) {
139 + if ( $event_timestamp < $min_timestamp ) {
140 + continue;
141 + }
142 +
143 + if ( $event_timestamp > $max_timestamp ) {
144 + break;
145 + }
146 +
147 + if ( isset( $cron[ $event->hook ][ $key ] ) ) {
148 + $duplicate = true;
149 + break;
150 + }
151 + }
152 +
153 + if ( $duplicate ) {
154 + if ( $wp_error ) {
155 + return new WP_Error(
156 + 'duplicate_event',
157 + __( 'A duplicate event already exists.' )
158 + );
159 + }
160 +
161 + return false;
162 + }
163 +
164 + /**
165 + * Modify an event before it is scheduled.
166 + *
167 + * @since 3.1.0
168 + *
169 + * @param object|false $event {
170 + * An object containing an event's data, or boolean false to prevent the event from being scheduled.
171 + *
172 + * @type string $hook Action hook to execute when the event is run.
173 + * @type int $timestamp Unix timestamp (UTC) for when to next run the event.
174 + * @type string|false $schedule How often the event should subsequently recur.
175 + * @type array $args Array containing each separate argument to pass to the hook's callback function.
176 + * @type int $interval Optional. The interval time in seconds for the schedule. Only present for recurring events.
177 + * }
178 + */
179 + $event = apply_filters( 'schedule_event', $event );
180 +
181 + // A plugin disallowed this event.
182 + if ( ! $event ) {
183 + if ( $wp_error ) {
184 + return new WP_Error(
185 + 'schedule_event_false',
186 + __( 'A plugin disallowed this event.' )
187 + );
188 + }
189 +
190 + return false;
191 + }
192 +
193 + $crons[ $event->timestamp ][ $event->hook ][ $key ] = array(
194 + 'schedule' => $event->schedule,
195 + 'args' => $event->args,
196 + );
197 + uksort( $crons, 'strnatcasecmp' );
198 +
199 + return _set_cron_array( $crons, $wp_error );
200 + }
201 +
202 + /**
203 + * Schedules a recurring event.
204 + *
205 + * Schedules a hook which will be triggered by WordPress at the specified interval.
206 + * The action will trigger when someone visits your WordPress site if the scheduled
207 + * time has passed.
208 + *
209 + * Valid values for the recurrence are 'hourly', 'twicedaily', 'daily', and 'weekly'.
210 + * These can be extended using the {@see 'cron_schedules'} filter in wp_get_schedules().
211 + *
212 + * Use wp_next_scheduled() to prevent duplicate events.
213 + *
214 + * Use wp_schedule_single_event() to schedule a non-recurring event.
215 + *
216 + * @since 2.1.0
217 + * @since 5.1.0 Return value modified to boolean indicating success or failure,
218 + * {@see 'pre_schedule_event'} filter added to short-circuit the function.
219 + * @since 5.7.0 The `$wp_error` parameter was added.
220 + *
221 + * @link https://developer.wordpress.org/reference/functions/wp_schedule_event/
222 + *
223 + * @param int $timestamp Unix timestamp (UTC) for when to next run the event.
224 + * @param string $recurrence How often the event should subsequently recur.
225 + * See wp_get_schedules() for accepted values.
226 + * @param string $hook Action hook to execute when the event is run.
227 + * @param array $args Optional. Array containing arguments to pass to the
228 + * hook's callback function. Each value in the array
229 + * is passed to the callback as an individual parameter.
230 + * The array keys are ignored. Default empty array.
231 + * @param bool $wp_error Optional. Whether to return a WP_Error on failure. Default false.
232 + * @return bool|WP_Error True if event successfully scheduled. False or WP_Error on failure.
233 + */
234 + function wp_schedule_event( $timestamp, $recurrence, $hook, $args = array(), $wp_error = false ) {
235 + // Make sure timestamp is a positive integer.
236 + if ( ! is_numeric( $timestamp ) || $timestamp <= 0 ) {
237 + if ( $wp_error ) {
238 + return new WP_Error(
239 + 'invalid_timestamp',
240 + __( 'Event timestamp must be a valid Unix timestamp.' )
241 + );
242 + }
243 +
244 + return false;
245 + }
246 +
247 + $schedules = wp_get_schedules();
248 +
249 + if ( ! isset( $schedules[ $recurrence ] ) ) {
250 + if ( $wp_error ) {
251 + return new WP_Error(
252 + 'invalid_schedule',
253 + __( 'Event schedule does not exist.' )
254 + );
255 + }
256 +
257 + return false;
258 + }
259 +
260 + $event = (object) array(
261 + 'hook' => $hook,
262 + 'timestamp' => $timestamp,
263 + 'schedule' => $recurrence,
264 + 'args' => $args,
265 + 'interval' => $schedules[ $recurrence ]['interval'],
266 + );
267 +
268 + /** This filter is documented in wp-includes/cron.php */
269 + $pre = apply_filters( 'pre_schedule_event', null, $event, $wp_error );
270 +
271 + if ( null !== $pre ) {
272 + if ( $wp_error && false === $pre ) {
273 + return new WP_Error(
274 + 'pre_schedule_event_false',
275 + __( 'A plugin prevented the event from being scheduled.' )
276 + );
277 + }
278 +
279 + if ( ! $wp_error && is_wp_error( $pre ) ) {
280 + return false;
281 + }
282 +
283 + return $pre;
284 + }
285 +
286 + /** This filter is documented in wp-includes/cron.php */
287 + $event = apply_filters( 'schedule_event', $event );
288 +
289 + // A plugin disallowed this event.
290 + if ( ! $event ) {
291 + if ( $wp_error ) {
292 + return new WP_Error(
293 + 'schedule_event_false',
294 + __( 'A plugin disallowed this event.' )
295 + );
296 + }
297 +
298 + return false;
299 + }
300 +
301 + $key = md5( serialize( $event->args ) );
302 +
303 + $crons = _get_cron_array();
304 +
305 + $crons[ $event->timestamp ][ $event->hook ][ $key ] = array(
306 + 'schedule' => $event->schedule,
307 + 'args' => $event->args,
308 + 'interval' => $event->interval,
309 + );
310 + uksort( $crons, 'strnatcasecmp' );
311 +
312 + return _set_cron_array( $crons, $wp_error );
313 + }
314 +
315 + /**
316 + * Reschedules a recurring event.
317 + *
318 + * Mainly for internal use, this takes the Unix timestamp (UTC) of a previously run
319 + * recurring event and reschedules it for its next run.
320 + *
321 + * To change upcoming scheduled events, use wp_schedule_event() to
322 + * change the recurrence frequency.
323 + *
324 + * @since 2.1.0
325 + * @since 5.1.0 Return value modified to boolean indicating success or failure,
326 + * {@see 'pre_reschedule_event'} filter added to short-circuit the function.
327 + * @since 5.7.0 The `$wp_error` parameter was added.
328 + *
329 + * @param int $timestamp Unix timestamp (UTC) for when the event was scheduled.
330 + * @param string $recurrence How often the event should subsequently recur.
331 + * See wp_get_schedules() for accepted values.
332 + * @param string $hook Action hook to execute when the event is run.
333 + * @param array $args Optional. Array containing arguments to pass to the
334 + * hook's callback function. Each value in the array
335 + * is passed to the callback as an individual parameter.
336 + * The array keys are ignored. Default empty array.
337 + * @param bool $wp_error Optional. Whether to return a WP_Error on failure. Default false.
338 + * @return bool|WP_Error True if event successfully rescheduled. False or WP_Error on failure.
339 + */
340 + function wp_reschedule_event( $timestamp, $recurrence, $hook, $args = array(), $wp_error = false ) {
341 + // Make sure timestamp is a positive integer.
342 + if ( ! is_numeric( $timestamp ) || $timestamp <= 0 ) {
343 + if ( $wp_error ) {
344 + return new WP_Error(
345 + 'invalid_timestamp',
346 + __( 'Event timestamp must be a valid Unix timestamp.' )
347 + );
348 + }
349 +
350 + return false;
351 + }
352 +
353 + $schedules = wp_get_schedules();
354 + $interval = 0;
355 +
356 + // First we try to get the interval from the schedule.
357 + if ( isset( $schedules[ $recurrence ] ) ) {
358 + $interval = $schedules[ $recurrence ]['interval'];
359 + }
360 +
361 + // Now we try to get it from the saved interval in case the schedule disappears.
362 + if ( 0 === $interval ) {
363 + $scheduled_event = wp_get_scheduled_event( $hook, $args, $timestamp );
364 +
365 + if ( $scheduled_event && isset( $scheduled_event->interval ) ) {
366 + $interval = $scheduled_event->interval;
367 + }
368 + }
369 +
370 + $event = (object) array(
371 + 'hook' => $hook,
372 + 'timestamp' => $timestamp,
373 + 'schedule' => $recurrence,
374 + 'args' => $args,
375 + 'interval' => $interval,
376 + );
377 +
378 + /**
379 + * Filter to override rescheduling of a recurring event.
380 + *
381 + * Returning a non-null value will short-circuit the normal rescheduling
382 + * process, causing the function to return the filtered value instead.
383 + *
384 + * For plugins replacing wp-cron, return true if the event was successfully
385 + * rescheduled, false or a WP_Error if not.
386 + *
387 + * @since 5.1.0
388 + * @since 5.7.0 The `$wp_error` parameter was added, and a `WP_Error` object can now be returned.
389 + *
390 + * @param null|bool|WP_Error $pre Value to return instead. Default null to continue adding the event.
391 + * @param object $event {
392 + * An object containing an event's data.
393 + *
394 + * @type string $hook Action hook to execute when the event is run.
395 + * @type int $timestamp Unix timestamp (UTC) for when to next run the event.
396 + * @type string $schedule How often the event should subsequently recur.
397 + * @type array $args Array containing each separate argument to pass to the hook's callback function.
398 + * @type int $interval The interval time in seconds for the schedule.
399 + * }
400 + * @param bool $wp_error Whether to return a WP_Error on failure.
401 + */
402 + $pre = apply_filters( 'pre_reschedule_event', null, $event, $wp_error );
403 +
404 + if ( null !== $pre ) {
405 + if ( $wp_error && false === $pre ) {
406 + return new WP_Error(
407 + 'pre_reschedule_event_false',
408 + __( 'A plugin prevented the event from being rescheduled.' )
409 + );
410 + }
411 +
412 + if ( ! $wp_error && is_wp_error( $pre ) ) {
413 + return false;
414 + }
415 +
416 + return $pre;
417 + }
418 +
419 + // Now we assume something is wrong and fail to schedule.
420 + if ( 0 === $interval ) {
421 + if ( $wp_error ) {
422 + return new WP_Error(
423 + 'invalid_schedule',
424 + __( 'Event schedule does not exist.' )
425 + );
426 + }
427 +
428 + return false;
429 + }
430 +
431 + $now = time();
432 +
433 + if ( $timestamp >= $now ) {
434 + $timestamp = $now + $interval;
435 + } else {
436 + $timestamp = $now + ( $interval - ( ( $now - $timestamp ) % $interval ) );
437 + }
438 +
439 + return wp_schedule_event( $timestamp, $recurrence, $hook, $args, $wp_error );
440 + }
441 +
442 + /**
443 + * Unschedules a previously scheduled event.
444 + *
445 + * The `$timestamp` and `$hook` parameters are required so that the event can be
446 + * identified.
447 + *
448 + * @since 2.1.0
449 + * @since 5.1.0 Return value modified to boolean indicating success or failure,
450 + * {@see 'pre_unschedule_event'} filter added to short-circuit the function.
451 + * @since 5.7.0 The `$wp_error` parameter was added.
452 + *
453 + * @param int $timestamp Unix timestamp (UTC) of the event.
454 + * @param string $hook Action hook of the event.
455 + * @param array $args Optional. Array containing each separate argument to pass to the hook's callback function.
456 + * Although not passed to a callback, these arguments are used to uniquely identify the
457 + * event, so they should be the same as those used when originally scheduling the event.
458 + * Default empty array.
459 + * @param bool $wp_error Optional. Whether to return a WP_Error on failure. Default false.
460 + * @return bool|WP_Error True if event successfully unscheduled. False or WP_Error on failure.
461 + */
462 + function wp_unschedule_event( $timestamp, $hook, $args = array(), $wp_error = false ) {
463 + // Make sure timestamp is a positive integer.
464 + if ( ! is_numeric( $timestamp ) || $timestamp <= 0 ) {
465 + if ( $wp_error ) {
466 + return new WP_Error(
467 + 'invalid_timestamp',
468 + __( 'Event timestamp must be a valid Unix timestamp.' )
469 + );
470 + }
471 +
472 + return false;
473 + }
474 +
475 + /**
476 + * Filter to override unscheduling of events.
477 + *
478 + * Returning a non-null value will short-circuit the normal unscheduling
479 + * process, causing the function to return the filtered value instead.
480 + *
481 + * For plugins replacing wp-cron, return true if the event was successfully
482 + * unscheduled, false or a WP_Error if not.
483 + *
484 + * @since 5.1.0
485 + * @since 5.7.0 The `$wp_error` parameter was added, and a `WP_Error` object can now be returned.
486 + *
487 + * @param null|bool|WP_Error $pre Value to return instead. Default null to continue unscheduling the event.
488 + * @param int $timestamp Unix timestamp (UTC) for when to run the event.
489 + * @param string $hook Action hook, the execution of which will be unscheduled.
490 + * @param array $args Arguments to pass to the hook's callback function.
491 + * @param bool $wp_error Whether to return a WP_Error on failure.
492 + */
493 + $pre = apply_filters( 'pre_unschedule_event', null, $timestamp, $hook, $args, $wp_error );
494 +
495 + if ( null !== $pre ) {
496 + if ( $wp_error && false === $pre ) {
497 + return new WP_Error(
498 + 'pre_unschedule_event_false',
499 + __( 'A plugin prevented the event from being unscheduled.' )
500 + );
501 + }
502 +
503 + if ( ! $wp_error && is_wp_error( $pre ) ) {
504 + return false;
505 + }
506 +
507 + return $pre;
508 + }
509 +
510 + $crons = _get_cron_array();
511 + $key = md5( serialize( $args ) );
512 +
513 + unset( $crons[ $timestamp ][ $hook ][ $key ] );
514 +
515 + if ( empty( $crons[ $timestamp ][ $hook ] ) ) {
516 + unset( $crons[ $timestamp ][ $hook ] );
517 + }
518 +
519 + if ( empty( $crons[ $timestamp ] ) ) {
520 + unset( $crons[ $timestamp ] );
521 + }
522 +
523 + return _set_cron_array( $crons, $wp_error );
524 + }
525 +
526 + /**
527 + * Unschedules all events attached to the hook with the specified arguments.
528 + *
529 + * Warning: This function may return boolean false, but may also return a non-boolean
530 + * value which evaluates to false. For information about casting to booleans see the
531 + * {@link https://www.php.net/manual/en/language.types.boolean.php PHP documentation}. Use
532 + * the `===` operator for testing the return value of this function.
533 + *
534 + * @since 2.1.0
535 + * @since 5.1.0 Return value modified to indicate success or failure,
536 + * {@see 'pre_clear_scheduled_hook'} filter added to short-circuit the function.
537 + * @since 5.7.0 The `$wp_error` parameter was added.
538 + *
539 + * @param string $hook Action hook, the execution of which will be unscheduled.
540 + * @param array $args Optional. Array containing each separate argument to pass to the hook's callback function.
541 + * Although not passed to a callback, these arguments are used to uniquely identify the
542 + * event, so they should be the same as those used when originally scheduling the event.
543 + * Default empty array.
544 + * @param bool $wp_error Optional. Whether to return a WP_Error on failure. Default false.
545 + * @return int|false|WP_Error On success an integer indicating number of events unscheduled (0 indicates no
546 + * events were registered with the hook and arguments combination), false or WP_Error
547 + * if unscheduling one or more events fail.
548 + */
549 + function wp_clear_scheduled_hook( $hook, $args = array(), $wp_error = false ) {
550 + /*
551 + * Backward compatibility.
552 + * Previously, this function took the arguments as discrete vars rather than an array like the rest of the API.
553 + */
554 + if ( ! is_array( $args ) ) {
555 + _deprecated_argument(
556 + __FUNCTION__,
557 + '3.0.0',
558 + __( 'This argument has changed to an array to match the behavior of the other cron functions.' )
559 + );
560 +
561 + $args = array_slice( func_get_args(), 1 ); // phpcs:ignore PHPCompatibility.FunctionUse.ArgumentFunctionsReportCurrentValue.NeedsInspection
562 + $wp_error = false;
563 + }
564 +
565 + /**
566 + * Filter to override clearing a scheduled hook.
567 + *
568 + * Returning a non-null value will short-circuit the normal unscheduling
569 + * process, causing the function to return the filtered value instead.
570 + *
571 + * For plugins replacing wp-cron, return the number of events successfully
572 + * unscheduled (zero if no events were registered with the hook) or false
573 + * or a WP_Error if unscheduling one or more events fails.
574 + *
575 + * @since 5.1.0
576 + * @since 5.7.0 The `$wp_error` parameter was added, and a `WP_Error` object can now be returned.
577 + *
578 + * @param null|int|false|WP_Error $pre Value to return instead. Default null to continue unscheduling the event.
579 + * @param string $hook Action hook, the execution of which will be unscheduled.
580 + * @param array $args Arguments to pass to the hook's callback function.
581 + * @param bool $wp_error Whether to return a WP_Error on failure.
582 + */
583 + $pre = apply_filters( 'pre_clear_scheduled_hook', null, $hook, $args, $wp_error );
584 +
585 + if ( null !== $pre ) {
586 + if ( $wp_error && false === $pre ) {
587 + return new WP_Error(
588 + 'pre_clear_scheduled_hook_false',
589 + __( 'A plugin prevented the hook from being cleared.' )
590 + );
591 + }
592 +
593 + if ( ! $wp_error && is_wp_error( $pre ) ) {
594 + return false;
595 + }
596 +
597 + return $pre;
598 + }
599 +
600 + /*
601 + * This logic duplicates wp_next_scheduled().
602 + * It's required due to a scenario where wp_unschedule_event() fails due to update_option() failing,
603 + * and, wp_next_scheduled() returns the same schedule in an infinite loop.
604 + */
605 + $crons = _get_cron_array();
606 + if ( empty( $crons ) ) {
607 + return 0;
608 + }
609 +
610 + $results = array();
611 + $key = md5( serialize( $args ) );
612 +
613 + foreach ( $crons as $timestamp => $cron ) {
614 + if ( isset( $cron[ $hook ][ $key ] ) ) {
615 + $results[] = wp_unschedule_event( $timestamp, $hook, $args, true );
616 + }
617 + }
618 +
619 + $errors = array_filter( $results, 'is_wp_error' );
620 + $error = new WP_Error();
621 +
622 + if ( $errors ) {
623 + if ( $wp_error ) {
624 + array_walk( $errors, array( $error, 'merge_from' ) );
625 +
626 + return $error;
627 + }
628 +
629 + return false;
630 + }
631 +
632 + return count( $results );
633 + }
634 +
635 + /**
636 + * Unschedules all events attached to the hook.
637 + *
638 + * Can be useful for plugins when deactivating to clean up the cron queue.
639 + *
640 + * Warning: This function may return boolean false, but may also return a non-boolean
641 + * value which evaluates to false. For information about casting to booleans see the
642 + * {@link https://www.php.net/manual/en/language.types.boolean.php PHP documentation}. Use
643 + * the `===` operator for testing the return value of this function.
644 + *
645 + * @since 4.9.0
646 + * @since 5.1.0 Return value added to indicate success or failure.
647 + * @since 5.7.0 The `$wp_error` parameter was added.
648 + *
649 + * @param string $hook Action hook, the execution of which will be unscheduled.
650 + * @param bool $wp_error Optional. Whether to return a WP_Error on failure. Default false.
651 + * @return int|false|WP_Error On success an integer indicating number of events unscheduled (0 indicates no
652 + * events were registered on the hook), false or WP_Error if unscheduling fails.
653 + */
654 + function wp_unschedule_hook( $hook, $wp_error = false ) {
655 + /**
656 + * Filter to override clearing all events attached to the hook.
657 + *
658 + * Returning a non-null value will short-circuit the normal unscheduling
659 + * process, causing the function to return the filtered value instead.
660 + *
661 + * For plugins replacing wp-cron, return the number of events successfully
662 + * unscheduled (zero if no events were registered with the hook). If unscheduling
663 + * one or more events fails then return either a WP_Error object or false depending
664 + * on the value of the `$wp_error` parameter.
665 + *
666 + * @since 5.1.0
667 + * @since 5.7.0 The `$wp_error` parameter was added, and a `WP_Error` object can now be returned.
668 + *
669 + * @param null|int|false|WP_Error $pre Value to return instead. Default null to continue unscheduling the hook.
670 + * @param string $hook Action hook, the execution of which will be unscheduled.
671 + * @param bool $wp_error Whether to return a WP_Error on failure.
672 + */
673 + $pre = apply_filters( 'pre_unschedule_hook', null, $hook, $wp_error );
674 +
675 + if ( null !== $pre ) {
676 + if ( $wp_error && false === $pre ) {
677 + return new WP_Error(
678 + 'pre_unschedule_hook_false',
679 + __( 'A plugin prevented the hook from being cleared.' )
680 + );
681 + }
682 +
683 + if ( ! $wp_error && is_wp_error( $pre ) ) {
684 + return false;
685 + }
686 +
687 + return $pre;
688 + }
689 +
690 + $crons = _get_cron_array();
691 + if ( empty( $crons ) ) {
692 + return 0;
693 + }
694 +
695 + $results = array();
696 +
697 + foreach ( $crons as $timestamp => $args ) {
698 + if ( ! empty( $crons[ $timestamp ][ $hook ] ) ) {
699 + $results[] = count( $crons[ $timestamp ][ $hook ] );
700 + }
701 +
702 + unset( $crons[ $timestamp ][ $hook ] );
703 +
704 + if ( empty( $crons[ $timestamp ] ) ) {
705 + unset( $crons[ $timestamp ] );
706 + }
707 + }
708 +
709 + /*
710 + * If the results are empty (zero events to unschedule), no attempt
711 + * to update the cron array is required.
712 + */
713 + if ( empty( $results ) ) {
714 + return 0;
715 + }
716 +
717 + $set = _set_cron_array( $crons, $wp_error );
718 +
719 + if ( true === $set ) {
720 + return array_sum( $results );
721 + }
722 +
723 + return $set;
724 + }
725 +
726 + /**
727 + * Retrieves a scheduled event.
728 + *
729 + * Retrieves the full event object for a given event, if no timestamp is specified the next
730 + * scheduled event is returned.
731 + *
732 + * @since 5.1.0
733 + *
734 + * @param string $hook Action hook of the event.
735 + * @param array $args Optional. Array containing each separate argument to pass to the hook's callback function.
736 + * Although not passed to a callback, these arguments are used to uniquely identify the
737 + * event, so they should be the same as those used when originally scheduling the event.
738 + * Default empty array.
739 + * @param int|null $timestamp Optional. Unix timestamp (UTC) of the event. If not specified, the next scheduled event
740 + * is returned. Default null.
741 + * @return object|false {
742 + * The event object. False if the event does not exist.
743 + *
744 + * @type string $hook Action hook to execute when the event is run.
745 + * @type int $timestamp Unix timestamp (UTC) for when to next run the event.
746 + * @type string|false $schedule How often the event should subsequently recur.
747 + * @type array $args Array containing each separate argument to pass to the hook's callback function.
748 + * @type int $interval Optional. The interval time in seconds for the schedule. Only present for recurring events.
749 + * }
750 + */
751 + function wp_get_scheduled_event( $hook, $args = array(), $timestamp = null ) {
752 + /**
753 + * Filter to override retrieving a scheduled event.
754 + *
755 + * Returning a non-null value will short-circuit the normal process,
756 + * returning the filtered value instead.
757 + *
758 + * Return false if the event does not exist, otherwise an event object
759 + * should be returned.
760 + *
761 + * @since 5.1.0
762 + *
763 + * @param null|false|object $pre Value to return instead. Default null to continue retrieving the event.
764 + * @param string $hook Action hook of the event.
765 + * @param array $args Array containing each separate argument to pass to the hook's callback function.
766 + * Although not passed to a callback, these arguments are used to uniquely identify
767 + * the event.
768 + * @param int|null $timestamp Unix timestamp (UTC) of the event. Null to retrieve next scheduled event.
769 + */
770 + $pre = apply_filters( 'pre_get_scheduled_event', null, $hook, $args, $timestamp );
771 +
772 + if ( null !== $pre ) {
773 + return $pre;
774 + }
775 +
776 + if ( null !== $timestamp && ! is_numeric( $timestamp ) ) {
777 + return false;
778 + }
779 +
780 + $crons = _get_cron_array();
781 + if ( empty( $crons ) ) {
782 + return false;
783 + }
784 +
785 + $key = md5( serialize( $args ) );
786 +
787 + if ( ! $timestamp ) {
788 + // Get next event.
789 + $next = false;
790 + foreach ( $crons as $timestamp => $cron ) {
791 + if ( isset( $cron[ $hook ][ $key ] ) ) {
792 + $next = $timestamp;
793 + break;
794 + }
795 + }
796 +
797 + if ( ! $next ) {
798 + return false;
799 + }
800 +
801 + $timestamp = $next;
802 + } elseif ( ! isset( $crons[ $timestamp ][ $hook ][ $key ] ) ) {
803 + return false;
804 + }
805 +
806 + $event = (object) array(
807 + 'hook' => $hook,
808 + 'timestamp' => $timestamp,
809 + 'schedule' => $crons[ $timestamp ][ $hook ][ $key ]['schedule'],
810 + 'args' => $args,
811 + );
812 +
813 + if ( isset( $crons[ $timestamp ][ $hook ][ $key ]['interval'] ) ) {
814 + $event->interval = $crons[ $timestamp ][ $hook ][ $key ]['interval'];
815 + }
816 +
817 + return $event;
818 + }
819 +
820 + /**
821 + * Retrieves the timestamp of the next scheduled event for the given hook.
822 + *
823 + * @since 2.1.0
824 + *
825 + * @param string $hook Action hook of the event.
826 + * @param array $args Optional. Array containing each separate argument to pass to the hook's callback function.
827 + * Although not passed to a callback, these arguments are used to uniquely identify the
828 + * event, so they should be the same as those used when originally scheduling the event.
829 + * Default empty array.
830 + * @return int|false The Unix timestamp (UTC) of the next time the event will occur. False if the event doesn't exist.
831 + */
832 + function wp_next_scheduled( $hook, $args = array() ) {
833 + $next_event = wp_get_scheduled_event( $hook, $args );
834 +
835 + if ( ! $next_event ) {
836 + return false;
837 + }
838 +
839 + /**
840 + * Filters the timestamp of the next scheduled event for the given hook.
841 + *
842 + * @since 6.8.0
843 + *
844 + * @param int $timestamp Unix timestamp (UTC) for when to next run the event.
845 + * @param object $next_event {
846 + * An object containing an event's data.
847 + *
848 + * @type string $hook Action hook of the event.
849 + * @type int $timestamp Unix timestamp (UTC) for when to next run the event.
850 + * @type string $schedule How often the event should subsequently recur.
851 + * @type array $args Array containing each separate argument to pass to the hook
852 + * callback function.
853 + * @type int $interval Optional. The interval time in seconds for the schedule. Only
854 + * present for recurring events.
855 + * }
856 + * @param array $args Array containing each separate argument to pass to the hook
857 + * callback function.
858 + */
859 + return apply_filters( 'wp_next_scheduled', $next_event->timestamp, $next_event, $hook, $args );
860 + }
861 +
862 + /**
863 + * Sends a request to run cron through HTTP request that doesn't halt page loading.
864 + *
865 + * @since 2.1.0
866 + * @since 5.1.0 Return values added.
867 + *
868 + * @param int $gmt_time Optional. Unix timestamp (UTC). Default 0 (current time is used).
869 + * @return bool True if spawned, false if no events spawned.
870 + */
871 + function spawn_cron( $gmt_time = 0 ) {
872 + if ( ! $gmt_time ) {
873 + $gmt_time = microtime( true );
874 + }
875 +
876 + if ( defined( 'DOING_CRON' ) || isset( $_GET['doing_wp_cron'] ) ) {
877 + return false;
878 + }
879 +
880 + /*
881 + * Get the cron lock, which is a Unix timestamp of when the last cron was spawned
882 + * and has not finished running.
883 + *
884 + * Multiple processes on multiple web servers can run this code concurrently,
885 + * this lock attempts to make spawning as atomic as possible.
886 + */
887 + $lock = (float) get_transient( 'doing_cron' );
888 +
889 + if ( $lock > $gmt_time + 10 * MINUTE_IN_SECONDS ) {
890 + $lock = 0;
891 + }
892 +
893 + // Don't run if another process is currently running it or more than once every 60 sec.
894 + if ( $lock + WP_CRON_LOCK_TIMEOUT > $gmt_time ) {
895 + return false;
896 + }
897 +
898 + // Confidence check.
899 + $crons = wp_get_ready_cron_jobs();
900 + if ( empty( $crons ) ) {
901 + return false;
902 + }
903 +
904 + $keys = array_keys( $crons );
905 + if ( isset( $keys[0] ) && $keys[0] > $gmt_time ) {
906 + return false;
907 + }
908 +
909 + if ( defined( 'ALTERNATE_WP_CRON' ) && ALTERNATE_WP_CRON ) {
910 + if ( 'GET' !== $_SERVER['REQUEST_METHOD'] || defined( 'DOING_AJAX' ) || defined( 'XMLRPC_REQUEST' ) ) {
911 + return false;
912 + }
913 +
914 + $doing_wp_cron = sprintf( '%.22F', $gmt_time );
915 + set_transient( 'doing_cron', $doing_wp_cron );
916 +
917 + ob_start();
918 + wp_redirect( add_query_arg( 'doing_wp_cron', $doing_wp_cron, wp_unslash( $_SERVER['REQUEST_URI'] ) ) );
919 + echo ' ';
920 +
921 + // Flush any buffers and send the headers.
922 + wp_ob_end_flush_all();
923 + flush();
924 +
925 + require_once ABSPATH . 'wp-cron.php';
926 + return true;
927 + }
928 +
929 + // Set the cron lock with the current unix timestamp, when the cron is being spawned.
930 + $doing_wp_cron = sprintf( '%.22F', $gmt_time );
931 + set_transient( 'doing_cron', $doing_wp_cron );
932 +
933 + /**
934 + * Filters the cron request arguments.
935 + *
936 + * @since 3.5.0
937 + * @since 4.5.0 The `$doing_wp_cron` parameter was added.
938 + *
939 + * @param array $cron_request_array {
940 + * An array of cron request URL arguments.
941 + *
942 + * @type string $url The cron request URL.
943 + * @type string $key The Unix timestamp (UTC) of the cron lock with microseconds.
944 + * @type array $args {
945 + * An array of cron request arguments.
946 + *
947 + * @type int $timeout The request timeout in seconds. Default .01 seconds.
948 + * @type bool $blocking Whether to set blocking for the request. Default false.
949 + * @type bool $sslverify Whether SSL should be verified for the request. Default false.
950 + * }
951 + * }
952 + * @param string $doing_wp_cron The Unix timestamp (UTC) of the cron lock with microseconds.
953 + */
954 + $cron_request = apply_filters(
955 + 'cron_request',
956 + array(
957 + 'url' => add_query_arg( 'doing_wp_cron', $doing_wp_cron, site_url( 'wp-cron.php' ) ),
958 + 'key' => $doing_wp_cron,
959 + 'args' => array(
960 + 'timeout' => 0.01,
961 + 'blocking' => false,
962 + /** This filter is documented in wp-includes/class-wp-http-streams.php */
963 + 'sslverify' => apply_filters( 'https_local_ssl_verify', false ),
964 + ),
965 + ),
966 + $doing_wp_cron
967 + );
968 +
969 + $result = wp_remote_post( $cron_request['url'], $cron_request['args'] );
970 +
971 + return ! is_wp_error( $result );
972 + }
973 +
974 + /**
975 + * Registers _wp_cron() to run on the {@see 'shutdown'} action.
976 + *
977 + * The spawn_cron() function attempts to make a non-blocking loopback request to `wp-cron.php` (when alternative
978 + * cron is not being used). However, the wp_remote_post() function does not always respect the `timeout` and
979 + * `blocking` parameters. A timeout of `0.01` may end up taking 1 second. When this runs at the {@see 'wp_loaded'}
980 + * action, it increases the Time To First Byte (TTFB) since the HTML cannot be sent while waiting for the cron request
981 + * to initiate. Moving the spawning of cron to the {@see 'shutdown'} hook allows for the server to flush the HTML document to
982 + * the browser while waiting for the request.
983 + *
984 + * @since 2.1.0
985 + * @since 5.1.0 Return value added to indicate success or failure.
986 + * @since 5.7.0 Functionality moved to _wp_cron() to which this becomes a wrapper.
987 + * @since 6.9.0 The _wp_cron() callback is moved from {@see 'wp_loaded'} to the {@see 'shutdown'} action,
988 + * unless `ALTERNATE_WP_CRON` is enabled; the function now always returns void.
989 + */
990 + function wp_cron(): void {
991 + if ( defined( 'ALTERNATE_WP_CRON' ) && ALTERNATE_WP_CRON ) {
992 + if ( did_action( 'wp_loaded' ) ) {
993 + _wp_cron();
994 + } else {
995 + add_action( 'wp_loaded', '_wp_cron', 20 );
996 + }
997 + } elseif ( doing_action( 'shutdown' ) ) {
998 + _wp_cron();
999 + } else {
1000 + add_action( 'shutdown', '_wp_cron' );
1001 + }
1002 + }
1003 +
1004 + /**
1005 + * Runs scheduled callbacks or spawns cron for all scheduled events.
1006 + *
1007 + * Warning: This function may return Boolean FALSE, but may also return a non-Boolean
1008 + * value which evaluates to FALSE. For information about casting to booleans see the
1009 + * {@link https://www.php.net/manual/en/language.types.boolean.php PHP documentation}. Use
1010 + * the `===` operator for testing the return value of this function.
1011 + *
1012 + * @since 5.7.0
1013 + * @access private
1014 + *
1015 + * @return int|false On success an integer indicating number of events spawned (0 indicates no
1016 + * events needed to be spawned), false if spawning fails for one or more events.
1017 + */
1018 + function _wp_cron() {
1019 + // Prevent infinite loops caused by lack of wp-cron.php.
1020 + if ( str_contains( $_SERVER['REQUEST_URI'], '/wp-cron.php' )
1021 + || ( defined( 'DISABLE_WP_CRON' ) && DISABLE_WP_CRON )
1022 + ) {
1023 + return 0;
1024 + }
1025 +
1026 + $crons = wp_get_ready_cron_jobs();
1027 + if ( empty( $crons ) ) {
1028 + return 0;
1029 + }
1030 +
1031 + $gmt_time = microtime( true );
1032 + $keys = array_keys( $crons );
1033 + if ( isset( $keys[0] ) && $keys[0] > $gmt_time ) {
1034 + return 0;
1035 + }
1036 +
1037 + $schedules = wp_get_schedules();
1038 + $results = array();
1039 +
1040 + foreach ( $crons as $timestamp => $cronhooks ) {
1041 + if ( $timestamp > $gmt_time ) {
1042 + break;
1043 + }
1044 +
1045 + foreach ( (array) $cronhooks as $hook => $args ) {
1046 + if ( isset( $schedules[ $hook ]['callback'] )
1047 + && ! call_user_func( $schedules[ $hook ]['callback'] )
1048 + ) {
1049 + continue;
1050 + }
1051 +
1052 + $results[] = spawn_cron( $gmt_time );
1053 + break 2;
1054 + }
1055 + }
1056 +
1057 + if ( in_array( false, $results, true ) ) {
1058 + return false;
1059 + }
1060 +
1061 + return count( $results );
1062 + }
1063 +
1064 + /**
1065 + * Retrieves supported event recurrence schedules.
1066 + *
1067 + * The default supported recurrences are 'hourly', 'twicedaily', 'daily', and 'weekly'.
1068 + * A plugin may add more by hooking into the {@see 'cron_schedules'} filter.
1069 + * The filter accepts an array of arrays. The outer array has a key that is the name
1070 + * of the schedule, for example 'monthly'. The value is an array with two keys,
1071 + * one is 'interval' and the other is 'display'.
1072 + *
1073 + * The 'interval' is a number in seconds of when the cron job should run.
1074 + * So for 'hourly' the time is `HOUR_IN_SECONDS` (`60 * 60` or `3600`). For 'monthly',
1075 + * the value would be `MONTH_IN_SECONDS` (`30 * 24 * 60 * 60` or `2592000`).
1076 + *
1077 + * The 'display' is the description. For the 'monthly' key, the 'display'
1078 + * would be `__( 'Once Monthly' )`.
1079 + *
1080 + * For your plugin, you will be passed an array. You can add your
1081 + * schedule by doing the following:
1082 + *
1083 + * // Filter parameter variable name is 'array'.
1084 + * $array['monthly'] = array(
1085 + * 'interval' => MONTH_IN_SECONDS,
1086 + * 'display' => __( 'Once Monthly' )
1087 + * );
1088 + *
1089 + * @since 2.1.0
1090 + * @since 5.4.0 The 'weekly' schedule was added.
1091 + *
1092 + * @return array {
1093 + * The array of cron schedules keyed by the schedule name.
1094 + *
1095 + * @type array ...$0 {
1096 + * Cron schedule information.
1097 + *
1098 + * @type int $interval The schedule interval in seconds.
1099 + * @type string $display The schedule display name.
1100 + * }
1101 + * }
1102 + */
1103 + function wp_get_schedules() {
1104 + $schedules = array(
1105 + 'hourly' => array(
1106 + 'interval' => HOUR_IN_SECONDS,
1107 + 'display' => __( 'Once Hourly' ),
1108 + ),
1109 + 'twicedaily' => array(
1110 + 'interval' => 12 * HOUR_IN_SECONDS,
1111 + 'display' => __( 'Twice Daily' ),
1112 + ),
1113 + 'daily' => array(
1114 + 'interval' => DAY_IN_SECONDS,
1115 + 'display' => __( 'Once Daily' ),
1116 + ),
1117 + 'weekly' => array(
1118 + 'interval' => WEEK_IN_SECONDS,
1119 + 'display' => __( 'Once Weekly' ),
1120 + ),
1121 + );
1122 +
1123 + /**
1124 + * Filters the non-default cron schedules.
1125 + *
1126 + * @since 2.1.0
1127 + *
1128 + * @param array $new_schedules {
1129 + * An array of non-default cron schedules keyed by the schedule name. Default empty array.
1130 + *
1131 + * @type array ...$0 {
1132 + * Cron schedule information.
1133 + *
1134 + * @type int $interval The schedule interval in seconds.
1135 + * @type string $display The schedule display name.
1136 + * }
1137 + * }
1138 + */
1139 + return array_merge( apply_filters( 'cron_schedules', array() ), $schedules );
1140 + }
1141 +
1142 + /**
1143 + * Retrieves the name of the recurrence schedule for an event.
1144 + *
1145 + * @see wp_get_schedules() for available schedules.
1146 + *
1147 + * @since 2.1.0
1148 + * @since 5.1.0 {@see 'get_schedule'} filter added.
1149 + *
1150 + * @param string $hook Action hook to identify the event.
1151 + * @param array $args Optional. Arguments passed to the event's callback function.
1152 + * Default empty array.
1153 + * @return string|false Schedule name on success, false if no schedule.
1154 + */
1155 + function wp_get_schedule( $hook, $args = array() ) {
1156 + $schedule = false;
1157 + $event = wp_get_scheduled_event( $hook, $args );
1158 +
1159 + if ( $event ) {
1160 + $schedule = $event->schedule;
1161 + }
1162 +
1163 + /**
1164 + * Filters the schedule name for a hook.
1165 + *
1166 + * @since 5.1.0
1167 + *
1168 + * @param string|false $schedule Schedule for the hook. False if not found.
1169 + * @param string $hook Action hook to execute when cron is run.
1170 + * @param array $args Arguments to pass to the hook's callback function.
1171 + */
1172 + return apply_filters( 'get_schedule', $schedule, $hook, $args );
1173 + }
1174 +
1175 + /**
1176 + * Retrieves cron jobs ready to be run.
1177 + *
1178 + * Returns the results of _get_cron_array() limited to events ready to be run,
1179 + * ie, with a timestamp in the past.
1180 + *
1181 + * @since 5.1.0
1182 + *
1183 + * @return array[] Array of cron job arrays ready to be run.
1184 + */
1185 + function wp_get_ready_cron_jobs() {
1186 + /**
1187 + * Filter to override retrieving ready cron jobs.
1188 + *
1189 + * Returning an array will short-circuit the normal retrieval of ready
1190 + * cron jobs, causing the function to return the filtered value instead.
1191 + *
1192 + * @since 5.1.0
1193 + *
1194 + * @param null|array[] $pre Array of ready cron tasks to return instead. Default null
1195 + * to continue using results from _get_cron_array().
1196 + */
1197 + $pre = apply_filters( 'pre_get_ready_cron_jobs', null );
1198 +
1199 + if ( null !== $pre ) {
1200 + return $pre;
1201 + }
1202 +
1203 + $crons = _get_cron_array();
1204 + $gmt_time = microtime( true );
1205 + $results = array();
1206 +
1207 + foreach ( $crons as $timestamp => $cronhooks ) {
1208 + if ( $timestamp > $gmt_time ) {
1209 + break;
1210 + }
1211 +
1212 + $results[ $timestamp ] = $cronhooks;
1213 + }
1214 +
1215 + return $results;
1216 + }
1217 +
1218 + //
1219 + // Private functions.
1220 + //
1221 +
1222 + /**
1223 + * Retrieves cron info array option.
1224 + *
1225 + * @since 2.1.0
1226 + * @since 6.1.0 Return type modified to consistently return an array.
1227 + * @access private
1228 + *
1229 + * @return array[] Array of cron events.
1230 + */
1231 + function _get_cron_array() {
1232 + $cron = get_option( 'cron' );
1233 + if ( ! is_array( $cron ) ) {
1234 + return array();
1235 + }
1236 +
1237 + if ( ! isset( $cron['version'] ) ) {
1238 + $cron = _upgrade_cron_array( $cron );
1239 + }
1240 +
1241 + unset( $cron['version'] );
1242 +
1243 + return $cron;
1244 + }
1245 +
1246 + /**
1247 + * Updates the cron option with the new cron array.
1248 + *
1249 + * @since 2.1.0
1250 + * @since 5.1.0 Return value modified to outcome of update_option().
1251 + * @since 5.7.0 The `$wp_error` parameter was added.
1252 + *
1253 + * @access private
1254 + *
1255 + * @param array[] $cron Array of cron info arrays from _get_cron_array().
1256 + * @param bool $wp_error Optional. Whether to return a WP_Error on failure. Default false.
1257 + * @return bool|WP_Error True if cron array updated. False or WP_Error on failure.
1258 + */
1259 + function _set_cron_array( $cron, $wp_error = false ) {
1260 + if ( ! is_array( $cron ) ) {
1261 + $cron = array();
1262 + }
1263 +
1264 + $cron['version'] = 2;
1265 +
1266 + $result = update_option( 'cron', $cron, true );
1267 +
1268 + if ( $wp_error && ! $result ) {
1269 + return new WP_Error(
1270 + 'could_not_set',
1271 + __( 'The cron event list could not be saved.' )
1272 + );
1273 + }
1274 +
1275 + return $result;
1276 + }
1277 +
1278 + /**
1279 + * Upgrades a cron info array.
1280 + *
1281 + * This function upgrades the cron info array to version 2.
1282 + *
1283 + * @since 2.1.0
1284 + * @access private
1285 + *
1286 + * @param array $cron Cron info array from _get_cron_array().
1287 + * @return array An upgraded cron info array.
1288 + */
1289 + function _upgrade_cron_array( $cron ) {
1290 + if ( isset( $cron['version'] ) && 2 === $cron['version'] ) {
1291 + return $cron;
1292 + }
1293 +
1294 + $new_cron = array();
1295 +
1296 + foreach ( (array) $cron as $timestamp => $hooks ) {
1297 + foreach ( (array) $hooks as $hook => $args ) {
1298 + $key = md5( serialize( $args['args'] ) );
1299 +
1300 + $new_cron[ $timestamp ][ $hook ][ $key ] = $args;
1301 + }
1302 + }
1303 +
1304 + $new_cron['version'] = 2;
1305 +
1306 + update_option( 'cron', $new_cron, true );
1307 +
1308 + return $new_cron;
1309 + }
1310 +