GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.

ZT_Debug_Bar_Cron::display_event_hook()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 7
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 5
nc 2
nop 2
dl 0
loc 7
rs 9.4285
c 0
b 0
f 0
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
		 * Lists all crons that are defined in WP Core.
84
		 *
85
		 * @var array
86
		 *
87
		 * @internal To find all, search WP trunk for `wp_schedule_(single_)?event`.
88
		 */
89
		private $_core_cron_hooks = array(
90
			'do_pings',
91
			'importer_scheduled_cleanup',     // WP 3.1+.
92
			'publish_future_post',
93
			'update_network_counts',          // WP 3.1+.
94
			'upgrader_scheduled_cleanup',     // WP 3.3+.
95
			'wp_maybe_auto_update',           // WP 3.7+.
96
			'wp_scheduled_auto_draft_delete', // WP 3.4+.
97
			'wp_scheduled_delete',            // WP 2.9+.
98
			'wp_split_shared_term_batch',     // WP 4.3+.
99
			'wp_update_plugins',
100
			'wp_update_themes',
101
			'wp_version_check',
102
		);
103
104
105
		/**
106
		 * Give the panel a title and set the enqueues.
107
		 *
108
		 * @return void
109
		 */
110
		public function init() {
111
			if ( ! function_exists( '_load_textdomain_just_in_time' ) ) {
112
				load_plugin_textdomain( 'debug-bar-cron' );
113
			}
114
115
			$this->title( __( 'Cron', 'debug-bar-cron' ) );
116
			add_action( 'wp_enqueue_scripts', array( $this, 'enqueue_scripts_styles' ) );
117
			add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_scripts_styles' ) );
118
		}
119
120
121
		/**
122
		 * Enqueue styles.
123
		 *
124
		 * @return void
125
		 */
126
		public function enqueue_scripts_styles() {
127
			$suffix = ( ( defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ) ? '' : '.min' );
128
129
			wp_enqueue_style(
130
				self::DBCRON_NAME,
131
				plugins_url( 'css/' . self::DBCRON_NAME . $suffix . '.css', __FILE__ ),
132
				array( 'debug-bar' ),
133
				self::DBCRON_STYLES_VERSION
134
			);
135
		}
136
137
138
		/**
139
		 * Show the menu item in Debug Bar.
140
		 *
141
		 * @return void
142
		 */
143
		public function prerender() {
144
			$this->set_visible( true );
145
		}
146
147
148
		/**
149
		 * Show the contents of the page.
150
		 *
151
		 * @return void
152
		 */
153
		public function render() {
154
			$this->get_crons();
155
156
			$this->_doing_cron = get_transient( 'doing_cron' ) ? __( 'Yes', 'debug-bar-cron' ) : __( 'No', 'debug-bar-cron' );
157
158
			// Get the time of the next event.
159
			$cron_times          = ( is_array( $this->_crons ) ? array_keys( $this->_crons ) : array() );
160
			$unix_time_next_cron = (int) $cron_times[0];
161
			$time_next_cron      = date( 'Y-m-d H:i:s', $unix_time_next_cron );
162
163
			$human_time_next_cron = human_time_diff( $unix_time_next_cron );
164
165
			// Add a class if past current time and doing cron is not running.
166
			$times_class = $this->is_time_in_past( $unix_time_next_cron ) ? ' past' : '';
167
168
			$this->load_debug_bar_pretty_output();
169
170
			echo // WPCS: XSS ok.
171
			'
172
			<div class="debug-bar-cron">
173
				<h2><span>', esc_html__( 'Total Events', 'debug-bar-cron' ), ':</span>', $this->_total_crons, '</h2>
174
				<h2><span>', esc_html__( 'Core Events', 'debug-bar-cron' ), ':</span>', $this->_total_core_crons, '</h2>
175
				<h2><span>', esc_html__( 'Custom Events', 'debug-bar-cron' ), ':</span>', $this->_total_user_crons, '</h2>
176
				<h2><span>', esc_html__( 'Doing Cron', 'debug-bar-cron' ), ':</span>', esc_html( $this->_doing_cron ), '</h2>
177
				<h2 class="times', esc_attr( $times_class ), '"><span>', esc_html__( 'Next Event', 'debug-bar-cron' ), ':</span>
178
					', esc_html( $time_next_cron ), '<br />
179
					', $unix_time_next_cron, '<br />
180
					', esc_html( $this->display_past_time( $human_time_next_cron, $unix_time_next_cron ) ), '
181
				</h2>
182
				<h2><span>', esc_html__( 'Current Time', 'debug-bar-cron' ), ':</span>', esc_html( date( 'H:i:s' ) ), '</h2>
183
184
				<div class="clear"></div>
185
186
				<h3>', esc_html__( 'Schedules', 'debug-bar-cron' ), '</h3>';
187
188
			$this->display_schedules();
189
190
			echo '
191
				<h3>', esc_html__( 'Custom Events', 'debug-bar-cron' ), '</h3>';
192
193
			$this->display_events( $this->_user_crons, __( 'No Custom Events scheduled.', 'debug-bar-cron' ) );
194
195
			echo '
196
				<h3>', esc_html__( 'Core Events', 'debug-bar-cron' ), '</h3>';
197
198
			$this->display_events( $this->_core_crons, __( 'No Core Events scheduled.', 'debug-bar-cron' ) );
199
200
			echo '
201
			</div>';
202
203
			$this->reset_debug_bar_pretty_output();
204
		}
205
206
207
		/**
208
		 * Gets all of the cron jobs.
209
		 *
210
		 * @return array|null Array of crons.
211
		 */
212
		private function get_crons() {
213
			if ( is_array( $this->_crons ) ) {
214
				return $this->_crons;
215
			}
216
217
			$crons = _get_cron_array();
218
			if ( is_array( $crons ) && ! empty( $crons ) ) {
219
				$this->_crons = $crons;
220
				$this->sort_count_crons();
221
			}
222
223
			return $this->_crons;
224
		}
225
226
227
		/**
228
		 * Sort and count crons.
229
		 *
230
		 * This function sorts the cron jobs into core crons, and custom crons. It also tallies
231
		 * a total count for the crons as this number is otherwise tough to get.
232
		 */
233
		private function sort_count_crons() {
234
			foreach ( $this->_crons as $time => $time_cron_array ) {
235
				foreach ( $time_cron_array as $hook => $data ) {
236
					$this->_total_crons += count( $data );
237
238
					if ( in_array( $hook, $this->_core_cron_hooks, true ) ) {
239
						$this->_core_crons[ $time ][ $hook ] = $data;
240
						$this->_total_core_crons            += count( $data );
241
					} else {
242
						$this->_user_crons[ $time ][ $hook ] = $data;
243
						$this->_total_user_crons            += count( $data );
244
					}
245
				}
246
			}
247
		}
248
249
250
		/**
251
		 * Displays the events in an easy to read table.
252
		 *
253
		 * @param array  $events        Array of events.
254
		 * @param string $no_events_msg Message to display if there are no events.
255
		 */
256
		private function display_events( $events, $no_events_msg ) {
257
			// Exit early if no events found.
258
			if ( ! is_array( $events ) || empty( $events ) ) {
259
				echo '
260
				<p>', esc_html( $no_events_msg ), '</p>';
261
				return;
262
			}
263
264
			echo '
265
				<table class="zt-debug-bar-cron-table zt-debug-bar-cron-event-table">
266
					<thead><tr>
267
						<th class="col1">', esc_html__( 'Next Execution', 'debug-bar-cron' ), '</th>
268
						<th class="col2">', esc_html__( 'Hook', 'debug-bar-cron' ), '</th>
269
						<th class="col3">', esc_html__( 'Interval Hook', 'debug-bar-cron' ), '</th>
270
						<th class="col4">', esc_html__( 'Interval Value', 'debug-bar-cron' ), '</th>
271
						<th class="col5">', esc_html__( 'Args', 'debug-bar-cron' ), '</th>
272
					</tr></thead>
273
					<tbody>';
274
275
			foreach ( $events as $time => $time_cron_array ) {
276
				$time        = (int) $time;
277
				$event_count = $this->get_arg_set_count( $time_cron_array );
278
				$show_time   = true;
279
280
				foreach ( $time_cron_array as $hook => $data ) {
281
					$row_attributes = $this->get_event_row_attributes( $time, $hook );
282
					$arg_set_count  = count( $data );
283
					$show_hook      = true;
284
285
					foreach ( $data as $hash => $info ) {
286
						echo // WPCS: xss ok.
287
						'
288
						<tr', $row_attributes, '>';
289
290
						if ( true === $show_time ) {
291
							$this->display_event_time( $time, $event_count );
292
							$show_time = false;
293
						}
294
295
						if ( true === $show_hook ) {
296
							$this->display_event_hook( $hook, $arg_set_count );
297
							$show_hook = false;
298
						}
299
300
						// Report the schedule.
301
						echo '
302
							<td>';
303
						$this->display_event_schedule( $info );
304
						echo '</td>';
305
306
						// Report the interval.
307
						echo '
308
							<td class="intervals">';
309
						$this->display_event_intervals( $info );
310
						echo '</td>';
311
312
						// Report the args.
313
						echo '
314
							<td>';
315
						$this->display_event_cron_arguments( $info['args'] );
316
						echo '</td>
317
						</tr>';
318
					}
319
					unset( $hash, $info );
320
				}
321
				unset( $hook, $data, $row_attributes, $arg_set_count, $show_hook );
322
			}
323
			unset( $time, $time_cron_array, $hook_count, $show_time );
324
325
			echo '
326
					</tbody>
327
				</table>';
328
		}
329
330
331
		/**
332
		 * Count the number of argument sets for a cron time.
333
		 *
334
		 * @param array $hook_array Array of hooks with argument sets.
335
		 *
336
		 * @return int
337
		 */
338
		private function get_arg_set_count( $hook_array ) {
339
			$count = 0;
340
			foreach ( $hook_array as $set ) {
341
				$count += count( $set );
342
			}
343
			return $count;
344
		}
345
346
347
		/**
348
		 * Create a HTML attribute string for an event row.
349
		 *
350
		 * @param int    $time Unix timestamp.
351
		 * @param string $hook Action hook for the cron job.
352
		 *
353
		 * @return string
354
		 */
355
		private function get_event_row_attributes( $time, $hook ) {
356
			$attributes = '';
357
			$classes    = array();
358
359
			// Add a class if past current time.
360
			if ( $this->is_time_in_past( $time ) ) {
361
				$classes[] = 'past';
362
			}
363
364
			// Verify if any events are hooked in.
365
			if ( false === has_action( $hook ) ) {
366
				/* translators: This text will display as a tooltip. %1$s will be replaced by a line break. */
367
				$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.', 'debug-bar-cron' ), "\n" ) . '"';
368
				$classes[]   = 'empty-event';
369
			}
370
371
			if ( ! empty( $classes ) ) {
372
				$attributes .= ' class="' . implode( ' ', $classes ) . '"';
373
			}
374
375
			return $attributes;
376
		}
377
378
379
		/**
380
		 * Display the timing for the event as a date, timestamp and human readable time difference.
381
		 *
382
		 * @param int $time        Timestamp.
383
		 * @param int $event_count Number of events running at this time.
384
		 */
385
		private function display_event_time( $time, $event_count ) {
386
			$row_span = ( $event_count > 1 ) ? ' rowspan="' . $event_count . '"' : '';
387
388
			echo // WPCS: xss ok.
389
			'
390
			<td' . $row_span . '>
391
				', date( 'Y-m-d H:i:s', $time ), '<br />
392
				', $time, '<br />
393
				', esc_html( $this->display_past_time( human_time_diff( $time ), $time ) ), '
394
			</td>';
395
		}
396
397
398
		/**
399
		 * Display the name of the cron job event hook.
400
		 *
401
		 * @param string $hook          Hook name.
402
		 * @param int    $arg_set_count Number of events running at this time and on this hook.
403
		 */
404
		private function display_event_hook( $hook, $arg_set_count ) {
405
			$row_span = ( $arg_set_count > 1 ) ? ' rowspan="' . $arg_set_count . '"' : '';
406
407
			echo // WPCS: xss ok.
408
			'
409
			<td' . $row_span . '>', esc_html( $hook ), '</td>';
410
		}
411
412
413
		/**
414
		 * Displays the the event schedule name for recurring events or else 'single event'.
415
		 *
416
		 * @param array $info Event info array.
417
		 */
418
		private function display_event_schedule( $info ) {
419
			if ( ! empty( $info['schedule'] ) ) {
420
				echo esc_html( $info['schedule'] );
421
			} else {
422
				echo esc_html__( 'Single Event', 'debug-bar-cron' );
423
			}
424
		}
425
426
427
		/**
428
		 * Displays the event interval in seconds, minutes and hours.
429
		 *
430
		 * @param array $info Event info array.
431
		 */
432
		private function display_event_intervals( $info ) {
433
			if ( ! empty( $info['interval'] ) ) {
434
				$interval = (int) $info['interval'];
435
				/* translators: %s is number of seconds. */
436
				printf( esc_html__( '%ss', 'debug-bar-cron' ) . '<br />', $interval ); // WPCS: XSS ok.
437
				/* translators: %s is number of minutes. */
438
				printf( esc_html__( '%sm', 'debug-bar-cron' ) . '<br />', $this->get_minutes( $interval ) ); // WPCS: XSS ok.
439
				/* translators: %s is number of hours. */
440
				printf( esc_html__( '%sh', 'debug-bar-cron' ), $this->get_hours( $interval ) ); // WPCS: XSS ok.
441
				unset( $interval );
442
			} else {
443
				echo esc_html__( 'Single Event', 'debug-bar-cron' );
444
			}
445
		}
446
447
448
		/**
449
		 * Displays the cron arguments in a readable format.
450
		 *
451
		 * @param mixed $args Cron argument(s).
452
		 *
453
		 * @return void
454
		 */
455
		private function display_event_cron_arguments( $args ) {
456
			// Arguments defaults to an empty array if no arguments are given.
457
			if ( is_array( $args ) && array() === $args ) {
458
				echo esc_html__( 'No Args', 'debug-bar-cron' );
459
				return;
460
			}
461
462
			// Ok, we have an argument, let's pretty print it.
463
			$this->print_pretty_output( $args );
464
		}
465
466
467
		/**
468
		 * Displays all of the schedules defined.
469
		 *
470
		 * @return void
471
		 */
472
		private function display_schedules() {
473
			echo '
474
				<table class="zt-debug-bar-cron-table zt-debug-bar-cron-schedule-table">
475
					<thead><tr>
476
						<th class="col1">', esc_html__( 'Interval Hook', 'debug-bar-cron' ), '</th>
477
						<th class="col2">', esc_html__( 'Interval (S)', 'debug-bar-cron' ), '</th>
478
						<th class="col3">', esc_html__( 'Interval (M)', 'debug-bar-cron' ), '</th>
479
						<th class="col4">', esc_html__( 'Interval (H)', 'debug-bar-cron' ), '</th>
480
						<th class="col5">', esc_html__( 'Display Name', 'debug-bar-cron' ), '</th>
481
					</tr></thead>
482
					<tbody>';
483
484
			$schedules = wp_get_schedules();
485
			ksort( $schedules );
486
			uasort( $schedules, array( $this, 'schedules_sorting' ) );
487
			foreach ( $schedules as $interval_hook => $data ) {
488
				$interval = (int) $data['interval'];
489
				echo // WPCS: XSS ok.
490
				'
491
						<tr>
492
							<td>', esc_html( $interval_hook ), '</td>
493
							<td>', $interval, '</td>
494
							<td>', $this->get_minutes( $interval ), '</td>
495
							<td>', $this->get_hours( $interval ), '</td>
496
							<td>', esc_html( $data['display'] ) . '</td>
497
						</tr>';
498
			}
499
500
			echo '
501
					</tbody>
502
				</table>';
503
		}
504
505
		/**
506
		 * Sorting method for cron schedules. Order by schedules interval.
507
		 *
508
		 * @param array $schedule_a First element of comparison pair.
509
		 * @param array $schedule_b Second element of comparison pair.
510
		 *
511
		 * @return int Return 1 if $schedule_a argument 'interval' greater then $schedule_b argument 'interval',
512
		 *             0 if both intervals equivalent and -1 otherwise.
513
		 */
514
		private function schedules_sorting( $schedule_a, $schedule_b ) {
515
			if ( (int) $schedule_a['interval'] === (int) $schedule_b['interval'] ) {
516
				return 0;
517
			} else {
518
				return ( ( (int) $schedule_a['interval'] > (int) $schedule_b['interval'] ) ? 1 : -1 );
519
			}
520
		}
521
522
		/**
523
		 * Verify if a given timestamp is in the past or the future.
524
		 *
525
		 * @param int $time Unix timestamp.
526
		 *
527
		 * @return bool True if the time has passed, false otherwise.
528
		 */
529
		private function is_time_in_past( $time ) {
530
			return ( time() > $time && 'No' === $this->_doing_cron );
531
		}
532
533
534
		/**
535
		 * Transform a time in seconds to minutes rounded to 2 decimals.
536
		 *
537
		 * @param int $time Unix timestamp.
538
		 *
539
		 * @return float
540
		 */
541
		private function get_minutes( $time ) {
542
			return round( ( (int) $time / 60 ), 2 );
543
		}
544
545
546
		/**
547
		 * Transform a time in seconds to hours rounded to 2 decimals.
548
		 *
549
		 * @param int $time Unix timestamp.
550
		 *
551
		 * @return float
552
		 */
553
		private function get_hours( $time ) {
554
			return round( ( (int) $time / 3600 ), 2 );
555
		}
556
557
558
		/**
559
		 * Compares time with current time and adds ' ago' if current time is greater than event time.
560
		 *
561
		 * @param string $human_time Human readable time difference.
562
		 * @param int    $time       Unix time of event.
563
		 *
564
		 * @return string
565
		 */
566
		private function display_past_time( $human_time, $time ) {
567
			if ( time() > $time ) {
568
				/* translators: %s is a human readable time difference. */
569
				return sprintf( __( '%s ago', 'debug-bar-cron' ), $human_time );
570
			} else {
571
				return $human_time;
572
			}
573
		}
574
575
576
		/**
577
		 * Load the pretty output class & set the recursion limit.
578
		 */
579
		private function load_debug_bar_pretty_output() {
580
			if ( ! class_exists( 'Debug_Bar_Pretty_Output' ) ) {
581
				require_once plugin_dir_path( __FILE__ ) . 'inc/debug-bar-pretty-output/class-debug-bar-pretty-output.php';
582
			}
583
584
			// Limit recursion depth if possible - method available since DBPO v1.4.
585
			if ( method_exists( 'Debug_Bar_Pretty_Output', 'limit_recursion' ) ) {
586
				Debug_Bar_Pretty_Output::limit_recursion( 2 );
587
			}
588
		}
589
590
591
		/**
592
		 * Print any type of variable with colour coding and a variable type indication.
593
		 *
594
		 * @param mixed $variable The variable to print.
595
		 */
596
		private function print_pretty_output( $variable ) {
597
			if ( defined( 'Debug_Bar_Pretty_Output::VERSION' ) ) {
598
				echo Debug_Bar_Pretty_Output::get_output( $variable, '', true ); // WPCS: XSS ok.
599
			} else {
600
				// An old version of the pretty output class was loaded.
601
				// Real possibility as there are several DB plugins using the pretty print class.
602
				Debug_Bar_Pretty_Output::output( $variable, '', true );
603
			}
604
		}
605
606
607
		/**
608
		 * Unset recursion depth limit for the pretty output class.
609
		 *
610
		 * @internal Method available since DBPO v1.4.
611
		 */
612
		private function reset_debug_bar_pretty_output() {
613
			if ( method_exists( 'Debug_Bar_Pretty_Output', 'unset_recursion_limit' ) ) {
614
				Debug_Bar_Pretty_Output::unset_recursion_limit();
615
			}
616
		}
617
	} // End of class ZT_Debug_Bar_Cron.
618
619
} // End of if class_exists wrapper.
620