|
1 <?php |
|
2 /** |
|
3 * WordPress CRON API |
|
4 * |
|
5 * @package WordPress |
|
6 */ |
|
7 |
|
8 /** |
|
9 * Schedules a hook to run only once. |
|
10 * |
|
11 * Schedules a hook which will be executed once by the Wordpress actions core at |
|
12 * a time which you specify. The action will fire off when someone visits your |
|
13 * WordPress site, if the schedule time has passed. |
|
14 * |
|
15 * @since 2.1.0 |
|
16 * @link http://codex.wordpress.org/Function_Reference/wp_schedule_single_event |
|
17 * |
|
18 * @param int $timestamp Timestamp for when to run the event. |
|
19 * @param string $hook Action hook to execute when cron is run. |
|
20 * @param array $args Optional. Arguments to pass to the hook's callback function. |
|
21 */ |
|
22 function wp_schedule_single_event( $timestamp, $hook, $args = array()) { |
|
23 // don't schedule a duplicate if there's already an identical event due in the next 10 minutes |
|
24 $next = wp_next_scheduled($hook, $args); |
|
25 if ( $next && $next <= $timestamp + 600 ) |
|
26 return; |
|
27 |
|
28 $crons = _get_cron_array(); |
|
29 $key = md5(serialize($args)); |
|
30 $crons[$timestamp][$hook][$key] = array( 'schedule' => false, 'args' => $args ); |
|
31 uksort( $crons, "strnatcasecmp" ); |
|
32 _set_cron_array( $crons ); |
|
33 } |
|
34 |
|
35 /** |
|
36 * Schedule a periodic event. |
|
37 * |
|
38 * Schedules a hook which will be executed by the WordPress actions core on a |
|
39 * specific interval, specified by you. The action will trigger when someone |
|
40 * visits your WordPress site, if the scheduled time has passed. |
|
41 * |
|
42 * Valid values for the recurrence are hourly, daily and twicedaily. These can |
|
43 * be extended using the cron_schedules filter in wp_get_schedules(). |
|
44 * |
|
45 * @since 2.1.0 |
|
46 * |
|
47 * @param int $timestamp Timestamp for when to run the event. |
|
48 * @param string $recurrence How often the event should recur. |
|
49 * @param string $hook Action hook to execute when cron is run. |
|
50 * @param array $args Optional. Arguments to pass to the hook's callback function. |
|
51 * @return bool|null False on failure, null when complete with scheduling event. |
|
52 */ |
|
53 function wp_schedule_event( $timestamp, $recurrence, $hook, $args = array()) { |
|
54 $crons = _get_cron_array(); |
|
55 $schedules = wp_get_schedules(); |
|
56 $key = md5(serialize($args)); |
|
57 if ( !isset( $schedules[$recurrence] ) ) |
|
58 return false; |
|
59 $crons[$timestamp][$hook][$key] = array( 'schedule' => $recurrence, 'args' => $args, 'interval' => $schedules[$recurrence]['interval'] ); |
|
60 uksort( $crons, "strnatcasecmp" ); |
|
61 _set_cron_array( $crons ); |
|
62 } |
|
63 |
|
64 /** |
|
65 * Reschedule a recurring event. |
|
66 * |
|
67 * @since 2.1.0 |
|
68 * |
|
69 * @param int $timestamp Timestamp for when to run the event. |
|
70 * @param string $recurrence How often the event should recur. |
|
71 * @param string $hook Action hook to execute when cron is run. |
|
72 * @param array $args Optional. Arguments to pass to the hook's callback function. |
|
73 * @return bool|null False on failure. Null when event is rescheduled. |
|
74 */ |
|
75 function wp_reschedule_event( $timestamp, $recurrence, $hook, $args = array()) { |
|
76 $crons = _get_cron_array(); |
|
77 $schedules = wp_get_schedules(); |
|
78 $key = md5(serialize($args)); |
|
79 $interval = 0; |
|
80 |
|
81 // First we try to get it from the schedule |
|
82 if ( 0 == $interval ) |
|
83 $interval = $schedules[$recurrence]['interval']; |
|
84 // Now we try to get it from the saved interval in case the schedule disappears |
|
85 if ( 0 == $interval ) |
|
86 $interval = $crons[$timestamp][$hook][$key]['interval']; |
|
87 // Now we assume something is wrong and fail to schedule |
|
88 if ( 0 == $interval ) |
|
89 return false; |
|
90 |
|
91 $now = time(); |
|
92 |
|
93 if ( $timestamp >= $now ) |
|
94 $timestamp = $now + $interval; |
|
95 else |
|
96 $timestamp = $now + ($interval - (($now - $timestamp) % $interval)); |
|
97 |
|
98 wp_schedule_event( $timestamp, $recurrence, $hook, $args ); |
|
99 } |
|
100 |
|
101 /** |
|
102 * Unschedule a previously scheduled cron job. |
|
103 * |
|
104 * The $timestamp and $hook parameters are required, so that the event can be |
|
105 * identified. |
|
106 * |
|
107 * @since 2.1.0 |
|
108 * |
|
109 * @param int $timestamp Timestamp for when to run the event. |
|
110 * @param string $hook Action hook, the execution of which will be unscheduled. |
|
111 * @param array $args Arguments to pass to the hook's callback function. |
|
112 * Although not passed to a callback function, these arguments are used |
|
113 * to uniquely identify the scheduled event, so they should be the same |
|
114 * as those used when originally scheduling the event. |
|
115 */ |
|
116 function wp_unschedule_event( $timestamp, $hook, $args = array() ) { |
|
117 $crons = _get_cron_array(); |
|
118 $key = md5(serialize($args)); |
|
119 unset( $crons[$timestamp][$hook][$key] ); |
|
120 if ( empty($crons[$timestamp][$hook]) ) |
|
121 unset( $crons[$timestamp][$hook] ); |
|
122 if ( empty($crons[$timestamp]) ) |
|
123 unset( $crons[$timestamp] ); |
|
124 _set_cron_array( $crons ); |
|
125 } |
|
126 |
|
127 /** |
|
128 * Unschedule all cron jobs attached to a specific hook. |
|
129 * |
|
130 * @since 2.1.0 |
|
131 * |
|
132 * @param string $hook Action hook, the execution of which will be unscheduled. |
|
133 * @param mixed $args,... Optional. Event arguments. |
|
134 */ |
|
135 function wp_clear_scheduled_hook( $hook ) { |
|
136 $args = array_slice( func_get_args(), 1 ); |
|
137 |
|
138 while ( $timestamp = wp_next_scheduled( $hook, $args ) ) |
|
139 wp_unschedule_event( $timestamp, $hook, $args ); |
|
140 } |
|
141 |
|
142 /** |
|
143 * Retrieve the next timestamp for a cron event. |
|
144 * |
|
145 * @since 2.1.0 |
|
146 * |
|
147 * @param string $hook Action hook to execute when cron is run. |
|
148 * @param array $args Optional. Arguments to pass to the hook's callback function. |
|
149 * @return bool|int The UNIX timestamp of the next time the scheduled event will occur. |
|
150 */ |
|
151 function wp_next_scheduled( $hook, $args = array() ) { |
|
152 $crons = _get_cron_array(); |
|
153 $key = md5(serialize($args)); |
|
154 if ( empty($crons) ) |
|
155 return false; |
|
156 foreach ( $crons as $timestamp => $cron ) { |
|
157 if ( isset( $cron[$hook][$key] ) ) |
|
158 return $timestamp; |
|
159 } |
|
160 return false; |
|
161 } |
|
162 |
|
163 /** |
|
164 * Send request to run cron through HTTP request that doesn't halt page loading. |
|
165 * |
|
166 * @since 2.1.0 |
|
167 * |
|
168 * @return null Cron could not be spawned, because it is not needed to run. |
|
169 */ |
|
170 function spawn_cron( $local_time = 0 ) { |
|
171 |
|
172 if ( !$local_time ) |
|
173 $local_time = time(); |
|
174 |
|
175 if ( defined('DOING_CRON') || isset($_GET['doing_wp_cron']) ) |
|
176 return; |
|
177 |
|
178 /* |
|
179 * do not even start the cron if local server timer has drifted |
|
180 * such as due to power failure, or misconfiguration |
|
181 */ |
|
182 $timer_accurate = check_server_timer( $local_time ); |
|
183 if ( !$timer_accurate ) |
|
184 return; |
|
185 |
|
186 /* |
|
187 * multiple processes on multiple web servers can run this code concurrently |
|
188 * try to make this as atomic as possible by setting doing_cron switch |
|
189 */ |
|
190 $flag = get_transient('doing_cron'); |
|
191 |
|
192 if ( $flag > $local_time + 10*60 ) |
|
193 $flag = 0; |
|
194 |
|
195 // don't run if another process is currently running it or more than once every 60 sec. |
|
196 if ( $flag + 60 > $local_time ) |
|
197 return; |
|
198 |
|
199 //sanity check |
|
200 $crons = _get_cron_array(); |
|
201 if ( !is_array($crons) ) |
|
202 return; |
|
203 |
|
204 $keys = array_keys( $crons ); |
|
205 if ( isset($keys[0]) && $keys[0] > $local_time ) |
|
206 return; |
|
207 |
|
208 if ( defined('ALTERNATE_WP_CRON') && ALTERNATE_WP_CRON ) { |
|
209 if ( !empty($_POST) || defined('DOING_AJAX') ) |
|
210 return; |
|
211 |
|
212 set_transient( 'doing_cron', $local_time ); |
|
213 |
|
214 ob_start(); |
|
215 wp_redirect( add_query_arg('doing_wp_cron', '', stripslashes($_SERVER['REQUEST_URI'])) ); |
|
216 echo ' '; |
|
217 |
|
218 // flush any buffers and send the headers |
|
219 while ( @ob_end_flush() ); |
|
220 flush(); |
|
221 |
|
222 @include_once(ABSPATH . 'wp-cron.php'); |
|
223 return; |
|
224 } |
|
225 |
|
226 set_transient( 'doing_cron', $local_time ); |
|
227 |
|
228 $cron_url = get_option( 'siteurl' ) . '/wp-cron.php?doing_wp_cron'; |
|
229 wp_remote_post( $cron_url, array('timeout' => 0.01, 'blocking' => false, 'sslverify' => apply_filters('https_local_ssl_verify', true)) ); |
|
230 } |
|
231 |
|
232 /** |
|
233 * Run scheduled callbacks or spawn cron for all scheduled events. |
|
234 * |
|
235 * @since 2.1.0 |
|
236 * |
|
237 * @return null When doesn't need to run Cron. |
|
238 */ |
|
239 function wp_cron() { |
|
240 |
|
241 // Prevent infinite loops caused by lack of wp-cron.php |
|
242 if ( strpos($_SERVER['REQUEST_URI'], '/wp-cron.php') !== false || ( defined('DISABLE_WP_CRON') && DISABLE_WP_CRON ) ) |
|
243 return; |
|
244 |
|
245 if ( false === $crons = _get_cron_array() ) |
|
246 return; |
|
247 |
|
248 $local_time = time(); |
|
249 $keys = array_keys( $crons ); |
|
250 if ( isset($keys[0]) && $keys[0] > $local_time ) |
|
251 return; |
|
252 |
|
253 $schedules = wp_get_schedules(); |
|
254 foreach ( $crons as $timestamp => $cronhooks ) { |
|
255 if ( $timestamp > $local_time ) break; |
|
256 foreach ( (array) $cronhooks as $hook => $args ) { |
|
257 if ( isset($schedules[$hook]['callback']) && !call_user_func( $schedules[$hook]['callback'] ) ) |
|
258 continue; |
|
259 spawn_cron( $local_time ); |
|
260 break 2; |
|
261 } |
|
262 } |
|
263 } |
|
264 |
|
265 /** |
|
266 * Retrieve supported and filtered Cron recurrences. |
|
267 * |
|
268 * The supported recurrences are 'hourly' and 'daily'. A plugin may add more by |
|
269 * hooking into the 'cron_schedules' filter. The filter accepts an array of |
|
270 * arrays. The outer array has a key that is the name of the schedule or for |
|
271 * example 'weekly'. The value is an array with two keys, one is 'interval' and |
|
272 * the other is 'display'. |
|
273 * |
|
274 * The 'interval' is a number in seconds of when the cron job should run. So for |
|
275 * 'hourly', the time is 3600 or 60*60. For weekly, the value would be |
|
276 * 60*60*24*7 or 604800. The value of 'interval' would then be 604800. |
|
277 * |
|
278 * The 'display' is the description. For the 'weekly' key, the 'display' would |
|
279 * be <code>__('Once Weekly')</code>. |
|
280 * |
|
281 * For your plugin, you will be passed an array. you can easily add your |
|
282 * schedule by doing the following. |
|
283 * <code> |
|
284 * // filter parameter variable name is 'array' |
|
285 * $array['weekly'] = array( |
|
286 * 'interval' => 604800, |
|
287 * 'display' => __('Once Weekly') |
|
288 * ); |
|
289 * </code> |
|
290 * |
|
291 * @since 2.1.0 |
|
292 * |
|
293 * @return array |
|
294 */ |
|
295 function wp_get_schedules() { |
|
296 $schedules = array( |
|
297 'hourly' => array( 'interval' => 3600, 'display' => __('Once Hourly') ), |
|
298 'twicedaily' => array( 'interval' => 43200, 'display' => __('Twice Daily') ), |
|
299 'daily' => array( 'interval' => 86400, 'display' => __('Once Daily') ), |
|
300 ); |
|
301 return array_merge( apply_filters( 'cron_schedules', array() ), $schedules ); |
|
302 } |
|
303 |
|
304 /** |
|
305 * Retrieve Cron schedule for hook with arguments. |
|
306 * |
|
307 * @since 2.1.0 |
|
308 * |
|
309 * @param string $hook Action hook to execute when cron is run. |
|
310 * @param array $args Optional. Arguments to pass to the hook's callback function. |
|
311 * @return string|bool False, if no schedule. Schedule on success. |
|
312 */ |
|
313 function wp_get_schedule($hook, $args = array()) { |
|
314 $crons = _get_cron_array(); |
|
315 $key = md5(serialize($args)); |
|
316 if ( empty($crons) ) |
|
317 return false; |
|
318 foreach ( $crons as $timestamp => $cron ) { |
|
319 if ( isset( $cron[$hook][$key] ) ) |
|
320 return $cron[$hook][$key]['schedule']; |
|
321 } |
|
322 return false; |
|
323 } |
|
324 |
|
325 // |
|
326 // Private functions |
|
327 // |
|
328 |
|
329 /** |
|
330 * Retrieve cron info array option. |
|
331 * |
|
332 * @since 2.1.0 |
|
333 * @access private |
|
334 * |
|
335 * @return array CRON info array. |
|
336 */ |
|
337 function _get_cron_array() { |
|
338 $cron = get_option('cron'); |
|
339 if ( ! is_array($cron) ) |
|
340 return false; |
|
341 |
|
342 if ( !isset($cron['version']) ) |
|
343 $cron = _upgrade_cron_array($cron); |
|
344 |
|
345 unset($cron['version']); |
|
346 |
|
347 return $cron; |
|
348 } |
|
349 |
|
350 /** |
|
351 * Updates the CRON option with the new CRON array. |
|
352 * |
|
353 * @since 2.1.0 |
|
354 * @access private |
|
355 * |
|
356 * @param array $cron Cron info array from {@link _get_cron_array()}. |
|
357 */ |
|
358 function _set_cron_array($cron) { |
|
359 $cron['version'] = 2; |
|
360 update_option( 'cron', $cron ); |
|
361 } |
|
362 |
|
363 /** |
|
364 * Upgrade a Cron info array. |
|
365 * |
|
366 * This function upgrades the Cron info array to version 2. |
|
367 * |
|
368 * @since 2.1.0 |
|
369 * @access private |
|
370 * |
|
371 * @param array $cron Cron info array from {@link _get_cron_array()}. |
|
372 * @return array An upgraded Cron info array. |
|
373 */ |
|
374 function _upgrade_cron_array($cron) { |
|
375 if ( isset($cron['version']) && 2 == $cron['version']) |
|
376 return $cron; |
|
377 |
|
378 $new_cron = array(); |
|
379 |
|
380 foreach ( (array) $cron as $timestamp => $hooks) { |
|
381 foreach ( (array) $hooks as $hook => $args ) { |
|
382 $key = md5(serialize($args['args'])); |
|
383 $new_cron[$timestamp][$hook][$key] = $args; |
|
384 } |
|
385 } |
|
386 |
|
387 $new_cron['version'] = 2; |
|
388 update_option( 'cron', $new_cron ); |
|
389 return $new_cron; |
|
390 } |
|
391 |
|
392 // stub for checking server timer accuracy, using outside standard time sources |
|
393 function check_server_timer( $local_time ) { |
|
394 return true; |
|
395 } |
|
396 |
|
397 ?> |