Make WordPress Core

Ticket #32656: 32656.3.diff

File 32656.3.diff, 19.0 KB (added by peterwilsoncc, 6 years ago)
  • src/wp-includes/cron.php

    diff --git src/wp-includes/cron.php src/wp-includes/cron.php
    index fbf5a629af..3c0a0fdff7 100644
     
    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 stdClass  $event {
     57         *     An object containing an event's data.
     58         *
     59         *     @type string       $hook      Action hook to execute when the event is run.
     60         *     @type int          $timestamp Unix timestamp (UTC) for when to next run the event.
     61         *     @type string|false $schedule  How often the event should subsequently recur.
     62         *     @type array        $args      Array containing each separate argument to pass to the hook's callback function.
     63         *     @type int          $interval  The interval time in seconds for the schedule. Only present for recurring events.
     64         * }
     65         */
     66        $pre = apply_filters( 'pre_schedule_event', null, $event );
     67        if ( null !== $pre ) {
     68                return $pre;
     69        }
     70
     71        // Don't schedule a duplicate if there's already an identical event due within 10 minutes of it
     72        $next = wp_next_scheduled( $hook, $args );
     73        if ( $next && abs( $next - $timestamp ) <= 10 * MINUTE_IN_SECONDS ) {
     74                return false;
     75        }
     76
    5177        /**
    5278         * Filters a single event before it is scheduled.
    5379         *
    function wp_schedule_single_event( $timestamp, $hook, $args = array() ) { 
    7298
    7399        $key = md5( serialize( $event->args ) );
    74100
     101        $crons = _get_cron_array();
    75102        $crons[ $event->timestamp ][ $event->hook ][ $key ] = array(
    76103                'schedule' => $event->schedule,
    77104                'args'     => $event->args,
    78105        );
    79106        uksort( $crons, 'strnatcasecmp' );
    80         _set_cron_array( $crons );
     107        return _set_cron_array( $crons );
    81108}
    82109
    83110/**
    function wp_schedule_single_event( $timestamp, $hook, $args = array() ) { 
    105132 * @param string $recurrence How often the event should subsequently recur. See wp_get_schedules() for accepted values.
    106133 * @param string $hook       Action hook to execute when the event is run.
    107134 * @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.
     135 * @return bool Whether or not the requested event has been scheduled.
    109136 */
    110137function wp_schedule_event( $timestamp, $recurrence, $hook, $args = array() ) {
    111138        // Make sure timestamp is a positive integer
    function wp_schedule_event( $timestamp, $recurrence, $hook, $args = array() ) { 
    113140                return false;
    114141        }
    115142
    116         $crons     = _get_cron_array();
    117143        $schedules = wp_get_schedules();
    118144
    119145        if ( ! isset( $schedules[ $recurrence ] ) ) {
    function wp_schedule_event( $timestamp, $recurrence, $hook, $args = array() ) { 
    127153                'args'      => $args,
    128154                'interval'  => $schedules[ $recurrence ]['interval'],
    129155        );
     156
     157        /** This filter is documented in wp-includes/cron.php */
     158        $pre = apply_filters( 'pre_schedule_event', null, $event );
     159        if ( null !== $pre ) {
     160                return $pre;
     161        }
     162
    130163        /** This filter is documented in wp-includes/cron.php */
    131164        $event = apply_filters( 'schedule_event', $event );
    132165
    function wp_schedule_event( $timestamp, $recurrence, $hook, $args = array() ) { 
    137170
    138171        $key = md5( serialize( $event->args ) );
    139172
     173        $crons = _get_cron_array();
    140174        $crons[ $event->timestamp ][ $event->hook ][ $key ] = array(
    141175                'schedule' => $event->schedule,
    142176                'args'     => $event->args,
    143177                'interval' => $event->interval,
    144178        );
    145179        uksort( $crons, 'strnatcasecmp' );
    146         _set_cron_array( $crons );
     180        return _set_cron_array( $crons );
    147181}
    148182
    149183/**
    function wp_schedule_event( $timestamp, $recurrence, $hook, $args = array() ) { 
    155189 * @param string $recurrence How often the event should subsequently recur. See wp_get_schedules() for accepted values.
    156190 * @param string $hook       Action hook to execute when the event is run.
    157191 * @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.
     192 * @return bool Whether or not the requested event has been rescheduled.
    159193 */
    160194function wp_reschedule_event( $timestamp, $recurrence, $hook, $args = array() ) {
    161195        // Make sure timestamp is a positive integer
    function wp_reschedule_event( $timestamp, $recurrence, $hook, $args = array() ) 
    163197                return false;
    164198        }
    165199
    166         $crons     = _get_cron_array();
    167200        $schedules = wp_get_schedules();
    168         $key       = md5( serialize( $args ) );
    169201        $interval  = 0;
    170202
    171         // First we try to get it from the schedule
     203        // First we try to get the interval from the schedule.
    172204        if ( isset( $schedules[ $recurrence ] ) ) {
    173205                $interval = $schedules[ $recurrence ]['interval'];
    174206        }
    175         // Now we try to get it from the saved interval in case the schedule disappears
     207
     208        // Now we try to get it from the saved interval in case the schedule disappears.
    176209        if ( 0 == $interval ) {
    177                 $interval = $crons[ $timestamp ][ $hook ][ $key ]['interval'];
     210                $crons    = _get_cron_array();
     211                $key      = md5( serialize( $args ) );
     212                $interval = $crons[ $timestamp ][ $hook ][ $key ][ 'interval' ];
     213        }
     214
     215        $event = (object) array(
     216                'hook'      => $hook,
     217                'timestamp' => $timestamp,
     218                'schedule'  => $recurrence,
     219                'args'      => $args,
     220                'interval'  => $schedules[ $recurrence ]['interval'],
     221        );
     222
     223        /**
     224         * Filter to preflight or hijack rescheduling of events.
     225         *
     226         * Passing a non-null value will short-circuit the normal rescheduling
     227         * process, returning the passed value instead.
     228         *
     229         * @param null|bool $pre   Value to return instead. Default null to continue adding the event.
     230         * @param stdClass  $event {
     231         *     An object containing an event's data.
     232         *
     233         *     @type string       $hook      Action hook to execute when the event is run.
     234         *     @type int          $timestamp Unix timestamp (UTC) for when to next run the event.
     235         *     @type string|false $schedule  How often the event should subsequently recur.
     236         *     @type array        $args      Array containing each separate argument to pass to the hook's callback function.
     237         *     @type int          $interval  The interval time in seconds for the schedule. Only present for recurring events.
     238         * }
     239         */
     240        $pre = apply_filters( 'pre_reschedule_event', null, $event );
     241        if ( null !== $pre ) {
     242                return $pre;
    178243        }
     244
    179245        // Now we assume something is wrong and fail to schedule
    180246        if ( 0 == $interval ) {
    181247                return false;
    function wp_reschedule_event( $timestamp, $recurrence, $hook, $args = array() ) 
    189255                $timestamp = $now + ( $interval - ( ( $now - $timestamp ) % $interval ) );
    190256        }
    191257
    192         wp_schedule_event( $timestamp, $recurrence, $hook, $args );
     258        return wp_schedule_event( $timestamp, $recurrence, $hook, $args );
    193259}
    194260
    195261/**
    function wp_reschedule_event( $timestamp, $recurrence, $hook, $args = array() ) 
    205271 * @param array  $args      Optional. Array containing each separate argument to pass to the hook's callback function.
    206272 *                          Although not passed to a callback, these arguments are used to uniquely identify the
    207273 *                          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.
     274 * @return bool Whether or not the requested event has been unscheduled.
    209275 */
    210276function wp_unschedule_event( $timestamp, $hook, $args = array() ) {
    211277        // Make sure timestamp is a positive integer
    function wp_unschedule_event( $timestamp, $hook, $args = array() ) { 
    213279                return false;
    214280        }
    215281
     282        /**
     283         * Filter to preflight or hijack unscheduling of events.
     284         *
     285         * Passing a non-null value will short-circuit the normal unscheduling
     286         * process, returning the passed value instead.
     287         *
     288         * @param null|bool $pre       Value to return instead. Default null to continue unscheduling the event.
     289         * @param int       $timestamp Timestamp for when to run the event.
     290         * @param string    $hook      Action hook, the execution of which will be unscheduled.
     291         * @param array     $args      Arguments to pass to the hook's callback function.
     292         */
     293        $pre = apply_filters( 'pre_unschedule_event', null, $timestamp, $hook, $args );
     294        if ( null !== $pre ) {
     295                return $pre;
     296        }
     297
    216298        $crons = _get_cron_array();
    217299        $key   = md5( serialize( $args ) );
    218300        unset( $crons[ $timestamp ][ $hook ][ $key ] );
    function wp_unschedule_event( $timestamp, $hook, $args = array() ) { 
    222304        if ( empty( $crons[ $timestamp ] ) ) {
    223305                unset( $crons[ $timestamp ] );
    224306        }
    225         _set_cron_array( $crons );
     307        return _set_cron_array( $crons );
    226308}
    227309
    228310/**
    function wp_unschedule_event( $timestamp, $hook, $args = array() ) { 
    232314 *
    233315 * @param string $hook Action hook, the execution of which will be unscheduled.
    234316 * @param array $args Optional. Arguments that were to be passed to the hook's callback function.
     317 * @return array Boolean values, indicating the result of attempting to unschedule each indicated event, with timestamps as keys.
    235318 */
    236319function wp_clear_scheduled_hook( $hook, $args = array() ) {
    237320        // Backward compatibility
    function wp_clear_scheduled_hook( $hook, $args = array() ) { 
    241324                $args = array_slice( func_get_args(), 1 );
    242325        }
    243326
     327        /**
     328         * Filter to preflight or hijack clearing a scheduled hook.
     329         *
     330         * Passing a non-null value will short-circuit the normal unscheduling
     331         * process, returning the passed value instead.
     332         *
     333         * @param null|array $pre  Value to return instead. Default null to continue unscheduling the event.
     334         * @param string     $hook Action hook, the execution of which will be unscheduled.
     335         * @param array      $args Arguments to pass to the hook's callback function.
     336         */
     337        $pre = apply_filters( 'pre_clear_scheduled_hook', null, $hook, $args );
     338        if ( null !== $pre ) {
     339                return $pre;
     340        }
     341
    244342        // This logic duplicates wp_next_scheduled()
    245343        // It's required due to a scenario where wp_unschedule_event() fails due to update_option() failing,
    246344        // and, wp_next_scheduled() returns the same schedule in an infinite loop.
    247345        $crons = _get_cron_array();
    248346        if ( empty( $crons ) ) {
    249                 return;
     347                return array();
    250348        }
    251349
    252         $key = md5( serialize( $args ) );
     350        $results = array();
     351        $key     = md5( serialize( $args ) );
    253352        foreach ( $crons as $timestamp => $cron ) {
    254353                if ( isset( $cron[ $hook ][ $key ] ) ) {
    255                         wp_unschedule_event( $timestamp, $hook, $args );
     354                        $results[ $timestamp ] = wp_unschedule_event( $timestamp, $hook, $args );
    256355                }
    257356        }
     357        return $results;
    258358}
    259359
    260360/**
    function wp_clear_scheduled_hook( $hook, $args = array() ) { 
    265365 * @since 4.9.0
    266366 *
    267367 * @param string $hook Action hook, the execution of which will be unscheduled.
     368 * @return bool Whether or not the requested events have been unscheduled.
    268369 */
    269370function wp_unschedule_hook( $hook ) {
     371        /**
     372         * Filter to preflight or hijack clearing all events attached to the hook.
     373         *
     374         * Passing a non-null value will short-circuit the normal unscheduling
     375         * process, returning the passed value instead.
     376         *
     377         * @param null|array $pre  Value to return instead. Default null to continue unscheduling the hook.
     378         * @param string     $hook Action hook, the execution of which will be unscheduled.
     379         */
     380        $pre = apply_filters( 'pre_unschedule_hook', null, $hook );
     381        if ( null !== $pre ) {
     382                return $pre;
     383        }
     384
    270385        $crons = _get_cron_array();
    271386
    272387        foreach ( $crons as $timestamp => $args ) {
    function wp_unschedule_hook( $hook ) { 
    277392                }
    278393        }
    279394
    280         _set_cron_array( $crons );
     395        return _set_cron_array( $crons );
    281396}
    282397
    283398/**
    function wp_unschedule_hook( $hook ) { 
    292407 * @return false|int The Unix timestamp of the next time the event will occur. False if the event doesn't exist.
    293408 */
    294409function wp_next_scheduled( $hook, $args = array() ) {
     410        /**
     411         * Filter to preflight or hijack unscheduling of events.
     412         *
     413         * Passing a non-null value will short-circuit the normal unscheduling
     414         * process, returning the passed value instead.
     415         *
     416         * @param null|bool $pre       Value to return instead. Default null to continue unscheduling the event.
     417         * @param string    $hook      Action hook of the event.
     418         * @param array     $args      Arguments to pass to the hook's callback function.
     419         */
     420        $pre = apply_filters( 'pre_next_scheduled', null, $hook, $args );
     421        if ( null !== $pre ) {
     422                return $pre;
     423        }
     424
    295425        $crons = _get_cron_array();
    296426        $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;
     427        $next  = false;
     428
     429        if ( ! empty( $crons ) ) {
     430                foreach ( $crons as $timestamp => $cron ) {
     431                        if ( isset( $cron[ $hook ][ $key ] ) ) {
     432                                $next = $timestamp;
     433                                break;
     434                        }
    303435                }
    304436        }
    305         return false;
     437
     438        /**
     439         * Filter the next scheduled event timestamp.
     440         *
     441         * @param int|bool $next The UNIX timestamp when the scheduled event will next occur, or false if not found.
     442         * @param string   $hook Action hook to execute when cron is run.
     443         * @param array    $args Arguments to be passed to the callback function. Used for deduplicating events.
     444         */
     445        return apply_filters( 'next_scheduled', $next, $hook, $args );
    306446}
    307447
    308448/**
    function wp_next_scheduled( $hook, $args = array() ) { 
    311451 * @since 2.1.0
    312452 *
    313453 * @param int $gmt_time Optional. Unix timestamp (UTC). Default 0 (current time is used).
     454 * @return null|WP_Error|array Null when cron could not be spawned, because it is not needed to run.
     455 *                             When cron runs, return the result of {@see wp_remote_post}
    314456 */
    315457function spawn_cron( $gmt_time = 0 ) {
    316458        if ( ! $gmt_time ) {
    function spawn_cron( $gmt_time = 0 ) { 
    318460        }
    319461
    320462        if ( defined( 'DOING_CRON' ) || isset( $_GET['doing_wp_cron'] ) ) {
    321                 return;
     463                return null;
    322464        }
    323465
    324466        /*
    function spawn_cron( $gmt_time = 0 ) { 
    336478
    337479        // don't run if another process is currently running it or more than once every 60 sec.
    338480        if ( $lock + WP_CRON_LOCK_TIMEOUT > $gmt_time ) {
    339                 return;
     481                return null;
    340482        }
    341483
    342484        //sanity check
    343485        $crons = _get_cron_array();
    344486        if ( ! is_array( $crons ) ) {
    345                 return;
     487                return null;
    346488        }
    347489
    348490        $keys = array_keys( $crons );
    349491        if ( isset( $keys[0] ) && $keys[0] > $gmt_time ) {
    350                 return;
     492                return null;
    351493        }
    352494
    353495        if ( defined( 'ALTERNATE_WP_CRON' ) && ALTERNATE_WP_CRON ) {
    354496                if ( 'GET' !== $_SERVER['REQUEST_METHOD'] || defined( 'DOING_AJAX' ) || defined( 'XMLRPC_REQUEST' ) ) {
    355                         return;
     497                        return null;
    356498                }
    357499
    358500                $doing_wp_cron = sprintf( '%.22F', $gmt_time );
    function spawn_cron( $gmt_time = 0 ) { 
    368510                flush();
    369511
    370512                WP_DEBUG ? include_once( ABSPATH . 'wp-cron.php' ) : @include_once( ABSPATH . 'wp-cron.php' );
    371                 return;
     513                return null;
    372514        }
    373515
    374516        // Set the cron lock with the current unix timestamp, when the cron is being spawned.
    function spawn_cron( $gmt_time = 0 ) { 
    409551                ), $doing_wp_cron
    410552        );
    411553
    412         wp_remote_post( $cron_request['url'], $cron_request['args'] );
     554        return wp_remote_post( $cron_request['url'], $cron_request['args'] );
    413555}
    414556
    415557/**
    416558 * Run scheduled callbacks or spawn cron for all scheduled events.
    417559 *
    418560 * @since 2.1.0
     561 *
     562 * @return array Array of spawn_cron() results for any cron jobs that were run, with cron timestamps as keys.
    419563 */
    420564function wp_cron() {
    421565        // Prevent infinite loops caused by lack of wp-cron.php
    422566        if ( strpos( $_SERVER['REQUEST_URI'], '/wp-cron.php' ) !== false || ( defined( 'DISABLE_WP_CRON' ) && DISABLE_WP_CRON ) ) {
    423                 return;
     567                return array();
    424568        }
    425569
    426         if ( false === $crons = _get_cron_array() ) {
    427                 return;
     570        $crons = _get_cron_array();
     571        if ( false === $crons ) {
     572                return array();
    428573        }
    429574
    430575        $gmt_time = microtime( true );
    431576        $keys     = array_keys( $crons );
    432577        if ( isset( $keys[0] ) && $keys[0] > $gmt_time ) {
    433                 return;
     578                return array();
    434579        }
    435580
     581        $results   = array();
    436582        $schedules = wp_get_schedules();
    437583        foreach ( $crons as $timestamp => $cronhooks ) {
    438584                if ( $timestamp > $gmt_time ) {
    function wp_cron() { 
    442588                        if ( isset( $schedules[ $hook ]['callback'] ) && ! call_user_func( $schedules[ $hook ]['callback'] ) ) {
    443589                                continue;
    444590                        }
    445                         spawn_cron( $gmt_time );
     591                        $results[ $timestamp ] = spawn_cron( $gmt_time );
    446592                        break 2;
    447593                }
    448594        }
     595
     596        return $results;
    449597}
    450598
    451599/**
    function wp_get_schedules() { 
    514662 * @return string|false False, if no schedule. Schedule name on success.
    515663 */
    516664function 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'];
     665        $crons    = _get_cron_array();
     666        $key      = md5( serialize( $args ) );
     667        $schedule = false;
     668
     669        if ( ! empty( $crons ) ) {
     670                foreach ( $crons as $timestamp => $cron ) {
     671                        if ( isset( $cron[ $hook ][ $key ] ) ) {
     672                                $schedule = $cron[ $hook ][ $key ]['schedule'];
     673                                break;
     674                        }
    525675                }
    526676        }
    527         return false;
     677
     678        /**
     679         * Filter the schedule for a hook.
     680         *
     681         * @param string|bool $schedule Schedule for the hook. False if not found.
     682         * @param string      $hook     Action hook to execute when cron is run.
     683         * @param array       $args     Optional. Arguments to pass to the hook's callback function.
     684         */
     685        return apply_filters( 'get_schedule', $schedule, $hook, $args );
    528686}
    529687
    530688//
    function _get_cron_array() { 
    561719 * @access private
    562720 *
    563721 * @param array $cron Cron info array from _get_cron_array().
     722 * @return bool Whether the update of the cron option succeeded (according to {@see update_option})
    564723 */
    565724function _set_cron_array( $cron ) {
    566725        $cron['version'] = 2;
    567         update_option( 'cron', $cron );
     726        return update_option( 'cron', $cron );
    568727}
    569728
    570729/**