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