Make WordPress Core

Ticket #49693: 49693-2.patch

File 49693-2.patch, 6.8 KB (added by aidvu, 4 years ago)

Patch + tests for wp_reschedule_event.

  • src/wp-includes/cron.php

     
    179179 *
    180180 * @link https://developer.wordpress.org/reference/functions/wp_schedule_event/
    181181 *
    182  * @param int    $timestamp  Unix timestamp (UTC) for when to next run the event.
    183  * @param string $recurrence How often the event should subsequently recur. See wp_get_schedules() for accepted values.
    184  * @param string $hook       Action hook to execute when the event is run.
    185  * @param array  $args       Optional. Array containing each separate argument to pass to the hook's callback function.
     182 * @param int    $timestamp    Unix timestamp (UTC) for when to next run the event.
     183 * @param string $recurrence   How often the event should subsequently recur. See wp_get_schedules() for accepted values.
     184 * @param string $hook         Action hook to execute when the event is run.
     185 * @param array  $args         Optional. Array containing each separate argument to pass to the hook's callback function.
     186 * @param bool   $rescheduling Optional. Whether this is an event rescheduling. Mostly for internal use.
    186187 * @return bool True if event successfully scheduled. False for failure.
    187188 */
    188 function wp_schedule_event( $timestamp, $recurrence, $hook, $args = array() ) {
     189function wp_schedule_event( $timestamp, $recurrence, $hook, $args = array(), $rescheduling = false ) {
    189190        // Make sure timestamp is a positive integer.
    190191        if ( ! is_numeric( $timestamp ) || $timestamp <= 0 ) {
    191192                return false;
     
    220221        }
    221222
    222223        $key = md5( serialize( $event->args ) );
     224        $crons = (array) _get_cron_array();
     225
     226        // If we're not rescheduling an event, drop if it has the same hook, args and schedule.
     227        if ( false === $rescheduling ) {
     228                foreach ( $crons as $event_timestamp => $cron ) {
     229                        if ( isset( $cron[ $event->hook ][ $key ] ) && $cron[ $event->hook ][ $key ]['schedule'] === $event->schedule ) {
     230                                return false;
     231                        }
     232                }
     233        }
    223234
    224         $crons = _get_cron_array();
    225235        $crons[ $event->timestamp ][ $event->hook ][ $key ] = array(
    226236                'schedule' => $event->schedule,
    227237                'args'     => $event->args,
     
    320330                $timestamp = $now + ( $interval - ( ( $now - $timestamp ) % $interval ) );
    321331        }
    322332
    323         return wp_schedule_event( $timestamp, $recurrence, $hook, $args );
     333        return wp_schedule_event( $timestamp, $recurrence, $hook, $args, true );
    324334}
    325335
    326336/**
  • tests/phpunit/tests/cron.php

     
    534534         * @ticket 45976.
    535535         */
    536536        function test_get_scheduled_event_recurring() {
    537                 $hook     = __FUNCTION__;
    538                 $args     = array( 'arg1' );
    539                 $ts_late  = strtotime( '+30 minutes' );
    540                 $ts_next  = strtotime( '+3 minutes' );
    541                 $schedule = 'hourly';
    542                 $interval = HOUR_IN_SECONDS;
     537                $hook         = __FUNCTION__;
     538                $args         = array( 'arg1' );
     539                $ts_late      = strtotime( '+30 minutes' );
     540                $ts_next      = strtotime( '+3 minutes' );
     541                $schedule_one = 'hourly';
     542                $schedule_two = 'daily';
     543                $interval_one = HOUR_IN_SECONDS;
     544                $interval_two = DAY_IN_SECONDS;
    543545
    544546                $expected1 = (object) array(
    545547                        'hook'      => $hook,
    546548                        'timestamp' => $ts_late,
    547                         'schedule'  => $schedule,
     549                        'schedule'  => $schedule_one,
    548550                        'args'      => $args,
    549                         'interval'  => $interval,
     551                        'interval'  => $interval_one,
    550552                );
    551553
    552554                $expected2 = (object) array(
    553555                        'hook'      => $hook,
    554556                        'timestamp' => $ts_next,
    555                         'schedule'  => $schedule,
     557                        'schedule'  => $schedule_two,
    556558                        'args'      => $args,
    557                         'interval'  => $interval,
     559                        'interval'  => $interval_two,
    558560                );
    559561
    560562                // Schedule late running event.
    561                 wp_schedule_event( $ts_late, $schedule, $hook, $args );
     563                wp_schedule_event( $ts_late, $schedule_one, $hook, $args );
    562564                // Schedule next running event.
    563                 wp_schedule_event( $ts_next, $schedule, $hook, $args );
     565                wp_schedule_event( $ts_next, $schedule_two, $hook, $args );
    564566
    565567                // Late running, timestamp specified.
    566568                $this->assertEquals( $expected1, wp_get_scheduled_event( $hook, $args, $ts_late ) );
     
    680682                $this->assertTrue( wp_schedule_single_event( $ts2, $hook, $args ) );
    681683                $this->assertTrue( wp_schedule_single_event( $ts3, $hook, $args ) );
    682684        }
     685
     686        /**
     687         * Recurring events that have the same hook, args and schedule are not allowed.
     688         *
     689         * @ticket 49693
     690         */
     691        function test_duplicate_recurring_event() {
     692                $hook           = __FUNCTION__;
     693                $args           = array( 'arg1' );
     694                $timestamp      = strtotime( '+60 minutes' );
     695                $timestamp_next = strtotime( '+120 minutes' );
     696                $schedule       = 'hourly';
     697
     698                // Schedule recurring event.
     699                $this->assertNotFalse( wp_schedule_event( $timestamp, $schedule, $hook, $args ) );
     700                // Make sure the event is correctly scheduled
     701                $this->assertNotFalse( wp_get_scheduled_event( $hook, $args ) );
     702
     703                $expected = _get_cron_array();
     704
     705                // Scheduling the same recurring event (hook and args), but with different timestamp should fail.
     706                $this->assertFalse( wp_schedule_event( $timestamp_next, $schedule, $hook, $args ) );
     707
     708                // Check cron option is unchanged.
     709                $this->assertEquals( $expected, _get_cron_array() );
     710        }
     711
     712        /**
     713         * Recurring events that have the same hook but different args or schedule are allowed.
     714         *
     715         * @ticket 49693
     716         */
     717        function test_not_duplicate_recurring_event() {
     718                $hook         = __FUNCTION__;
     719                $args_one     = array( 'arg1' );
     720                $args_two     = array( 'arg2' );
     721                $timestamp    = strtotime( '+60 minutes' );
     722                $schedule_one = 'hourly';
     723                $schedule_two = 'daily';
     724
     725                // Schedule recurring event.
     726                $this->assertNotFalse( wp_schedule_event( $timestamp, $schedule_one, $hook, $args_one ) );
     727
     728                // Schedule recurring event as above, but with different schedule is allowed.
     729                $this->assertNotFalse( wp_schedule_event( $timestamp, $schedule_two, $hook, $args_one ) );
     730
     731                // Schedule recurring event as above, but with different args is allowed.
     732                $this->assertNotFalse( wp_schedule_event( $timestamp, $schedule_one, $hook, $args_two ) );
     733        }
     734
     735        /**
     736         * Make sure that rescheduling still works after duplicate removal.
     737         *
     738         * @ticket 49693
     739         */
     740        function test_reschedule_recurring_event() {
     741                $hook   = __FUNCTION__;
     742                $ts_one = strtotime( '+30 minutes' );
     743
     744                // Confirm there's no events.
     745                $this->assertEmpty( _get_cron_array() );
     746
     747                // Add an event.
     748                $this->assertTrue( wp_schedule_event( $ts_one, 'hourly', $hook ) );
     749
     750                // Reschedule it.
     751                $this->assertNotFalse( wp_reschedule_event( $ts_one, 'hourly', $hook ) );
     752
     753                // Make sure the original event is still there.
     754                $this->assertNotFalse( wp_get_scheduled_event( $hook, array(), $ts_one ) );
     755
     756                // Make sure the rescheduled event is also there.
     757                $this->assertEquals( 2, count( _get_cron_array() ) );
     758        }
    683759}