Make WordPress Core

Changeset 50143


Ignore:
Timestamp:
02/02/2021 01:47:46 PM (4 years ago)
Author:
johnbillion
Message:

Cron API: Introduce a $wp_error parameter to functions that write to the cron array.

This allows the functions to return a WP_Error object containing more information in case of a problem, instead of just boolean false.

The various pre_ filters in these functions are also updated so they can return or be passed a WP_Error object.

Fixes #49961

Location:
trunk
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/wp-includes/cron.php

    r50135 r50143  
    2424 * @since 5.1.0 Return value modified to boolean indicating success or failure,
    2525 *              {@see 'pre_schedule_event'} filter added to short-circuit the function.
     26 * @since 5.7.0 The `$wp_error` parameter was added.
    2627 *
    2728 * @link https://developer.wordpress.org/reference/functions/wp_schedule_single_event/
     
    3334 *                           to the callback as an individual parameter. The array keys
    3435 *                           are ignored. Default: empty array.
    35  * @return bool True if event successfully scheduled. False for failure.
    36  */
    37 function wp_schedule_single_event( $timestamp, $hook, $args = array() ) {
     36 * @param bool   $wp_error   Optional. Whether to return a WP_Error on failure. Default false.
     37 * @return bool|WP_Error True if event successfully scheduled. False or WP_Error on failure.
     38 */
     39function wp_schedule_single_event( $timestamp, $hook, $args = array(), $wp_error = false ) {
    3840    // Make sure timestamp is a positive integer.
    3941    if ( ! is_numeric( $timestamp ) || $timestamp <= 0 ) {
     42        if ( $wp_error ) {
     43            return new WP_Error(
     44                'invalid_timestamp',
     45                __( 'Event timestamp must be a valid Unix timestamp.' )
     46            );
     47        }
     48
    4049        return false;
    4150    }
     
    6372     * filter to check if another plugin has disallowed the event before scheduling.
    6473     *
    65      * Return true if the event was scheduled, false if not.
     74     * Return true if the event was scheduled, false or a WP_Error if not.
    6675     *
    6776     * @since 5.1.0
    68      *
    69      * @param null|bool $pre   Value to return instead. Default null to continue adding the event.
    70      * @param stdClass  $event {
     77     * @since 5.7.0 The `$wp_error` parameter was added, and a `WP_Error` object can now be returned.
     78     *
     79     * @param null|bool|WP_Error $pre      Value to return instead. Default null to continue adding the event.
     80     * @param stdClass           $event    {
    7181     *     An object containing an event's data.
    7282     *
     
    7787     *     @type int          $interval  The interval time in seconds for the schedule. Only present for recurring events.
    7888     * }
    79      */
    80     $pre = apply_filters( 'pre_schedule_event', null, $event );
     89     * @param bool               $wp_error Whether to return a WP_Error on failure.
     90     */
     91    $pre = apply_filters( 'pre_schedule_event', null, $event, $wp_error );
     92
    8193    if ( null !== $pre ) {
     94        if ( $wp_error && false === $pre ) {
     95            return new WP_Error(
     96                'pre_schedule_event_false',
     97                __( 'A plugin prevented the event from being scheduled.' )
     98            );
     99        }
     100
     101        if ( ! $wp_error && is_wp_error( $pre ) ) {
     102            return false;
     103        }
     104
    82105        return $pre;
    83106    }
     
    126149
    127150    if ( $duplicate ) {
     151        if ( $wp_error ) {
     152            return new WP_Error(
     153                'duplicate_event',
     154                __( 'A duplicate event already exists.' )
     155            );
     156        }
     157
    128158        return false;
    129159    }
     
    148178    // A plugin disallowed this event.
    149179    if ( ! $event ) {
     180        if ( $wp_error ) {
     181            return new WP_Error(
     182                'schedule_event_false',
     183                __( 'A plugin disallowed this event.' )
     184            );
     185        }
     186
    150187        return false;
    151188    }
     
    156193    );
    157194    uksort( $crons, 'strnatcasecmp' );
    158     return _set_cron_array( $crons );
     195
     196    return _set_cron_array( $crons, $wp_error );
    159197}
    160198
     
    180218 * @since 5.1.0 Return value modified to boolean indicating success or failure,
    181219 *              {@see 'pre_schedule_event'} filter added to short-circuit the function.
     220 * @since 5.7.0 The `$wp_error` parameter was added.
    182221 *
    183222 * @link https://developer.wordpress.org/reference/functions/wp_schedule_event/
     
    191230 *                           to the callback as an individual parameter. The array keys
    192231 *                           are ignored. Default: empty array.
    193  * @return bool True if event successfully scheduled. False for failure.
    194  */
    195 function wp_schedule_event( $timestamp, $recurrence, $hook, $args = array() ) {
     232 * @param bool   $wp_error   Optional. Whether to return a WP_Error on failure. Default false.
     233 * @return bool|WP_Error True if event successfully scheduled. False or WP_Error on failure.
     234 */
     235function wp_schedule_event( $timestamp, $recurrence, $hook, $args = array(), $wp_error = false ) {
    196236    // Make sure timestamp is a positive integer.
    197237    if ( ! is_numeric( $timestamp ) || $timestamp <= 0 ) {
     238        if ( $wp_error ) {
     239            return new WP_Error(
     240                'invalid_timestamp',
     241                __( 'Event timestamp must be a valid Unix timestamp.' )
     242            );
     243        }
     244
    198245        return false;
    199246    }
     
    202249
    203250    if ( ! isset( $schedules[ $recurrence ] ) ) {
     251        if ( $wp_error ) {
     252            return new WP_Error(
     253                'invalid_schedule',
     254                __( 'Event schedule does not exist.' )
     255            );
     256        }
     257
    204258        return false;
    205259    }
     
    214268
    215269    /** This filter is documented in wp-includes/cron.php */
    216     $pre = apply_filters( 'pre_schedule_event', null, $event );
     270    $pre = apply_filters( 'pre_schedule_event', null, $event, $wp_error );
     271
    217272    if ( null !== $pre ) {
     273        if ( $wp_error && false === $pre ) {
     274            return new WP_Error(
     275                'pre_schedule_event_false',
     276                __( 'A plugin prevented the event from being scheduled.' )
     277            );
     278        }
     279
     280        if ( ! $wp_error && is_wp_error( $pre ) ) {
     281            return false;
     282        }
     283
    218284        return $pre;
    219285    }
     
    224290    // A plugin disallowed this event.
    225291    if ( ! $event ) {
     292        if ( $wp_error ) {
     293            return new WP_Error(
     294                'schedule_event_false',
     295                __( 'A plugin disallowed this event.' )
     296            );
     297        }
     298
    226299        return false;
    227300    }
     
    236309    );
    237310    uksort( $crons, 'strnatcasecmp' );
    238     return _set_cron_array( $crons );
     311
     312    return _set_cron_array( $crons, $wp_error );
    239313}
    240314
     
    251325 * @since 5.1.0 Return value modified to boolean indicating success or failure,
    252326 *              {@see 'pre_reschedule_event'} filter added to short-circuit the function.
     327 * @since 5.7.0 The `$wp_error` parameter was added.
    253328 *
    254329 * @param int    $timestamp  Unix timestamp (UTC) for when the event was scheduled.
     
    260335 *                           to the callback as an individual parameter. The array keys
    261336 *                           are ignored. Default: empty array.
    262  * @return bool True if event successfully rescheduled. False for failure.
    263  */
    264 function wp_reschedule_event( $timestamp, $recurrence, $hook, $args = array() ) {
     337 * @param bool   $wp_error   Optional. Whether to return a WP_Error on failure. Default false.
     338 * @return bool|WP_Error True if event successfully rescheduled. False or WP_Error on failure.
     339 */
     340function wp_reschedule_event( $timestamp, $recurrence, $hook, $args = array(), $wp_error = false ) {
    265341    // Make sure timestamp is a positive integer.
    266342    if ( ! is_numeric( $timestamp ) || $timestamp <= 0 ) {
     343        if ( $wp_error ) {
     344            return new WP_Error(
     345                'invalid_timestamp',
     346                __( 'Event timestamp must be a valid Unix timestamp.' )
     347            );
     348        }
     349
    267350        return false;
    268351    }
     
    302385     *
    303386     * @since 5.1.0
    304      *
    305      * @param null|bool $pre   Value to return instead. Default null to continue adding the event.
    306      * @param stdClass  $event {
     387     * @since 5.7.0 The `$wp_error` parameter was added, and a `WP_Error` object can now be returned.
     388     *
     389     * @param null|bool|WP_Error $pre      Value to return instead. Default null to continue adding the event.
     390     * @param stdClass           $event    {
    307391     *     An object containing an event's data.
    308392     *
     
    313397     *     @type int          $interval  The interval time in seconds for the schedule. Only present for recurring events.
    314398     * }
     399     * @param bool               $wp_error Whether to return a WP_Error on failure.
    315400     */
    316401    $pre = apply_filters( 'pre_reschedule_event', null, $event );
     402
    317403    if ( null !== $pre ) {
     404        if ( $wp_error && false === $pre ) {
     405            return new WP_Error(
     406                'pre_reschedule_event_false',
     407                __( 'A plugin prevented the event from being rescheduled.' )
     408            );
     409        }
     410
     411        if ( ! $wp_error && is_wp_error( $pre ) ) {
     412            return false;
     413        }
     414
    318415        return $pre;
    319416    }
     
    321418    // Now we assume something is wrong and fail to schedule.
    322419    if ( 0 == $interval ) {
     420        if ( $wp_error ) {
     421            return new WP_Error(
     422                'invalid_schedule',
     423                __( 'Event schedule does not exist.' )
     424            );
     425        }
     426
    323427        return false;
    324428    }
     
    332436    }
    333437
    334     return wp_schedule_event( $timestamp, $recurrence, $hook, $args );
     438    return wp_schedule_event( $timestamp, $recurrence, $hook, $args, $wp_error );
    335439}
    336440
     
    344448 * @since 5.1.0 Return value modified to boolean indicating success or failure,
    345449 *              {@see 'pre_unschedule_event'} filter added to short-circuit the function.
     450 * @since 5.7.0 The `$wp_error` parameter was added.
    346451 *
    347452 * @param int    $timestamp Unix timestamp (UTC) of the event.
     
    350455 *                          Although not passed to a callback, these arguments are used to uniquely identify the
    351456 *                          event, so they should be the same as those used when originally scheduling the event.
    352  * @return bool True if event successfully unscheduled. False for failure.
    353  */
    354 function wp_unschedule_event( $timestamp, $hook, $args = array() ) {
     457 * @param bool   $wp_error  Optional. Whether to return a WP_Error on failure. Default false.
     458 * @return bool|WP_Error True if event successfully unscheduled. False or WP_Error on failure.
     459 */
     460function wp_unschedule_event( $timestamp, $hook, $args = array(), $wp_error = false ) {
    355461    // Make sure timestamp is a positive integer.
    356462    if ( ! is_numeric( $timestamp ) || $timestamp <= 0 ) {
     463        if ( $wp_error ) {
     464            return new WP_Error(
     465                'invalid_timestamp',
     466                __( 'Event timestamp must be a valid Unix timestamp.' )
     467            );
     468        }
     469
    357470        return false;
    358471    }
     
    368481     *
    369482     * @since 5.1.0
    370      *
    371      * @param null|bool $pre       Value to return instead. Default null to continue unscheduling the event.
    372      * @param int       $timestamp Timestamp for when to run the event.
    373      * @param string    $hook      Action hook, the execution of which will be unscheduled.
    374      * @param array     $args      Arguments to pass to the hook's callback function.
    375      */
    376     $pre = apply_filters( 'pre_unschedule_event', null, $timestamp, $hook, $args );
     483     * @since 5.7.0 The `$wp_error` parameter was added, and a `WP_Error` object can now be returned.
     484     *
     485     * @param null|bool|WP_Error $pre       Value to return instead. Default null to continue unscheduling the event.
     486     * @param int                $timestamp Timestamp for when to run the event.
     487     * @param string             $hook      Action hook, the execution of which will be unscheduled.
     488     * @param array              $args      Arguments to pass to the hook's callback function.
     489     * @param bool               $wp_error  Whether to return a WP_Error on failure.
     490     */
     491    $pre = apply_filters( 'pre_unschedule_event', null, $timestamp, $hook, $args, $wp_error );
     492
    377493    if ( null !== $pre ) {
     494        if ( $wp_error && false === $pre ) {
     495            return new WP_Error(
     496                'pre_unschedule_event_false',
     497                __( 'A plugin prevented the event from being unscheduled.' )
     498            );
     499        }
     500
     501        if ( ! $wp_error && is_wp_error( $pre ) ) {
     502            return false;
     503        }
     504
    378505        return $pre;
    379506    }
     
    388515        unset( $crons[ $timestamp ] );
    389516    }
    390     return _set_cron_array( $crons );
     517
     518    return _set_cron_array( $crons, $wp_error );
    391519}
    392520
     
    407535 *                     Although not passed to a callback, these arguments are used to uniquely identify the
    408536 *                     event, so they should be the same as those used when originally scheduling the event.
    409  * @return int|false On success an integer indicating number of events unscheduled (0 indicates no
    410  *                   events were registered with the hook and arguments combination), false if
    411  *                   unscheduling one or more events fail.
    412  */
    413 function wp_clear_scheduled_hook( $hook, $args = array() ) {
     537 * @param bool   $wp_error  Optional. Whether to return a WP_Error on failure. Default false.
     538 * @return int|false|WP_Error On success an integer indicating number of events unscheduled (0 indicates no
     539 *                            events were registered with the hook and arguments combination), false or WP_Error
     540 *                            if unscheduling one or more events fail.
     541 */
     542function wp_clear_scheduled_hook( $hook, $args = array(), $wp_error = false ) {
    414543    // Backward compatibility.
    415544    // Previously, this function took the arguments as discrete vars rather than an array like the rest of the API.
     
    417546        _deprecated_argument( __FUNCTION__, '3.0.0', __( 'This argument has changed to an array to match the behavior of the other cron functions.' ) );
    418547        $args = array_slice( func_get_args(), 1 ); // phpcs:ignore PHPCompatibility.FunctionUse.ArgumentFunctionsReportCurrentValue.NeedsInspection
     548        $wp_error = false;
    419549    }
    420550
     
    430560     *
    431561     * @since 5.1.0
    432      *
    433      * @param null|int|false $pre  Value to return instead. Default null to continue unscheduling the event.
    434      * @param string         $hook Action hook, the execution of which will be unscheduled.
    435      * @param array          $args Arguments to pass to the hook's callback function.
    436      */
    437     $pre = apply_filters( 'pre_clear_scheduled_hook', null, $hook, $args );
     562     * @since 5.7.0 The `$wp_error` parameter was added, and a `WP_Error` object can now be returned.
     563     *
     564     * @param null|int|false|WP_Error $pre      Value to return instead. Default null to continue unscheduling the event.
     565     * @param string                  $hook     Action hook, the execution of which will be unscheduled.
     566     * @param array                   $args     Arguments to pass to the hook's callback function.
     567     * @param bool                    $wp_error Whether to return a WP_Error on failure.
     568     */
     569    $pre = apply_filters( 'pre_clear_scheduled_hook', null, $hook, $args, $wp_error );
     570
    438571    if ( null !== $pre ) {
     572        if ( $wp_error && false === $pre ) {
     573            return new WP_Error(
     574                'pre_clear_scheduled_hook_false',
     575                __( 'A plugin prevented the hook from being cleared.' )
     576            );
     577        }
     578
     579        if ( ! $wp_error && is_wp_error( $pre ) ) {
     580            return false;
     581        }
     582
    439583        return $pre;
    440584    }
     
    452596    $results = array();
    453597    $key     = md5( serialize( $args ) );
     598
    454599    foreach ( $crons as $timestamp => $cron ) {
    455600        if ( isset( $cron[ $hook ][ $key ] ) ) {
    456             $results[] = wp_unschedule_event( $timestamp, $hook, $args );
    457         }
    458     }
    459     if ( in_array( false, $results, true ) ) {
    460         return false;
    461     }
     601            $results[] = wp_unschedule_event( $timestamp, $hook, $args, true );
     602        }
     603    }
     604
     605    $errors = array_filter( $results, 'is_wp_error' );
     606    $error  = new WP_Error();
     607
     608    if ( $errors ) {
     609        if ( $wp_error ) {
     610            array_walk( $errors, array( $error, 'merge_from' ) );
     611
     612            return $error;
     613        }
     614
     615        return false;
     616    }
     617
    462618    return count( $results );
    463619}
     
    475631 * @since 4.9.0
    476632 * @since 5.1.0 Return value added to indicate success or failure.
    477  *
    478  * @param string $hook Action hook, the execution of which will be unscheduled.
    479  * @return int|false On success an integer indicating number of events unscheduled (0 indicates no
    480  *                   events were registered on the hook), false if unscheduling fails.
    481  */
    482 function wp_unschedule_hook( $hook ) {
     633 * @since 5.7.0 The `$wp_error` parameter was added.
     634 *
     635 * @param string $hook     Action hook, the execution of which will be unscheduled.
     636 * @param bool   $wp_error Optional. Whether to return a WP_Error on failure. Default false.
     637 * @return int|false|WP_Error On success an integer indicating number of events unscheduled (0 indicates no
     638 *                            events were registered on the hook), false or WP_Error if unscheduling fails.
     639 */
     640function wp_unschedule_hook( $hook, $wp_error = false ) {
    483641    /**
    484642     * Filter to preflight or hijack clearing all events attached to the hook.
     
    492650     *
    493651     * @since 5.1.0
    494      *
    495      * @param null|int|false $pre  Value to return instead. Default null to continue unscheduling the hook.
    496      * @param string         $hook Action hook, the execution of which will be unscheduled.
    497      */
    498     $pre = apply_filters( 'pre_unschedule_hook', null, $hook );
     652     * @since 5.7.0 The `$wp_error` parameter was added, and a `WP_Error` object can now be returned.
     653     *
     654     * @param null|int|false|WP_Error $pre      Value to return instead. Default null to continue unscheduling the hook.
     655     * @param string                  $hook     Action hook, the execution of which will be unscheduled.
     656     * @param bool                    $wp_error Whether to return a WP_Error on failure.
     657     */
     658    $pre = apply_filters( 'pre_unschedule_hook', null, $hook, $wp_error );
     659
    499660    if ( null !== $pre ) {
     661        if ( $wp_error && false === $pre ) {
     662            return new WP_Error(
     663                'pre_unschedule_hook_false',
     664                __( 'A plugin prevented the hook from being cleared.' )
     665            );
     666        }
     667
     668        if ( ! $wp_error && is_wp_error( $pre ) ) {
     669            return false;
     670        }
     671
    500672        return $pre;
    501673    }
     
    525697        return 0;
    526698    }
    527     if ( _set_cron_array( $crons ) ) {
     699
     700    $set = _set_cron_array( $crons, $wp_error );
     701
     702    if ( true === $set ) {
    528703        return array_sum( $results );
    529704    }
    530     return false;
     705
     706    return $set;
    531707}
    532708
     
    9931169
    9941170/**
    995  * Updates the CRON option with the new CRON array.
     1171 * Updates the cron option with the new cron array.
    9961172 *
    9971173 * @since 2.1.0
    9981174 * @since 5.1.0 Return value modified to outcome of update_option().
     1175 * @since 5.7.0 The `$wp_error` parameter was added.
    9991176 *
    10001177 * @access private
    10011178 *
    1002  * @param array $cron Cron info array from _get_cron_array().
    1003  * @return bool True if cron array updated, false on failure.
    1004  */
    1005 function _set_cron_array( $cron ) {
     1179 * @param array $cron     Cron info array from _get_cron_array().
     1180 * @param bool  $wp_error Optional. Whether to return a WP_Error on failure. Default false.
     1181 * @return bool|WP_Error True if cron array updated. False or WP_Error on failure.
     1182 */
     1183function _set_cron_array( $cron, $wp_error = false ) {
    10061184    $cron['version'] = 2;
    1007     return update_option( 'cron', $cron );
     1185    $result = update_option( 'cron', $cron );
     1186
     1187    if ( $wp_error && ! $result ) {
     1188        return new WP_Error(
     1189            'could_not_set',
     1190            __( 'The cron event list could not be saved.' )
     1191        );
     1192    }
     1193
     1194    return $result;
    10081195}
    10091196
  • trunk/tests/phpunit/tests/cron.php

    r48937 r50143  
    272272        // First one works.
    273273        $this->assertTrue( wp_schedule_single_event( $ts1, $hook, $args ) );
    274         // Second one is ignored.
     274
     275        // Subsequent ones are ignored.
    275276        $this->assertFalse( wp_schedule_single_event( $ts2, $hook, $args ) );
     277        $subsequent = wp_schedule_single_event( $ts2, $hook, $args, true );
     278        $this->assertWPError( $subsequent );
     279        $this->assertSame( 'duplicate_event', $subsequent->get_error_code() );
    276280
    277281        // The next event should be at +5 minutes, not +3.
     
    618622        // Third event fails.
    619623        $this->assertFalse( wp_schedule_single_event( $ts3, $hook, $args ) );
     624
     625        // Fourth event fails.
     626        $subsequent = wp_schedule_single_event( $ts3, $hook, $args, true );
     627        $this->assertWPError( $subsequent );
     628        $this->assertSame( 'duplicate_event', $subsequent->get_error_code() );
    620629    }
    621630
     
    640649        // Third event fails.
    641650        $this->assertFalse( wp_schedule_single_event( $ts3, $hook, $args ) );
     651
     652        // Fourth event fails.
     653        $subsequent = wp_schedule_single_event( $ts3, $hook, $args, true );
     654        $this->assertWPError( $subsequent );
     655        $this->assertSame( 'duplicate_event', $subsequent->get_error_code() );
     656
    642657    }
    643658
     
    660675        $this->assertFalse( wp_schedule_single_event( $ts2, $hook, $args ) );
    661676        $this->assertFalse( wp_schedule_single_event( $ts3, $hook, $args ) );
     677
     678        $subsequent = wp_schedule_single_event( $ts3, $hook, $args, true );
     679        $this->assertWPError( $subsequent );
     680        $this->assertSame( 'duplicate_event', $subsequent->get_error_code() );
    662681    }
    663682
     
    681700        $this->assertTrue( wp_schedule_single_event( $ts3, $hook, $args ) );
    682701    }
     702
     703    /**
     704     * @ticket 49961
     705     */
     706    public function test_invalid_timestamp_for_event_returns_error() {
     707        $single_event      = wp_schedule_single_event( -50, 'hook', array(), true );
     708        $event             = wp_schedule_event( -50, 'daily', 'hook', array(), true );
     709        $rescheduled_event = wp_reschedule_event( -50, 'daily', 'hook', array(), true );
     710        $unscheduled_event = wp_unschedule_event( -50, 'hook', array(), true );
     711
     712        $this->assertWPError( $single_event );
     713        $this->assertSame( 'invalid_timestamp', $single_event->get_error_code() );
     714
     715        $this->assertWPError( $event );
     716        $this->assertSame( 'invalid_timestamp', $event->get_error_code() );
     717
     718        $this->assertWPError( $rescheduled_event );
     719        $this->assertSame( 'invalid_timestamp', $rescheduled_event->get_error_code() );
     720
     721        $this->assertWPError( $unscheduled_event );
     722        $this->assertSame( 'invalid_timestamp', $unscheduled_event->get_error_code() );
     723    }
     724
     725    /**
     726     * @ticket 49961
     727     */
     728    public function test_invalid_recurrence_for_event_returns_error() {
     729        $event             = wp_schedule_event( time(), 'invalid', 'hook', array(), true );
     730        $rescheduled_event = wp_reschedule_event( time(), 'invalid', 'hook', array(), true );
     731
     732        $this->assertWPError( $event );
     733        $this->assertSame( 'invalid_schedule', $event->get_error_code() );
     734
     735        $this->assertWPError( $rescheduled_event );
     736        $this->assertSame( 'invalid_schedule', $rescheduled_event->get_error_code() );
     737    }
     738
     739    /**
     740     * @ticket 49961
     741     */
     742    public function test_disallowed_event_returns_false_when_wp_error_is_set_to_false() {
     743        add_filter( 'schedule_event', '__return_false' );
     744
     745        $single_event      = wp_schedule_single_event( time(), 'hook', array() );
     746        $event             = wp_schedule_event( time(), 'daily', 'hook', array() );
     747        $rescheduled_event = wp_reschedule_event( time(), 'daily', 'hook', array() );
     748
     749        $this->assertFalse( $single_event );
     750        $this->assertFalse( $event );
     751        $this->assertFalse( $rescheduled_event );
     752    }
     753
     754    /**
     755     * @ticket 49961
     756     */
     757    public function test_disallowed_event_returns_error_when_wp_error_is_set_to_true() {
     758        add_filter( 'schedule_event', '__return_false' );
     759
     760        $single_event      = wp_schedule_single_event( time(), 'hook', array(), true );
     761        $event             = wp_schedule_event( time(), 'daily', 'hook', array(), true );
     762        $rescheduled_event = wp_reschedule_event( time(), 'daily', 'hook', array(), true );
     763
     764        $this->assertWPError( $single_event );
     765        $this->assertSame( 'schedule_event_false', $single_event->get_error_code() );
     766
     767        $this->assertWPError( $event );
     768        $this->assertSame( 'schedule_event_false', $event->get_error_code() );
     769
     770        $this->assertWPError( $rescheduled_event );
     771        $this->assertSame( 'schedule_event_false', $rescheduled_event->get_error_code() );
     772    }
     773
     774    /**
     775     * @ticket 49961
     776     */
     777    public function test_schedule_short_circuit_with_error_returns_false_when_wp_error_is_set_to_false() {
     778        $return_error = function() {
     779            return new WP_Error(
     780                'my_error',
     781                'An error ocurred'
     782            );
     783        };
     784
     785        // Add filters which return a WP_Error:
     786        add_filter( 'pre_schedule_event', $return_error );
     787        add_filter( 'pre_reschedule_event', $return_error );
     788
     789        // Schedule events without the `$wp_error` parameter:
     790        $single_event      = wp_schedule_single_event( time(), 'hook', array() );
     791        $event             = wp_schedule_event( time(), 'daily', 'hook', array() );
     792        $rescheduled_event = wp_reschedule_event( time(), 'daily', 'hook', array() );
     793
     794        // Ensure boolean false is returned:
     795        $this->assertFalse( $single_event );
     796        $this->assertFalse( $event );
     797        $this->assertFalse( $rescheduled_event );
     798    }
     799
     800    /**
     801     * @ticket 49961
     802     */
     803    public function test_schedule_short_circuit_with_error_returns_error_when_wp_error_is_set_to_true() {
     804        $return_error = function() {
     805            return new WP_Error(
     806                'my_error',
     807                'An error ocurred'
     808            );
     809        };
     810
     811        // Add filters which return a WP_Error:
     812        add_filter( 'pre_schedule_event', $return_error );
     813        add_filter( 'pre_reschedule_event', $return_error );
     814
     815        // Schedule events with the `$wp_error` parameter:
     816        $single_event      = wp_schedule_single_event( time(), 'hook', array(), true );
     817        $event             = wp_schedule_event( time(), 'daily', 'hook', array(), true );
     818        $rescheduled_event = wp_reschedule_event( time(), 'daily', 'hook', array(), true );
     819
     820        // Ensure the error object is returned:
     821        $this->assertWPError( $single_event );
     822        $this->assertSame( 'my_error', $single_event->get_error_code() );
     823
     824        $this->assertWPError( $event );
     825        $this->assertSame( 'my_error', $event->get_error_code() );
     826
     827        $this->assertWPError( $rescheduled_event );
     828        $this->assertSame( 'my_error', $rescheduled_event->get_error_code() );
     829    }
     830
     831    /**
     832     * @ticket 49961
     833     */
     834    public function test_schedule_short_circuit_with_false_returns_false_when_wp_error_is_set_to_false() {
     835        // Add filters which return false:
     836        add_filter( 'pre_schedule_event', '__return_false' );
     837        add_filter( 'pre_reschedule_event', '__return_false' );
     838
     839        // Schedule events without the `$wp_error` parameter:
     840        $single_event      = wp_schedule_single_event( time(), 'hook', array() );
     841        $event             = wp_schedule_event( time(), 'daily', 'hook', array() );
     842        $rescheduled_event = wp_reschedule_event( time(), 'daily', 'hook', array() );
     843
     844        // Ensure false is returned:
     845        $this->assertFalse( $single_event );
     846        $this->assertFalse( $event );
     847        $this->assertFalse( $rescheduled_event );
     848    }
     849
     850    /**
     851     * @ticket 49961
     852     */
     853    public function test_schedule_short_circuit_with_false_returns_error_when_wp_error_is_set_to_true() {
     854        // Add filters which return false:
     855        add_filter( 'pre_schedule_event', '__return_false' );
     856        add_filter( 'pre_reschedule_event', '__return_false' );
     857
     858        // Schedule events with the `$wp_error` parameter:
     859        $single_event      = wp_schedule_single_event( time(), 'hook', array(), true );
     860        $event             = wp_schedule_event( time(), 'daily', 'hook', array(), true );
     861        $rescheduled_event = wp_reschedule_event( time(), 'daily', 'hook', array(), true );
     862
     863        // Ensure an error object is returned:
     864        $this->assertWPError( $single_event );
     865        $this->assertSame( 'pre_schedule_event_false', $single_event->get_error_code() );
     866
     867        $this->assertWPError( $event );
     868        $this->assertSame( 'pre_schedule_event_false', $event->get_error_code() );
     869
     870        $this->assertWPError( $rescheduled_event );
     871        $this->assertSame( 'pre_reschedule_event_false', $rescheduled_event->get_error_code() );
     872    }
     873
     874    /**
     875     * @ticket 49961
     876     * @expectedDeprecated wp_clear_scheduled_hook
     877     */
     878    public function test_deprecated_argument_usage_of_wp_clear_scheduled_hook() {
     879        add_filter(
     880            'pre_clear_scheduled_hook',
     881            function( $pre, $hook, $args, $wp_error ) {
     882                $this->assertSame( array( 1, 2, 3 ), $args );
     883                $this->assertFalse( $wp_error );
     884
     885                return $pre;
     886            },
     887            10,
     888            4
     889        );
     890
     891        $cleared = wp_clear_scheduled_hook( 'hook', 1, 2, 3 );
     892
     893        $this->assertSame( 0, $cleared );
     894    }
     895
     896    /**
     897     * @ticket 49961
     898     */
     899    public function test_clear_scheduled_hook_returns_default_pre_filter_error_when_wp_error_is_set_to_true() {
     900        add_filter( 'pre_unschedule_event', '__return_false' );
     901
     902        wp_schedule_single_event( strtotime( '+1 hour' ), 'test_hook' );
     903        wp_schedule_single_event( strtotime( '+2 hours' ), 'test_hook' );
     904
     905        $cleared = wp_clear_scheduled_hook( 'test_hook', array(), true );
     906
     907        $this->assertWPError( $cleared );
     908        $this->assertSame(
     909            array(
     910                'pre_unschedule_event_false',
     911            ),
     912            $cleared->get_error_codes()
     913        );
     914        $this->assertCount( 2, $cleared->get_error_messages() );
     915    }
     916
     917    /**
     918     * @ticket 49961
     919     */
     920    public function test_clear_scheduled_hook_returns_custom_pre_filter_error_when_wp_error_is_set_to_true() {
     921        add_filter(
     922            'pre_unschedule_event',
     923            function( $pre ) {
     924                return new WP_Error( 'error_code', 'error message' );
     925            }
     926        );
     927
     928        wp_schedule_single_event( strtotime( '+1 hour' ), 'test_hook' );
     929        wp_schedule_single_event( strtotime( '+2 hours' ), 'test_hook' );
     930
     931        $cleared = wp_clear_scheduled_hook( 'test_hook', array(), true );
     932
     933        $this->assertWPError( $cleared );
     934        $this->assertSame(
     935            array(
     936                'error_code',
     937            ),
     938            $cleared->get_error_codes()
     939        );
     940        $this->assertSame(
     941            array(
     942                'error message',
     943                'error message',
     944            ),
     945            $cleared->get_error_messages()
     946        );
     947    }
     948
     949    /**
     950     * @ticket 49961
     951     */
     952    public function test_unschedule_short_circuit_with_error_returns_false_when_wp_error_is_set_to_false() {
     953        $return_error = function() {
     954            return new WP_Error(
     955                'my_error',
     956                'An error ocurred'
     957            );
     958        };
     959
     960        // Add a filter which returns a WP_Error:
     961        add_filter( 'pre_unschedule_hook', $return_error );
     962
     963        // Unschedule a hook without the `$wp_error` parameter:
     964        $result = wp_unschedule_hook( 'hook' );
     965
     966        // Ensure boolean false is returned:
     967        $this->assertFalse( $result );
     968    }
     969
     970    /**
     971     * @ticket 49961
     972     */
     973    public function test_unschedule_short_circuit_with_error_returns_error_when_wp_error_is_set_to_true() {
     974        $return_error = function() {
     975            return new WP_Error(
     976                'my_error',
     977                'An error ocurred'
     978            );
     979        };
     980
     981        // Add a filter which returns a WP_Error:
     982        add_filter( 'pre_unschedule_hook', $return_error );
     983
     984        // Unschedule a hook with the `$wp_error` parameter:
     985        $result = wp_unschedule_hook( 'hook', true );
     986
     987        // Ensure the error object is returned:
     988        $this->assertWPError( $result );
     989        $this->assertSame( 'my_error', $result->get_error_code() );
     990    }
     991
     992    /**
     993     * @ticket 49961
     994     */
     995    public function test_unschedule_short_circuit_with_false_returns_false_when_wp_error_is_set_to_false() {
     996        // Add a filter which returns false:
     997        add_filter( 'pre_unschedule_hook', '__return_false' );
     998
     999        // Unschedule a hook without the `$wp_error` parameter:
     1000        $result = wp_unschedule_hook( 'hook' );
     1001
     1002        // Ensure false is returned:
     1003        $this->assertFalse( $result );
     1004    }
     1005
     1006    /**
     1007     * @ticket 49961
     1008     */
     1009    public function test_unschedule_short_circuit_with_false_returns_error_when_wp_error_is_set_to_true() {
     1010        // Add a filter which returns false:
     1011        add_filter( 'pre_unschedule_hook', '__return_false' );
     1012
     1013        // Unchedule a hook with the `$wp_error` parameter:
     1014        $result = wp_unschedule_hook( 'hook', true );
     1015
     1016        // Ensure an error object is returned:
     1017        $this->assertWPError( $result );
     1018        $this->assertSame( 'pre_unschedule_hook_false', $result->get_error_code() );
     1019    }
     1020
     1021    /**
     1022     * @ticket 49961
     1023     */
     1024    public function test_cron_array_error_is_returned_when_scheduling_single_event() {
     1025        // Force update_option() to fail by setting the new value to match the existing:
     1026        add_filter(
     1027            'pre_update_option_cron',
     1028            function() {
     1029                return get_option( 'cron' );
     1030            }
     1031        );
     1032
     1033        // Attempt to schedule a valid event:
     1034        $event = wp_schedule_single_event( time(), 'hook', array(), true );
     1035
     1036        // Ensure an error object is returned:
     1037        $this->assertWPError( $event );
     1038        $this->assertSame( 'could_not_set', $event->get_error_code() );
     1039    }
     1040
     1041    /**
     1042     * @ticket 49961
     1043     */
     1044    public function test_cron_array_error_is_returned_when_scheduling_event() {
     1045        // Force update_option() to fail by setting the new value to match the existing:
     1046        add_filter(
     1047            'pre_update_option_cron',
     1048            function() {
     1049                return get_option( 'cron' );
     1050            }
     1051        );
     1052
     1053        // Attempt to schedule a valid event:
     1054        $event = wp_schedule_event( time(), 'daily', 'hook', array(), true );
     1055
     1056        // Ensure an error object is returned:
     1057        $this->assertWPError( $event );
     1058        $this->assertSame( 'could_not_set', $event->get_error_code() );
     1059    }
     1060
     1061    /**
     1062     * @ticket 49961
     1063     */
     1064    public function test_cron_array_error_is_returned_when_unscheduling_hook() {
     1065        // Schedule a valid event:
     1066        $event = wp_schedule_event( strtotime( '+1 hour' ), 'daily', 'hook', array(), true );
     1067
     1068        // Force update_option() to fail by setting the new value to match the existing:
     1069        add_filter(
     1070            'pre_update_option_cron',
     1071            function() {
     1072                return get_option( 'cron' );
     1073            }
     1074        );
     1075
     1076        // Attempt to unschedule the hook:
     1077        $unscheduled = wp_unschedule_hook( 'hook', true );
     1078
     1079        // Ensure an error object is returned:
     1080        $this->assertTrue( $event );
     1081        $this->assertWPError( $unscheduled );
     1082        $this->assertSame( 'could_not_set', $unscheduled->get_error_code() );
     1083    }
     1084
     1085    /**
     1086     * @ticket 49961
     1087     */
     1088    public function test_cron_array_error_is_returned_when_unscheduling_event() {
     1089        // Schedule a valid event:
     1090        $event = wp_schedule_event( strtotime( '+1 hour' ), 'daily', 'hook', array(), true );
     1091
     1092        // Force update_option() to fail by setting the new value to match the existing:
     1093        add_filter(
     1094            'pre_update_option_cron',
     1095            function() {
     1096                return get_option( 'cron' );
     1097            }
     1098        );
     1099
     1100        // Attempt to unschedule the event:
     1101        $unscheduled = wp_unschedule_event( wp_next_scheduled( 'hook' ), 'hook', array(), true );
     1102
     1103        // Ensure an error object is returned:
     1104        $this->assertTrue( $event );
     1105        $this->assertWPError( $unscheduled );
     1106        $this->assertSame( 'could_not_set', $unscheduled->get_error_code() );
     1107    }
     1108
    6831109}
Note: See TracChangeset for help on using the changeset viewer.