These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | /** |
||
3 | * Debug Bar Cron - Debug Bar Panel. |
||
4 | * |
||
5 | * @package WordPress\Plugins\Debug Bar Cron |
||
6 | * @author Zack Tollman, Helen Hou-Sandi, Juliette Reinders Folmer |
||
7 | * @link https://github.com/tollmanz/debug-bar-cron |
||
8 | * @version 0.1.2 |
||
9 | * @license http://creativecommons.org/licenses/GPL/2.0/ GNU General Public License, version 2 or higher |
||
10 | */ |
||
11 | |||
12 | // Avoid direct calls to this file. |
||
13 | if ( ! function_exists( 'add_action' ) ) { |
||
14 | header( 'Status: 403 Forbidden' ); |
||
15 | header( 'HTTP/1.1 403 Forbidden' ); |
||
16 | exit(); |
||
17 | } |
||
18 | |||
19 | /** |
||
20 | * The class in this file extends the functionality provided by the parent plugin "Debug Bar". |
||
21 | */ |
||
22 | if ( ! class_exists( 'ZT_Debug_Bar_Cron' ) && class_exists( 'Debug_Bar_Panel' ) ) { |
||
23 | |||
24 | /** |
||
25 | * Add a new Debug Bar Panel. |
||
26 | */ |
||
27 | class ZT_Debug_Bar_Cron extends Debug_Bar_Panel { |
||
28 | |||
29 | const DBCRON_STYLES_VERSION = '1.0'; |
||
30 | |||
31 | const DBCRON_NAME = 'debug-bar-cron'; |
||
32 | |||
33 | /** |
||
34 | * Holds all of the cron events. |
||
35 | * |
||
36 | * @var array |
||
37 | */ |
||
38 | private $_crons; |
||
39 | |||
40 | /** |
||
41 | * Holds only the cron events initiated by WP core. |
||
42 | * |
||
43 | * @var array |
||
44 | */ |
||
45 | private $_core_crons; |
||
46 | |||
47 | /** |
||
48 | * Holds the cron events created by plugins or themes. |
||
49 | * |
||
50 | * @var array |
||
51 | */ |
||
52 | private $_user_crons; |
||
53 | |||
54 | /** |
||
55 | * Total number of cron events. |
||
56 | * |
||
57 | * @var int |
||
58 | */ |
||
59 | private $_total_crons = 0; |
||
60 | |||
61 | /** |
||
62 | * Total number of cron events created by plugins and themes. |
||
63 | * |
||
64 | * @var int |
||
65 | */ |
||
66 | private $_total_user_crons = 0; |
||
67 | |||
68 | /** |
||
69 | * Total number of WP core cron events. |
||
70 | * |
||
71 | * @var int |
||
72 | */ |
||
73 | private $_total_core_crons = 0; |
||
74 | |||
75 | /** |
||
76 | * Whether cron is being executed or not. |
||
77 | * |
||
78 | * @var string |
||
79 | */ |
||
80 | private $_doing_cron = 'No'; |
||
81 | |||
82 | |||
83 | /** |
||
84 | * Give the panel a title and set the enqueues. |
||
85 | * |
||
86 | * @return void |
||
87 | */ |
||
88 | public function init() { |
||
89 | load_plugin_textdomain( 'zt-debug-bar-cron', false, dirname( plugin_basename( __FILE__ ) ) . '/languages/' ); |
||
90 | $this->title( __( 'Cron', 'zt-debug-bar-cron' ) ); |
||
91 | add_action( 'wp_enqueue_scripts', array( $this, 'enqueue_scripts_styles' ) ); |
||
92 | add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_scripts_styles' ) ); |
||
93 | } |
||
94 | |||
95 | |||
96 | /** |
||
97 | * Enqueue styles. |
||
98 | * |
||
99 | * @return void |
||
100 | */ |
||
101 | public function enqueue_scripts_styles() { |
||
102 | $suffix = ( ( defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ) ? '' : '.min' ); |
||
103 | |||
104 | wp_enqueue_style( |
||
105 | self::DBCRON_NAME, |
||
106 | plugins_url( 'css/' . self::DBCRON_NAME . $suffix . '.css', __FILE__ ), |
||
107 | array( 'debug-bar' ), |
||
108 | self::DBCRON_STYLES_VERSION |
||
109 | ); |
||
110 | } |
||
111 | |||
112 | |||
113 | /** |
||
114 | * Show the menu item in Debug Bar. |
||
115 | * |
||
116 | * @return void |
||
117 | */ |
||
118 | public function prerender() { |
||
119 | $this->set_visible( true ); |
||
120 | } |
||
121 | |||
122 | |||
123 | /** |
||
124 | * Show the contents of the page. |
||
125 | * |
||
126 | * @return void |
||
127 | */ |
||
128 | public function render() { |
||
129 | $this->get_crons(); |
||
130 | |||
131 | $this->_doing_cron = get_transient( 'doing_cron' ) ? __( 'Yes', 'zt-debug-bar-cron' ) : __( 'No', 'zt-debug-bar-cron' ); |
||
132 | |||
133 | // Get the time of the next event. |
||
134 | $cron_times = ( is_array( $this->_crons ) ? array_keys( $this->_crons ) : array() ); |
||
135 | $unix_time_next_cron = (int) $cron_times[0]; |
||
136 | $time_next_cron = date( 'Y-m-d H:i:s', $unix_time_next_cron ); |
||
137 | |||
138 | $human_time_next_cron = human_time_diff( $unix_time_next_cron ); |
||
139 | |||
140 | // Add a class if past current time and doing cron is not running. |
||
141 | $times_class = $this->is_time_in_past( $unix_time_next_cron ) ? ' past' : ''; |
||
142 | |||
143 | $this->load_debug_bar_pretty_output(); |
||
144 | |||
145 | echo // WPCS: XSS ok. |
||
146 | ' |
||
147 | <div class="debug-bar-cron"> |
||
148 | <h2><span>', esc_html__( 'Total Events', 'zt-debug-bar-cron' ), ':</span>', $this->_total_crons, '</h2> |
||
149 | <h2><span>', esc_html__( 'Core Events', 'zt-debug-bar-cron' ), ':</span>', $this->_total_core_crons, '</h2> |
||
150 | <h2><span>', esc_html__( 'Custom Events', 'zt-debug-bar-cron' ), ':</span>', $this->_total_user_crons, '</h2> |
||
151 | <h2><span>', esc_html__( 'Doing Cron', 'zt-debug-bar-cron' ), ':</span>', esc_html( $this->_doing_cron ), '</h2> |
||
152 | <h2 class="times', esc_attr( $times_class ), '"><span>', esc_html__( 'Next Event', 'zt-debug-bar-cron' ), ':</span> |
||
153 | ', esc_html( $time_next_cron ), '<br /> |
||
154 | ', $unix_time_next_cron, '<br /> |
||
155 | ', esc_html( $this->display_past_time( $human_time_next_cron, $unix_time_next_cron ) ), ' |
||
156 | </h2> |
||
157 | <h2><span>', esc_html__( 'Current Time', 'zt-debug-bar-cron' ), ':</span>', esc_html( date( 'H:i:s' ) ), '</h2> |
||
158 | |||
159 | <div class="clear"></div> |
||
160 | |||
161 | <h3>', esc_html__( 'Schedules', 'zt-debug-bar-cron' ), '</h3>'; |
||
162 | |||
163 | $this->display_schedules(); |
||
164 | |||
165 | echo ' |
||
166 | <h3>', esc_html__( 'Custom Events', 'zt-debug-bar-cron' ), '</h3>'; |
||
167 | |||
168 | $this->display_events( $this->_user_crons, __( 'No Custom Events scheduled.', 'zt-debug-bar-cron' ) ); |
||
169 | |||
170 | echo ' |
||
171 | <h3>', esc_html__( 'Core Events', 'zt-debug-bar-cron' ), '</h3>'; |
||
172 | |||
173 | $this->display_events( $this->_core_crons, __( 'No Core Events scheduled.', 'zt-debug-bar-cron' ) ); |
||
174 | |||
175 | echo ' |
||
176 | </div>'; |
||
177 | |||
178 | $this->reset_debug_bar_pretty_output(); |
||
179 | } |
||
180 | |||
181 | |||
182 | /** |
||
183 | * Gets all of the cron jobs. |
||
184 | * |
||
185 | * This function sorts the cron jobs into core crons, and custom crons. It also tallies |
||
186 | * a total count for the crons as this number is otherwise tough to get. |
||
187 | * |
||
188 | * @return array|null Array of crons. |
||
189 | */ |
||
190 | private function get_crons() { |
||
191 | if ( is_array( $this->_crons ) ) { |
||
192 | return $this->_crons; |
||
193 | } |
||
194 | |||
195 | $crons = _get_cron_array(); |
||
196 | if ( ! is_array( $crons ) || array() === $crons ) { |
||
197 | return $this->_crons; |
||
198 | } |
||
199 | |||
200 | $this->_crons = $crons; |
||
201 | |||
202 | // Lists all crons that are defined in WP Core. |
||
203 | // @internal To find all, search WP trunk for `wp_schedule_(single_)?event`. |
||
204 | $core_cron_hooks = array( |
||
205 | 'do_pings', |
||
206 | 'importer_scheduled_cleanup', // WP 3.1+. |
||
207 | 'publish_future_post', |
||
208 | 'update_network_counts', // WP 3.1+. |
||
209 | 'upgrader_scheduled_cleanup', // WP 3.3+. |
||
210 | 'wp_maybe_auto_update', // WP 3.7+. |
||
211 | 'wp_scheduled_auto_draft_delete', // WP 3.4+. |
||
212 | 'wp_scheduled_delete', // WP 2.9+. |
||
213 | 'wp_split_shared_term_batch', // WP 4.3+. |
||
214 | 'wp_update_plugins', |
||
215 | 'wp_update_themes', |
||
216 | 'wp_version_check', |
||
217 | ); |
||
218 | |||
219 | // Sort and count crons. |
||
220 | foreach ( $this->_crons as $time => $time_cron_array ) { |
||
221 | foreach ( $time_cron_array as $hook => $data ) { |
||
222 | $this->_total_crons += count( $data ); |
||
223 | |||
224 | if ( in_array( $hook, $core_cron_hooks, true ) ) { |
||
225 | $this->_core_crons[ $time ][ $hook ] = $data; |
||
226 | $this->_total_core_crons += count( $data ); |
||
227 | } else { |
||
228 | $this->_user_crons[ $time ][ $hook ] = $data; |
||
229 | $this->_total_user_crons += count( $data ); |
||
230 | } |
||
231 | } |
||
232 | } |
||
233 | |||
234 | return $this->_crons; |
||
235 | } |
||
236 | |||
237 | |||
238 | /** |
||
239 | * Displays the events in an easy to read table. |
||
240 | * |
||
241 | * @param array $events Array of events. |
||
242 | * @param string $no_events_msg Message to display if there are no events. |
||
243 | */ |
||
244 | private function display_events( $events, $no_events_msg ) { |
||
245 | // Exit early if no events found. |
||
246 | if ( ! is_array( $events ) || empty( $events ) ) { |
||
247 | echo ' |
||
248 | <p>', esc_html( $no_events_msg ), '</p>'; |
||
249 | return; |
||
250 | } |
||
251 | |||
252 | echo ' |
||
253 | <table class="zt-debug-bar-cron-table zt-debug-bar-cron-event-table"> |
||
254 | <thead><tr> |
||
255 | <th class="col1">', esc_html__( 'Next Execution', 'zt-debug-bar-cron' ), '</th> |
||
256 | <th class="col2">', esc_html__( 'Hook', 'zt-debug-bar-cron' ), '</th> |
||
257 | <th class="col3">', esc_html__( 'Interval Hook', 'zt-debug-bar-cron' ), '</th> |
||
258 | <th class="col4">', esc_html__( 'Interval Value', 'zt-debug-bar-cron' ), '</th> |
||
259 | <th class="col5">', esc_html__( 'Args', 'zt-debug-bar-cron' ), '</th> |
||
260 | </tr></thead> |
||
261 | <tbody>'; |
||
262 | |||
263 | foreach ( $events as $time => $time_cron_array ) { |
||
264 | $time = (int) $time; |
||
265 | foreach ( $time_cron_array as $hook => $data ) { |
||
266 | $row_attributes = $this->get_event_row_attributes( $time, $hook ); |
||
267 | |||
268 | foreach ( $data as $hash => $info ) { |
||
269 | echo // WPCS: xss ok. |
||
270 | ' |
||
271 | <tr', $row_attributes, '> |
||
272 | <td> |
||
273 | ', date( 'Y-m-d H:i:s', $time ), '<br /> |
||
274 | ', $time, '<br /> |
||
275 | ', esc_html( $this->display_past_time( human_time_diff( $time ), $time ) ), ' |
||
276 | </td> |
||
277 | <td>', esc_html( $hook ), '</td>'; |
||
278 | |||
279 | |||
280 | // Report the schedule. |
||
281 | echo ' |
||
282 | <td>'; |
||
283 | if ( ! empty( $info['schedule'] ) ) { |
||
284 | echo esc_html( $info['schedule'] ); |
||
285 | } else { |
||
286 | echo esc_html__( 'Single Event', 'zt-debug-bar-cron' ); |
||
287 | } |
||
288 | echo '</td>'; |
||
289 | |||
290 | // Report the interval. |
||
291 | echo ' |
||
292 | <td>'; |
||
293 | if ( isset( $info['interval'] ) ) { |
||
294 | $interval = (int) $info['interval']; |
||
295 | /* TRANSLATORS: %s is number of seconds. */ |
||
296 | printf( esc_html__( '%ss', 'zt-debug-bar-cron' ) . '<br />', $interval ); // WPCS: XSS ok. |
||
297 | /* TRANSLATORS: %s is number of minutes. */ |
||
298 | printf( esc_html__( '%sm', 'zt-debug-bar-cron' ) . '<br />', $this->get_minutes( $interval ) ); // WPCS: XSS ok. |
||
299 | /* TRANSLATORS: %s is number of hours. */ |
||
300 | printf( esc_html__( '%sh', 'zt-debug-bar-cron' ), $this->get_hours( $interval ) ); // WPCS: XSS ok. |
||
301 | } else { |
||
302 | echo esc_html__( 'Single Event', 'zt-debug-bar-cron' ); |
||
303 | } |
||
304 | echo '</td>'; |
||
305 | |||
306 | // Report the args. |
||
307 | echo ' |
||
308 | <td>'; |
||
309 | $this->display_cron_arguments( $info['args'] ); |
||
310 | echo '</td> |
||
311 | </tr>'; |
||
312 | } |
||
313 | } |
||
314 | } |
||
315 | |||
316 | echo ' |
||
317 | </tbody> |
||
318 | </table>'; |
||
319 | } |
||
320 | |||
321 | |||
322 | /** |
||
323 | * Create a HTML attribute string for an event row. |
||
324 | * |
||
325 | * @param int $time Unix timestamp. |
||
326 | * @param string $hook Action hook for the cron job. |
||
327 | * |
||
328 | * @return string |
||
329 | */ |
||
330 | private function get_event_row_attributes( $time, $hook ) { |
||
331 | $attributes = ''; |
||
332 | $classes = array(); |
||
333 | |||
334 | // Add a class if past current time. |
||
335 | if ( $this->is_time_in_past( $time ) ) { |
||
336 | $classes[] = 'past'; |
||
337 | } |
||
338 | |||
339 | // Verify if any events are hooked in. |
||
340 | if ( false === has_action( $hook ) ) { |
||
341 | /* TRANSLATORS: This text will display as a tooltip. %1$s will be replaced by a line break. */ |
||
342 | $attributes .= ' title="' . sprintf( esc_attr__( 'No actions are hooked into this event at this time.%1$sThe most likely reason for this is that a plugin or theme was de-activated or uninstalled and didn\'t clean up after itself.%1$sHowever, a number of plugins also use the best practice of lean loading and only hook in conditionally, so check carefully if you intend to remove this event.', 'zt-debug-bar-cron' ), "\n" ) . '"'; |
||
343 | $classes[] = 'empty-event'; |
||
344 | } |
||
345 | |||
346 | if ( ! empty( $classes ) ) { |
||
347 | $attributes .= ' class="' . implode( ' ', $classes ) . '"'; |
||
348 | } |
||
349 | |||
350 | return $attributes; |
||
351 | } |
||
352 | |||
353 | |||
354 | /** |
||
355 | * Displays the cron arguments in a readable format. |
||
356 | * |
||
357 | * @param mixed $args Cron argument(s). |
||
358 | * |
||
359 | * @return void |
||
360 | */ |
||
361 | private function display_cron_arguments( $args ) { |
||
362 | // Arguments defaults to an empty array if no arguments are given. |
||
363 | if ( is_array( $args ) && array() === $args ) { |
||
364 | echo esc_html__( 'No Args', 'zt-debug-bar-cron' ); |
||
365 | return; |
||
366 | } |
||
367 | |||
368 | // Ok, we have an argument, let's pretty print it. |
||
369 | $this->print_pretty_output( $args ); |
||
370 | } |
||
371 | |||
372 | |||
373 | /** |
||
374 | * Displays all of the schedules defined. |
||
375 | * |
||
376 | * @return void |
||
377 | */ |
||
378 | private function display_schedules() { |
||
379 | echo ' |
||
380 | <table class="zt-debug-bar-cron-table zt-debug-bar-cron-schedule-table"> |
||
381 | <thead><tr> |
||
382 | <th class="col1">', esc_html__( 'Interval Hook', 'zt-debug-bar-cron' ), '</th> |
||
383 | <th class="col2">', esc_html__( 'Interval (S)', 'zt-debug-bar-cron' ), '</th> |
||
384 | <th class="col3">', esc_html__( 'Interval (M)', 'zt-debug-bar-cron' ), '</th> |
||
385 | <th class="col4">', esc_html__( 'Interval (H)', 'zt-debug-bar-cron' ), '</th> |
||
386 | <th class="col5">', esc_html__( 'Display Name', 'zt-debug-bar-cron' ), '</th> |
||
387 | </tr></thead> |
||
388 | <tbody>'; |
||
389 | |||
390 | |||
391 | $schedules = wp_get_schedules(); |
||
392 | ksort( $schedules ); |
||
393 | uasort( $schedules, array( $this, 'schedules_sorting' ) ); |
||
394 | foreach ( $schedules as $interval_hook => $data ) { |
||
395 | $interval = (int) $data['interval']; |
||
396 | echo // WPCS: XSS ok. |
||
397 | ' |
||
398 | <tr> |
||
399 | <td>', esc_html( $interval_hook ), '</td> |
||
400 | <td>', $interval, '</td> |
||
401 | <td>', $this->get_minutes( $interval ), '</td> |
||
402 | <td>', $this->get_hours( $interval ), '</td> |
||
403 | <td>', esc_html( $data['display'] ) . '</td> |
||
404 | </tr>'; |
||
405 | } |
||
406 | |||
407 | echo ' |
||
408 | </tbody> |
||
409 | </table>'; |
||
410 | } |
||
411 | |||
412 | /** |
||
413 | * Sorting method for cron scheldules. Order by schedules interval. |
||
414 | * |
||
415 | * @param array $a First element of comparison pair. |
||
416 | * @param array $b Second element of comparison pair. |
||
417 | * |
||
418 | * @return int Return 1 if $a argument 'interval' greater then $b argument 'interval', 0 if both intervals equivalent and -1 otherwise. |
||
419 | */ |
||
420 | function schedules_sorting( $a, $b ) { |
||
0 ignored issues
–
show
|
|||
421 | if ( (int) $a['interval'] === (int) $b['interval'] ) { |
||
422 | return 0; |
||
423 | } else { |
||
424 | return ( ( (int) $a['interval'] > (int) $b['interval'] ) ? 1 : -1 ); |
||
425 | } |
||
426 | } |
||
427 | |||
428 | /** |
||
429 | * Verify if a given timestamp is in the past or the future. |
||
430 | * |
||
431 | * @param int $time Unix timestamp. |
||
432 | * |
||
433 | * @return bool True if the time has passed, false otherwise. |
||
434 | */ |
||
435 | private function is_time_in_past( $time ) { |
||
436 | return ( time() > $time && 'No' === $this->_doing_cron ); |
||
437 | } |
||
438 | |||
439 | |||
440 | /** |
||
441 | * Transform a time in seconds to minutes rounded to 2 decimals. |
||
442 | * |
||
443 | * @param int $time Unix timestamp. |
||
444 | * |
||
445 | * @return int|float |
||
446 | */ |
||
447 | private function get_minutes( $time ) { |
||
448 | return round( ( (int) $time / 60 ), 2 ); |
||
449 | } |
||
450 | |||
451 | |||
452 | /** |
||
453 | * Transform a time in seconds to hours rounded to 2 decimals. |
||
454 | * |
||
455 | * @param int $time Unix timestamp. |
||
456 | * |
||
457 | * @return int|float |
||
458 | */ |
||
459 | private function get_hours( $time ) { |
||
460 | return round( ( (int) $time / 3600 ), 2 ); |
||
461 | } |
||
462 | |||
463 | |||
464 | /** |
||
465 | * Compares time with current time and adds ' ago' if current time is greater than event time. |
||
466 | * |
||
467 | * @param string $human_time Human readable time difference. |
||
468 | * @param int $time Unix time of event. |
||
469 | * |
||
470 | * @return string |
||
471 | */ |
||
472 | private function display_past_time( $human_time, $time ) { |
||
473 | if ( time() > $time ) { |
||
474 | /* TRANSLATORS: %s is a human readable time difference. */ |
||
475 | return sprintf( __( '%s ago', 'zt-debug-bar-cron' ), $human_time ); |
||
476 | } else { |
||
477 | return $human_time; |
||
478 | } |
||
479 | } |
||
480 | |||
481 | |||
482 | /** |
||
483 | * Load the pretty output class & set the recursion limit. |
||
484 | */ |
||
485 | private function load_debug_bar_pretty_output() { |
||
486 | if ( ! class_exists( 'Debug_Bar_Pretty_Output' ) ) { |
||
487 | require_once plugin_dir_path( __FILE__ ) . 'inc/debug-bar-pretty-output/class-debug-bar-pretty-output.php'; |
||
488 | } |
||
489 | |||
490 | // Limit recursion depth if possible - method available since DBPO v1.4. |
||
491 | if ( method_exists( 'Debug_Bar_Pretty_Output', 'limit_recursion' ) ) { |
||
492 | Debug_Bar_Pretty_Output::limit_recursion( 2 ); |
||
493 | } |
||
494 | } |
||
495 | |||
496 | |||
497 | /** |
||
498 | * Print any type of variable with colour coding and a variable type indication. |
||
499 | * |
||
500 | * @param mixed $variable The variable to print. |
||
501 | */ |
||
502 | private function print_pretty_output( $variable ) { |
||
503 | if ( defined( 'Debug_Bar_Pretty_Output::VERSION' ) ) { |
||
504 | echo Debug_Bar_Pretty_Output::get_output( $variable, '', true ); // WPCS: XSS ok. |
||
505 | } else { |
||
506 | // An old version of the pretty output class was loaded. |
||
507 | // Real possibility as there are several DB plugins using the pretty print class. |
||
508 | Debug_Bar_Pretty_Output::output( $variable, '', true ); |
||
509 | } |
||
510 | } |
||
511 | |||
512 | |||
513 | /** |
||
514 | * Unset recursion depth limit for the pretty output class. |
||
515 | * |
||
516 | * @internal Method available since DBPO v1.4. |
||
517 | */ |
||
518 | private function reset_debug_bar_pretty_output() { |
||
519 | if ( method_exists( 'Debug_Bar_Pretty_Output', 'unset_recursion_limit' ) ) { |
||
520 | Debug_Bar_Pretty_Output::unset_recursion_limit(); |
||
521 | } |
||
522 | } |
||
523 | } // End of class ZT_Debug_Bar_Cron. |
||
524 | |||
525 | } // End of if class_exists wrapper. |
||
526 |
Adding explicit visibility (
private
,protected
, orpublic
) is generally recommend to communicate to other developers how, and from where this method is intended to be used.