WordPress.org

Make WordPress Core

Ticket #32656: 32656.2.diff

File 32656.2.diff, 15.9 KB (added by peterwilsoncc, 19 months ago)
  • src/wp-includes/cron.php

    diff --git a/src/wp-includes/cron.php b/src/wp-includes/cron.php
    index fbf5a629af..d5dccc4539 100644
    a b  
    2626 * @param int    $timestamp  Unix timestamp (UTC) for when to next run the event.
    2727 * @param string $hook       Action hook to execute when the event is run.
    2828 * @param array  $args       Optional. Array containing each separate argument to pass to the hook's callback function.
    29  * @return false|void False if the event did not get scheduled.
     29 * @return bool Whether or not the requested event has been scheduled.
    3030 */
    3131function wp_schedule_single_event( $timestamp, $hook, $args = array() ) {
    3232        // Make sure timestamp is a positive integer
    function wp_schedule_single_event( $timestamp, $hook, $args = array() ) { 
    3434                return false;
    3535        }
    3636
    37         // Don't schedule a duplicate if there's already an identical event due within 10 minutes of it
    38         $next = wp_next_scheduled( $hook, $args );
    39         if ( $next && abs( $next - $timestamp ) <= 10 * MINUTE_IN_SECONDS ) {
    40                 return false;
    41         }
    42 
    43         $crons = _get_cron_array();
    4437        $event = (object) array(
    4538                'hook'      => $hook,
    4639                'timestamp' => $timestamp,
    function wp_schedule_single_event( $timestamp, $hook, $args = array() ) { 
    4841                'args'      => $args,
    4942        );
    5043
     44        /**
     45         * Filter to preflight or hijack scheduling an event.
     46         *
     47         * Passing a non-null value will short-circuit adding the event to the cron
     48         * array, returning the passed value instead.
     49         *
     50         * Both single events and recurring events are passed through this filter;
     51         * single events have `$event->schedule` as false, whereas recurring events
     52         * have this set to a recurrence from {@see wp_get_schedules}. Recurring
     53         * events also have the integer recurrence interval set as `$event->interval`
     54         *
     55         * @param null|bool $pre   Value to return instead. Default null to continue adding the event.
     56         * @param object    $event An object containing the event's data.
     57         */
     58        $pre = apply_filters( 'pre_schedule_event', null, $event );
     59        if ( null !== $pre ) {
     60                return $pre;
     61        }
     62
     63        // Don't schedule a duplicate if there's already an identical event due within 10 minutes of it
     64        $next = wp_next_scheduled( $hook, $args );
     65        if ( $next && abs( $next - $timestamp ) <= 10 * MINUTE_IN_SECONDS ) {
     66                return false;
     67        }
     68
    5169        /**
    5270         * Filters a single event before it is scheduled.
    5371         *
    function wp_schedule_single_event( $timestamp, $hook, $args = array() ) { 
    7290
    7391        $key = md5( serialize( $event->args ) );
    7492
     93        $crons = _get_cron_array();
    7594        $crons[ $event->timestamp ][ $event->hook ][ $key ] = array(
    7695                'schedule' => $event->schedule,
    7796                'args'     => $event->args,
    7897        );
    7998        uksort( $crons, 'strnatcasecmp' );
    80         _set_cron_array( $crons );
     99        return _set_cron_array( $crons );
    81100}
    82101
    83102/**
    function wp_schedule_single_event( $timestamp, $hook, $args = array() ) { 
    105124 * @param string $recurrence How often the event should subsequently recur. See wp_get_schedules() for accepted values.
    106125 * @param string $hook       Action hook to execute when the event is run.
    107126 * @param array  $args       Optional. Array containing each separate argument to pass to the hook's callback function.
    108  * @return false|void False if the event did not get scheduled.
     127 * @return bool Whether or not the requested event has been scheduled.
    109128 */
    110129function wp_schedule_event( $timestamp, $recurrence, $hook, $args = array() ) {
    111130        // Make sure timestamp is a positive integer
    function wp_schedule_event( $timestamp, $recurrence, $hook, $args = array() ) { 
    113132                return false;
    114133        }
    115134
    116         $crons     = _get_cron_array();
    117135        $schedules = wp_get_schedules();
    118136
    119137        if ( ! isset( $schedules[ $recurrence ] ) ) {
    function wp_schedule_event( $timestamp, $recurrence, $hook, $args = array() ) { 
    127145                'args'      => $args,
    128146                'interval'  => $schedules[ $recurrence ]['interval'],
    129147        );
     148
     149        /** This filter is documented in wp-includes/cron.php */
     150        $pre = apply_filters( 'pre_schedule_event', null, $event );
     151        if ( null !== $pre ) {
     152                return $pre;
     153        }
     154
    130155        /** This filter is documented in wp-includes/cron.php */
    131156        $event = apply_filters( 'schedule_event', $event );
    132157
    function wp_schedule_event( $timestamp, $recurrence, $hook, $args = array() ) { 
    137162
    138163        $key = md5( serialize( $event->args ) );
    139164
     165        $crons = _get_cron_array();
    140166        $crons[ $event->timestamp ][ $event->hook ][ $key ] = array(
    141167                'schedule' => $event->schedule,
    142168                'args'     => $event->args,
    143169                'interval' => $event->interval,
    144170        );
    145171        uksort( $crons, 'strnatcasecmp' );
    146         _set_cron_array( $crons );
     172        return _set_cron_array( $crons );
    147173}
    148174
    149175/**
    function wp_schedule_event( $timestamp, $recurrence, $hook, $args = array() ) { 
    155181 * @param string $recurrence How often the event should subsequently recur. See wp_get_schedules() for accepted values.
    156182 * @param string $hook       Action hook to execute when the event is run.
    157183 * @param array  $args       Optional. Array containing each separate argument to pass to the hook's callback function.
    158  * @return false|void False if the event did not get rescheduled.
     184 * @return bool Whether or not the requested event has been rescheduled.
    159185 */
    160186function wp_reschedule_event( $timestamp, $recurrence, $hook, $args = array() ) {
    161187        // Make sure timestamp is a positive integer
    function wp_reschedule_event( $timestamp, $recurrence, $hook, $args = array() ) 
    163189                return false;
    164190        }
    165191
     192        /**
     193         * Filter to preflight or hijack rescheduling of events.
     194         *
     195         * Passing a non-null value will short-circuit the normal rescheduling
     196         * process, returning the passed value instead.
     197         *
     198         * Note that `$recurrence` is the original stored value. This is not
     199         * guaranteed to exist when the event is rescheduled, so plugins should
     200         * store the interval value and fall back to this if needed.
     201         *
     202         * @param null|bool $pre        Value to return instead. Default null to continue rescheduling the event.
     203         * @param int       $timestamp  Timestamp for when the event originally ran.
     204         * @param string    $recurrence How often the event should recur.
     205         * @param string    $hook       Action hook to execute when cron is run.
     206         * @param array     $args       Optional. Arguments to pass to the hook's callback function.
     207         */
     208        $pre = apply_filters( 'pre_reschedule_event', null, $timestamp, $recurrence, $hook, $args );
     209        if ( null !== $pre ) {
     210                return $pre;
     211        }
     212
    166213        $crons     = _get_cron_array();
    167214        $schedules = wp_get_schedules();
    168215        $key       = md5( serialize( $args ) );
    function wp_reschedule_event( $timestamp, $recurrence, $hook, $args = array() ) 
    189236                $timestamp = $now + ( $interval - ( ( $now - $timestamp ) % $interval ) );
    190237        }
    191238
    192         wp_schedule_event( $timestamp, $recurrence, $hook, $args );
     239        return wp_schedule_event( $timestamp, $recurrence, $hook, $args );
    193240}
    194241
    195242/**
    function wp_reschedule_event( $timestamp, $recurrence, $hook, $args = array() ) 
    205252 * @param array  $args      Optional. Array containing each separate argument to pass to the hook's callback function.
    206253 *                          Although not passed to a callback, these arguments are used to uniquely identify the
    207254 *                          event, so they should be the same as those used when originally scheduling the event.
    208  * @return false|void False if the event did not get unscheduled.
     255 * @return bool Whether or not the requested event has been unscheduled.
    209256 */
    210257function wp_unschedule_event( $timestamp, $hook, $args = array() ) {
    211258        // Make sure timestamp is a positive integer
    function wp_unschedule_event( $timestamp, $hook, $args = array() ) { 
    213260                return false;
    214261        }
    215262
     263        /**
     264         * Filter to preflight or hijack unscheduling of events.
     265         *
     266         * Passing a non-null value will short-circuit the normal unscheduling
     267         * process, returning the passed value instead.
     268         *
     269         * @param null|bool $pre       Value to return instead. Default null to continue unscheduling the event.
     270         * @param int       $timestamp Timestamp for when to run the event.
     271         * @param string    $hook      Action hook, the execution of which will be unscheduled.
     272         * @param array     $args      Arguments to pass to the hook's callback function.
     273         */
     274        $pre = apply_filters( 'pre_unschedule_event', null, $timestamp, $hook, $args );
     275        if ( null !== $pre ) {
     276                return $pre;
     277        }
     278
    216279        $crons = _get_cron_array();
    217280        $key   = md5( serialize( $args ) );
    218281        unset( $crons[ $timestamp ][ $hook ][ $key ] );
    function wp_unschedule_event( $timestamp, $hook, $args = array() ) { 
    222285        if ( empty( $crons[ $timestamp ] ) ) {
    223286                unset( $crons[ $timestamp ] );
    224287        }
    225         _set_cron_array( $crons );
     288        return _set_cron_array( $crons );
    226289}
    227290
    228291/**
    function wp_unschedule_event( $timestamp, $hook, $args = array() ) { 
    232295 *
    233296 * @param string $hook Action hook, the execution of which will be unscheduled.
    234297 * @param array $args Optional. Arguments that were to be passed to the hook's callback function.
     298 * @return array Boolean values, indicating the result of attempting to unschedule each indicated event, with timestamps as keys.
    235299 */
    236300function wp_clear_scheduled_hook( $hook, $args = array() ) {
    237301        // Backward compatibility
    function wp_clear_scheduled_hook( $hook, $args = array() ) { 
    241305                $args = array_slice( func_get_args(), 1 );
    242306        }
    243307
     308        /**
     309         * Filter to preflight or hijack clearing a scheduled hook.
     310         *
     311         * Passing a non-null value will short-circuit the normal unscheduling
     312         * process, returning the passed value instead.
     313         *
     314         * @param null|array $pre  Value to return instead. Default null to continue unscheduling the event.
     315         * @param string     $hook Action hook, the execution of which will be unscheduled.
     316         * @param array      $args Arguments to pass to the hook's callback function.
     317         */
     318        $pre = apply_filters( 'pre_clear_scheduled_hook', null, $hook, $args );
     319        if ( null !== $pre ) {
     320                return $pre;
     321        }
     322
    244323        // This logic duplicates wp_next_scheduled()
    245324        // It's required due to a scenario where wp_unschedule_event() fails due to update_option() failing,
    246325        // and, wp_next_scheduled() returns the same schedule in an infinite loop.
    247326        $crons = _get_cron_array();
    248327        if ( empty( $crons ) ) {
    249                 return;
     328                return array();
    250329        }
    251330
    252         $key = md5( serialize( $args ) );
     331        $results = array();
     332        $key     = md5( serialize( $args ) );
    253333        foreach ( $crons as $timestamp => $cron ) {
    254334                if ( isset( $cron[ $hook ][ $key ] ) ) {
    255                         wp_unschedule_event( $timestamp, $hook, $args );
     335                        $results[ $timestamp ] = wp_unschedule_event( $timestamp, $hook, $args );
    256336                }
    257337        }
     338        return $results;
    258339}
    259340
    260341/**
    function wp_unschedule_hook( $hook ) { 
    294375function wp_next_scheduled( $hook, $args = array() ) {
    295376        $crons = _get_cron_array();
    296377        $key   = md5( serialize( $args ) );
    297         if ( empty( $crons ) ) {
    298                 return false;
    299         }
    300         foreach ( $crons as $timestamp => $cron ) {
    301                 if ( isset( $cron[ $hook ][ $key ] ) ) {
    302                         return $timestamp;
     378        $next  = false;
     379
     380        if ( ! empty( $crons ) ) {
     381                foreach ( $crons as $timestamp => $cron ) {
     382                        if ( isset( $cron[ $hook ][ $key ] ) ) {
     383                                $next = $timestamp;
     384                                break;
     385                        }
    303386                }
    304387        }
    305         return false;
     388
     389        /**
     390         * Filter the next scheduled event timestamp.
     391         *
     392         * @param int|bool $next The UNIX timestamp when the scheduled event will next occur, or false if not found.
     393         * @param string   $hook Action hook to execute when cron is run.
     394         * @param array    $args Arguments to be passed to the callback function. Used for deduplicating events.
     395         */
     396        return apply_filters( 'next_scheduled', $next, $hook, $args );
    306397}
    307398
    308399/**
    function wp_next_scheduled( $hook, $args = array() ) { 
    311402 * @since 2.1.0
    312403 *
    313404 * @param int $gmt_time Optional. Unix timestamp (UTC). Default 0 (current time is used).
     405 * @return null|WP_Error|array Null when cron could not be spawned, because it is not needed to run.
     406 *                             When cron runs, return the result of {@see wp_remote_post}
    314407 */
    315408function spawn_cron( $gmt_time = 0 ) {
    316409        if ( ! $gmt_time ) {
    function spawn_cron( $gmt_time = 0 ) { 
    318411        }
    319412
    320413        if ( defined( 'DOING_CRON' ) || isset( $_GET['doing_wp_cron'] ) ) {
    321                 return;
     414                return null;
    322415        }
    323416
    324417        /*
    function spawn_cron( $gmt_time = 0 ) { 
    336429
    337430        // don't run if another process is currently running it or more than once every 60 sec.
    338431        if ( $lock + WP_CRON_LOCK_TIMEOUT > $gmt_time ) {
    339                 return;
     432                return null;
    340433        }
    341434
    342435        //sanity check
    343436        $crons = _get_cron_array();
    344437        if ( ! is_array( $crons ) ) {
    345                 return;
     438                return null;
    346439        }
    347440
    348441        $keys = array_keys( $crons );
    349442        if ( isset( $keys[0] ) && $keys[0] > $gmt_time ) {
    350                 return;
     443                return null;
    351444        }
    352445
    353446        if ( defined( 'ALTERNATE_WP_CRON' ) && ALTERNATE_WP_CRON ) {
    354447                if ( 'GET' !== $_SERVER['REQUEST_METHOD'] || defined( 'DOING_AJAX' ) || defined( 'XMLRPC_REQUEST' ) ) {
    355                         return;
     448                        return null;
    356449                }
    357450
    358451                $doing_wp_cron = sprintf( '%.22F', $gmt_time );
    function spawn_cron( $gmt_time = 0 ) { 
    368461                flush();
    369462
    370463                WP_DEBUG ? include_once( ABSPATH . 'wp-cron.php' ) : @include_once( ABSPATH . 'wp-cron.php' );
    371                 return;
     464                return null;
    372465        }
    373466
    374467        // Set the cron lock with the current unix timestamp, when the cron is being spawned.
    function spawn_cron( $gmt_time = 0 ) { 
    409502                ), $doing_wp_cron
    410503        );
    411504
    412         wp_remote_post( $cron_request['url'], $cron_request['args'] );
     505        return wp_remote_post( $cron_request['url'], $cron_request['args'] );
    413506}
    414507
    415508/**
    416509 * Run scheduled callbacks or spawn cron for all scheduled events.
    417510 *
    418511 * @since 2.1.0
     512 *
     513 * @return array Array of spawn_cron() results for any cron jobs that were run, with cron timestamps as keys.
    419514 */
    420515function wp_cron() {
    421516        // Prevent infinite loops caused by lack of wp-cron.php
    422517        if ( strpos( $_SERVER['REQUEST_URI'], '/wp-cron.php' ) !== false || ( defined( 'DISABLE_WP_CRON' ) && DISABLE_WP_CRON ) ) {
    423                 return;
     518                return array();
    424519        }
    425520
    426         if ( false === $crons = _get_cron_array() ) {
    427                 return;
     521        $crons = _get_cron_array();
     522        if ( false === $crons ) {
     523                return array();
    428524        }
    429525
    430526        $gmt_time = microtime( true );
    431527        $keys     = array_keys( $crons );
    432528        if ( isset( $keys[0] ) && $keys[0] > $gmt_time ) {
    433                 return;
     529                return array();
    434530        }
    435531
     532        $results   = array();
    436533        $schedules = wp_get_schedules();
    437534        foreach ( $crons as $timestamp => $cronhooks ) {
    438535                if ( $timestamp > $gmt_time ) {
    function wp_cron() { 
    442539                        if ( isset( $schedules[ $hook ]['callback'] ) && ! call_user_func( $schedules[ $hook ]['callback'] ) ) {
    443540                                continue;
    444541                        }
    445                         spawn_cron( $gmt_time );
     542                        $results[ $timestamp ] = spawn_cron( $gmt_time );
    446543                        break 2;
    447544                }
    448545        }
     546
     547        return $results;
    449548}
    450549
    451550/**
    function wp_get_schedules() { 
    514613 * @return string|false False, if no schedule. Schedule name on success.
    515614 */
    516615function wp_get_schedule( $hook, $args = array() ) {
    517         $crons = _get_cron_array();
    518         $key   = md5( serialize( $args ) );
    519         if ( empty( $crons ) ) {
    520                 return false;
    521         }
    522         foreach ( $crons as $timestamp => $cron ) {
    523                 if ( isset( $cron[ $hook ][ $key ] ) ) {
    524                         return $cron[ $hook ][ $key ]['schedule'];
     616        $crons    = _get_cron_array();
     617        $key      = md5( serialize( $args ) );
     618        $schedule = false;
     619
     620        if ( ! empty( $crons ) ) {
     621                foreach ( $crons as $timestamp => $cron ) {
     622                        if ( isset( $cron[ $hook ][ $key ] ) ) {
     623                                $schedule = $cron[ $hook ][ $key ]['schedule'];
     624                                break;
     625                        }
    525626                }
    526627        }
    527         return false;
     628
     629        /**
     630         * Filter the schedule for a hook.
     631         *
     632         * @param string|bool $schedule Schedule for the hook. False if not found.
     633         * @param string      $hook     Action hook to execute when cron is run.
     634         * @param array       $args     Optional. Arguments to pass to the hook's callback function.
     635         */
     636        return apply_filters( 'get_schedule', $schedule, $hook, $args );
    528637}
    529638
    530639//
    function _get_cron_array() { 
    561670 * @access private
    562671 *
    563672 * @param array $cron Cron info array from _get_cron_array().
     673 * @return bool Whether the update of the cron option succeeded (according to {@see update_option})
    564674 */
    565675function _set_cron_array( $cron ) {
    566676        $cron['version'] = 2;
    567         update_option( 'cron', $cron );
     677        return update_option( 'cron', $cron );
    568678}
    569679
    570680/**