WordPress.org

Make WordPress Core

Ticket #21072: 21072.2.diff

File 21072.2.diff, 17.3 KB (added by peterwilsoncc, 2 years ago)
  • src/wp-includes/cron.php

    diff --git src/wp-includes/cron.php src/wp-includes/cron.php
    index fbf5a629af..e66ea346e1 100644
     
    2121 * Use wp_schedule_event() to schedule a recurring event.
    2222 *
    2323 * @since 2.1.0
     24 * @since 5.0.0 Return value modified to boolean indicating success or failure.
     25 *
    2426 * @link https://codex.wordpress.org/Function_Reference/wp_schedule_single_event
    2527 *
    2628 * @param int    $timestamp  Unix timestamp (UTC) for when to next run the event.
    2729 * @param string $hook       Action hook to execute when the event is run.
    2830 * @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.
     31 * @return bool True if event successfully scheduled. False for failure.
    3032 */
    3133function wp_schedule_single_event( $timestamp, $hook, $args = array() ) {
    3234        // Make sure timestamp is a positive integer
    function wp_schedule_single_event( $timestamp, $hook, $args = array() ) { 
    7779                'args'     => $event->args,
    7880        );
    7981        uksort( $crons, 'strnatcasecmp' );
    80         _set_cron_array( $crons );
     82        return _set_cron_array( $crons );
    8183}
    8284
    8385/**
    function wp_schedule_single_event( $timestamp, $hook, $args = array() ) { 
    99101 * Use wp_schedule_single_event() to schedule a non-recurring event.
    100102 *
    101103 * @since 2.1.0
     104 * @since 5.0.0 Return value modified to boolean indicating success or failure.
     105 *
    102106 * @link https://codex.wordpress.org/Function_Reference/wp_schedule_event
    103107 *
    104108 * @param int    $timestamp  Unix timestamp (UTC) for when to next run the event.
    105109 * @param string $recurrence How often the event should subsequently recur. See wp_get_schedules() for accepted values.
    106110 * @param string $hook       Action hook to execute when the event is run.
    107111 * @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.
     112 * @return bool True if event successfully scheduled. False for failure.
    109113 */
    110114function wp_schedule_event( $timestamp, $recurrence, $hook, $args = array() ) {
    111115        // Make sure timestamp is a positive integer
    function wp_schedule_event( $timestamp, $recurrence, $hook, $args = array() ) { 
    143147                'interval' => $event->interval,
    144148        );
    145149        uksort( $crons, 'strnatcasecmp' );
    146         _set_cron_array( $crons );
     150        return _set_cron_array( $crons );
    147151}
    148152
    149153/**
    150154 * Reschedules a recurring event.
    151155 *
    152156 * @since 2.1.0
     157 * @since 5.0.0 Return value modified to boolean indicating success or failure.
    153158 *
    154159 * @param int    $timestamp  Unix timestamp (UTC) for when to next run the event.
    155160 * @param string $recurrence How often the event should subsequently recur. See wp_get_schedules() for accepted values.
    156161 * @param string $hook       Action hook to execute when the event is run.
    157162 * @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.
     163 * @return bool True if event successfully rescheduled. False for failure.
    159164 */
    160165function wp_reschedule_event( $timestamp, $recurrence, $hook, $args = array() ) {
    161166        // Make sure timestamp is a positive integer
    function wp_reschedule_event( $timestamp, $recurrence, $hook, $args = array() ) 
    189194                $timestamp = $now + ( $interval - ( ( $now - $timestamp ) % $interval ) );
    190195        }
    191196
    192         wp_schedule_event( $timestamp, $recurrence, $hook, $args );
     197        return wp_schedule_event( $timestamp, $recurrence, $hook, $args );
    193198}
    194199
    195200/**
    function wp_reschedule_event( $timestamp, $recurrence, $hook, $args = array() ) 
    199204 * identified.
    200205 *
    201206 * @since 2.1.0
     207 * @since 5.0.0 Return value modified to boolean indicating success or failure.
    202208 *
    203209 * @param int    $timestamp Unix timestamp (UTC) of the event.
    204210 * @param string $hook      Action hook of the event.
    205211 * @param array  $args      Optional. Array containing each separate argument to pass to the hook's callback function.
    206212 *                          Although not passed to a callback, these arguments are used to uniquely identify the
    207213 *                          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.
     214 * @return bool True if event successfully unscheduled. False for failure.
    209215 */
    210216function wp_unschedule_event( $timestamp, $hook, $args = array() ) {
    211217        // Make sure timestamp is a positive integer
    function wp_unschedule_event( $timestamp, $hook, $args = array() ) { 
    222228        if ( empty( $crons[ $timestamp ] ) ) {
    223229                unset( $crons[ $timestamp ] );
    224230        }
    225         _set_cron_array( $crons );
     231        return _set_cron_array( $crons );
    226232}
    227233
    228234/**
    229235 * Unschedules all events attached to the hook with the specified arguments.
    230236 *
     237 * Warning: This function may return Boolean FALSE, but may also return a non-Boolean
     238 * value which evaluates to FALSE. For information about casting to booleans see the
     239 * {@link http://php.net/manual/en/language.types.boolean.php PHP documentation}. Use
     240 * the `===` operator for testing the return value of this function.
     241 *
    231242 * @since 2.1.0
     243 * @since 5.0.0 Return value modified to indicate success or failure.
    232244 *
    233245 * @param string $hook Action hook, the execution of which will be unscheduled.
    234246 * @param array $args Optional. Arguments that were to be passed to the hook's callback function.
     247 * @return bool|int On success an integer indicating number of events unscheduled (0 indicates no
     248 *                  events were registered with the hook and arguments combination), false if
     249 *                  unscheduling one or more events fail.
    235250 */
    236251function wp_clear_scheduled_hook( $hook, $args = array() ) {
    237252        // Backward compatibility
    function wp_clear_scheduled_hook( $hook, $args = array() ) { 
    246261        // and, wp_next_scheduled() returns the same schedule in an infinite loop.
    247262        $crons = _get_cron_array();
    248263        if ( empty( $crons ) ) {
    249                 return;
     264                return 0;
    250265        }
    251266
    252         $key = md5( serialize( $args ) );
     267        $results = array();
     268        $key     = md5( serialize( $args ) );
    253269        foreach ( $crons as $timestamp => $cron ) {
    254270                if ( isset( $cron[ $hook ][ $key ] ) ) {
    255                         wp_unschedule_event( $timestamp, $hook, $args );
     271                        $results[] = wp_unschedule_event( $timestamp, $hook, $args );
    256272                }
    257273        }
     274        if ( in_array( false, $results, true ) ) {
     275                return false;
     276        }
     277        return count( $results );
    258278}
    259279
    260280/**
    function wp_clear_scheduled_hook( $hook, $args = array() ) { 
    262282 *
    263283 * Can be useful for plugins when deactivating to clean up the cron queue.
    264284 *
     285 * Warning: This function may return Boolean FALSE, but may also return a non-Boolean
     286 * value which evaluates to FALSE. For information about casting to booleans see the
     287 * {@link http://php.net/manual/en/language.types.boolean.php PHP documentation}. Use
     288 * the `===` operator for testing the return value of this function.
     289 *
    265290 * @since 4.9.0
     291 * @since 5.0.0 Return value added to indicate success or failure.
    266292 *
    267293 * @param string $hook Action hook, the execution of which will be unscheduled.
     294 * @return bool|int On success an integer indicating number of events unscheduled (0 indicates no
     295 *                  events were registered on the hook), false if unscheduling fails.
    268296 */
    269297function wp_unschedule_hook( $hook ) {
    270298        $crons = _get_cron_array();
     299        if ( empty( $crons ) ) {
     300                return 0;
     301        }
    271302
     303        $results = array();
    272304        foreach ( $crons as $timestamp => $args ) {
     305                if ( ! empty( $crons[ $timestamp ][ $hook ] ) ) {
     306                        $results[] = count( $crons[ $timestamp ][ $hook ] );
     307                }
    273308                unset( $crons[ $timestamp ][ $hook ] );
    274309
    275310                if ( empty( $crons[ $timestamp ] ) ) {
    function wp_unschedule_hook( $hook ) { 
    277312                }
    278313        }
    279314
    280         _set_cron_array( $crons );
     315        if ( _set_cron_array( $crons ) ) {
     316                return array_sum( $results );
     317        }
     318        return false;
    281319}
    282320
    283321/**
    function wp_next_scheduled( $hook, $args = array() ) { 
    309347 * Sends a request to run cron through HTTP request that doesn't halt page loading.
    310348 *
    311349 * @since 2.1.0
     350 * @since 5.0.0 Return values added.
    312351 *
    313352 * @param int $gmt_time Optional. Unix timestamp (UTC). Default 0 (current time is used).
     353 * @return false|WP_Error|array False if no events need to run needed to run.
     354 *                              When cron runs, return the result of {@see wp_remote_post}
    314355 */
    315356function spawn_cron( $gmt_time = 0 ) {
    316357        if ( ! $gmt_time ) {
    function spawn_cron( $gmt_time = 0 ) { 
    318359        }
    319360
    320361        if ( defined( 'DOING_CRON' ) || isset( $_GET['doing_wp_cron'] ) ) {
    321                 return;
     362                return false;
    322363        }
    323364
    324365        /*
    function spawn_cron( $gmt_time = 0 ) { 
    336377
    337378        // don't run if another process is currently running it or more than once every 60 sec.
    338379        if ( $lock + WP_CRON_LOCK_TIMEOUT > $gmt_time ) {
    339                 return;
     380                return false;
    340381        }
    341382
    342383        //sanity check
    343384        $crons = _get_cron_array();
    344385        if ( ! is_array( $crons ) ) {
    345                 return;
     386                return false;
    346387        }
    347388
    348389        $keys = array_keys( $crons );
    349390        if ( isset( $keys[0] ) && $keys[0] > $gmt_time ) {
    350                 return;
     391                return false;
    351392        }
    352393
    353394        if ( defined( 'ALTERNATE_WP_CRON' ) && ALTERNATE_WP_CRON ) {
    354395                if ( 'GET' !== $_SERVER['REQUEST_METHOD'] || defined( 'DOING_AJAX' ) || defined( 'XMLRPC_REQUEST' ) ) {
    355                         return;
     396                        return false;
    356397                }
    357398
    358399                $doing_wp_cron = sprintf( '%.22F', $gmt_time );
    function spawn_cron( $gmt_time = 0 ) { 
    368409                flush();
    369410
    370411                WP_DEBUG ? include_once( ABSPATH . 'wp-cron.php' ) : @include_once( ABSPATH . 'wp-cron.php' );
    371                 return;
     412                return false;
    372413        }
    373414
    374415        // Set the cron lock with the current unix timestamp, when the cron is being spawned.
    function spawn_cron( $gmt_time = 0 ) { 
    409450                ), $doing_wp_cron
    410451        );
    411452
    412         wp_remote_post( $cron_request['url'], $cron_request['args'] );
     453        return wp_remote_post( $cron_request['url'], $cron_request['args'] );
    413454}
    414455
    415456/**
    416457 * Run scheduled callbacks or spawn cron for all scheduled events.
    417458 *
     459 * Warning: This function may return Boolean FALSE, but may also return a non-Boolean
     460 * value which evaluates to FALSE. For information about casting to booleans see the
     461 * {@link http://php.net/manual/en/language.types.boolean.php PHP documentation}. Use
     462 * the `===` operator for testing the return value of this function.
     463 *
    418464 * @since 2.1.0
     465 * @since 5.0.0 Return value added to indicate success or failure.
     466 *
     467 * @return bool|int On success an integer indicating number of events spawned (0 indicates no
     468 *                  events needed to be spawned), false if spawning fails for one or more events.
    419469 */
    420470function wp_cron() {
    421471        // Prevent infinite loops caused by lack of wp-cron.php
    422472        if ( strpos( $_SERVER['REQUEST_URI'], '/wp-cron.php' ) !== false || ( defined( 'DISABLE_WP_CRON' ) && DISABLE_WP_CRON ) ) {
    423                 return;
     473                return 0;
    424474        }
    425475
    426         if ( false === $crons = _get_cron_array() ) {
    427                 return;
     476        $crons = _get_cron_array();
     477        if ( false === $crons ) {
     478                return 0;
    428479        }
    429480
    430481        $gmt_time = microtime( true );
    431482        $keys     = array_keys( $crons );
    432483        if ( isset( $keys[0] ) && $keys[0] > $gmt_time ) {
    433                 return;
     484                return 0;
    434485        }
    435486
    436487        $schedules = wp_get_schedules();
     488        $results   = array();
    437489        foreach ( $crons as $timestamp => $cronhooks ) {
    438490                if ( $timestamp > $gmt_time ) {
    439491                        break;
    function wp_cron() { 
    442494                        if ( isset( $schedules[ $hook ]['callback'] ) && ! call_user_func( $schedules[ $hook ]['callback'] ) ) {
    443495                                continue;
    444496                        }
    445                         spawn_cron( $gmt_time );
     497                        if ( is_wp_error( spawn_cron( $gmt_time ) ) ) {
     498                                $results[] = false;
     499                        }
     500                        $results[] = true;
    446501                        break 2;
    447502                }
    448503        }
     504
     505        if ( in_array( false, $results, true ) ) {
     506                return false;
     507        }
     508        return count( $results );
     509
    449510}
    450511
    451512/**
    function _get_cron_array() { 
    558619 * Updates the CRON option with the new CRON array.
    559620 *
    560621 * @since 2.1.0
     622 * @since 5.0.0 Return value modified to outcome of {@see update_option}.
     623 *
    561624 * @access private
    562625 *
    563626 * @param array $cron Cron info array from _get_cron_array().
     627 * @return bool True if cron array updated, false on failure.
    564628 */
    565629function _set_cron_array( $cron ) {
    566630        $cron['version'] = 2;
    567         update_option( 'cron', $cron );
     631        return update_option( 'cron', $cron );
    568632}
    569633
    570634/**
  • tests/phpunit/tests/cron.php

    diff --git tests/phpunit/tests/cron.php tests/phpunit/tests/cron.php
    index 8caab773d9..1c8ec97a1a 100644
    class Tests_Cron extends WP_UnitTestCase { 
    2929                $hook      = __FUNCTION__;
    3030                $timestamp = strtotime( '+1 hour' );
    3131
    32                 wp_schedule_single_event( $timestamp, $hook );
     32                $scheduled = wp_schedule_single_event( $timestamp, $hook );
     33                $this->assertTrue( $scheduled );
    3334                $this->assertEquals( $timestamp, wp_next_scheduled( $hook ) );
    3435
    3536                // it's a non recurring event
    class Tests_Cron extends WP_UnitTestCase { 
    4344                $timestamp = strtotime( '+1 hour' );
    4445                $args      = array( 'foo' );
    4546
    46                 wp_schedule_single_event( $timestamp, $hook, $args );
     47                $scheduled = wp_schedule_single_event( $timestamp, $hook, $args );
     48                $this->assertTrue( $scheduled );
    4749                // this returns the timestamp only if we provide matching args
    4850                $this->assertEquals( $timestamp, wp_next_scheduled( $hook, $args ) );
    4951                // these don't match so return nothing
    class Tests_Cron extends WP_UnitTestCase { 
    6062                $recur     = 'hourly';
    6163                $timestamp = strtotime( '+1 hour' );
    6264
    63                 wp_schedule_event( $timestamp, $recur, $hook );
     65                $scheduled = wp_schedule_event( $timestamp, $recur, $hook );
     66                $this->assertTrue( $scheduled );
    6467                // it's scheduled for the right time
    6568                $this->assertEquals( $timestamp, wp_next_scheduled( $hook ) );
    6669                // it's a recurring event
    class Tests_Cron extends WP_UnitTestCase { 
    7477                $recur     = 'hourly';
    7578                $args      = array( 'foo' );
    7679
    77                 wp_schedule_event( $timestamp, 'hourly', $hook, $args );
     80                $scheduled = wp_schedule_event( $timestamp, 'hourly', $hook, $args );
     81                $this->assertTrue( $scheduled );
    7882                // this returns the timestamp only if we provide matching args
    7983                $this->assertEquals( $timestamp, wp_next_scheduled( $hook, $args ) );
    8084                // these don't match so return nothing
    class Tests_Cron extends WP_UnitTestCase { 
    9498                $this->assertEquals( $timestamp, wp_next_scheduled( $hook ) );
    9599
    96100                // now unschedule it and make sure it's gone
    97                 wp_unschedule_event( $timestamp, $hook );
     101                $unscheduled = wp_unschedule_event( $timestamp, $hook );
     102                $this->assertTrue( $unscheduled );
    98103                $this->assertEquals( false, wp_next_scheduled( $hook ) );
    99104        }
    100105
    class Tests_Cron extends WP_UnitTestCase { 
    113118                $this->assertTrue( wp_next_scheduled( $hook, $args ) > 0 );
    114119
    115120                // clear the schedule for the no args events and make sure it's gone
    116                 wp_clear_scheduled_hook( $hook );
     121                $hook_unscheduled = wp_clear_scheduled_hook( $hook );
     122                $this->assertSame( 2, $hook_unscheduled );
    117123                $this->assertFalse( wp_next_scheduled( $hook ) );
    118124                // the args events should still be there
    119125                $this->assertTrue( wp_next_scheduled( $hook, $args ) > 0 );
    class Tests_Cron extends WP_UnitTestCase { 
    124130                $this->assertFalse( wp_next_scheduled( $hook, $args ) );
    125131        }
    126132
     133        function test_clear_undefined_schedule() {
     134                $hook = __FUNCTION__;
     135                $args = array( 'arg1' );
     136
     137                wp_schedule_single_event( strtotime( '+1 hour' ), $hook, $args );
     138                wp_schedule_single_event( strtotime( '+2 hour' ), $hook, $args );
     139
     140                // clear the schedule for no args events and ensure no events are cleared.
     141                $hook_unscheduled = wp_clear_scheduled_hook( $hook );
     142                $this->assertSame( 0, $hook_unscheduled );
     143        }
     144
    127145        function test_clear_schedule_multiple_args() {
    128146                $hook = __FUNCTION__;
    129147                $args = array( 'arg1', 'arg2' );
    class Tests_Cron extends WP_UnitTestCase { 
    206224                $this->assertTrue( wp_next_scheduled( $hook, $args ) > 0 );
    207225
    208226                // clear the schedule and make sure it's gone.
    209                 wp_unschedule_hook( $hook );
     227                $unschedule_hook = wp_unschedule_hook( $hook );
     228                $this->assertSame( 4, $unschedule_hook );
    210229                $this->assertFalse( wp_next_scheduled( $hook ) );
    211230        }
    212231
    class Tests_Cron extends WP_UnitTestCase { 
    221240                $ts2  = strtotime( '+3 minutes' );
    222241
    223242                // first one works
    224                 wp_schedule_single_event( $ts1, $hook, $args );
     243                $this->assertTrue( wp_schedule_single_event( $ts1, $hook, $args ) );
    225244                // second one is ignored
    226                 wp_schedule_single_event( $ts2, $hook, $args );
     245                $this->assertFalse( wp_schedule_single_event( $ts2, $hook, $args ) );
    227246
    228247                // the next event should be at +5 minutes, not +3
    229248                $this->assertEquals( $ts1, wp_next_scheduled( $hook, $args ) );
    class Tests_Cron extends WP_UnitTestCase { 
    240259                $ts2  = strtotime( '+3 minutes' );
    241260
    242261                // first one works
    243                 wp_schedule_single_event( $ts1, $hook, $args );
     262                $this->assertTrue( wp_schedule_single_event( $ts1, $hook, $args ) );
    244263                // second works too
    245                 wp_schedule_single_event( $ts2, $hook, $args );
     264                $this->assertTrue( wp_schedule_single_event( $ts2, $hook, $args ) );
    246265
    247266                // the next event should be at +3 minutes, even though that one was scheduled second
    248267                $this->assertEquals( $ts2, wp_next_scheduled( $hook, $args ) );
    class Tests_Cron extends WP_UnitTestCase { 
    259278                $ts2  = strtotime( '+30 minutes' );
    260279
    261280                // first one works
    262                 wp_schedule_single_event( $ts1, $hook, $args );
     281                $this->assertTrue( wp_schedule_single_event( $ts1, $hook, $args ) );
    263282                // second works too
    264                 wp_schedule_single_event( $ts2, $hook, $args );
     283                $this->assertTrue( wp_schedule_single_event( $ts2, $hook, $args ) );
    265284
    266285                // the next event should be at +3 minutes
    267286                $this->assertEquals( $ts1, wp_next_scheduled( $hook, $args ) );