wp/wp-includes/cron.php
changeset 9 177826044cd9
parent 7 cf61fcea0001
child 16 a86126ab1dd4
equal deleted inserted replaced
8:c7c34916027a 9:177826044cd9
     6  */
     6  */
     7 
     7 
     8 /**
     8 /**
     9  * Schedules an event to run only once.
     9  * Schedules an event to run only once.
    10  *
    10  *
    11  * Schedules an event which will execute once by the WordPress actions core at
    11  * Schedules a hook which will be triggered by WordPress at the specified time.
    12  * a time which you specify. The action will fire off when someone visits your
    12  * The action will trigger when someone visits your WordPress site if the scheduled
    13  * WordPress site, if the schedule time has passed.
    13  * time has passed.
    14  *
    14  *
    15  * Note that scheduling an event to occur within 10 minutes of an existing event
    15  * Note that scheduling an event to occur within 10 minutes of an existing event
    16  * with the same action hook will be ignored unless you pass unique `$args` values
    16  * with the same action hook will be ignored unless you pass unique `$args` values
    17  * for each scheduled event.
    17  * for each scheduled event.
    18  *
    18  *
    19  * @since 2.1.0
    19  * Use wp_next_scheduled() to prevent duplicate events.
       
    20  *
       
    21  * Use wp_schedule_event() to schedule a recurring event.
       
    22  *
       
    23  * @since 2.1.0
       
    24  * @since 5.1.0 Return value modified to boolean indicating success or failure,
       
    25  *              {@see 'pre_schedule_event'} filter added to short-circuit the function.
       
    26  *
    20  * @link https://codex.wordpress.org/Function_Reference/wp_schedule_single_event
    27  * @link https://codex.wordpress.org/Function_Reference/wp_schedule_single_event
    21  *
    28  *
    22  * @param int $timestamp Unix timestamp (UTC) for when to run the event.
    29  * @param int    $timestamp  Unix timestamp (UTC) for when to next run the event.
    23  * @param string $hook Action hook to execute when event is run.
    30  * @param string $hook       Action hook to execute when the event is run.
    24  * @param array $args Optional. Arguments to pass to the hook's callback function.
    31  * @param array  $args       Optional. Array containing each separate argument to pass to the hook's callback function.
    25  * @return false|void False if the event does not get scheduled.
    32  * @return bool True if event successfully scheduled. False for failure.
    26  */
    33  */
    27 function wp_schedule_single_event( $timestamp, $hook, $args = array()) {
    34 function wp_schedule_single_event( $timestamp, $hook, $args = array() ) {
    28 	// Make sure timestamp is a positive integer
    35 	// Make sure timestamp is a positive integer
    29 	if ( ! is_numeric( $timestamp ) || $timestamp <= 0 ) {
    36 	if ( ! is_numeric( $timestamp ) || $timestamp <= 0 ) {
    30 		return false;
    37 		return false;
    31 	}
    38 	}
    32 
    39 
    33 	// Don't schedule a duplicate if there's already an identical event due within 10 minutes of it
    40 	$event = (object) array(
    34 	$next = wp_next_scheduled($hook, $args);
    41 		'hook'      => $hook,
    35 	if ( $next && abs( $next - $timestamp ) <= 10 * MINUTE_IN_SECONDS ) {
    42 		'timestamp' => $timestamp,
    36 		return false;
    43 		'schedule'  => false,
    37 	}
    44 		'args'      => $args,
    38 
    45 	);
    39 	$crons = _get_cron_array();
    46 
    40 	$event = (object) array( 'hook' => $hook, 'timestamp' => $timestamp, 'schedule' => false, 'args' => $args );
    47 	/**
    41 	/**
    48 	 * Filter to preflight or hijack scheduling an event.
    42 	 * Filters a single event before it is scheduled.
    49 	 *
       
    50 	 * Returning a non-null value will short-circuit adding the event to the
       
    51 	 * cron array, causing the function to return the filtered value instead.
       
    52 	 *
       
    53 	 * Both single events and recurring events are passed through this filter;
       
    54 	 * single events have `$event->schedule` as false, whereas recurring events
       
    55 	 * have this set to a recurrence from wp_get_schedules(). Recurring
       
    56 	 * events also have the integer recurrence interval set as `$event->interval`.
       
    57 	 *
       
    58 	 * For plugins replacing wp-cron, it is recommended you check for an
       
    59 	 * identical event within ten minutes and apply the {@see 'schedule_event'}
       
    60 	 * filter to check if another plugin has disallowed the event before scheduling.
       
    61 	 *
       
    62 	 * Return true if the event was scheduled, false if not.
       
    63 	 *
       
    64 	 * @since 5.1.0
       
    65 	 *
       
    66 	 * @param null|bool $pre   Value to return instead. Default null to continue adding the event.
       
    67 	 * @param stdClass  $event {
       
    68 	 *     An object containing an event's data.
       
    69 	 *
       
    70 	 *     @type string       $hook      Action hook to execute when the event is run.
       
    71 	 *     @type int          $timestamp Unix timestamp (UTC) for when to next run the event.
       
    72 	 *     @type string|false $schedule  How often the event should subsequently recur.
       
    73 	 *     @type array        $args      Array containing each separate argument to pass to the hook's callback function.
       
    74 	 *     @type int          $interval  The interval time in seconds for the schedule. Only present for recurring events.
       
    75 	 * }
       
    76 	 */
       
    77 	$pre = apply_filters( 'pre_schedule_event', null, $event );
       
    78 	if ( null !== $pre ) {
       
    79 		return $pre;
       
    80 	}
       
    81 
       
    82 	/*
       
    83 	 * Check for a duplicated event.
       
    84 	 *
       
    85 	 * Don't schedule an event if there's already an identical event
       
    86 	 * within 10 minutes.
       
    87 	 *
       
    88 	 * When scheduling events within ten minutes of the current time,
       
    89 	 * all past identical events are considered duplicates.
       
    90 	 *
       
    91 	 * When scheduling an event with a past timestamp (ie, before the
       
    92 	 * current time) all events scheduled within the next ten minutes
       
    93 	 * are considered duplicates.
       
    94 	 */
       
    95 	$crons     = (array) _get_cron_array();
       
    96 	$key       = md5( serialize( $event->args ) );
       
    97 	$duplicate = false;
       
    98 
       
    99 	if ( $event->timestamp < time() + 10 * MINUTE_IN_SECONDS ) {
       
   100 		$min_timestamp = 0;
       
   101 	} else {
       
   102 		$min_timestamp = $event->timestamp - 10 * MINUTE_IN_SECONDS;
       
   103 	}
       
   104 
       
   105 	if ( $event->timestamp < time() ) {
       
   106 		$max_timestamp = time() + 10 * MINUTE_IN_SECONDS;
       
   107 	} else {
       
   108 		$max_timestamp = $event->timestamp + 10 * MINUTE_IN_SECONDS;
       
   109 	}
       
   110 
       
   111 	foreach ( $crons as $event_timestamp => $cron ) {
       
   112 		if ( $event_timestamp < $min_timestamp ) {
       
   113 			continue;
       
   114 		}
       
   115 		if ( $event_timestamp > $max_timestamp ) {
       
   116 			break;
       
   117 		}
       
   118 		if ( isset( $cron[ $event->hook ][ $key ] ) ) {
       
   119 			$duplicate = true;
       
   120 			break;
       
   121 		}
       
   122 	}
       
   123 
       
   124 	if ( $duplicate ) {
       
   125 		return false;
       
   126 	}
       
   127 
       
   128 	/**
       
   129 	 * Modify an event before it is scheduled.
    43 	 *
   130 	 *
    44 	 * @since 3.1.0
   131 	 * @since 3.1.0
    45 	 *
   132 	 *
    46 	 * @param stdClass $event {
   133 	 * @param stdClass $event {
    47 	 *     An object containing an event's data.
   134 	 *     An object containing an event's data.
    48 	 *
   135 	 *
    49 	 *     @type string       $hook      Action hook to execute when event is run.
   136 	 *     @type string       $hook      Action hook to execute when the event is run.
    50 	 *     @type int          $timestamp Unix timestamp (UTC) for when to run the event.
   137 	 *     @type int          $timestamp Unix timestamp (UTC) for when to next run the event.
    51 	 *     @type string|false $schedule  How often the event should recur. See `wp_get_schedules()`.
   138 	 *     @type string|false $schedule  How often the event should subsequently recur.
    52 	 *     @type array        $args      Arguments to pass to the hook's callback function.
   139 	 *     @type array        $args      Array containing each separate argument to pass to the hook's callback function.
       
   140 	 *     @type int          $interval  The interval time in seconds for the schedule. Only present for recurring events.
    53 	 * }
   141 	 * }
    54 	 */
   142 	 */
    55 	$event = apply_filters( 'schedule_event', $event );
   143 	$event = apply_filters( 'schedule_event', $event );
    56 
   144 
    57 	// A plugin disallowed this event
   145 	// A plugin disallowed this event
    58 	if ( ! $event )
   146 	if ( ! $event ) {
    59 		return false;
   147 		return false;
    60 
   148 	}
    61 	$key = md5(serialize($event->args));
   149 
    62 
   150 	$crons[ $event->timestamp ][ $event->hook ][ $key ] = array(
    63 	$crons[$event->timestamp][$event->hook][$key] = array( 'schedule' => $event->schedule, 'args' => $event->args );
   151 		'schedule' => $event->schedule,
    64 	uksort( $crons, "strnatcasecmp" );
   152 		'args'     => $event->args,
    65 	_set_cron_array( $crons );
   153 	);
    66 }
   154 	uksort( $crons, 'strnatcasecmp' );
    67 
   155 	return _set_cron_array( $crons );
    68 /**
   156 }
    69  * Schedule a recurring event.
   157 
    70  *
   158 /**
    71  * Schedules a hook which will be executed by the WordPress actions core on a
   159  * Schedules a recurring event.
    72  * specific interval, specified by you. The action will trigger when someone
   160  *
    73  * visits your WordPress site, if the scheduled time has passed.
   161  * Schedules a hook which will be triggered by WordPress at the specified interval.
    74  *
   162  * The action will trigger when someone visits your WordPress site if the scheduled
    75  * Valid values for the recurrence are hourly, daily, and twicedaily. These can
   163  * time has passed.
       
   164  *
       
   165  * Valid values for the recurrence are 'hourly', 'daily', and 'twicedaily'. These can
    76  * be extended using the {@see 'cron_schedules'} filter in wp_get_schedules().
   166  * be extended using the {@see 'cron_schedules'} filter in wp_get_schedules().
    77  *
   167  *
    78  * Use wp_next_scheduled() to prevent duplicates
   168  * Note that scheduling an event to occur within 10 minutes of an existing event
    79  *
   169  * with the same action hook will be ignored unless you pass unique `$args` values
    80  * @since 2.1.0
   170  * for each scheduled event.
    81  *
   171  *
    82  * @param int $timestamp Unix timestamp (UTC) for when to run the event.
   172  * Use wp_next_scheduled() to prevent duplicate events.
    83  * @param string $recurrence How often the event should recur.
   173  *
    84  * @param string $hook Action hook to execute when event is run.
   174  * Use wp_schedule_single_event() to schedule a non-recurring event.
    85  * @param array $args Optional. Arguments to pass to the hook's callback function.
   175  *
    86  * @return false|void False if the event does not get scheduled.
   176  * @since 2.1.0
    87  */
   177  * @since 5.1.0 Return value modified to boolean indicating success or failure,
    88 function wp_schedule_event( $timestamp, $recurrence, $hook, $args = array()) {
   178  *              {@see 'pre_schedule_event'} filter added to short-circuit the function.
       
   179  *
       
   180  * @link https://codex.wordpress.org/Function_Reference/wp_schedule_event
       
   181  *
       
   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  * @return bool True if event successfully scheduled. False for failure.
       
   187  */
       
   188 function wp_schedule_event( $timestamp, $recurrence, $hook, $args = array() ) {
    89 	// Make sure timestamp is a positive integer
   189 	// Make sure timestamp is a positive integer
    90 	if ( ! is_numeric( $timestamp ) || $timestamp <= 0 ) {
   190 	if ( ! is_numeric( $timestamp ) || $timestamp <= 0 ) {
    91 		return false;
   191 		return false;
    92 	}
   192 	}
    93 
   193 
    94 	$crons = _get_cron_array();
       
    95 	$schedules = wp_get_schedules();
   194 	$schedules = wp_get_schedules();
    96 
   195 
    97 	if ( !isset( $schedules[$recurrence] ) )
   196 	if ( ! isset( $schedules[ $recurrence ] ) ) {
    98 		return false;
   197 		return false;
    99 
   198 	}
   100 	$event = (object) array( 'hook' => $hook, 'timestamp' => $timestamp, 'schedule' => $recurrence, 'args' => $args, 'interval' => $schedules[$recurrence]['interval'] );
   199 
       
   200 	$event = (object) array(
       
   201 		'hook'      => $hook,
       
   202 		'timestamp' => $timestamp,
       
   203 		'schedule'  => $recurrence,
       
   204 		'args'      => $args,
       
   205 		'interval'  => $schedules[ $recurrence ]['interval'],
       
   206 	);
       
   207 
       
   208 	/** This filter is documented in wp-includes/cron.php */
       
   209 	$pre = apply_filters( 'pre_schedule_event', null, $event );
       
   210 	if ( null !== $pre ) {
       
   211 		return $pre;
       
   212 	}
       
   213 
   101 	/** This filter is documented in wp-includes/cron.php */
   214 	/** This filter is documented in wp-includes/cron.php */
   102 	$event = apply_filters( 'schedule_event', $event );
   215 	$event = apply_filters( 'schedule_event', $event );
   103 
   216 
   104 	// A plugin disallowed this event
   217 	// A plugin disallowed this event
   105 	if ( ! $event )
   218 	if ( ! $event ) {
   106 		return false;
   219 		return false;
   107 
   220 	}
   108 	$key = md5(serialize($event->args));
   221 
   109 
   222 	$key = md5( serialize( $event->args ) );
   110 	$crons[$event->timestamp][$event->hook][$key] = array( 'schedule' => $event->schedule, 'args' => $event->args, 'interval' => $event->interval );
   223 
   111 	uksort( $crons, "strnatcasecmp" );
   224 	$crons = _get_cron_array();
   112 	_set_cron_array( $crons );
   225 	$crons[ $event->timestamp ][ $event->hook ][ $key ] = array(
   113 }
   226 		'schedule' => $event->schedule,
   114 
   227 		'args'     => $event->args,
   115 /**
   228 		'interval' => $event->interval,
   116  * Reschedule a recurring event.
   229 	);
   117  *
   230 	uksort( $crons, 'strnatcasecmp' );
   118  * @since 2.1.0
   231 	return _set_cron_array( $crons );
   119  *
   232 }
   120  * @param int $timestamp Unix timestamp (UTC) for when to run the event.
   233 
   121  * @param string $recurrence How often the event should recur.
   234 /**
   122  * @param string $hook Action hook to execute when event is run.
   235  * Reschedules a recurring event.
   123  * @param array $args Optional. Arguments to pass to the hook's callback function.
   236  *
   124  * @return false|void False if the event does not get rescheduled.
   237  * Mainly for internal use, this takes the time stamp of a previously run
       
   238  * recurring event and reschedules it for its next run.
       
   239  *
       
   240  * To change upcoming scheduled events, use wp_schedule_event() to
       
   241  * change the recurrence frequency.
       
   242  *
       
   243  * @since 2.1.0
       
   244  * @since 5.1.0 Return value modified to boolean indicating success or failure,
       
   245  *              {@see 'pre_reschedule_event'} filter added to short-circuit the function.
       
   246  *
       
   247  * @param int    $timestamp  Unix timestamp (UTC) for when the event was scheduled.
       
   248  * @param string $recurrence How often the event should subsequently recur. See wp_get_schedules() for accepted values.
       
   249  * @param string $hook       Action hook to execute when the event is run.
       
   250  * @param array  $args       Optional. Array containing each separate argument to pass to the hook's callback function.
       
   251  * @return bool True if event successfully rescheduled. False for failure.
   125  */
   252  */
   126 function wp_reschedule_event( $timestamp, $recurrence, $hook, $args = array() ) {
   253 function wp_reschedule_event( $timestamp, $recurrence, $hook, $args = array() ) {
   127 	// Make sure timestamp is a positive integer
   254 	// Make sure timestamp is a positive integer
   128 	if ( ! is_numeric( $timestamp ) || $timestamp <= 0 ) {
   255 	if ( ! is_numeric( $timestamp ) || $timestamp <= 0 ) {
   129 		return false;
   256 		return false;
   130 	}
   257 	}
   131 
   258 
   132 	$crons = _get_cron_array();
       
   133 	$schedules = wp_get_schedules();
   259 	$schedules = wp_get_schedules();
   134 	$key = md5( serialize( $args ) );
   260 	$interval  = 0;
   135 	$interval = 0;
   261 
   136 
   262 	// First we try to get the interval from the schedule.
   137 	// First we try to get it from the schedule
       
   138 	if ( isset( $schedules[ $recurrence ] ) ) {
   263 	if ( isset( $schedules[ $recurrence ] ) ) {
   139 		$interval = $schedules[ $recurrence ]['interval'];
   264 		$interval = $schedules[ $recurrence ]['interval'];
   140 	}
   265 	}
   141 	// Now we try to get it from the saved interval in case the schedule disappears
   266 
   142 	if ( 0 == $interval ) {
   267 	// Now we try to get it from the saved interval in case the schedule disappears.
   143 		$interval = $crons[ $timestamp ][ $hook ][ $key ]['interval'];
   268 	if ( 0 === $interval ) {
   144 	}
   269 		$scheduled_event = wp_get_scheduled_event( $hook, $args, $timestamp );
       
   270 		if ( $scheduled_event && isset( $scheduled_event->interval ) ) {
       
   271 			$interval = $scheduled_event->interval;
       
   272 		}
       
   273 	}
       
   274 
       
   275 	$event = (object) array(
       
   276 		'hook'      => $hook,
       
   277 		'timestamp' => $timestamp,
       
   278 		'schedule'  => $recurrence,
       
   279 		'args'      => $args,
       
   280 		'interval'  => $interval,
       
   281 	);
       
   282 
       
   283 	/**
       
   284 	 * Filter to preflight or hijack rescheduling of events.
       
   285 	 *
       
   286 	 * Returning a non-null value will short-circuit the normal rescheduling
       
   287 	 * process, causing the function to return the filtered value instead.
       
   288 	 *
       
   289 	 * For plugins replacing wp-cron, return true if the event was successfully
       
   290 	 * rescheduled, false if not.
       
   291 	 *
       
   292 	 * @since 5.1.0
       
   293 	 *
       
   294 	 * @param null|bool $pre   Value to return instead. Default null to continue adding the event.
       
   295 	 * @param stdClass  $event {
       
   296 	 *     An object containing an event's data.
       
   297 	 *
       
   298 	 *     @type string       $hook      Action hook to execute when the event is run.
       
   299 	 *     @type int          $timestamp Unix timestamp (UTC) for when to next run the event.
       
   300 	 *     @type string|false $schedule  How often the event should subsequently recur.
       
   301 	 *     @type array        $args      Array containing each separate argument to pass to the hook's callback function.
       
   302 	 *     @type int          $interval  The interval time in seconds for the schedule. Only present for recurring events.
       
   303 	 * }
       
   304 	 */
       
   305 	$pre = apply_filters( 'pre_reschedule_event', null, $event );
       
   306 	if ( null !== $pre ) {
       
   307 		return $pre;
       
   308 	}
       
   309 
   145 	// Now we assume something is wrong and fail to schedule
   310 	// Now we assume something is wrong and fail to schedule
   146 	if ( 0 == $interval ) {
   311 	if ( 0 == $interval ) {
   147 		return false;
   312 		return false;
   148 	}
   313 	}
   149 
   314 
   153 		$timestamp = $now + $interval;
   318 		$timestamp = $now + $interval;
   154 	} else {
   319 	} else {
   155 		$timestamp = $now + ( $interval - ( ( $now - $timestamp ) % $interval ) );
   320 		$timestamp = $now + ( $interval - ( ( $now - $timestamp ) % $interval ) );
   156 	}
   321 	}
   157 
   322 
   158 	wp_schedule_event( $timestamp, $recurrence, $hook, $args );
   323 	return wp_schedule_event( $timestamp, $recurrence, $hook, $args );
   159 }
   324 }
   160 
   325 
   161 /**
   326 /**
   162  * Unschedule a previously scheduled event.
   327  * Unschedule a previously scheduled event.
   163  *
   328  *
   164  * The $timestamp and $hook parameters are required so that the event can be
   329  * The $timestamp and $hook parameters are required so that the event can be
   165  * identified.
   330  * identified.
   166  *
   331  *
   167  * @since 2.1.0
   332  * @since 2.1.0
   168  *
   333  * @since 5.1.0 Return value modified to boolean indicating success or failure,
   169  * @param int $timestamp Unix timestamp (UTC) for when to run the event.
   334  *              {@see 'pre_unschedule_event'} filter added to short-circuit the function.
   170  * @param string $hook Action hook, the execution of which will be unscheduled.
   335  *
   171  * @param array $args Arguments to pass to the hook's callback function.
   336  * @param int    $timestamp Unix timestamp (UTC) of the event.
   172  * Although not passed to a callback function, these arguments are used
   337  * @param string $hook      Action hook of the event.
   173  * to uniquely identify the scheduled event, so they should be the same
   338  * @param array  $args      Optional. Array containing each separate argument to pass to the hook's callback function.
   174  * as those used when originally scheduling the event.
   339  *                          Although not passed to a callback, these arguments are used to uniquely identify the
   175  * @return false|void False if the event does not get unscheduled.
   340  *                          event, so they should be the same as those used when originally scheduling the event.
       
   341  * @return bool True if event successfully unscheduled. False for failure.
   176  */
   342  */
   177 function wp_unschedule_event( $timestamp, $hook, $args = array() ) {
   343 function wp_unschedule_event( $timestamp, $hook, $args = array() ) {
   178 	// Make sure timestamp is a positive integer
   344 	// Make sure timestamp is a positive integer
   179 	if ( ! is_numeric( $timestamp ) || $timestamp <= 0 ) {
   345 	if ( ! is_numeric( $timestamp ) || $timestamp <= 0 ) {
   180 		return false;
   346 		return false;
   181 	}
   347 	}
   182 
   348 
       
   349 	/**
       
   350 	 * Filter to preflight or hijack unscheduling of events.
       
   351 	 *
       
   352 	 * Returning a non-null value will short-circuit the normal unscheduling
       
   353 	 * process, causing the function to return the filtered value instead.
       
   354 	 *
       
   355 	 * For plugins replacing wp-cron, return true if the event was successfully
       
   356 	 * unscheduled, false if not.
       
   357 	 *
       
   358 	 * @since 5.1.0
       
   359 	 *
       
   360 	 * @param null|bool $pre       Value to return instead. Default null to continue unscheduling the event.
       
   361 	 * @param int       $timestamp Timestamp for when to run the event.
       
   362 	 * @param string    $hook      Action hook, the execution of which will be unscheduled.
       
   363 	 * @param array     $args      Arguments to pass to the hook's callback function.
       
   364 	 */
       
   365 	$pre = apply_filters( 'pre_unschedule_event', null, $timestamp, $hook, $args );
       
   366 	if ( null !== $pre ) {
       
   367 		return $pre;
       
   368 	}
       
   369 
   183 	$crons = _get_cron_array();
   370 	$crons = _get_cron_array();
   184 	$key = md5(serialize($args));
   371 	$key   = md5( serialize( $args ) );
   185 	unset( $crons[$timestamp][$hook][$key] );
   372 	unset( $crons[ $timestamp ][ $hook ][ $key ] );
   186 	if ( empty($crons[$timestamp][$hook]) )
   373 	if ( empty( $crons[ $timestamp ][ $hook ] ) ) {
   187 		unset( $crons[$timestamp][$hook] );
   374 		unset( $crons[ $timestamp ][ $hook ] );
   188 	if ( empty($crons[$timestamp]) )
   375 	}
   189 		unset( $crons[$timestamp] );
   376 	if ( empty( $crons[ $timestamp ] ) ) {
   190 	_set_cron_array( $crons );
   377 		unset( $crons[ $timestamp ] );
       
   378 	}
       
   379 	return _set_cron_array( $crons );
   191 }
   380 }
   192 
   381 
   193 /**
   382 /**
   194  * Unschedules all events attached to the hook with the specified arguments.
   383  * Unschedules all events attached to the hook with the specified arguments.
   195  *
   384  *
   196  * @since 2.1.0
   385  * Warning: This function may return Boolean FALSE, but may also return a non-Boolean
       
   386  * value which evaluates to FALSE. For information about casting to booleans see the
       
   387  * {@link https://php.net/manual/en/language.types.boolean.php PHP documentation}. Use
       
   388  * the `===` operator for testing the return value of this function.
       
   389  *
       
   390  * @since 2.1.0
       
   391  * @since 5.1.0 Return value modified to indicate success or failure,
       
   392  *              {@see 'pre_clear_scheduled_hook'} filter added to short-circuit the function.
   197  *
   393  *
   198  * @param string $hook Action hook, the execution of which will be unscheduled.
   394  * @param string $hook Action hook, the execution of which will be unscheduled.
   199  * @param array $args Optional. Arguments that were to be passed to the hook's callback function.
   395  * @param array $args Optional. Arguments that were to be passed to the hook's callback function.
       
   396  * @return bool|int On success an integer indicating number of events unscheduled (0 indicates no
       
   397  *                  events were registered with the hook and arguments combination), false if
       
   398  *                  unscheduling one or more events fail.
   200  */
   399  */
   201 function wp_clear_scheduled_hook( $hook, $args = array() ) {
   400 function wp_clear_scheduled_hook( $hook, $args = array() ) {
   202 	// Backward compatibility
   401 	// Backward compatibility
   203 	// Previously this function took the arguments as discrete vars rather than an array like the rest of the API
   402 	// Previously this function took the arguments as discrete vars rather than an array like the rest of the API
   204 	if ( !is_array($args) ) {
   403 	if ( ! is_array( $args ) ) {
   205 		_deprecated_argument( __FUNCTION__, '3.0.0', __('This argument has changed to an array to match the behavior of the other cron functions.') );
   404 		_deprecated_argument( __FUNCTION__, '3.0.0', __( 'This argument has changed to an array to match the behavior of the other cron functions.' ) );
   206 		$args = array_slice( func_get_args(), 1 );
   405 		$args = array_slice( func_get_args(), 1 );
       
   406 	}
       
   407 
       
   408 	/**
       
   409 	 * Filter to preflight or hijack clearing a scheduled hook.
       
   410 	 *
       
   411 	 * Returning a non-null value will short-circuit the normal unscheduling
       
   412 	 * process, causing the function to return the filtered value instead.
       
   413 	 *
       
   414 	 * For plugins replacing wp-cron, return the number of events successfully
       
   415 	 * unscheduled (zero if no events were registered with the hook) or false
       
   416 	 * if unscheduling one or more events fails.
       
   417 	 *
       
   418 	 * @since 5.1.0
       
   419 	 *
       
   420 	 * @param null|array $pre  Value to return instead. Default null to continue unscheduling the event.
       
   421 	 * @param string     $hook Action hook, the execution of which will be unscheduled.
       
   422 	 * @param array      $args Arguments to pass to the hook's callback function.
       
   423 	 */
       
   424 	$pre = apply_filters( 'pre_clear_scheduled_hook', null, $hook, $args );
       
   425 	if ( null !== $pre ) {
       
   426 		return $pre;
   207 	}
   427 	}
   208 
   428 
   209 	// This logic duplicates wp_next_scheduled()
   429 	// This logic duplicates wp_next_scheduled()
   210 	// It's required due to a scenario where wp_unschedule_event() fails due to update_option() failing,
   430 	// It's required due to a scenario where wp_unschedule_event() fails due to update_option() failing,
   211 	// and, wp_next_scheduled() returns the same schedule in an infinite loop.
   431 	// and, wp_next_scheduled() returns the same schedule in an infinite loop.
   212 	$crons = _get_cron_array();
   432 	$crons = _get_cron_array();
   213 	if ( empty( $crons ) )
   433 	if ( empty( $crons ) ) {
   214 		return;
   434 		return 0;
   215 
   435 	}
   216 	$key = md5( serialize( $args ) );
   436 
       
   437 	$results = array();
       
   438 	$key     = md5( serialize( $args ) );
   217 	foreach ( $crons as $timestamp => $cron ) {
   439 	foreach ( $crons as $timestamp => $cron ) {
   218 		if ( isset( $cron[ $hook ][ $key ] ) ) {
   440 		if ( isset( $cron[ $hook ][ $key ] ) ) {
   219 			wp_unschedule_event( $timestamp, $hook, $args );
   441 			$results[] = wp_unschedule_event( $timestamp, $hook, $args );
   220 		}
   442 		}
   221 	}
   443 	}
       
   444 	if ( in_array( false, $results, true ) ) {
       
   445 		return false;
       
   446 	}
       
   447 	return count( $results );
   222 }
   448 }
   223 
   449 
   224 /**
   450 /**
   225  * Unschedules all events attached to the hook.
   451  * Unschedules all events attached to the hook.
   226  *
   452  *
   227  * Can be useful for plugins when deactivating to clean up the cron queue.
   453  * Can be useful for plugins when deactivating to clean up the cron queue.
   228  *
   454  *
       
   455  * Warning: This function may return Boolean FALSE, but may also return a non-Boolean
       
   456  * value which evaluates to FALSE. For information about casting to booleans see the
       
   457  * {@link https://php.net/manual/en/language.types.boolean.php PHP documentation}. Use
       
   458  * the `===` operator for testing the return value of this function.
       
   459  *
   229  * @since 4.9.0
   460  * @since 4.9.0
       
   461  * @since 5.1.0 Return value added to indicate success or failure.
   230  *
   462  *
   231  * @param string $hook Action hook, the execution of which will be unscheduled.
   463  * @param string $hook Action hook, the execution of which will be unscheduled.
       
   464  * @return bool|int On success an integer indicating number of events unscheduled (0 indicates no
       
   465  *                  events were registered on the hook), false if unscheduling fails.
   232  */
   466  */
   233 function wp_unschedule_hook( $hook ) {
   467 function wp_unschedule_hook( $hook ) {
       
   468 	/**
       
   469 	 * Filter to preflight or hijack clearing all events attached to the hook.
       
   470 	 *
       
   471 	 * Returning a non-null value will short-circuit the normal unscheduling
       
   472 	 * process, causing the function to return the filtered value instead.
       
   473 	 *
       
   474 	 * For plugins replacing wp-cron, return the number of events successfully
       
   475 	 * unscheduled (zero if no events were registered with the hook) or false
       
   476 	 * if unscheduling one or more events fails.
       
   477 	 *
       
   478 	 * @since 5.1.0
       
   479 	 *
       
   480 	 * @param null|array $pre  Value to return instead. Default null to continue unscheduling the hook.
       
   481 	 * @param string     $hook Action hook, the execution of which will be unscheduled.
       
   482 	 */
       
   483 	$pre = apply_filters( 'pre_unschedule_hook', null, $hook );
       
   484 	if ( null !== $pre ) {
       
   485 		return $pre;
       
   486 	}
       
   487 
   234 	$crons = _get_cron_array();
   488 	$crons = _get_cron_array();
   235 
   489 	if ( empty( $crons ) ) {
   236 	foreach( $crons as $timestamp => $args ) {
   490 		return 0;
       
   491 	}
       
   492 
       
   493 	$results = array();
       
   494 	foreach ( $crons as $timestamp => $args ) {
       
   495 		if ( ! empty( $crons[ $timestamp ][ $hook ] ) ) {
       
   496 			$results[] = count( $crons[ $timestamp ][ $hook ] );
       
   497 		}
   237 		unset( $crons[ $timestamp ][ $hook ] );
   498 		unset( $crons[ $timestamp ][ $hook ] );
   238 
   499 
   239 		if ( empty( $crons[ $timestamp ] ) ) {
   500 		if ( empty( $crons[ $timestamp ] ) ) {
   240 			unset( $crons[ $timestamp ] );
   501 			unset( $crons[ $timestamp ] );
   241 		}
   502 		}
   242 	}
   503 	}
   243 
   504 
   244 	_set_cron_array( $crons );
   505 	/*
       
   506 	 * If the results are empty (zero events to unschedule), no attempt
       
   507 	 * to update the cron array is required.
       
   508 	 */
       
   509 	if ( empty( $results ) ) {
       
   510 		return 0;
       
   511 	}
       
   512 	if ( _set_cron_array( $crons ) ) {
       
   513 		return array_sum( $results );
       
   514 	}
       
   515 	return false;
       
   516 }
       
   517 
       
   518 /**
       
   519  * Retrieve a scheduled event.
       
   520  *
       
   521  * Retrieve the full event object for a given event, if no timestamp is specified the next
       
   522  * scheduled event is returned.
       
   523  *
       
   524  * @since 5.1.0
       
   525  *
       
   526  * @param string   $hook      Action hook of the event.
       
   527  * @param array    $args      Optional. Array containing each separate argument to pass to the hook's callback function.
       
   528  *                            Although not passed to a callback, these arguments are used to uniquely identify the
       
   529  *                            event, so they should be the same as those used when originally scheduling the event.
       
   530  * @param int|null $timestamp Optional. Unix timestamp (UTC) of the event. If not specified, the next scheduled event is returned.
       
   531  * @return bool|object The event object. False if the event does not exist.
       
   532  */
       
   533 function wp_get_scheduled_event( $hook, $args = array(), $timestamp = null ) {
       
   534 	/**
       
   535 	 * Filter to preflight or hijack retrieving a scheduled event.
       
   536 	 *
       
   537 	 * Returning a non-null value will short-circuit the normal process,
       
   538 	 * returning the filtered value instead.
       
   539 	 *
       
   540 	 * Return false if the event does not exist, otherwise an event object
       
   541 	 * should be returned.
       
   542 	 *
       
   543 	 * @since 5.1.0
       
   544 	 *
       
   545 	 * @param null|bool $pre       Value to return instead. Default null to continue retrieving the event.
       
   546 	 * @param string    $hook      Action hook of the event.
       
   547 	 * @param array     $args      Array containing each separate argument to pass to the hook's callback function.
       
   548 	 *                             Although not passed to a callback, these arguments are used to uniquely identify the
       
   549 	 *                             event.
       
   550 	 * @param int|null  $timestamp Unix timestamp (UTC) of the event. Null to retrieve next scheduled event.
       
   551 	 */
       
   552 	$pre = apply_filters( 'pre_get_scheduled_event', null, $hook, $args, $timestamp );
       
   553 	if ( null !== $pre ) {
       
   554 		return $pre;
       
   555 	}
       
   556 
       
   557 	if ( null !== $timestamp && ! is_numeric( $timestamp ) ) {
       
   558 		return false;
       
   559 	}
       
   560 
       
   561 	$crons = _get_cron_array();
       
   562 	if ( empty( $crons ) ) {
       
   563 		return false;
       
   564 	}
       
   565 
       
   566 	$key = md5( serialize( $args ) );
       
   567 
       
   568 	if ( ! $timestamp ) {
       
   569 		// Get next event.
       
   570 		$next = false;
       
   571 		foreach ( $crons as $timestamp => $cron ) {
       
   572 			if ( isset( $cron[ $hook ][ $key ] ) ) {
       
   573 				$next = $timestamp;
       
   574 				break;
       
   575 			}
       
   576 		}
       
   577 		if ( ! $next ) {
       
   578 			return false;
       
   579 		}
       
   580 
       
   581 		$timestamp = $next;
       
   582 	} elseif ( ! isset( $crons[ $timestamp ][ $hook ][ $key ] ) ) {
       
   583 		return false;
       
   584 	}
       
   585 
       
   586 	$event = (object) array(
       
   587 		'hook'      => $hook,
       
   588 		'timestamp' => $timestamp,
       
   589 		'schedule'  => $crons[ $timestamp ][ $hook ][ $key ]['schedule'],
       
   590 		'args'      => $args,
       
   591 	);
       
   592 
       
   593 	if ( isset( $crons[ $timestamp ][ $hook ][ $key ]['interval'] ) ) {
       
   594 		$event->interval = $crons[ $timestamp ][ $hook ][ $key ]['interval'];
       
   595 	}
       
   596 
       
   597 	return $event;
   245 }
   598 }
   246 
   599 
   247 /**
   600 /**
   248  * Retrieve the next timestamp for an event.
   601  * Retrieve the next timestamp for an event.
   249  *
   602  *
   250  * @since 2.1.0
   603  * @since 2.1.0
   251  *
   604  *
   252  * @param string $hook Action hook to execute when event is run.
   605  * @param string $hook Action hook of the event.
   253  * @param array $args Optional. Arguments to pass to the hook's callback function.
   606  * @param array  $args Optional. Array containing each separate argument to pass to the hook's callback function.
   254  * @return false|int The Unix timestamp of the next time the scheduled event will occur.
   607  *                     Although not passed to a callback, these arguments are used to uniquely identify the
       
   608  *                     event, so they should be the same as those used when originally scheduling the event.
       
   609  * @return false|int The Unix timestamp of the next time the event will occur. False if the event doesn't exist.
   255  */
   610  */
   256 function wp_next_scheduled( $hook, $args = array() ) {
   611 function wp_next_scheduled( $hook, $args = array() ) {
   257 	$crons = _get_cron_array();
   612 	$next_event = wp_get_scheduled_event( $hook, $args );
   258 	$key = md5(serialize($args));
   613 	if ( ! $next_event ) {
   259 	if ( empty($crons) )
   614 		return false;
   260 		return false;
   615 	}
   261 	foreach ( $crons as $timestamp => $cron ) {
   616 
   262 		if ( isset( $cron[$hook][$key] ) )
   617 	return $next_event->timestamp;
   263 			return $timestamp;
       
   264 	}
       
   265 	return false;
       
   266 }
   618 }
   267 
   619 
   268 /**
   620 /**
   269  * Sends a request to run cron through HTTP request that doesn't halt page loading.
   621  * Sends a request to run cron through HTTP request that doesn't halt page loading.
   270  *
   622  *
   271  * @since 2.1.0
   623  * @since 2.1.0
       
   624  * @since 5.1.0 Return values added.
   272  *
   625  *
   273  * @param int $gmt_time Optional. Unix timestamp (UTC). Default 0 (current time is used).
   626  * @param int $gmt_time Optional. Unix timestamp (UTC). Default 0 (current time is used).
       
   627  * @return bool True if spawned, false if no events spawned.
   274  */
   628  */
   275 function spawn_cron( $gmt_time = 0 ) {
   629 function spawn_cron( $gmt_time = 0 ) {
   276 	if ( ! $gmt_time )
   630 	if ( ! $gmt_time ) {
   277 		$gmt_time = microtime( true );
   631 		$gmt_time = microtime( true );
   278 
   632 	}
   279 	if ( defined('DOING_CRON') || isset($_GET['doing_wp_cron']) )
   633 
   280 		return;
   634 	if ( defined( 'DOING_CRON' ) || isset( $_GET['doing_wp_cron'] ) ) {
       
   635 		return false;
       
   636 	}
   281 
   637 
   282 	/*
   638 	/*
   283 	 * Get the cron lock, which is a Unix timestamp of when the last cron was spawned
   639 	 * Get the cron lock, which is a Unix timestamp of when the last cron was spawned
   284 	 * and has not finished running.
   640 	 * and has not finished running.
   285 	 *
   641 	 *
   286 	 * Multiple processes on multiple web servers can run this code concurrently,
   642 	 * Multiple processes on multiple web servers can run this code concurrently,
   287 	 * this lock attempts to make spawning as atomic as possible.
   643 	 * this lock attempts to make spawning as atomic as possible.
   288 	 */
   644 	 */
   289 	$lock = get_transient('doing_cron');
   645 	$lock = get_transient( 'doing_cron' );
   290 
   646 
   291 	if ( $lock > $gmt_time + 10 * MINUTE_IN_SECONDS )
   647 	if ( $lock > $gmt_time + 10 * MINUTE_IN_SECONDS ) {
   292 		$lock = 0;
   648 		$lock = 0;
       
   649 	}
   293 
   650 
   294 	// don't run if another process is currently running it or more than once every 60 sec.
   651 	// don't run if another process is currently running it or more than once every 60 sec.
   295 	if ( $lock + WP_CRON_LOCK_TIMEOUT > $gmt_time )
   652 	if ( $lock + WP_CRON_LOCK_TIMEOUT > $gmt_time ) {
   296 		return;
   653 		return false;
       
   654 	}
   297 
   655 
   298 	//sanity check
   656 	//sanity check
   299 	$crons = _get_cron_array();
   657 	$crons = wp_get_ready_cron_jobs();
   300 	if ( !is_array($crons) )
   658 	if ( empty( $crons ) ) {
   301 		return;
   659 		return false;
       
   660 	}
   302 
   661 
   303 	$keys = array_keys( $crons );
   662 	$keys = array_keys( $crons );
   304 	if ( isset($keys[0]) && $keys[0] > $gmt_time )
   663 	if ( isset( $keys[0] ) && $keys[0] > $gmt_time ) {
   305 		return;
   664 		return false;
       
   665 	}
   306 
   666 
   307 	if ( defined( 'ALTERNATE_WP_CRON' ) && ALTERNATE_WP_CRON ) {
   667 	if ( defined( 'ALTERNATE_WP_CRON' ) && ALTERNATE_WP_CRON ) {
   308 		if ( 'GET' !== $_SERVER['REQUEST_METHOD'] || defined( 'DOING_AJAX' ) ||  defined( 'XMLRPC_REQUEST' ) ) {
   668 		if ( 'GET' !== $_SERVER['REQUEST_METHOD'] || defined( 'DOING_AJAX' ) || defined( 'XMLRPC_REQUEST' ) ) {
   309 			return;
   669 			return false;
   310 		}
   670 		}
   311 
   671 
   312 		$doing_wp_cron = sprintf( '%.22F', $gmt_time );
   672 		$doing_wp_cron = sprintf( '%.22F', $gmt_time );
   313 		set_transient( 'doing_cron', $doing_wp_cron );
   673 		set_transient( 'doing_cron', $doing_wp_cron );
   314 
   674 
   315 		ob_start();
   675 		ob_start();
   316 		wp_redirect( add_query_arg( 'doing_wp_cron', $doing_wp_cron, wp_unslash( $_SERVER['REQUEST_URI'] ) ) );
   676 		wp_redirect( add_query_arg( 'doing_wp_cron', $doing_wp_cron, wp_unslash( $_SERVER['REQUEST_URI'] ) ) );
   317 		echo ' ';
   677 		echo ' ';
   318 
   678 
   319 		// flush any buffers and send the headers
   679 		// flush any buffers and send the headers
   320 		while ( @ob_end_flush() );
   680 		while ( @ob_end_flush() ) {
       
   681 		}
   321 		flush();
   682 		flush();
   322 
   683 
   323 		WP_DEBUG ? include_once( ABSPATH . 'wp-cron.php' ) : @include_once( ABSPATH . 'wp-cron.php' );
   684 		WP_DEBUG ? include_once( ABSPATH . 'wp-cron.php' ) : @include_once( ABSPATH . 'wp-cron.php' );
   324 		return;
   685 		return true;
   325 	}
   686 	}
   326 
   687 
   327 	// Set the cron lock with the current unix timestamp, when the cron is being spawned.
   688 	// Set the cron lock with the current unix timestamp, when the cron is being spawned.
   328 	$doing_wp_cron = sprintf( '%.22F', $gmt_time );
   689 	$doing_wp_cron = sprintf( '%.22F', $gmt_time );
   329 	set_transient( 'doing_cron', $doing_wp_cron );
   690 	set_transient( 'doing_cron', $doing_wp_cron );
   347 	 *         @type bool $sslverify Whether SSL should be verified for the request. Default false.
   708 	 *         @type bool $sslverify Whether SSL should be verified for the request. Default false.
   348 	 *     }
   709 	 *     }
   349 	 * }
   710 	 * }
   350 	 * @param string $doing_wp_cron The unix timestamp of the cron lock.
   711 	 * @param string $doing_wp_cron The unix timestamp of the cron lock.
   351 	 */
   712 	 */
   352 	$cron_request = apply_filters( 'cron_request', array(
   713 	$cron_request = apply_filters(
   353 		'url'  => add_query_arg( 'doing_wp_cron', $doing_wp_cron, site_url( 'wp-cron.php' ) ),
   714 		'cron_request',
   354 		'key'  => $doing_wp_cron,
   715 		array(
   355 		'args' => array(
   716 			'url'  => add_query_arg( 'doing_wp_cron', $doing_wp_cron, site_url( 'wp-cron.php' ) ),
   356 			'timeout'   => 0.01,
   717 			'key'  => $doing_wp_cron,
   357 			'blocking'  => false,
   718 			'args' => array(
   358 			/** This filter is documented in wp-includes/class-wp-http-streams.php */
   719 				'timeout'   => 0.01,
   359 			'sslverify' => apply_filters( 'https_local_ssl_verify', false )
   720 				'blocking'  => false,
   360 		)
   721 				/** This filter is documented in wp-includes/class-wp-http-streams.php */
   361 	), $doing_wp_cron );
   722 				'sslverify' => apply_filters( 'https_local_ssl_verify', false ),
   362 
   723 			),
   363 	wp_remote_post( $cron_request['url'], $cron_request['args'] );
   724 		),
       
   725 		$doing_wp_cron
       
   726 	);
       
   727 
       
   728 	$result = wp_remote_post( $cron_request['url'], $cron_request['args'] );
       
   729 	return ! is_wp_error( $result );
   364 }
   730 }
   365 
   731 
   366 /**
   732 /**
   367  * Run scheduled callbacks or spawn cron for all scheduled events.
   733  * Run scheduled callbacks or spawn cron for all scheduled events.
   368  *
   734  *
   369  * @since 2.1.0
   735  * Warning: This function may return Boolean FALSE, but may also return a non-Boolean
       
   736  * value which evaluates to FALSE. For information about casting to booleans see the
       
   737  * {@link https://php.net/manual/en/language.types.boolean.php PHP documentation}. Use
       
   738  * the `===` operator for testing the return value of this function.
       
   739  *
       
   740  * @since 2.1.0
       
   741  * @since 5.1.0 Return value added to indicate success or failure.
       
   742  *
       
   743  * @return bool|int On success an integer indicating number of events spawned (0 indicates no
       
   744  *                  events needed to be spawned), false if spawning fails for one or more events.
   370  */
   745  */
   371 function wp_cron() {
   746 function wp_cron() {
   372 	// Prevent infinite loops caused by lack of wp-cron.php
   747 	// Prevent infinite loops caused by lack of wp-cron.php
   373 	if ( strpos($_SERVER['REQUEST_URI'], '/wp-cron.php') !== false || ( defined('DISABLE_WP_CRON') && DISABLE_WP_CRON ) )
   748 	if ( strpos( $_SERVER['REQUEST_URI'], '/wp-cron.php' ) !== false || ( defined( 'DISABLE_WP_CRON' ) && DISABLE_WP_CRON ) ) {
   374 		return;
   749 		return 0;
   375 
   750 	}
   376 	if ( false === $crons = _get_cron_array() )
   751 
   377 		return;
   752 	$crons = wp_get_ready_cron_jobs();
       
   753 	if ( empty( $crons ) ) {
       
   754 		return 0;
       
   755 	}
   378 
   756 
   379 	$gmt_time = microtime( true );
   757 	$gmt_time = microtime( true );
   380 	$keys = array_keys( $crons );
   758 	$keys     = array_keys( $crons );
   381 	if ( isset($keys[0]) && $keys[0] > $gmt_time )
   759 	if ( isset( $keys[0] ) && $keys[0] > $gmt_time ) {
   382 		return;
   760 		return 0;
       
   761 	}
   383 
   762 
   384 	$schedules = wp_get_schedules();
   763 	$schedules = wp_get_schedules();
       
   764 	$results   = array();
   385 	foreach ( $crons as $timestamp => $cronhooks ) {
   765 	foreach ( $crons as $timestamp => $cronhooks ) {
   386 		if ( $timestamp > $gmt_time ) break;
   766 		if ( $timestamp > $gmt_time ) {
       
   767 			break;
       
   768 		}
   387 		foreach ( (array) $cronhooks as $hook => $args ) {
   769 		foreach ( (array) $cronhooks as $hook => $args ) {
   388 			if ( isset($schedules[$hook]['callback']) && !call_user_func( $schedules[$hook]['callback'] ) )
   770 			if ( isset( $schedules[ $hook ]['callback'] ) && ! call_user_func( $schedules[ $hook ]['callback'] ) ) {
   389 				continue;
   771 				continue;
   390 			spawn_cron( $gmt_time );
   772 			}
       
   773 			$results[] = spawn_cron( $gmt_time );
   391 			break 2;
   774 			break 2;
   392 		}
   775 		}
   393 	}
   776 	}
       
   777 
       
   778 	if ( in_array( false, $results, true ) ) {
       
   779 		return false;
       
   780 	}
       
   781 	return count( $results );
   394 }
   782 }
   395 
   783 
   396 /**
   784 /**
   397  * Retrieve supported event recurrence schedules.
   785  * Retrieve supported event recurrence schedules.
   398  *
   786  *
   413  * schedule by doing the following.
   801  * schedule by doing the following.
   414  *
   802  *
   415  *     // Filter parameter variable name is 'array'.
   803  *     // Filter parameter variable name is 'array'.
   416  *     $array['weekly'] = array(
   804  *     $array['weekly'] = array(
   417  *         'interval' => 604800,
   805  *         'interval' => 604800,
   418  *     	   'display'  => __( 'Once Weekly' )
   806  *         'display'  => __( 'Once Weekly' )
   419  *     );
   807  *     );
   420  *
       
   421  *
   808  *
   422  * @since 2.1.0
   809  * @since 2.1.0
   423  *
   810  *
   424  * @return array
   811  * @return array
   425  */
   812  */
   426 function wp_get_schedules() {
   813 function wp_get_schedules() {
   427 	$schedules = array(
   814 	$schedules = array(
   428 		'hourly'     => array( 'interval' => HOUR_IN_SECONDS,      'display' => __( 'Once Hourly' ) ),
   815 		'hourly'     => array(
   429 		'twicedaily' => array( 'interval' => 12 * HOUR_IN_SECONDS, 'display' => __( 'Twice Daily' ) ),
   816 			'interval' => HOUR_IN_SECONDS,
   430 		'daily'      => array( 'interval' => DAY_IN_SECONDS,       'display' => __( 'Once Daily' ) ),
   817 			'display'  => __( 'Once Hourly' ),
       
   818 		),
       
   819 		'twicedaily' => array(
       
   820 			'interval' => 12 * HOUR_IN_SECONDS,
       
   821 			'display'  => __( 'Twice Daily' ),
       
   822 		),
       
   823 		'daily'      => array(
       
   824 			'interval' => DAY_IN_SECONDS,
       
   825 			'display'  => __( 'Once Daily' ),
       
   826 		),
   431 	);
   827 	);
   432 	/**
   828 	/**
   433 	 * Filters the non-default cron schedules.
   829 	 * Filters the non-default cron schedules.
   434 	 *
   830 	 *
   435 	 * @since 2.1.0
   831 	 * @since 2.1.0
   443  * Retrieve the recurrence schedule for an event.
   839  * Retrieve the recurrence schedule for an event.
   444  *
   840  *
   445  * @see wp_get_schedules() for available schedules.
   841  * @see wp_get_schedules() for available schedules.
   446  *
   842  *
   447  * @since 2.1.0
   843  * @since 2.1.0
       
   844  * @since 5.1.0 {@see 'get_schedule'} filter added.
   448  *
   845  *
   449  * @param string $hook Action hook to identify the event.
   846  * @param string $hook Action hook to identify the event.
   450  * @param array $args Optional. Arguments passed to the event's callback function.
   847  * @param array $args Optional. Arguments passed to the event's callback function.
   451  * @return string|false False, if no schedule. Schedule name on success.
   848  * @return string|false False, if no schedule. Schedule name on success.
   452  */
   849  */
   453 function wp_get_schedule($hook, $args = array()) {
   850 function wp_get_schedule( $hook, $args = array() ) {
       
   851 	$schedule = false;
       
   852 	$event    = wp_get_scheduled_event( $hook, $args );
       
   853 
       
   854 	if ( $event ) {
       
   855 		$schedule = $event->schedule;
       
   856 	}
       
   857 
       
   858 	/**
       
   859 	 * Filter the schedule for a hook.
       
   860 	 *
       
   861 	 * @since 5.1.0
       
   862 	 *
       
   863 	 * @param string|bool $schedule Schedule for the hook. False if not found.
       
   864 	 * @param string      $hook     Action hook to execute when cron is run.
       
   865 	 * @param array       $args     Optional. Arguments to pass to the hook's callback function.
       
   866 	 */
       
   867 	return apply_filters( 'get_schedule', $schedule, $hook, $args );
       
   868 }
       
   869 
       
   870 /**
       
   871  * Retrieve cron jobs ready to be run.
       
   872  *
       
   873  * Returns the results of _get_cron_array() limited to events ready to be run,
       
   874  * ie, with a timestamp in the past.
       
   875  *
       
   876  * @since 5.1.0
       
   877  *
       
   878  * @return array Cron jobs ready to be run.
       
   879  */
       
   880 function wp_get_ready_cron_jobs() {
       
   881 	/**
       
   882 	 * Filter to preflight or hijack retrieving ready cron jobs.
       
   883 	 *
       
   884 	 * Returning an array will short-circuit the normal retrieval of ready
       
   885 	 * cron jobs, causing the function to return the filtered value instead.
       
   886 	 *
       
   887 	 * @since 5.1.0
       
   888 	 *
       
   889 	 * @param null|array $pre Array of ready cron tasks to return instead. Default null
       
   890 	 *                        to continue using results from _get_cron_array().
       
   891 	 */
       
   892 	$pre = apply_filters( 'pre_get_ready_cron_jobs', null );
       
   893 	if ( null !== $pre ) {
       
   894 		return $pre;
       
   895 	}
       
   896 
   454 	$crons = _get_cron_array();
   897 	$crons = _get_cron_array();
   455 	$key = md5(serialize($args));
   898 
   456 	if ( empty($crons) )
   899 	if ( false === $crons ) {
   457 		return false;
   900 		return array();
   458 	foreach ( $crons as $timestamp => $cron ) {
   901 	}
   459 		if ( isset( $cron[$hook][$key] ) )
   902 
   460 			return $cron[$hook][$key]['schedule'];
   903 	$gmt_time = microtime( true );
   461 	}
   904 	$keys     = array_keys( $crons );
   462 	return false;
   905 	if ( isset( $keys[0] ) && $keys[0] > $gmt_time ) {
       
   906 		return array();
       
   907 	}
       
   908 
       
   909 	$results = array();
       
   910 	foreach ( $crons as $timestamp => $cronhooks ) {
       
   911 		if ( $timestamp > $gmt_time ) {
       
   912 			break;
       
   913 		}
       
   914 		$results[ $timestamp ] = $cronhooks;
       
   915 	}
       
   916 
       
   917 	return $results;
   463 }
   918 }
   464 
   919 
   465 //
   920 //
   466 // Private functions
   921 // Private functions
   467 //
   922 //
   472  * @since 2.1.0
   927  * @since 2.1.0
   473  * @access private
   928  * @access private
   474  *
   929  *
   475  * @return false|array CRON info array.
   930  * @return false|array CRON info array.
   476  */
   931  */
   477 function _get_cron_array()  {
   932 function _get_cron_array() {
   478 	$cron = get_option('cron');
   933 	$cron = get_option( 'cron' );
   479 	if ( ! is_array($cron) )
   934 	if ( ! is_array( $cron ) ) {
   480 		return false;
   935 		return false;
   481 
   936 	}
   482 	if ( !isset($cron['version']) )
   937 
   483 		$cron = _upgrade_cron_array($cron);
   938 	if ( ! isset( $cron['version'] ) ) {
   484 
   939 		$cron = _upgrade_cron_array( $cron );
   485 	unset($cron['version']);
   940 	}
       
   941 
       
   942 	unset( $cron['version'] );
   486 
   943 
   487 	return $cron;
   944 	return $cron;
   488 }
   945 }
   489 
   946 
   490 /**
   947 /**
   491  * Updates the CRON option with the new CRON array.
   948  * Updates the CRON option with the new CRON array.
   492  *
   949  *
   493  * @since 2.1.0
   950  * @since 2.1.0
       
   951  * @since 5.1.0 Return value modified to outcome of update_option().
       
   952  *
   494  * @access private
   953  * @access private
   495  *
   954  *
   496  * @param array $cron Cron info array from _get_cron_array().
   955  * @param array $cron Cron info array from _get_cron_array().
   497  */
   956  * @return bool True if cron array updated, false on failure.
   498 function _set_cron_array($cron) {
   957  */
       
   958 function _set_cron_array( $cron ) {
   499 	$cron['version'] = 2;
   959 	$cron['version'] = 2;
   500 	update_option( 'cron', $cron );
   960 	return update_option( 'cron', $cron );
   501 }
   961 }
   502 
   962 
   503 /**
   963 /**
   504  * Upgrade a Cron info array.
   964  * Upgrade a Cron info array.
   505  *
   965  *
   509  * @access private
   969  * @access private
   510  *
   970  *
   511  * @param array $cron Cron info array from _get_cron_array().
   971  * @param array $cron Cron info array from _get_cron_array().
   512  * @return array An upgraded Cron info array.
   972  * @return array An upgraded Cron info array.
   513  */
   973  */
   514 function _upgrade_cron_array($cron) {
   974 function _upgrade_cron_array( $cron ) {
   515 	if ( isset($cron['version']) && 2 == $cron['version'])
   975 	if ( isset( $cron['version'] ) && 2 == $cron['version'] ) {
   516 		return $cron;
   976 		return $cron;
       
   977 	}
   517 
   978 
   518 	$new_cron = array();
   979 	$new_cron = array();
   519 
   980 
   520 	foreach ( (array) $cron as $timestamp => $hooks) {
   981 	foreach ( (array) $cron as $timestamp => $hooks ) {
   521 		foreach ( (array) $hooks as $hook => $args ) {
   982 		foreach ( (array) $hooks as $hook => $args ) {
   522 			$key = md5(serialize($args['args']));
   983 			$key                                     = md5( serialize( $args['args'] ) );
   523 			$new_cron[$timestamp][$hook][$key] = $args;
   984 			$new_cron[ $timestamp ][ $hook ][ $key ] = $args;
   524 		}
   985 		}
   525 	}
   986 	}
   526 
   987 
   527 	$new_cron['version'] = 2;
   988 	$new_cron['version'] = 2;
   528 	update_option( 'cron', $new_cron );
   989 	update_option( 'cron', $new_cron );