Completed
Branch feature/minor-refactoring (0da00e)
by Juliette
02:57 queued 14s
created

ZT_Debug_Bar_Cron::print_pretty_output()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 9
Code Lines 5

Duplication

Lines 0
Ratio 0 %
Metric Value
dl 0
loc 9
rs 9.6667
cc 2
eloc 5
nc 2
nop 1
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_null( $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++;
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-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
				foreach ( $time_cron_array as $hook => $data ) {
265
					foreach ( $data as $hash => $info ) {
266
						echo '
267
						<tr>
268
							<td';
269
270
						// Add a class if past current time.
271
						if ( $this->is_time_in_past( $time ) ) {
272
							echo ' class="past"';
273
						}
274
275
						echo '>
276
								', esc_html( date( 'Y-m-d H:i:s', $time ) ), '<br />
277
								', intval( $time ), '<br />
278
								', esc_html( $this->display_past_time( human_time_diff( $time ), $time ) ), '
279
							</td>
280
							<td>', esc_html( $hook ), '</td>';
281
282
283
						// Report the schedule.
284
						echo '
285
							<td>';
286
						if ( $info['schedule'] ) {
287
							echo esc_html( $info['schedule'] );
288
						} else {
289
							echo esc_html__( 'Single Event', 'zt-debug-bar-cron' );
290
						}
291
						echo '</td>';
292
293
						// Report the interval.
294
						echo '
295
							<td>';
296
						if ( isset( $info['interval'] ) ) {
297
							$interval = (int) $info['interval'];
298
							/* TRANSLATORS: %s is number of seconds. */
299
							printf( esc_html__( '%ss', 'zt-debug-bar-cron' ) . '<br />', $interval ); // WPCS: XSS ok.
300
							/* TRANSLATORS: %s is number of minutes. */
301
							printf( esc_html__( '%sm', 'zt-debug-bar-cron' ) . '<br />', ( $interval / 60 ) ); // WPCS: XSS ok.
302
							/* TRANSLATORS: %s is number of hours. */
303
							printf( esc_html__( '%sh', 'zt-debug-bar-cron' ), ( $interval / ( 60 * 60 ) ) ); // WPCS: XSS ok.
304
						} else {
305
							echo esc_html__( 'Single Event', 'zt-debug-bar-cron' );
306
						}
307
						echo '</td>';
308
309
						// Report the args.
310
						echo '
311
							<td>';
312
						$this->display_cron_arguments( $info['args'] );
313
						echo '</td>
314
						</tr>';
315
					}
316
				}
317
			}
318
319
			echo '
320
					</tbody>
321
				</table>';
322
		}
323
324
325
		/**
326
		 * Displays the cron arguments in a readable format.
327
		 *
328
		 * @param mixed $args Cron argument(s).
329
		 *
330
		 * @return void
331
		 */
332
		private function display_cron_arguments( $args ) {
333
			// Arguments defaults to an empty array if no arguments are given.
334
			if ( is_array( $args ) && array() === $args ) {
335
				echo esc_html__( 'No Args', 'zt-debug-bar-cron' );
336
				return;
337
			}
338
339
			// Ok, we have an argument, let's pretty print it.
340
			$this->print_pretty_output( $args );
341
		}
342
343
344
		/**
345
		 * Displays all of the schedules defined.
346
		 *
347
		 * @return void
348
		 */
349
		private function display_schedules() {
350
			echo '
351
				<table class="zt-debug-bar-cron-event-table">
352
					<thead><tr>
353
						<th class="col1">', esc_html__( 'Interval Hook', 'zt-debug-bar-cron' ), '</th>
354
						<th class="col2">', esc_html__( 'Interval (S)', 'zt-debug-bar-cron' ), '</th>
355
						<th class="col3">', esc_html__( 'Interval (M)', 'zt-debug-bar-cron' ), '</th>
356
						<th class="col4">', esc_html__( 'Interval (H)', 'zt-debug-bar-cron' ), '</th>
357
						<th class="col5">', esc_html__( 'Display Name', 'zt-debug-bar-cron' ), '</th>
358
					</tr></thead>
359
					<tbody>';
360
361
362
			$schedules = wp_get_schedules();
363
			foreach ( $schedules as $interval_hook => $data ) {
364
				$interval = (int) $data['interval'];
365
				echo  // WPCS: XSS ok.
366
				'
367
						<tr>
368
							<td>', esc_html( $interval_hook ), '</td>
369
							<td>', $interval, '</td>
370
							<td>', ( $interval / 60 ), '</td>
371
							<td>', ( $interval / ( 60 * 60 ) ), '</td>
372
							<td>', esc_html( $data['display'] ) . '</td>
373
						</tr>';
374
			}
375
376
			echo '
377
					</tbody>
378
				</table>';
379
		}
380
381
382
		/**
383
		 * Verify if a given timestamp is in the past or the future.
384
		 *
385
		 * @param int $time Timestamp.
386
		 *
387
		 * @return bool True if the time has passed, false otherwise.
388
		 */
389
		private function is_time_in_past( $time ) {
390
			return ( time() > $time && 'No' === $this->_doing_cron );
391
		}
392
393
394
		/**
395
		 * Compares time with current time and adds ' ago' if current time is greater than event time.
396
		 *
397
		 * @param string $human_time Human readable time difference.
398
		 * @param int    $time       Unix time of event.
399
		 *
400
		 * @return string
401
		 */
402
		private function display_past_time( $human_time, $time ) {
403
			if ( time() > $time ) {
404
				/* TRANSLATORS: %s is a human readable time difference. */
405
				return sprintf( __( '%s ago', 'zt-debug-bar-cron' ), $human_time );
406
			} else {
407
				return $human_time;
408
			}
409
		}
410
411
412
		/**
413
		 * Load the pretty output class & set the recursion limit.
414
		 */
415
		private function load_debug_bar_pretty_output() {
416
			if ( ! class_exists( 'Debug_Bar_Pretty_Output' ) ) {
417
				require_once plugin_dir_path( __FILE__ ) . 'inc/debug-bar-pretty-output/class-debug-bar-pretty-output.php';
418
			}
419
420
			// Limit recursion depth if possible - method available since DBPO v1.4.
421
			if ( method_exists( 'Debug_Bar_Pretty_Output', 'limit_recursion' ) ) {
422
				Debug_Bar_Pretty_Output::limit_recursion( 2 );
423
			}
424
		}
425
426
427
		/**
428
		 * Print any type of variable with colour coding and a variable type indication.
429
		 *
430
		 * @param mixed $variable The variable to print.
431
		 */
432
		private function print_pretty_output( $variable ) {
433
			if ( defined( 'Debug_Bar_Pretty_Output::VERSION' ) ) {
434
				echo Debug_Bar_Pretty_Output::get_output( $variable, '', true ); // WPCS: XSS ok.
435
			} else {
436
				// An old version of the pretty output class was loaded.
437
				// Real possibility as there are several DB plugins using the pretty print class.
438
				Debug_Bar_Pretty_Output::output( $variable, '', true );
439
			}
440
		}
441
442
443
		/**
444
		 * Unset recursion depth limit for the pretty output class.
445
		 *
446
		 * @internal Method available since DBPO v1.4.
447
		 */
448
		private function reset_debug_bar_pretty_output() {
449
			if ( method_exists( 'Debug_Bar_Pretty_Output', 'unset_recursion_limit' ) ) {
450
				Debug_Bar_Pretty_Output::unset_recursion_limit();
451
			}
452
		}
453
	} // End of class ZT_Debug_Bar_Cron.
454
455
} // End of if class_exists wrapper.
456