Query Monitor - Version 2.7.0

Version Description

  • Detect broken dependencies for scripts and styles.
  • Calculate and output the dependents of scripts and styles.
  • Add transparent support for Debug Bar add-on panels.
  • Add support for WordPress.com VIP plugins in the component detection.
  • Sortable and filterable columns for HTTP requests.
  • Display a warning when something's hooked onto the all action.
  • Clearer output for the template file and component names when a child theme is in use.
  • Move the current blog information to the Request component. Display current site information if we're running a multi-network.
  • Allow default error handlers, such as error logging, to continue to function as expected.
  • Don't skip outputting the calling function name in the database error list.
  • New namespaced filter names for a bunch of filterable things.
  • Add a qm/process filter to allow users to disable QM's processing and output.
  • Display the value of WP_HTTP_BLOCK_EXTERNAL and WP_ACCESSIBLE_HOSTS in the HTTP component.
  • New storage and registration mechanisms for collectors, dispatchers, and output handlers.
  • CSS tweaks to better match wp-admin styles.
Download this release

Release Info

Developer johnbillion
Plugin Icon 128x128 Query Monitor
Version 2.7.0
Comparing to
See all releases

Code changes from version 2.6.10 to 2.7.0

Files changed (52) hide show
  1. assets/query-monitor.css +116 -20
  2. assets/query-monitor.js +32 -1
  3. Backtrace.php → classes/Backtrace.php +4 -6
  4. Collector.php → classes/Collector.php +40 -1
  5. classes/Collectors.php +51 -0
  6. Dispatcher.php → classes/Dispatcher.php +0 -19
  7. classes/Dispatchers.php +49 -0
  8. Output.php → classes/Output.php +1 -1
  9. Plugin.php → classes/Plugin.php +0 -0
  10. Util.php → classes/Util.php +57 -16
  11. classes/debug_bar.php +52 -0
  12. classes/debug_bar_panel.php +65 -0
  13. collectors/admin.php +6 -6
  14. collectors/assets.php +59 -10
  15. collectors/conditionals.php +8 -7
  16. collectors/db_callers.php +5 -5
  17. collectors/db_components.php +5 -5
  18. collectors/db_queries.php +7 -37
  19. collectors/debug_bar.php +90 -0
  20. collectors/environment.php +9 -12
  21. collectors/hooks.php +51 -38
  22. collectors/http.php +24 -25
  23. collectors/overview.php +4 -4
  24. collectors/php_errors.php +8 -7
  25. collectors/redirects.php +2 -6
  26. collectors/request.php +13 -5
  27. collectors/theme.php +16 -12
  28. collectors/transients.php +2 -6
  29. dispatchers/Headers.php +1 -5
  30. dispatchers/Html.php +5 -9
  31. output/Headers.php +2 -5
  32. output/Html.php +26 -41
  33. output/headers/php_errors.php +6 -3
  34. output/headers/redirects.php +7 -4
  35. output/html/admin.php +8 -14
  36. output/html/assets.php +109 -64
  37. output/html/conditionals.php +8 -5
  38. output/html/db_callers.php +16 -15
  39. output/html/db_components.php +16 -15
  40. output/html/db_queries.php +27 -20
  41. output/html/debug_bar.php +74 -0
  42. output/html/environment.php +7 -13
  43. output/html/hooks.php +58 -19
  44. output/html/http.php +42 -25
  45. output/html/overview.php +9 -6
  46. output/html/php_errors.php +11 -8
  47. output/html/request.php +35 -4
  48. output/html/theme.php +25 -12
  49. output/html/transients.php +9 -6
  50. query-monitor.php +38 -44
  51. readme.txt +31 -12
  52. wp-content/db.php +5 -7
assets/query-monitor.css CHANGED
@@ -116,7 +116,7 @@ GNU General Public License for more details.
116
 
117
  #qm {
118
  clear: both !important;
119
- background: #f3f3f3 !important;
120
  margin: 25px 0 0 !important;
121
  border-top: 1px solid #ccc !important;
122
  padding: 0 0 35px !important;
@@ -163,7 +163,7 @@ body.wp-admin.folded #qm {
163
  #qm-wrapper > p {
164
  color: #777 !important;
165
  font: 13px/15px 'Open Sans', Arial !important;
166
- margin: 20px 1% -15px !important;
167
  font-style: italic !important;
168
  }
169
 
@@ -191,11 +191,10 @@ body.wp-admin.folded #qm {
191
  clear: left !important;
192
  }
193
 
194
- .qm>table {
195
  color: #555 !important;
196
  border-collapse: collapse !important;
197
- border-style: hidden !important;
198
- box-shadow: 0 0 0 1px #ddd, 0 1px 2px 1px rgba(0,0,0,0.05) !important;
199
  width: 100% !important;
200
  table-layout: auto !important;
201
  margin: 0 !important;
@@ -204,24 +203,34 @@ body.wp-admin.folded #qm {
204
  .qm td,
205
  .qm th {
206
  background: #fff !important;
 
207
  text-align: left !important;
208
  font-family: Menlo, Monaco, Consolas, 'Courier New', monospace !important;
209
  font-size: 11px !important;
210
  font-weight: normal !important;
211
  font-style: normal !important;
212
  line-height: 16px !important;
213
- border: 1px solid #eee !important;
214
  padding: 5px 8px 4px !important;
215
  vertical-align: top !important;
216
  text-shadow: none !important;
217
  text-transform: none !important;
218
  }
219
 
 
 
 
 
 
 
 
220
  .qm tbody tr:hover th,
221
  .qm tbody tr:hover td {
222
- background: #f5f5f5 !important;
223
  }
224
 
 
 
225
  #qm-conditionals tbody tr:hover td,
226
  #qm-overview tbody tr:hover td,
227
  #qm-authentication tbody tr:hover td,
@@ -235,7 +244,12 @@ body.wp-admin.folded #qm {
235
  }
236
 
237
  .qm th.qm-num {
238
- width: 4em !important;
 
 
 
 
 
239
  }
240
 
241
  .qm .qm-inner-toggle {
@@ -259,6 +273,12 @@ body.wp-admin.folded #qm {
259
  padding: 0 !important;
260
  }
261
 
 
 
 
 
 
 
262
  .qm ul {
263
  margin: 0 !important;
264
  padding: 0 0 0 10px !important;
@@ -269,6 +289,19 @@ body.wp-admin.folded #qm {
269
  margin-bottom: 2px !important;
270
  }
271
 
 
 
 
 
 
 
 
 
 
 
 
 
 
272
  .qm code {
273
  font-family: Menlo, Monaco, Consolas, 'Courier New', monospace !important;
274
  font-size: 11px !important;
@@ -276,7 +309,7 @@ body.wp-admin.folded #qm {
276
  font-style: normal !important;
277
  line-height: 16px !important;
278
  color: inherit !important;
279
- background: #f3f3f3 !important;
280
  padding: 3px 4px 2px !important;
281
  margin: 0 !important;
282
  }
@@ -291,11 +324,15 @@ body.wp-admin.folded #qm {
291
  color: #ccc !important;
292
  }
293
 
294
- .qm .qm-sql {
295
  word-wrap: break-word !important;
296
  word-break: break-all !important;
297
  }
298
 
 
 
 
 
299
  .qm .qm-nonselectsql {
300
  color: #a0a !important;
301
  }
@@ -342,19 +379,24 @@ body.wp-admin.folded #qm {
342
  background: #eee !important;
343
  }
344
 
345
- .qm .qm-warn {
 
 
 
 
346
  color: #f00 !important;
347
  }
348
 
 
 
 
 
 
349
  .qm span.qm-expensive,
350
  .qm td.qm-expensive {
351
  color: #f44 !important;
352
  }
353
 
354
- .qm td.qm-priority {
355
- text-align: right !important;
356
- }
357
-
358
  /* Filters */
359
 
360
  select.qm-filter {
@@ -378,11 +420,10 @@ select.qm-filter {
378
  }
379
 
380
  .qm-hide,
381
- .qm-hide-hooks-component,
382
- .qm-hide-hooks-name,
383
- .qm-hide-db_queries-type,
384
- .qm-hide-db_queries-caller,
385
- .qm-hide-db_queries-component {
386
  display: none !important;
387
  }
388
 
@@ -442,3 +483,58 @@ html[dir="rtl"] .qm td,
442
  html[dir="rtl"] .qm th {
443
  text-align: right !important;
444
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
116
 
117
  #qm {
118
  clear: both !important;
119
+ background: #f1f1f1 !important;
120
  margin: 25px 0 0 !important;
121
  border-top: 1px solid #ccc !important;
122
  padding: 0 0 35px !important;
163
  #qm-wrapper > p {
164
  color: #777 !important;
165
  font: 13px/15px 'Open Sans', Arial !important;
166
+ margin: 20px 20px -15px !important;
167
  font-style: italic !important;
168
  }
169
 
191
  clear: left !important;
192
  }
193
 
194
+ .qm table {
195
  color: #555 !important;
196
  border-collapse: collapse !important;
197
+ box-shadow: none !important;
 
198
  width: 100% !important;
199
  table-layout: auto !important;
200
  margin: 0 !important;
203
  .qm td,
204
  .qm th {
205
  background: #fff !important;
206
+ box-sizing: border-box !important;
207
  text-align: left !important;
208
  font-family: Menlo, Monaco, Consolas, 'Courier New', monospace !important;
209
  font-size: 11px !important;
210
  font-weight: normal !important;
211
  font-style: normal !important;
212
  line-height: 16px !important;
213
+ border: 1px solid #e8e8e8 !important;
214
  padding: 5px 8px 4px !important;
215
  vertical-align: top !important;
216
  text-shadow: none !important;
217
  text-transform: none !important;
218
  }
219
 
220
+ .qm .qm-totally-legit-spacer td {
221
+ background-color: #f1f1f1 !important;
222
+ border-right-color: #f1f1f1 !important;
223
+ border-left-color: #f1f1f1 !important;
224
+ height: 20px !important;
225
+ }
226
+
227
  .qm tbody tr:hover th,
228
  .qm tbody tr:hover td {
229
+ background: #f9f9f9 !important;
230
  }
231
 
232
+ .qm-debug-bar tbody tr:hover th,
233
+ .qm-debug-bar tbody tr:hover td,
234
  #qm-conditionals tbody tr:hover td,
235
  #qm-overview tbody tr:hover td,
236
  #qm-authentication tbody tr:hover td,
244
  }
245
 
246
  .qm th.qm-num {
247
+ width: 5.5em !important;
248
+ text-align: center !important;
249
+ }
250
+
251
+ .qm td.qm-num {
252
+ text-align: right !important;
253
  }
254
 
255
  .qm .qm-inner-toggle {
273
  padding: 0 !important;
274
  }
275
 
276
+ .qm ol {
277
+ margin: 0 !important;
278
+ padding: 0 0 0 30px !important;
279
+ list-style: decimal !important;
280
+ }
281
+
282
  .qm ul {
283
  margin: 0 !important;
284
  padding: 0 0 0 10px !important;
289
  margin-bottom: 2px !important;
290
  }
291
 
292
+ .qm pre {
293
+ font-family: Menlo, Monaco, Consolas, 'Courier New', monospace !important;
294
+ font-size: 11px !important;
295
+ font-weight: normal !important;
296
+ font-style: normal !important;
297
+ line-height: 16px !important;
298
+ color: inherit !important;
299
+ background: transparent; !important;
300
+ border: none !important;
301
+ margin: 0 !important;
302
+ padding: 0 !important;
303
+ }
304
+
305
  .qm code {
306
  font-family: Menlo, Monaco, Consolas, 'Courier New', monospace !important;
307
  font-size: 11px !important;
309
  font-style: normal !important;
310
  line-height: 16px !important;
311
  color: inherit !important;
312
+ background: #f1f1f1 !important;
313
  padding: 3px 4px 2px !important;
314
  margin: 0 !important;
315
  }
324
  color: #ccc !important;
325
  }
326
 
327
+ .qm .qm-wrap {
328
  word-wrap: break-word !important;
329
  word-break: break-all !important;
330
  }
331
 
332
+ .qm .qm-nowrap {
333
+ white-space: nowrap !important;
334
+ }
335
+
336
  .qm .qm-nonselectsql {
337
  color: #a0a !important;
338
  }
379
  background: #eee !important;
380
  }
381
 
382
+ .qm tr.error,
383
+ .qm .qm-warn,
384
+ .qm .qm-warn td,
385
+ .qm .qm-warn th,
386
+ .qm .qm-warn td .qm-info {
387
  color: #f00 !important;
388
  }
389
 
390
+ .qm tbody tr td.qm-highlight,
391
+ .qm .qm-highlight td {
392
+ background-color: #ffd !important;
393
+ }
394
+
395
  .qm span.qm-expensive,
396
  .qm td.qm-expensive {
397
  color: #f44 !important;
398
  }
399
 
 
 
 
 
400
  /* Filters */
401
 
402
  select.qm-filter {
420
  }
421
 
422
  .qm-hide,
423
+ .qm-hide-name,
424
+ .qm-hide-type,
425
+ .qm-hide-caller,
426
+ .qm-hide-component {
 
427
  display: none !important;
428
  }
429
 
483
  html[dir="rtl"] .qm th {
484
  text-align: right !important;
485
  }
486
+
487
+ /* Debug bar add-ons */
488
+
489
+ .qm-debug-bar pre {
490
+ font-size: 11px !important;
491
+ padding: 10px !important;
492
+ }
493
+
494
+ .qm-debug-bar .left {
495
+ float: left !important;
496
+ }
497
+
498
+ .qm-debug-bar .right {
499
+ float: right !important;
500
+ }
501
+
502
+ .qm-debug-bar h1, .qm-debug-bar h2, .qm-debug-bar h3 {
503
+ font-family: Menlo, Monaco, Consolas, 'Courier New', monospace !important;
504
+ font-weight: normal !important;
505
+ }
506
+
507
+ .qm-debug-bar h2 {
508
+ float: left !important;
509
+ min-width: 150px !important;
510
+ padding: 5px 10px 15px !important;
511
+ clear: none !important;
512
+ text-align: center !important;
513
+ font-size: 16px !important;
514
+ margin: 3px 8px 15px 0 !important;
515
+ }
516
+
517
+ .qm-debug-bar h2 span {
518
+ font-size: 11px !important;
519
+ white-space: nowrap !important;
520
+ display: block !important;
521
+ margin-bottom: 8px !important;
522
+ }
523
+
524
+ .qm-debug-bar h3 {
525
+ margin: 15px 0 5px !important;
526
+ font-size: 13px !important;
527
+ }
528
+
529
+ .qm-debug-bar .qm-debug-bar-output {
530
+ position: relative !important;
531
+ }
532
+
533
+ .qm-debug-bar .qm-debug-bar-output table {
534
+ margin-top: 4px !important;
535
+ margin-bottom: 4px !important;
536
+ }
537
+
538
+ #qm #debug-menu-target-Debug_Bar_Console {
539
+ min-height: 400px !important;
540
+ }
assets/query-monitor.js CHANGED
@@ -115,10 +115,19 @@ jQuery( function($) {
115
  tr = table.find('tbody tr[data-qm-' + filter + ']'),
116
  val = $(this).val().replace(/[[\]()'"]/g, "\\$&"),
117
  total = tr.removeClass('qm-hide-' + filter).length,
 
118
  time = 0;
119
 
120
- if ( $(this).val() !== '' )
 
 
 
 
 
 
 
121
  tr.not('[data-qm-' + filter + '*="' + val + '"]').addClass('qm-hide-' + filter);
 
122
 
123
  var matches = tr.filter(':visible');
124
  matches.each(function(i){
@@ -148,6 +157,28 @@ jQuery( function($) {
148
  e.preventDefault();
149
  });
150
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
151
  $( document ).ajaxSuccess( function( event, response, options ) {
152
 
153
  var errors = response.getResponseHeader( 'X-QM-Errors' );
115
  tr = table.find('tbody tr[data-qm-' + filter + ']'),
116
  val = $(this).val().replace(/[[\]()'"]/g, "\\$&"),
117
  total = tr.removeClass('qm-hide-' + filter).length,
118
+ hilite = $(this).attr('data-highlight'),
119
  time = 0;
120
 
121
+ if ( hilite ) {
122
+ table.find('tr').removeClass('qm-highlight');
123
+ }
124
+
125
+ if ( $(this).val() !== '' ) {
126
+ if ( hilite ) {
127
+ tr.filter('[data-qm-'+hilite+'*="' + val + '"]').addClass('qm-highlight');
128
+ }
129
  tr.not('[data-qm-' + filter + '*="' + val + '"]').addClass('qm-hide-' + filter);
130
+ }
131
 
132
  var matches = tr.filter(':visible');
133
  matches.each(function(i){
157
  e.preventDefault();
158
  });
159
 
160
+ $('#qm').find('.qm-highlighter').on('mouseenter',function(e){
161
+
162
+ var subject = $(this).data('qm-highlight');
163
+ var table = $(this).closest('table');
164
+
165
+ if ( !subject ) {
166
+ return;
167
+ }
168
+
169
+ $(this).addClass('qm-highlight');
170
+
171
+ $.each( subject.split(' '), function( i, el ){
172
+ table.find('tr[data-qm-subject="'+el+'"]').addClass('qm-highlight');
173
+ });
174
+
175
+ }).on('mouseleave',function(e){
176
+
177
+ $(this).removeClass('qm-highlight');
178
+ $(this).closest('table').find('tr').removeClass('qm-highlight');
179
+
180
+ });
181
+
182
  $( document ).ajaxSuccess( function( event, response, options ) {
183
 
184
  var errors = response.getResponseHeader( 'X-QM-Errors' );
Backtrace.php → classes/Backtrace.php RENAMED
@@ -20,7 +20,6 @@ class QM_Backtrace {
20
  protected static $ignore_class = array(
21
  'wpdb' => true,
22
  'QueryMonitor' => true,
23
- 'QueryMonitorDB' => true,
24
  'ExtQuery' => true,
25
  'W3_Db' => true,
26
  'Debug_Bar_PHP' => true,
@@ -46,7 +45,6 @@ class QM_Backtrace {
46
  'do_action_ref_array' => 1,
47
  'apply_filters_ref_array' => 1,
48
  'get_template_part' => 2,
49
- 'section_template' => 2,
50
  'load_template' => 'dir',
51
  'get_header' => 1,
52
  'get_sidebar' => 1,
@@ -200,10 +198,10 @@ class QM_Backtrace {
200
  if ( !self::$filtered and function_exists( 'did_action' ) and did_action( 'plugins_loaded' ) ) {
201
 
202
  # Only run apply_filters on these once
203
- self::$ignore_class = apply_filters( 'query_monitor_ignore_class', self::$ignore_class );
204
- self::$ignore_method = apply_filters( 'query_monitor_ignore_method', self::$ignore_method );
205
- self::$ignore_func = apply_filters( 'query_monitor_ignore_func', self::$ignore_func );
206
- self::$show_args = apply_filters( 'query_monitor_show_args', self::$show_args );
207
  self::$filtered = true;
208
 
209
  }
20
  protected static $ignore_class = array(
21
  'wpdb' => true,
22
  'QueryMonitor' => true,
 
23
  'ExtQuery' => true,
24
  'W3_Db' => true,
25
  'Debug_Bar_PHP' => true,
45
  'do_action_ref_array' => 1,
46
  'apply_filters_ref_array' => 1,
47
  'get_template_part' => 2,
 
48
  'load_template' => 'dir',
49
  'get_header' => 1,
50
  'get_sidebar' => 1,
198
  if ( !self::$filtered and function_exists( 'did_action' ) and did_action( 'plugins_loaded' ) ) {
199
 
200
  # Only run apply_filters on these once
201
+ self::$ignore_class = apply_filters( 'qm/trace/ignore_class', self::$ignore_class );
202
+ self::$ignore_method = apply_filters( 'qm/trace/ignore_method', self::$ignore_method );
203
+ self::$ignore_func = apply_filters( 'qm/trace/ignore_func', self::$ignore_func );
204
+ self::$show_args = apply_filters( 'qm/trace/show_args', self::$show_args );
205
  self::$filtered = true;
206
 
207
  }
Collector.php → classes/Collector.php RENAMED
@@ -17,7 +17,10 @@ GNU General Public License for more details.
17
  if ( ! class_exists( 'QM_Collector' ) ) {
18
  abstract class QM_Collector {
19
 
20
- protected $data = array();
 
 
 
21
 
22
  public function __construct() {}
23
 
@@ -27,6 +30,38 @@ abstract class QM_Collector {
27
 
28
  abstract public function name();
29
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
30
  public static function timer_stop_float() {
31
  global $timestart;
32
  return microtime( true ) - $timestart;
@@ -46,6 +81,10 @@ abstract class QM_Collector {
46
  return $this->data;
47
  }
48
 
 
 
 
 
49
  public static function sort_ltime( $a, $b ) {
50
  if ( $a['ltime'] == $b['ltime'] ) {
51
  return 0;
17
  if ( ! class_exists( 'QM_Collector' ) ) {
18
  abstract class QM_Collector {
19
 
20
+ protected $data = array(
21
+ 'types' => array(),
22
+ 'component_times' => array(),
23
+ );
24
 
25
  public function __construct() {}
26
 
30
 
31
  abstract public function name();
32
 
33
+ protected function log_type( $type ) {
34
+
35
+ if ( isset( $this->data['types'][$type] ) ) {
36
+ $this->data['types'][$type]++;
37
+ } else {
38
+ $this->data['types'][$type] = 1;
39
+ }
40
+
41
+ }
42
+
43
+ protected function log_component( $component, $ltime, $type ) {
44
+
45
+ if ( !isset( $this->data['component_times'][$component->name] ) ) {
46
+ $this->data['component_times'][$component->name] = array(
47
+ 'component' => $component->name,
48
+ 'calls' => 0,
49
+ 'ltime' => 0,
50
+ 'types' => array()
51
+ );
52
+ }
53
+
54
+ $this->data['component_times'][$component->name]['calls']++;
55
+ $this->data['component_times'][$component->name]['ltime'] += $ltime;
56
+
57
+ if ( isset( $this->data['component_times'][$component->name]['types'][$type] ) ) {
58
+ $this->data['component_times'][$component->name]['types'][$type]++;
59
+ } else {
60
+ $this->data['component_times'][$component->name]['types'][$type] = 1;
61
+ }
62
+
63
+ }
64
+
65
  public static function timer_stop_float() {
66
  global $timestart;
67
  return microtime( true ) - $timestart;
81
  return $this->data;
82
  }
83
 
84
+ final public function set_id( $id ) {
85
+ $this->id = $id;
86
+ }
87
+
88
  public static function sort_ltime( $a, $b ) {
89
  if ( $a['ltime'] == $b['ltime'] ) {
90
  return 0;
classes/Collectors.php ADDED
@@ -0,0 +1,51 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ Copyright 2009-2015 John Blackbourn
4
+
5
+ This program is free software; you can redistribute it and/or modify
6
+ it under the terms of the GNU General Public License as published by
7
+ the Free Software Foundation; either version 2 of the License, or
8
+ (at your option) any later version.
9
+
10
+ This program is distributed in the hope that it will be useful,
11
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ GNU General Public License for more details.
14
+
15
+ */
16
+
17
+ if ( ! class_exists( 'QM_Collectors' ) ) {
18
+ class QM_Collectors implements IteratorAggregate {
19
+
20
+ private $items = array();
21
+
22
+ public function getIterator() {
23
+ return new ArrayIterator( $this->items );
24
+ }
25
+
26
+ public static function add( QM_Collector $collector ) {
27
+ $collectors = self::init();
28
+ $collectors->items[ $collector->id ] = $collector;
29
+ }
30
+
31
+ public static function get( $id ) {
32
+ $collectors = self::init();
33
+ if ( isset( $collectors->items[ $id ] ) ) {
34
+ return $collectors->items[ $id ];
35
+ }
36
+ return false;
37
+ }
38
+
39
+ public static function init() {
40
+ static $instance;
41
+
42
+ if ( !$instance ) {
43
+ $instance = new QM_Collectors;
44
+ }
45
+
46
+ return $instance;
47
+
48
+ }
49
+
50
+ }
51
+ }
Dispatcher.php → classes/Dispatcher.php RENAMED
@@ -40,8 +40,6 @@ abstract class QM_Dispatcher {
40
  // nothing
41
  }
42
 
43
- abstract public function get_outputter( QM_Collector $collector );
44
-
45
  public function user_can_view() {
46
 
47
  if ( !did_action( 'plugins_loaded' ) ) {
@@ -70,22 +68,5 @@ abstract class QM_Dispatcher {
70
  return false;
71
  }
72
 
73
- public function output( QM_Collector $collector ) {
74
-
75
- $filter = 'query_monitor_output_' . $this->id . '_' . $collector->id;
76
- $output = apply_filters( $filter, null, $collector );
77
-
78
- if ( false === $output ) {
79
- return;
80
- }
81
-
82
- if ( !is_a( $output, 'QM_Output' ) ) {
83
- $output = $this->get_outputter( $collector );
84
- }
85
-
86
- $output->output();
87
-
88
- }
89
-
90
  }
91
  }
40
  // nothing
41
  }
42
 
 
 
43
  public function user_can_view() {
44
 
45
  if ( !did_action( 'plugins_loaded' ) ) {
68
  return false;
69
  }
70
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
71
  }
72
  }
classes/Dispatchers.php ADDED
@@ -0,0 +1,49 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ Copyright 2009-2015 John Blackbourn
4
+
5
+ This program is free software; you can redistribute it and/or modify
6
+ it under the terms of the GNU General Public License as published by
7
+ the Free Software Foundation; either version 2 of the License, or
8
+ (at your option) any later version.
9
+
10
+ This program is distributed in the hope that it will be useful,
11
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ GNU General Public License for more details.
14
+
15
+ */
16
+
17
+ class QM_Dispatchers implements IteratorAggregate {
18
+
19
+ private $items = array();
20
+
21
+ public function getIterator() {
22
+ return new ArrayIterator( $this->items );
23
+ }
24
+
25
+ public static function add( QM_Dispatcher $dispatcher ) {
26
+ $dispatchers = self::init();
27
+ $dispatchers->items[ $dispatcher->id ] = $dispatcher;
28
+ }
29
+
30
+ public static function get( $id ) {
31
+ $dispatchers = self::init();
32
+ if ( isset( $dispatchers->items[ $id ] ) ) {
33
+ return $dispatchers->items[ $id ];
34
+ }
35
+ return false;
36
+ }
37
+
38
+ public static function init() {
39
+ static $instance;
40
+
41
+ if ( !$instance ) {
42
+ $instance = new QM_Dispatchers;
43
+ }
44
+
45
+ return $instance;
46
+
47
+ }
48
+
49
+ }
Output.php → classes/Output.php RENAMED
@@ -14,7 +14,7 @@ GNU General Public License for more details.
14
 
15
  */
16
 
17
- if ( ! class_exists( 'QM_Output' ) ) {
18
  interface QM_Output {
19
 
20
  public function __construct( QM_Collector $collector );
14
 
15
  */
16
 
17
+ if ( ! interface_exists( 'QM_Output' ) ) {
18
  interface QM_Output {
19
 
20
  public function __construct( QM_Collector $collector );
Plugin.php → classes/Plugin.php RENAMED
File without changes
Util.php → classes/Util.php RENAMED
@@ -61,6 +61,15 @@ class QM_Util {
61
  }
62
 
63
  public static function get_file_dirs() {
 
 
 
 
 
 
 
 
 
64
  return self::$file_dirs;
65
  }
66
 
@@ -72,16 +81,7 @@ class QM_Util {
72
  return self::$file_components[$file];
73
  }
74
 
75
- if ( empty( self::$file_dirs ) ) {
76
- self::$file_dirs['plugin'] = self::standard_dir( WP_PLUGIN_DIR );
77
- self::$file_dirs['muplugin'] = self::standard_dir( WPMU_PLUGIN_DIR );
78
- self::$file_dirs['stylesheet'] = self::standard_dir( get_stylesheet_directory() );
79
- self::$file_dirs['template'] = self::standard_dir( get_template_directory() );
80
- self::$file_dirs['other'] = self::standard_dir( WP_CONTENT_DIR );
81
- self::$file_dirs['core'] = self::standard_dir( ABSPATH );
82
- }
83
-
84
- foreach ( self::$file_dirs as $type => $dir ) {
85
  if ( 0 === strpos( $file, $dir ) ) {
86
  break;
87
  }
@@ -91,7 +91,7 @@ class QM_Util {
91
 
92
  switch ( $type ) {
93
  case 'plugin':
94
- case 'muplugin':
95
  $plug = plugin_basename( $file );
96
  if ( strpos( $plug, '/' ) ) {
97
  $plug = explode( '/', $plug );
@@ -102,8 +102,24 @@ class QM_Util {
102
  $name = sprintf( __( 'Plugin: %s', 'query-monitor' ), $plug );
103
  $context = $plug;
104
  break;
 
 
 
 
 
 
 
 
 
 
 
 
105
  case 'stylesheet':
106
- $name = __( 'Theme', 'query-monitor' );
 
 
 
 
107
  break;
108
  case 'template':
109
  $name = __( 'Parent Theme', 'query-monitor' );
@@ -148,7 +164,7 @@ class QM_Util {
148
 
149
  $ref = new ReflectionFunction( $callback['function'] );
150
  $file = trim( QM_Util::standard_dir( $ref->getFileName(), '' ), '/' );
151
- $callback['name'] = sprintf( __( '{closure}() on line %1$d of %2$s', 'query-monitor' ), $ref->getEndLine(), $file );
152
 
153
  } else {
154
 
@@ -157,9 +173,19 @@ class QM_Util {
157
 
158
  }
159
 
160
- $callback['file'] = $ref->getFileName();
161
- $callback['line'] = $ref->getStartLine();
162
- $callback['component'] = self::get_file_component( $ref->getFileName() );
 
 
 
 
 
 
 
 
 
 
163
 
164
  } catch ( ReflectionException $e ) {
165
 
@@ -222,5 +248,20 @@ class QM_Util {
222
 
223
  }
224
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
225
  }
226
  }
61
  }
62
 
63
  public static function get_file_dirs() {
64
+ if ( empty( self::$file_dirs ) ) {
65
+ self::$file_dirs['plugin'] = self::standard_dir( WP_PLUGIN_DIR );
66
+ self::$file_dirs['mu-plugin'] = self::standard_dir( WPMU_PLUGIN_DIR );
67
+ self::$file_dirs['vip-plugin'] = self::standard_dir( get_theme_root() . '/vip/plugins' );
68
+ self::$file_dirs['stylesheet'] = self::standard_dir( get_stylesheet_directory() );
69
+ self::$file_dirs['template'] = self::standard_dir( get_template_directory() );
70
+ self::$file_dirs['other'] = self::standard_dir( WP_CONTENT_DIR );
71
+ self::$file_dirs['core'] = self::standard_dir( ABSPATH );
72
+ }
73
  return self::$file_dirs;
74
  }
75
 
81
  return self::$file_components[$file];
82
  }
83
 
84
+ foreach ( self::get_file_dirs() as $type => $dir ) {
 
 
 
 
 
 
 
 
 
85
  if ( 0 === strpos( $file, $dir ) ) {
86
  break;
87
  }
91
 
92
  switch ( $type ) {
93
  case 'plugin':
94
+ case 'mu-plugin':
95
  $plug = plugin_basename( $file );
96
  if ( strpos( $plug, '/' ) ) {
97
  $plug = explode( '/', $plug );
102
  $name = sprintf( __( 'Plugin: %s', 'query-monitor' ), $plug );
103
  $context = $plug;
104
  break;
105
+ case 'vip-plugin':
106
+ $plug = str_replace( self::$file_dirs['vip-plugin'], '', $file );
107
+ $plug = trim( $plug, '/' );
108
+ if ( strpos( $plug, '/' ) ) {
109
+ $plug = explode( '/', $plug );
110
+ $plug = reset( $plug );
111
+ } else {
112
+ $plug = basename( $plug );
113
+ }
114
+ $name = sprintf( __( 'VIP Plugin: %s', 'query-monitor' ), $plug );
115
+ $context = $plug;
116
+ break;
117
  case 'stylesheet':
118
+ if ( is_child_theme() ) {
119
+ $name = __( 'Child Theme', 'query-monitor' );
120
+ } else {
121
+ $name = __( 'Theme', 'query-monitor' );
122
+ }
123
  break;
124
  case 'template':
125
  $name = __( 'Parent Theme', 'query-monitor' );
164
 
165
  $ref = new ReflectionFunction( $callback['function'] );
166
  $file = trim( QM_Util::standard_dir( $ref->getFileName(), '' ), '/' );
167
+ $callback['name'] = sprintf( __( 'Closure on line %1$d of %2$s', 'query-monitor' ), $ref->getStartLine(), $file );
168
 
169
  } else {
170
 
173
 
174
  }
175
 
176
+ $callback['file'] = $ref->getFileName();
177
+ $callback['line'] = $ref->getStartLine();
178
+
179
+ if ( '__lambda_func' === $ref->getName() ) {
180
+ if ( preg_match( '|(?P<file>.*)\((?P<line>[0-9]+)\)|', $callback['file'], $matches ) ) {
181
+ $callback['file'] = $matches['file'];
182
+ $callback['line'] = $matches['line'];
183
+ $file = trim( QM_Util::standard_dir( $callback['file'], '' ), '/' );
184
+ $callback['name'] = sprintf( __( 'Anonymous function on line %1$d of %2$s', 'query-monitor' ), $callback['line'], $file );
185
+ }
186
+ }
187
+
188
+ $callback['component'] = self::get_file_component( $callback['file'] );
189
 
190
  } catch ( ReflectionException $e ) {
191
 
248
 
249
  }
250
 
251
+ public static function is_multi_network() {
252
+ global $wpdb;
253
+
254
+ if ( ! is_multisite() ) {
255
+ return false;
256
+ }
257
+
258
+ $num_sites = $wpdb->get_var( "
259
+ SELECT COUNT(*)
260
+ FROM {$wpdb->site}
261
+ " );
262
+
263
+ return ( $num_sites > 1 );
264
+ }
265
+
266
  }
267
  }
classes/debug_bar.php ADDED
@@ -0,0 +1,52 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ Copyright 2009-2015 John Blackbourn
4
+
5
+ This program is free software; you can redistribute it and/or modify
6
+ it under the terms of the GNU General Public License as published by
7
+ the Free Software Foundation; either version 2 of the License, or
8
+ (at your option) any later version.
9
+
10
+ This program is distributed in the hope that it will be useful,
11
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ GNU General Public License for more details.
14
+
15
+ */
16
+
17
+ class Debug_Bar {
18
+ public $panels = array();
19
+
20
+ public function __construct() {
21
+ add_action( 'wp_head', array( $this, 'ensure_ajaxurl' ), 1 );
22
+
23
+ $this->enqueue();
24
+ $this->init_panels();
25
+ }
26
+
27
+ public function enqueue() {
28
+ wp_register_style( 'debug-bar', false, array(
29
+ 'query-monitor'
30
+ ) );
31
+ wp_register_script( 'debug-bar', false, array(
32
+ 'query-monitor'
33
+ ) );
34
+
35
+ do_action( 'debug_bar_enqueue_scripts' );
36
+ }
37
+
38
+ public function init_panels() {
39
+ require_once 'debug_bar_panel.php';
40
+
41
+ $this->panels = apply_filters( 'debug_bar_panels', array() );
42
+ }
43
+
44
+ public function ensure_ajaxurl() {
45
+ ?>
46
+ <script type="text/javascript">
47
+ var ajaxurl = '<?php echo admin_url( 'admin-ajax.php' ); ?>';
48
+ </script>
49
+ <?php
50
+ }
51
+
52
+ }
classes/debug_bar_panel.php ADDED
@@ -0,0 +1,65 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ Copyright 2009-2015 John Blackbourn
4
+
5
+ This program is free software; you can redistribute it and/or modify
6
+ it under the terms of the GNU General Public License as published by
7
+ the Free Software Foundation; either version 2 of the License, or
8
+ (at your option) any later version.
9
+
10
+ This program is distributed in the hope that it will be useful,
11
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ GNU General Public License for more details.
14
+
15
+ */
16
+
17
+ abstract class Debug_Bar_Panel {
18
+
19
+ public $_title = '';
20
+ public $_visible = true;
21
+
22
+ public function __construct( $title = '' ) {
23
+ $this->title( $title );
24
+
25
+ if ( $this->init() === false ) {
26
+ $this->set_visible( false );
27
+ return;
28
+ }
29
+
30
+ # @TODO convert to QM classes
31
+ add_filter( 'debug_bar_classes', array( $this, 'debug_bar_classes' ) );
32
+ }
33
+
34
+ /**
35
+ * Initializes the panel.
36
+ */
37
+ public function init() {}
38
+
39
+ public function prerender() {}
40
+
41
+ /**
42
+ * Renders the panel.
43
+ */
44
+ public function render() {}
45
+
46
+ public function is_visible() {
47
+ return $this->_visible;
48
+ }
49
+
50
+ public function set_visible( $visible ) {
51
+ $this->_visible = $visible;
52
+ }
53
+
54
+ public function title( $title = null ) {
55
+ if ( ! isset( $title ) ) {
56
+ return $this->_title;
57
+ }
58
+ $this->_title = $title;
59
+ }
60
+
61
+ public function debug_bar_classes( $classes ) {
62
+ return $classes;
63
+ }
64
+
65
+ }
collectors/admin.php CHANGED
@@ -39,11 +39,11 @@ class QM_Collector_Admin extends QM_Collector {
39
 
40
  }
41
 
42
- function register_qm_collector_admin( array $qm ) {
43
- if ( is_admin() ) {
44
- $qm['admin'] = new QM_Collector_Admin;
45
- }
46
- return $qm;
47
  }
48
 
49
- add_filter( 'query_monitor_collectors', 'register_qm_collector_admin', 70 );
 
 
39
 
40
  }
41
 
42
+ function register_qm_collector_admin( array $collectors, QueryMonitor $qm ) {
43
+ $collectors['admin'] = new QM_Collector_Admin;
44
+ return $collectors;
 
 
45
  }
46
 
47
+ if ( is_admin() ) {
48
+ add_filter( 'qm/collectors', 'register_qm_collector_admin', 10, 2 );
49
+ }
collectors/assets.php CHANGED
@@ -24,24 +24,73 @@ class QM_Collector_Assets extends QM_Collector {
24
  add_action( 'wp_print_footer_scripts', array( $this, 'action_print_footer_scripts' ) );
25
  add_action( 'admin_head', array( $this, 'action_head' ), 999 );
26
  add_action( 'wp_head', array( $this, 'action_head' ), 999 );
 
27
  }
28
 
29
  public function action_head() {
30
  global $wp_scripts, $wp_styles;
31
 
32
- $this->data['header_styles'] = $wp_styles->done;
33
- $this->data['header_scripts'] = $wp_scripts->done;
34
 
35
  }
36
 
37
  public function action_print_footer_scripts() {
38
  global $wp_scripts, $wp_styles;
39
 
40
- $this->data['raw_scripts'] = $wp_scripts;
41
- $this->data['raw_styles'] = $wp_styles;
 
42
 
43
- $this->data['footer_scripts'] = array_diff( $wp_scripts->done, $this->data['header_scripts'] );
44
- $this->data['footer_styles'] = array_diff( $wp_styles->done, $this->data['header_styles'] );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
45
 
46
  }
47
 
@@ -51,9 +100,9 @@ class QM_Collector_Assets extends QM_Collector {
51
 
52
  }
53
 
54
- function register_qm_collector_assets( array $qm ) {
55
- $qm['assets'] = new QM_Collector_Assets;
56
- return $qm;
57
  }
58
 
59
- add_filter( 'query_monitor_collectors', 'register_qm_collector_assets', 80 );
24
  add_action( 'wp_print_footer_scripts', array( $this, 'action_print_footer_scripts' ) );
25
  add_action( 'admin_head', array( $this, 'action_head' ), 999 );
26
  add_action( 'wp_head', array( $this, 'action_head' ), 999 );
27
+ add_action( 'login_head', array( $this, 'action_head' ), 999 );
28
  }
29
 
30
  public function action_head() {
31
  global $wp_scripts, $wp_styles;
32
 
33
+ $this->data['header']['styles'] = $wp_styles->done;
34
+ $this->data['header']['scripts'] = $wp_scripts->done;
35
 
36
  }
37
 
38
  public function action_print_footer_scripts() {
39
  global $wp_scripts, $wp_styles;
40
 
41
+ // @TODO remove the need for these raw scripts & styles to be collected
42
+ $this->data['raw']['scripts'] = $wp_scripts;
43
+ $this->data['raw']['styles'] = $wp_styles;
44
 
45
+ $this->data['footer']['scripts'] = array_diff( $wp_scripts->done, $this->data['header']['scripts'] );
46
+ $this->data['footer']['styles'] = array_diff( $wp_styles->done, $this->data['header']['styles'] );
47
+
48
+ }
49
+
50
+ public function process() {
51
+ if ( !isset( $this->data['raw'] ) ) {
52
+ return;
53
+ }
54
+
55
+ foreach ( array( 'scripts', 'styles' ) as $type ) {
56
+ foreach ( array( 'header', 'footer' ) as $position ) {
57
+ if ( empty( $this->data[ $position ][ $type ] ) ) {
58
+ $this->data[ $position ][ $type ] = array();
59
+ } else {
60
+ sort( $this->data[ $position ][ $type ] );
61
+ }
62
+ }
63
+ $raw = $this->data['raw'][ $type ];
64
+ $broken = array_diff( $raw->queue, $raw->done );
65
+
66
+ if ( !empty( $broken ) ) {
67
+ foreach ( $broken as $handle ) {
68
+ $item = $raw->query( $handle );
69
+ $broken = array_merge( $broken, $this->get_broken_dependencies( $item, $raw ) );
70
+ }
71
+
72
+ $this->data['broken'][ $type ] = array_unique( $broken );
73
+ sort( $this->data['broken'][ $type ] );
74
+ }
75
+
76
+ }
77
+ }
78
+
79
+ protected function get_broken_dependencies( _WP_Dependency $item, WP_Dependencies $dependencies ) {
80
+
81
+ $broken = array();
82
+
83
+ foreach ( $item->deps as $handle ) {
84
+
85
+ if ( $dep = $dependencies->query( $handle ) ) {
86
+ $broken = array_merge( $broken, $this->get_broken_dependencies( $dep, $dependencies ) );
87
+ } else {
88
+ $broken[] = $item->handle;
89
+ }
90
+
91
+ }
92
+
93
+ return $broken;
94
 
95
  }
96
 
100
 
101
  }
102
 
103
+ function register_qm_collector_assets( array $collectors, QueryMonitor $qm ) {
104
+ $collectors['assets'] = new QM_Collector_Assets;
105
+ return $collectors;
106
  }
107
 
108
+ add_filter( 'qm/collectors', 'register_qm_collector_assets', 10, 2 );
collectors/conditionals.php CHANGED
@@ -24,12 +24,13 @@ class QM_Collector_Conditionals extends QM_Collector {
24
 
25
  public function process() {
26
 
27
- $conds = apply_filters( 'query_monitor_conditionals', array(
28
  'is_404', 'is_archive', 'is_admin', 'is_attachment', 'is_author', 'is_blog_admin', 'is_category', 'is_comments_popup', 'is_customize_preview', 'is_date',
29
  'is_day', 'is_feed', 'is_front_page', 'is_home', 'is_main_network', 'is_main_site', 'is_month', 'is_network_admin',
30
  'is_page', 'is_page_template', 'is_paged', 'is_post_type_archive', 'is_preview', 'is_robots', 'is_rtl', 'is_search', 'is_single',
31
  'is_singular', 'is_ssl', 'is_sticky', 'is_tag', 'is_tax', 'is_time', 'is_trackback', 'is_year'
32
  ) );
 
33
 
34
  $true = $false = $na = array();
35
 
@@ -39,8 +40,8 @@ class QM_Collector_Conditionals extends QM_Collector {
39
  if ( ( 'is_sticky' == $cond ) and !get_post( $id = null ) ) {
40
  # Special case for is_sticky to prevent PHP notices
41
  $false[] = $cond;
42
- } else if ( ( 'is_main_site' == $cond ) and !is_multisite() ) {
43
- # Special case for is_main_site to prevent it from being annoying on single site installs
44
  $na[] = $cond;
45
  } else {
46
  if ( call_user_func( $cond ) ) {
@@ -60,9 +61,9 @@ class QM_Collector_Conditionals extends QM_Collector {
60
 
61
  }
62
 
63
- function register_qm_collector_conditionals( array $qm ) {
64
- $qm['conditionals'] = new QM_Collector_Conditionals;
65
- return $qm;
66
  }
67
 
68
- add_filter( 'query_monitor_collectors', 'register_qm_collector_conditionals', 50 );
24
 
25
  public function process() {
26
 
27
+ $conds = apply_filters( 'qm/collect/conditionals', array(
28
  'is_404', 'is_archive', 'is_admin', 'is_attachment', 'is_author', 'is_blog_admin', 'is_category', 'is_comments_popup', 'is_customize_preview', 'is_date',
29
  'is_day', 'is_feed', 'is_front_page', 'is_home', 'is_main_network', 'is_main_site', 'is_month', 'is_network_admin',
30
  'is_page', 'is_page_template', 'is_paged', 'is_post_type_archive', 'is_preview', 'is_robots', 'is_rtl', 'is_search', 'is_single',
31
  'is_singular', 'is_ssl', 'is_sticky', 'is_tag', 'is_tax', 'is_time', 'is_trackback', 'is_year'
32
  ) );
33
+ $conds = apply_filters( 'query_monitor_conditionals', $conds );
34
 
35
  $true = $false = $na = array();
36
 
40
  if ( ( 'is_sticky' == $cond ) and !get_post( $id = null ) ) {
41
  # Special case for is_sticky to prevent PHP notices
42
  $false[] = $cond;
43
+ } else if ( ! is_multisite() and in_array( $cond, array( 'is_main_network', 'is_main_site' ) ) ) {
44
+ # Special case for multisite conditionals to prevent them from being annoying on single site installs
45
  $na[] = $cond;
46
  } else {
47
  if ( call_user_func( $cond ) ) {
61
 
62
  }
63
 
64
+ function register_qm_collector_conditionals( array $collectors, QueryMonitor $qm ) {
65
+ $collectors['conditionals'] = new QM_Collector_Conditionals;
66
+ return $collectors;
67
  }
68
 
69
+ add_filter( 'qm/collectors', 'register_qm_collector_conditionals', 10, 2 );
collectors/db_callers.php CHANGED
@@ -24,7 +24,7 @@ class QM_Collector_DB_Callers extends QM_Collector {
24
 
25
  public function process() {
26
 
27
- if ( $dbq = QueryMonitor::get_collector( 'db_queries' ) ) {
28
  if ( isset( $dbq->data['times'] ) ) {
29
  $this->data['times'] = $dbq->data['times'];
30
  usort( $this->data['times'], 'QM_Collector::sort_ltime' );
@@ -38,9 +38,9 @@ class QM_Collector_DB_Callers extends QM_Collector {
38
 
39
  }
40
 
41
- function register_qm_collector_db_callers( array $qm ) {
42
- $qm['db_callers'] = new QM_Collector_DB_Callers;
43
- return $qm;
44
  }
45
 
46
- add_filter( 'query_monitor_collectors', 'register_qm_collector_db_callers', 30 );
24
 
25
  public function process() {
26
 
27
+ if ( $dbq = QM_Collectors::get( 'db_queries' ) ) {
28
  if ( isset( $dbq->data['times'] ) ) {
29
  $this->data['times'] = $dbq->data['times'];
30
  usort( $this->data['times'], 'QM_Collector::sort_ltime' );
38
 
39
  }
40
 
41
+ function register_qm_collector_db_callers( array $collectors, QueryMonitor $qm ) {
42
+ $collectors['db_callers'] = new QM_Collector_DB_Callers;
43
+ return $collectors;
44
  }
45
 
46
+ add_filter( 'qm/collectors', 'register_qm_collector_db_callers', 20, 2 );
collectors/db_components.php CHANGED
@@ -24,7 +24,7 @@ class QM_Collector_DB_Components extends QM_Collector {
24
 
25
  public function process() {
26
 
27
- if ( $dbq = QueryMonitor::get_collector( 'db_queries' ) ) {
28
  if ( isset( $dbq->data['component_times'] ) ) {
29
  $this->data['times'] = $dbq->data['component_times'];
30
  usort( $this->data['times'], 'QM_Collector::sort_ltime' );
@@ -38,9 +38,9 @@ class QM_Collector_DB_Components extends QM_Collector {
38
 
39
  }
40
 
41
- function register_qm_collector_db_components( array $qm ) {
42
- $qm['db_components'] = new QM_Collector_DB_Components;
43
- return $qm;
44
  }
45
 
46
- add_filter( 'query_monitor_collectors', 'register_qm_collector_db_components', 40 );
24
 
25
  public function process() {
26
 
27
+ if ( $dbq = QM_Collectors::get( 'db_queries' ) ) {
28
  if ( isset( $dbq->data['component_times'] ) ) {
29
  $this->data['times'] = $dbq->data['component_times'];
30
  usort( $this->data['times'], 'QM_Collector::sort_ltime' );
38
 
39
  }
40
 
41
+ function register_qm_collector_db_components( array $collectors, QueryMonitor $qm ) {
42
+ $collectors['db_components'] = new QM_Collector_DB_Components;
43
+ return $collectors;
44
  }
45
 
46
+ add_filter( 'qm/collectors', 'register_qm_collector_db_components', 20, 2 );
collectors/db_queries.php CHANGED
@@ -56,28 +56,20 @@ class QM_Collector_DB_Queries extends QM_Collector {
56
  $this->data['total_time'] = 0;
57
  $this->data['errors'] = array();
58
 
59
- $this->db_objects = apply_filters( 'query_monitor_db_objects', array(
60
  '$wpdb' => $GLOBALS['wpdb']
61
  ) );
62
 
63
  foreach ( $this->db_objects as $name => $db ) {
64
  if ( is_a( $db, 'wpdb' ) ) {
65
  $this->process_db_object( $name, $db );
 
 
66
  }
67
  }
68
 
69
  }
70
 
71
- protected function log_type( $type ) {
72
-
73
- if ( isset( $this->data['types'][$type] ) ) {
74
- $this->data['types'][$type]++;
75
- } else {
76
- $this->data['types'][$type] = 1;
77
- }
78
-
79
- }
80
-
81
  protected function log_caller( $caller, $ltime, $type ) {
82
 
83
  if ( !isset( $this->data['times'][$caller] ) ) {
@@ -100,28 +92,6 @@ class QM_Collector_DB_Queries extends QM_Collector {
100
 
101
  }
102
 
103
- protected function log_component( $component, $ltime, $type ) {
104
-
105
- if ( !isset( $this->data['component_times'][$component->name] ) ) {
106
- $this->data['component_times'][$component->name] = array(
107
- 'component' => $component->name,
108
- 'calls' => 0,
109
- 'ltime' => 0,
110
- 'types' => array()
111
- );
112
- }
113
-
114
- $this->data['component_times'][$component->name]['calls']++;
115
- $this->data['component_times'][$component->name]['ltime'] += $ltime;
116
-
117
- if ( isset( $this->data['component_times'][$component->name]['types'][$type] ) ) {
118
- $this->data['component_times'][$component->name]['types'][$type]++;
119
- } else {
120
- $this->data['component_times'][$component->name]['types'][$type] = 1;
121
- }
122
-
123
- }
124
-
125
  public function process_db_object( $id, wpdb $db ) {
126
 
127
  $rows = array();
@@ -224,9 +194,9 @@ class QM_Collector_DB_Queries extends QM_Collector {
224
 
225
  }
226
 
227
- function register_qm_collector_db_queries( array $qm ) {
228
- $qm['db_queries'] = new QM_Collector_DB_Queries;
229
- return $qm;
230
  }
231
 
232
- add_filter( 'query_monitor_collectors', 'register_qm_collector_db_queries', 20 );
56
  $this->data['total_time'] = 0;
57
  $this->data['errors'] = array();
58
 
59
+ $this->db_objects = apply_filters( 'qm/collect/db_objects', array(
60
  '$wpdb' => $GLOBALS['wpdb']
61
  ) );
62
 
63
  foreach ( $this->db_objects as $name => $db ) {
64
  if ( is_a( $db, 'wpdb' ) ) {
65
  $this->process_db_object( $name, $db );
66
+ } else {
67
+ unset( $this->db_objects[ $name ] );
68
  }
69
  }
70
 
71
  }
72
 
 
 
 
 
 
 
 
 
 
 
73
  protected function log_caller( $caller, $ltime, $type ) {
74
 
75
  if ( !isset( $this->data['times'][$caller] ) ) {
92
 
93
  }
94
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
95
  public function process_db_object( $id, wpdb $db ) {
96
 
97
  $rows = array();
194
 
195
  }
196
 
197
+ function register_qm_collector_db_queries( array $collectors, QueryMonitor $qm ) {
198
+ $collectors['db_queries'] = new QM_Collector_DB_Queries;
199
+ return $collectors;
200
  }
201
 
202
+ add_filter( 'qm/collectors', 'register_qm_collector_db_queries', 10, 2 );
collectors/debug_bar.php ADDED
@@ -0,0 +1,90 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ Copyright 2009-2015 John Blackbourn
4
+
5
+ This program is free software; you can redistribute it and/or modify
6
+ it under the terms of the GNU General Public License as published by
7
+ the Free Software Foundation; either version 2 of the License, or
8
+ (at your option) any later version.
9
+
10
+ This program is distributed in the hope that it will be useful,
11
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ GNU General Public License for more details.
14
+
15
+ */
16
+
17
+ final class QM_Collector_Debug_Bar extends QM_Collector {
18
+
19
+ public $id = 'debug_bar';
20
+ private $panel = null;
21
+
22
+ public function __construct() {
23
+ parent::__construct();
24
+ }
25
+
26
+ public function name() {
27
+ $title = $this->get_panel()->title();
28
+ return sprintf( 'Debug Bar: %s', $title );
29
+ }
30
+
31
+ public function set_panel( Debug_Bar_Panel $panel ) {
32
+ $this->panel = $panel;
33
+ }
34
+
35
+ public function get_panel() {
36
+ return $this->panel;
37
+ }
38
+
39
+ public function process() {
40
+ $this->get_panel()->prerender();
41
+ }
42
+
43
+ public function is_visible() {
44
+ return $this->get_panel()->is_visible();
45
+ }
46
+
47
+ public function render() {
48
+ return $this->get_panel()->render();
49
+ }
50
+
51
+ }
52
+
53
+ function register_qm_collectors_debug_bar() {
54
+
55
+ global $debug_bar;
56
+
57
+ if ( class_exists( 'Debug_Bar' ) ) {
58
+ return;
59
+ }
60
+
61
+ $collectors = QM_Collectors::init();
62
+ $qm = QueryMonitor::init();
63
+
64
+ require_once $qm->plugin_path( 'classes/debug_bar.php' );
65
+
66
+ $debug_bar = new Debug_Bar;
67
+ $redundant = array(
68
+ 'debug_bar_actions_addon_panel',
69
+ 'debug_bar_remote_requests_panel',
70
+ 'debug_bar_screen_info_panel',
71
+ 'ps_listdeps_debug_bar_panel',
72
+ );
73
+
74
+ foreach ( $debug_bar->panels as $panel ) {
75
+ $panel_id = strtolower( get_class( $panel ) );
76
+
77
+ if ( in_array( $panel_id, $redundant ) ) {
78
+ continue;
79
+ }
80
+
81
+ $collector = new QM_Collector_Debug_Bar;
82
+ $collector->set_id( "debug_bar_{$panel_id}" );
83
+ $collector->set_panel( $panel );
84
+
85
+ $collectors->add( $collector );
86
+ }
87
+
88
+ }
89
+
90
+ add_action( 'init', 'register_qm_collectors_debug_bar' );
collectors/environment.php CHANGED
@@ -36,7 +36,7 @@ class QM_Collector_Environment extends QM_Collector {
36
 
37
  parent::__construct();
38
 
39
- # If QueryMonitorDB is in place then we'll use the values which were
40
  # caught early before any plugins had a chance to alter them
41
 
42
  foreach ( $this->php_vars as $setting ) {
@@ -88,7 +88,7 @@ class QM_Collector_Environment extends QM_Collector {
88
 
89
  public function process() {
90
 
91
- global $wp_version, $blog_id;
92
 
93
  $mysql_vars = array(
94
  'key_buffer_size' => true, # Key cache size limit
@@ -99,14 +99,10 @@ class QM_Collector_Environment extends QM_Collector {
99
  'query_cache_type' => 'ON' # Query cache on or off
100
  );
101
 
102
- if ( $dbq = QueryMonitor::get_collector( 'db_queries' ) ) {
103
 
104
  foreach ( $dbq->db_objects as $id => $db ) {
105
 
106
- if ( !is_a( $db, 'wpdb' ) ) {
107
- continue;
108
- }
109
-
110
  $variables = $db->get_results( "
111
  SHOW VARIABLES
112
  WHERE Variable_name IN ( '" . implode( "', '", array_keys( $mysql_vars ) ) . "' )
@@ -158,6 +154,7 @@ class QM_Collector_Environment extends QM_Collector {
158
  'WP_DEBUG_DISPLAY' => self::format_bool_constant( 'WP_DEBUG_DISPLAY' ),
159
  'WP_DEBUG_LOG' => self::format_bool_constant( 'WP_DEBUG_LOG' ),
160
  'SCRIPT_DEBUG' => self::format_bool_constant( 'SCRIPT_DEBUG' ),
 
161
  'CONCATENATE_SCRIPTS' => self::format_bool_constant( 'CONCATENATE_SCRIPTS' ),
162
  'COMPRESS_SCRIPTS' => self::format_bool_constant( 'COMPRESS_SCRIPTS' ),
163
  'COMPRESS_CSS' => self::format_bool_constant( 'COMPRESS_CSS' ),
@@ -165,7 +162,7 @@ class QM_Collector_Environment extends QM_Collector {
165
  );
166
 
167
  if ( is_multisite() ) {
168
- $this->data['wp']['blog_id'] = $blog_id;
169
  }
170
 
171
  $server = explode( ' ', $_SERVER['SERVER_SOFTWARE'] );
@@ -227,9 +224,9 @@ class QM_Collector_Environment extends QM_Collector {
227
 
228
  }
229
 
230
- function register_qm_collector_environment( array $qm ) {
231
- $qm['environment'] = new QM_Collector_Environment;
232
- return $qm;
233
  }
234
 
235
- add_filter( 'query_monitor_collectors', 'register_qm_collector_environment', 120 );
36
 
37
  parent::__construct();
38
 
39
+ # If QM_DB is in place then we'll use the values which were
40
  # caught early before any plugins had a chance to alter them
41
 
42
  foreach ( $this->php_vars as $setting ) {
88
 
89
  public function process() {
90
 
91
+ global $wp_version;
92
 
93
  $mysql_vars = array(
94
  'key_buffer_size' => true, # Key cache size limit
99
  'query_cache_type' => 'ON' # Query cache on or off
100
  );
101
 
102
+ if ( $dbq = QM_Collectors::get( 'db_queries' ) ) {
103
 
104
  foreach ( $dbq->db_objects as $id => $db ) {
105
 
 
 
 
 
106
  $variables = $db->get_results( "
107
  SHOW VARIABLES
108
  WHERE Variable_name IN ( '" . implode( "', '", array_keys( $mysql_vars ) ) . "' )
154
  'WP_DEBUG_DISPLAY' => self::format_bool_constant( 'WP_DEBUG_DISPLAY' ),
155
  'WP_DEBUG_LOG' => self::format_bool_constant( 'WP_DEBUG_LOG' ),
156
  'SCRIPT_DEBUG' => self::format_bool_constant( 'SCRIPT_DEBUG' ),
157
+ 'WP_CACHE' => self::format_bool_constant( 'WP_CACHE' ),
158
  'CONCATENATE_SCRIPTS' => self::format_bool_constant( 'CONCATENATE_SCRIPTS' ),
159
  'COMPRESS_SCRIPTS' => self::format_bool_constant( 'COMPRESS_SCRIPTS' ),
160
  'COMPRESS_CSS' => self::format_bool_constant( 'COMPRESS_CSS' ),
162
  );
163
 
164
  if ( is_multisite() ) {
165
+ $this->data['wp']['SUNRISE'] = self::format_bool_constant( 'SUNRISE' );
166
  }
167
 
168
  $server = explode( ' ', $_SERVER['SERVER_SOFTWARE'] );
224
 
225
  }
226
 
227
+ function register_qm_collector_environment( array $collectors, QueryMonitor $qm ) {
228
+ $collectors['environment'] = new QM_Collector_Environment;
229
+ return $collectors;
230
  }
231
 
232
+ add_filter( 'qm/collectors', 'register_qm_collector_environment', 20, 2 );
collectors/hooks.php CHANGED
@@ -26,7 +26,9 @@ class QM_Collector_Hooks extends QM_Collector {
26
 
27
  global $wp_actions, $wp_filter;
28
 
29
- if ( is_admin() and ( $admin = QueryMonitor::get_collector( 'admin' ) ) ) {
 
 
30
  $this->data['screen'] = $admin->data['base'];
31
  } else {
32
  $this->data['screen'] = '';
@@ -34,67 +36,78 @@ class QM_Collector_Hooks extends QM_Collector {
34
 
35
  $hooks = $all_parts = $components = array();
36
 
37
- $hide_qm = ( defined( 'QM_HIDE_SELF' ) and QM_HIDE_SELF );
 
 
 
 
 
38
 
39
  foreach ( $wp_actions as $name => $count ) {
40
 
41
- $actions = array();
42
- $action_components = array();
43
 
44
- if ( isset( $wp_filter[$name] ) ) {
 
45
 
46
- # http://core.trac.wordpress.org/ticket/17817
47
- $action = $wp_filter[$name];
48
 
49
- foreach ( $action as $priority => $callbacks ) {
 
 
50
 
51
- foreach ( $callbacks as $callback ) {
52
 
53
- $callback = QM_Util::populate_callback( $callback );
54
 
55
- if ( isset( $callback['component'] ) ) {
56
- if ( $hide_qm and ( 'query-monitor' === $callback['component']->context ) ) {
57
- continue;
58
- }
59
 
60
- $action_components[$callback['component']->name] = $callback['component']->name;
61
- }
 
 
62
 
63
- $actions[] = array(
64
- 'priority' => $priority,
65
- 'callback' => $callback,
66
- );
67
 
 
 
 
 
 
 
 
 
 
 
68
  }
69
 
 
 
 
 
 
70
  }
71
 
72
  }
73
 
74
- $action_parts = array_filter( preg_split( '#[_/-]#', $name ) );
75
- $all_parts = array_merge( $all_parts, $action_parts );
76
- $components = array_merge( $components, $action_components );
77
-
78
- $hooks[$name] = array(
79
- 'name' => $name,
80
- 'actions' => $actions,
81
- 'parts' => $action_parts,
82
- 'components' => $action_components,
83
- );
84
-
85
  }
86
 
87
- $this->data['hooks'] = $hooks;
88
- $this->data['parts'] = array_unique( array_filter( $all_parts ) );
89
- $this->data['components'] = array_unique( array_filter( $components ) );
 
 
 
 
 
90
 
91
  }
92
 
93
  }
94
 
95
- function register_qm_collector_hooks( array $qm ) {
96
- $qm['hooks'] = new QM_Collector_Hooks;
97
- return $qm;
98
  }
99
 
100
- add_filter( 'query_monitor_collectors', 'register_qm_collector_hooks', 80 );
26
 
27
  global $wp_actions, $wp_filter;
28
 
29
+ $this->hide_qm = ( defined( 'QM_HIDE_SELF' ) and QM_HIDE_SELF );
30
+
31
+ if ( is_admin() and ( $admin = QM_Collectors::get( 'admin' ) ) ) {
32
  $this->data['screen'] = $admin->data['base'];
33
  } else {
34
  $this->data['screen'] = '';
36
 
37
  $hooks = $all_parts = $components = array();
38
 
39
+ if ( has_filter( 'all' ) ) {
40
+
41
+ $hooks['all'] = $this->process_action( 'all', $wp_filter );
42
+ $this->data['warnings']['all_hooked'] = $hooks['all'];
43
+
44
+ }
45
 
46
  foreach ( $wp_actions as $name => $count ) {
47
 
48
+ $hooks[$name] = $this->process_action( $name, $wp_filter );
 
49
 
50
+ $all_parts = array_merge( $all_parts, $hooks[$name]['parts'] );
51
+ $components = array_merge( $components, $hooks[$name]['components'] );
52
 
53
+ }
 
54
 
55
+ $this->data['hooks'] = $hooks;
56
+ $this->data['parts'] = array_unique( array_filter( $all_parts ) );
57
+ $this->data['components'] = array_unique( array_filter( $components ) );
58
 
59
+ }
60
 
61
+ protected function process_action( $name, array $wp_filter ) {
62
 
63
+ $actions = $components = array();
 
 
 
64
 
65
+ if ( isset( $wp_filter[$name] ) ) {
66
+
67
+ # http://core.trac.wordpress.org/ticket/17817
68
+ $action = $wp_filter[$name];
69
 
70
+ foreach ( $action as $priority => $callbacks ) {
 
 
 
71
 
72
+ foreach ( $callbacks as $callback ) {
73
+
74
+ $callback = QM_Util::populate_callback( $callback );
75
+
76
+ if ( isset( $callback['component'] ) ) {
77
+ if ( $this->hide_qm and ( 'query-monitor' === $callback['component']->context ) ) {
78
+ continue;
79
+ }
80
+
81
+ $components[$callback['component']->name] = $callback['component']->name;
82
  }
83
 
84
+ $actions[] = array(
85
+ 'priority' => $priority,
86
+ 'callback' => $callback,
87
+ );
88
+
89
  }
90
 
91
  }
92
 
 
 
 
 
 
 
 
 
 
 
 
93
  }
94
 
95
+ $parts = array_filter( preg_split( '#[_/-]#', $name ) );
96
+
97
+ return array(
98
+ 'name' => $name,
99
+ 'actions' => $actions,
100
+ 'parts' => $parts,
101
+ 'components' => $components,
102
+ );
103
 
104
  }
105
 
106
  }
107
 
108
+ function register_qm_collector_hooks( array $collectors, QueryMonitor $qm ) {
109
+ $collectors['hooks'] = new QM_Collector_Hooks;
110
+ return $collectors;
111
  }
112
 
113
+ add_filter( 'qm/collectors', 'register_qm_collector_hooks', 20, 2 );
collectors/http.php CHANGED
@@ -29,7 +29,6 @@ class QM_Collector_HTTP extends QM_Collector {
29
  add_filter( 'http_request_args', array( $this, 'filter_http_request_args' ), 99, 2 );
30
  add_filter( 'pre_http_request', array( $this, 'filter_pre_http_request' ), 99, 3 );
31
  add_action( 'http_api_debug', array( $this, 'action_http_api_debug' ), 99, 5 );
32
- add_filter( 'http_response', array( $this, 'filter_http_response' ), 99, 3 );
33
 
34
  }
35
 
@@ -83,7 +82,7 @@ class QM_Collector_HTTP extends QM_Collector {
83
  }
84
 
85
  // Something's filtering the response, so we'll log it
86
- $this->filter_http_response( $response, $args, $url );
87
 
88
  return $response;
89
  }
@@ -97,26 +96,19 @@ class QM_Collector_HTTP extends QM_Collector {
97
  * @param array $args HTTP request arguments.
98
  * @param string $url The request URL.
99
  */
100
- public function action_http_api_debug( $response, $action, $class = null, $args = null, $url = null ) {
101
 
102
  switch ( $action ) {
103
 
104
  case 'response':
105
 
106
- # https://core.trac.wordpress.org/ticket/18732
107
- if ( empty( $args ) or empty( $args['_qm_key'] ) ) {
108
- return;
109
- }
110
-
111
  if ( !empty( $class ) ) {
112
  $this->data['http'][$args['_qm_key']]['transport'] = str_replace( 'wp_http_', '', strtolower( $class ) );
113
  } else {
114
  $this->data['http'][$args['_qm_key']]['transport'] = null;
115
  }
116
 
117
- if ( is_wp_error( $response ) ) {
118
- $this->filter_http_response( $response, $args, $url );
119
- }
120
 
121
  break;
122
 
@@ -129,22 +121,19 @@ class QM_Collector_HTTP extends QM_Collector {
129
  }
130
 
131
  /**
132
- * Filter the HTTP response in order to log the response.
133
  *
134
  * @param array|WP_Error $response The HTTP response.
135
  * @param array $args HTTP request arguments.
136
  * @param string $url The request URL.
137
- * @return array|WP_Error The HTTP response.
138
  */
139
- public function filter_http_response( $response, array $args, $url ) {
140
  $this->data['http'][$args['_qm_key']]['end'] = microtime( true );
141
  $this->data['http'][$args['_qm_key']]['response'] = $response;
142
  if ( isset( $args['_qm_original_key'] ) ) {
143
  $this->data['http'][$args['_qm_original_key']]['end'] = $this->data['http'][$args['_qm_original_key']]['start'];
144
  $this->data['http'][$args['_qm_original_key']]['response'] = new WP_Error( 'http_request_not_executed', __( 'Request not executed due to a filter on pre_http_request', 'query-monitor' ) );
145
  }
146
-
147
- return $response;
148
  }
149
 
150
  public function process() {
@@ -155,9 +144,16 @@ class QM_Collector_HTTP extends QM_Collector {
155
  'WP_PROXY_USERNAME',
156
  'WP_PROXY_PASSWORD',
157
  'WP_PROXY_BYPASS_HOSTS',
 
 
158
  ) as $var ) {
159
  if ( defined( $var ) and constant( $var ) ) {
160
- $this->data['vars'][$var] = constant( $var );
 
 
 
 
 
161
  }
162
  }
163
 
@@ -167,7 +163,7 @@ class QM_Collector_HTTP extends QM_Collector {
167
  return;
168
  }
169
 
170
- $silent = apply_filters( 'query_monitor_silent_http_error_codes', array(
171
  'http_request_not_executed',
172
  'airplane_mode_enabled'
173
  ) );
@@ -184,8 +180,10 @@ class QM_Collector_HTTP extends QM_Collector {
184
  if ( !in_array( $http['response']->get_error_code(), $silent ) ) {
185
  $this->data['errors']['error'][] = $key;
186
  }
 
187
  } else {
188
- if ( intval( wp_remote_retrieve_response_code( $http['response'] ) ) >= 400 ) {
 
189
  $this->data['errors']['warning'][] = $key;
190
  }
191
  }
@@ -193,15 +191,16 @@ class QM_Collector_HTTP extends QM_Collector {
193
  $http['ltime'] = ( $http['end'] - $http['start'] );
194
  $this->data['ltime'] += $http['ltime'];
195
 
 
 
 
 
 
196
  }
197
 
198
  }
199
 
200
  }
201
 
202
- function register_qm_collector_http( array $qm ) {
203
- $qm['http'] = new QM_Collector_HTTP;
204
- return $qm;
205
- }
206
-
207
- add_filter( 'query_monitor_collectors', 'register_qm_collector_http', 100 );
29
  add_filter( 'http_request_args', array( $this, 'filter_http_request_args' ), 99, 2 );
30
  add_filter( 'pre_http_request', array( $this, 'filter_pre_http_request' ), 99, 3 );
31
  add_action( 'http_api_debug', array( $this, 'action_http_api_debug' ), 99, 5 );
 
32
 
33
  }
34
 
82
  }
83
 
84
  // Something's filtering the response, so we'll log it
85
+ $this->log_http_response( $response, $args, $url );
86
 
87
  return $response;
88
  }
96
  * @param array $args HTTP request arguments.
97
  * @param string $url The request URL.
98
  */
99
+ public function action_http_api_debug( $response, $action, $class, $args, $url ) {
100
 
101
  switch ( $action ) {
102
 
103
  case 'response':
104
 
 
 
 
 
 
105
  if ( !empty( $class ) ) {
106
  $this->data['http'][$args['_qm_key']]['transport'] = str_replace( 'wp_http_', '', strtolower( $class ) );
107
  } else {
108
  $this->data['http'][$args['_qm_key']]['transport'] = null;
109
  }
110
 
111
+ $this->log_http_response( $response, $args, $url );
 
 
112
 
113
  break;
114
 
121
  }
122
 
123
  /**
124
+ * Log an HTTP response.
125
  *
126
  * @param array|WP_Error $response The HTTP response.
127
  * @param array $args HTTP request arguments.
128
  * @param string $url The request URL.
 
129
  */
130
+ public function log_http_response( $response, array $args, $url ) {
131
  $this->data['http'][$args['_qm_key']]['end'] = microtime( true );
132
  $this->data['http'][$args['_qm_key']]['response'] = $response;
133
  if ( isset( $args['_qm_original_key'] ) ) {
134
  $this->data['http'][$args['_qm_original_key']]['end'] = $this->data['http'][$args['_qm_original_key']]['start'];
135
  $this->data['http'][$args['_qm_original_key']]['response'] = new WP_Error( 'http_request_not_executed', __( 'Request not executed due to a filter on pre_http_request', 'query-monitor' ) );
136
  }
 
 
137
  }
138
 
139
  public function process() {
144
  'WP_PROXY_USERNAME',
145
  'WP_PROXY_PASSWORD',
146
  'WP_PROXY_BYPASS_HOSTS',
147
+ 'WP_HTTP_BLOCK_EXTERNAL',
148
+ 'WP_ACCESSIBLE_HOSTS',
149
  ) as $var ) {
150
  if ( defined( $var ) and constant( $var ) ) {
151
+ $val = constant( $var );
152
+ if ( true === $val ) {
153
+ # @TODO this transformation should happen in the output, not the collector
154
+ $val = 'true';
155
+ }
156
+ $this->data['vars'][$var] = $val;
157
  }
158
  }
159
 
163
  return;
164
  }
165
 
166
+ $silent = apply_filters( 'qm/collect/silent_http_errors', array(
167
  'http_request_not_executed',
168
  'airplane_mode_enabled'
169
  ) );
180
  if ( !in_array( $http['response']->get_error_code(), $silent ) ) {
181
  $this->data['errors']['error'][] = $key;
182
  }
183
+ $http['type'] = __( 'Error', 'query-monitor' );
184
  } else {
185
+ $http['type'] = intval( wp_remote_retrieve_response_code( $http['response'] ) );
186
+ if ( $http['type'] >= 400 ) {
187
  $this->data['errors']['warning'][] = $key;
188
  }
189
  }
191
  $http['ltime'] = ( $http['end'] - $http['start'] );
192
  $this->data['ltime'] += $http['ltime'];
193
 
194
+ $http['component'] = $http['trace']->get_component();
195
+
196
+ $this->log_type( $http['type'] );
197
+ $this->log_component( $http['component'], $http['ltime'], $http['type'] );
198
+
199
  }
200
 
201
  }
202
 
203
  }
204
 
205
+ # Load early in case a plugin is doing an HTTP request when it initialises instead of after the `plugins_loaded` hook
206
+ QM_Collectors::add( new QM_Collector_HTTP );
 
 
 
 
collectors/overview.php CHANGED
@@ -48,9 +48,9 @@ class QM_Collector_Overview extends QM_Collector {
48
 
49
  }
50
 
51
- function register_qm_collector_overview( array $qm ) {
52
- $qm['overview'] = new QM_Collector_Overview;
53
- return $qm;
54
  }
55
 
56
- add_filter( 'query_monitor_collectors', 'register_qm_collector_overview', 10 );
48
 
49
  }
50
 
51
+ function register_qm_collector_overview( array $collectors, QueryMonitor $qm ) {
52
+ $collectors['overview'] = new QM_Collector_Overview;
53
+ return $collectors;
54
  }
55
 
56
+ add_filter( 'qm/collectors', 'register_qm_collector_overview', 1, 2 );
collectors/php_errors.php CHANGED
@@ -30,6 +30,7 @@ if ( defined( 'E_USER_DEPRECATED' ) ) {
30
  class QM_Collector_PHP_Errors extends QM_Collector {
31
 
32
  public $id = 'php_errors';
 
33
 
34
  public function name() {
35
  return __( 'PHP Errors', 'query-monitor' );
@@ -40,6 +41,9 @@ class QM_Collector_PHP_Errors extends QM_Collector {
40
  parent::__construct();
41
  set_error_handler( array( $this, 'error_handler' ) );
42
 
 
 
 
43
  }
44
 
45
  public function error_handler( $errno, $message, $file = null, $line = null ) {
@@ -103,20 +107,17 @@ class QM_Collector_PHP_Errors extends QM_Collector {
103
 
104
  }
105
 
106
- return apply_filters( 'query_monitor_php_errors_return_value', true );
107
 
108
  }
109
 
110
  public function tear_down() {
111
  parent::tear_down();
 
112
  restore_error_handler();
113
  }
114
 
115
  }
116
 
117
- function register_qm_collector_php_errors( array $qm ) {
118
- $qm['php_errors'] = new QM_Collector_PHP_Errors;
119
- return $qm;
120
- }
121
-
122
- add_filter( 'query_monitor_collectors', 'register_qm_collector_php_errors', 110 );
30
  class QM_Collector_PHP_Errors extends QM_Collector {
31
 
32
  public $id = 'php_errors';
33
+ private $display_errors = null;
34
 
35
  public function name() {
36
  return __( 'PHP Errors', 'query-monitor' );
41
  parent::__construct();
42
  set_error_handler( array( $this, 'error_handler' ) );
43
 
44
+ $this->display_errors = ini_get( 'display_errors' );
45
+ ini_set( 'display_errors', 0 );
46
+
47
  }
48
 
49
  public function error_handler( $errno, $message, $file = null, $line = null ) {
107
 
108
  }
109
 
110
+ return apply_filters( 'qm/collect/php_errors_return_value', false );
111
 
112
  }
113
 
114
  public function tear_down() {
115
  parent::tear_down();
116
+ ini_set( 'display_errors', $this->display_errors );
117
  restore_error_handler();
118
  }
119
 
120
  }
121
 
122
+ # Load early to catch early errors
123
+ QM_Collectors::add( new QM_Collector_PHP_Errors );
 
 
 
 
collectors/redirects.php CHANGED
@@ -45,9 +45,5 @@ class QM_Collector_Redirects extends QM_Collector {
45
 
46
  }
47
 
48
- function register_qm_collector_redirects( array $qm ) {
49
- $qm['redirects'] = new QM_Collector_Redirects;
50
- return $qm;
51
- }
52
-
53
- add_filter( 'query_monitor_collectors', 'register_qm_collector_redirects', 140 );
45
 
46
  }
47
 
48
+ # Load early in case a plugin is doing a redirect when it initialises instead of after the `plugins_loaded` hook
49
+ QM_Collectors::add( new QM_Collector_Redirects );
 
 
 
 
collectors/request.php CHANGED
@@ -24,10 +24,18 @@ class QM_Collector_Request extends QM_Collector {
24
 
25
  public function process() {
26
 
27
- global $wp, $wp_query;
28
 
29
  $qo = get_queried_object();
30
 
 
 
 
 
 
 
 
 
31
  if ( is_admin() ) {
32
  $this->data['request']['request'] = $_SERVER['REQUEST_URI'];
33
  foreach ( array( 'query_string' ) as $item ) {
@@ -125,9 +133,9 @@ class QM_Collector_Request extends QM_Collector {
125
 
126
  }
127
 
128
- function register_qm_collector_request( array $qm ) {
129
- $qm['request'] = new QM_Collector_Request;
130
- return $qm;
131
  }
132
 
133
- add_filter( 'query_monitor_collectors', 'register_qm_collector_request', 60 );
24
 
25
  public function process() {
26
 
27
+ global $wp, $wp_query, $current_blog, $current_site;
28
 
29
  $qo = get_queried_object();
30
 
31
+ if ( is_multisite() ) {
32
+ $this->data['multisite']['current_blog'] = $current_blog;
33
+ }
34
+
35
+ if ( QM_Util::is_multi_network() ) {
36
+ $this->data['multisite']['current_site'] = $current_site;
37
+ }
38
+
39
  if ( is_admin() ) {
40
  $this->data['request']['request'] = $_SERVER['REQUEST_URI'];
41
  foreach ( array( 'query_string' ) as $item ) {
133
 
134
  }
135
 
136
+ function register_qm_collector_request( array $collectors, QueryMonitor $qm ) {
137
+ $collectors['request'] = new QM_Collector_Request;
138
+ return $collectors;
139
  }
140
 
141
+ add_filter( 'qm/collectors', 'register_qm_collector_request', 10, 2 );
collectors/theme.php CHANGED
@@ -39,14 +39,18 @@ class QM_Collector_Theme extends QM_Collector {
39
  $template_path = QM_Util::standard_dir( $template );
40
  $stylesheet_directory = QM_Util::standard_dir( get_stylesheet_directory() );
41
  $template_directory = QM_Util::standard_dir( get_template_directory() );
 
42
 
43
- $template_file = str_replace( array( $stylesheet_directory, $template_directory ), '', $template_path );
44
- $template_file = ltrim( $template_file, '/' );
 
 
45
 
46
- $this->data['template_path'] = $template_path;
47
- $this->data['template_file'] = $template_file;
48
- $this->data['stylesheet'] = get_stylesheet();
49
- $this->data['template'] = get_template();
 
50
 
51
  if ( isset( $this->data['body_class'] ) ) {
52
  asort( $this->data['body_class'] );
@@ -56,11 +60,11 @@ class QM_Collector_Theme extends QM_Collector {
56
 
57
  }
58
 
59
- function register_qm_collector_theme( array $qm ) {
60
- if ( !is_admin() ) {
61
- $qm['theme'] = new QM_Collector_Theme;
62
- }
63
- return $qm;
64
  }
65
 
66
- add_filter( 'query_monitor_collectors', 'register_qm_collector_theme', 70 );
 
 
39
  $template_path = QM_Util::standard_dir( $template );
40
  $stylesheet_directory = QM_Util::standard_dir( get_stylesheet_directory() );
41
  $template_directory = QM_Util::standard_dir( get_template_directory() );
42
+ $theme_directory = QM_Util::standard_dir( get_theme_root() );
43
 
44
+ $template_file = str_replace( array( $stylesheet_directory, $template_directory ), '', $template_path );
45
+ $template_file = ltrim( $template_file, '/' );
46
+ $theme_template = str_replace( $theme_directory, '', $template_path );
47
+ $theme_template = ltrim( $theme_template, '/' );
48
 
49
+ $this->data['template_path'] = $template_path;
50
+ $this->data['template_file'] = $template_file;
51
+ $this->data['theme_template'] = $theme_template;
52
+ $this->data['stylesheet'] = get_stylesheet();
53
+ $this->data['template'] = get_template();
54
 
55
  if ( isset( $this->data['body_class'] ) ) {
56
  asort( $this->data['body_class'] );
60
 
61
  }
62
 
63
+ function register_qm_collector_theme( array $collectors, QueryMonitor $qm ) {
64
+ $collectors['theme'] = new QM_Collector_Theme;
65
+ return $collectors;
 
 
66
  }
67
 
68
+ if ( !is_admin() ) {
69
+ add_filter( 'qm/collectors', 'register_qm_collector_theme', 10, 2 );
70
+ }
collectors/transients.php CHANGED
@@ -58,9 +58,5 @@ class QM_Collector_Transients extends QM_Collector {
58
 
59
  }
60
 
61
- function register_qm_collector_transients( array $qm ) {
62
- $qm['transients'] = new QM_Collector_Transients;
63
- return $qm;
64
- }
65
-
66
- add_filter( 'query_monitor_collectors', 'register_qm_collector_transients', 90 );
58
 
59
  }
60
 
61
+ # Load early in case a plugin is setting transients when it initialises instead of after the `plugins_loaded` hook
62
+ QM_Collectors::add( new QM_Collector_Transients );
 
 
 
 
dispatchers/Headers.php CHANGED
@@ -51,10 +51,6 @@ class QM_Dispatcher_Headers extends QM_Dispatcher {
51
 
52
  }
53
 
54
- public function get_outputter( QM_Collector $collector ) {
55
- return new QM_Output_Headers( $collector );
56
- }
57
-
58
  public function is_active() {
59
 
60
  if ( ! $this->user_can_view() ) {
@@ -77,4 +73,4 @@ function register_qm_dispatcher_headers( array $dispatchers, QM_Plugin $qm ) {
77
  return $dispatchers;
78
  }
79
 
80
- add_filter( 'query_monitor_dispatchers', 'register_qm_dispatcher_headers', 10, 2 );
51
 
52
  }
53
 
 
 
 
 
54
  public function is_active() {
55
 
56
  if ( ! $this->user_can_view() ) {
73
  return $dispatchers;
74
  }
75
 
76
+ add_filter( 'qm/dispatchers', 'register_qm_dispatcher_headers', 10, 2 );
dispatchers/Html.php CHANGED
@@ -172,7 +172,7 @@ class QM_Dispatcher_Html extends QM_Dispatcher {
172
 
173
  if ( !is_admin() ) {
174
  $absolute = function_exists( 'twentyfifteen_setup' );
175
- if ( apply_filters( 'query_monitor_absolute_position', $absolute ) ) {
176
  $class[] = 'qm-absolute';
177
  }
178
  }
@@ -236,14 +236,10 @@ class QM_Dispatcher_Html extends QM_Dispatcher {
236
 
237
  }
238
 
239
- public function get_outputter( QM_Collector $collector ) {
240
- return new QM_Output_Html( $collector );
241
- }
242
-
243
  public function js_admin_bar_menu() {
244
 
245
- $class = implode( ' ', apply_filters( 'query_monitor_class', array() ) );
246
- $title = implode( '&nbsp;&nbsp;&nbsp;', apply_filters( 'query_monitor_title', array() ) );
247
 
248
  if ( empty( $title ) ) {
249
  $title = __( 'Query Monitor', 'query-monitor' );
@@ -257,7 +253,7 @@ class QM_Dispatcher_Html extends QM_Dispatcher {
257
  'sub' => array()
258
  );
259
 
260
- foreach ( apply_filters( 'query_monitor_menus', array() ) as $menu ) {
261
  $admin_bar_menu['sub'][] = $menu;
262
  }
263
 
@@ -290,4 +286,4 @@ function register_qm_dispatcher_html( array $dispatchers, QM_Plugin $qm ) {
290
  return $dispatchers;
291
  }
292
 
293
- add_filter( 'query_monitor_dispatchers', 'register_qm_dispatcher_html', 10, 2 );
172
 
173
  if ( !is_admin() ) {
174
  $absolute = function_exists( 'twentyfifteen_setup' );
175
+ if ( apply_filters( 'qm/output/absolute_position', $absolute ) ) {
176
  $class[] = 'qm-absolute';
177
  }
178
  }
236
 
237
  }
238
 
 
 
 
 
239
  public function js_admin_bar_menu() {
240
 
241
+ $class = implode( ' ', apply_filters( 'qm/output/menu_class', array() ) );
242
+ $title = implode( '&nbsp;&nbsp;&nbsp;', apply_filters( 'qm/output/title', array() ) );
243
 
244
  if ( empty( $title ) ) {
245
  $title = __( 'Query Monitor', 'query-monitor' );
253
  'sub' => array()
254
  );
255
 
256
+ foreach ( apply_filters( 'qm/output/menus', array() ) as $menu ) {
257
  $admin_bar_menu['sub'][] = $menu;
258
  }
259
 
286
  return $dispatchers;
287
  }
288
 
289
+ add_filter( 'qm/dispatchers', 'register_qm_dispatcher_html', 10, 2 );
output/Headers.php CHANGED
@@ -14,15 +14,12 @@ GNU General Public License for more details.
14
 
15
  */
16
 
17
- class QM_Output_Headers implements QM_Output {
18
 
19
  public function __construct( QM_Collector $collector ) {
20
  $this->collector = $collector;
21
  }
22
 
23
- public function output() {
24
- # Headers output does nothing by default
25
- return false;
26
- }
27
 
28
  }
14
 
15
  */
16
 
17
+ abstract class QM_Output_Headers implements QM_Output {
18
 
19
  public function __construct( QM_Collector $collector ) {
20
  $this->collector = $collector;
21
  }
22
 
23
+ abstract public function output();
 
 
 
24
 
25
  }
output/Html.php CHANGED
@@ -14,47 +14,22 @@ GNU General Public License for more details.
14
 
15
  */
16
 
17
- class QM_Output_Html implements QM_Output {
18
 
19
  protected static $file_link_format = null;
20
 
 
 
21
  public function __construct( QM_Collector $collector ) {
22
  $this->collector = $collector;
23
  }
24
 
25
- public function output() {
26
-
27
- $data = $this->collector->get_data();
28
- $name = $this->collector->name();
29
-
30
- if ( empty( $data ) )
31
- return;
32
 
33
- echo '<div class="qm" id="' . esc_attr( $this->collector->id() ) . '">';
34
- echo '<table cellspacing="0">';
35
- if ( !empty( $name ) ) {
36
- echo '<thead>';
37
- echo '<tr>';
38
- echo '<th colspan="2">' . esc_html( $name ) . '</th>';
39
- echo '</tr>';
40
- echo '</thead>';
41
- }
42
- echo '<tbody>';
43
-
44
- foreach ( $data as $key => $value ) {
45
- echo '<tr>';
46
- echo '<td>' . esc_html( $key ) . '</td>';
47
- if ( is_object( $value ) or is_array( $value ) ) {
48
- echo '<td><pre>' . print_r( $value, true ) . '</pre></td>';
49
- } else {
50
- echo '<td>' . esc_html( $value ) . '</td>';
51
- }
52
- echo '</tr>';
53
- }
54
-
55
- echo '</tbody>';
56
- echo '</table>';
57
- echo '</div>';
58
 
59
  }
60
 
@@ -91,15 +66,20 @@ class QM_Output_Html implements QM_Output {
91
 
92
  }
93
 
94
- protected function build_filter( $name, array $values ) {
 
 
 
 
95
 
96
  usort( $values, 'strcasecmp' );
97
 
98
- $out = '<select id="qm-filter-' . esc_attr( $this->collector->id . '-' . $name ) . '" class="qm-filter" data-filter="' . esc_attr( $this->collector->id . '-' . $name ) . '">';
99
  $out .= '<option value="">' . _x( 'All', '"All" option for filters', 'query-monitor' ) . '</option>';
100
 
101
- foreach ( $values as $value )
102
  $out .= '<option value="' . esc_attr( $value ) . '">' . esc_html( $value ) . '</option>';
 
103
 
104
  $out .= '</select>';
105
 
@@ -134,8 +114,12 @@ class QM_Output_Html implements QM_Output {
134
  'ALTER', 'AND', 'COMMIT', 'CREATE', 'DESCRIBE', 'DELETE', 'DROP', 'ELSE', 'END', 'FROM', 'GROUP',
135
  'HAVING', 'INNER', 'INSERT', 'LEFT', 'LIMIT', 'ON', 'OR', 'ORDER', 'OUTER', 'REPLACE', 'RIGHT', 'ROLLBACK', 'SELECT', 'SET',
136
  'SHOW', 'START', 'THEN', 'TRUNCATE', 'UPDATE', 'VALUES', 'WHEN', 'WHERE'
137
- ) as $cmd )
138
  $sql = trim( str_replace( " $cmd ", "<br>$cmd ", $sql ) );
 
 
 
 
139
 
140
  return $sql;
141
 
@@ -159,15 +143,16 @@ class QM_Output_Html implements QM_Output {
159
 
160
  # Further reading:
161
  # http://simonwheatley.co.uk/2012/07/clickable-stack-traces/
162
- # https://github.com/dhoulb/subl
163
 
164
  if ( !isset( self::$file_link_format ) ) {
165
  $format = ini_get( 'xdebug.file_link_format' );
166
- $format = apply_filters( 'query_monitor_file_link_format', $format );
167
- if ( empty( $format ) )
168
  self::$file_link_format = false;
169
- else
170
  self::$file_link_format = str_replace( array( '%f', '%l' ), array( '%1$s', '%2$d' ), $format );
 
171
  }
172
 
173
  if ( false === self::$file_link_format ) {
14
 
15
  */
16
 
17
+ abstract class QM_Output_Html implements QM_Output {
18
 
19
  protected static $file_link_format = null;
20
 
21
+ abstract public function output();
22
+
23
  public function __construct( QM_Collector $collector ) {
24
  $this->collector = $collector;
25
  }
26
 
27
+ public function admin_menu( array $menu ) {
 
 
 
 
 
 
28
 
29
+ $menu[] = $this->menu( array(
30
+ 'title' => $this->collector->name(),
31
+ ) );
32
+ return $menu;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
33
 
34
  }
35
 
66
 
67
  }
68
 
69
+ protected function build_filter( $name, array $values, $highlight = '' ) {
70
+
71
+ if ( empty( $values ) ) {
72
+ return '';
73
+ }
74
 
75
  usort( $values, 'strcasecmp' );
76
 
77
+ $out = '<select id="qm-filter-' . esc_attr( $this->collector->id . '-' . $name ) . '" class="qm-filter" data-filter="' . esc_attr( $name ) . '" data-highlight="' . esc_attr( $highlight ) . '">';
78
  $out .= '<option value="">' . _x( 'All', '"All" option for filters', 'query-monitor' ) . '</option>';
79
 
80
+ foreach ( $values as $value ) {
81
  $out .= '<option value="' . esc_attr( $value ) . '">' . esc_html( $value ) . '</option>';
82
+ }
83
 
84
  $out .= '</select>';
85
 
114
  'ALTER', 'AND', 'COMMIT', 'CREATE', 'DESCRIBE', 'DELETE', 'DROP', 'ELSE', 'END', 'FROM', 'GROUP',
115
  'HAVING', 'INNER', 'INSERT', 'LEFT', 'LIMIT', 'ON', 'OR', 'ORDER', 'OUTER', 'REPLACE', 'RIGHT', 'ROLLBACK', 'SELECT', 'SET',
116
  'SHOW', 'START', 'THEN', 'TRUNCATE', 'UPDATE', 'VALUES', 'WHEN', 'WHERE'
117
+ ) as $cmd ) {
118
  $sql = trim( str_replace( " $cmd ", "<br>$cmd ", $sql ) );
119
+ }
120
+
121
+ # @TODO profile this as an alternative:
122
+ # $sql = preg_replace( '# (ALTER|AND|COMMIT|CREATE|DESCRIBE) #', '<br>$1 ', $sql );
123
 
124
  return $sql;
125
 
143
 
144
  # Further reading:
145
  # http://simonwheatley.co.uk/2012/07/clickable-stack-traces/
146
+ # https://github.com/grych/subl-handler
147
 
148
  if ( !isset( self::$file_link_format ) ) {
149
  $format = ini_get( 'xdebug.file_link_format' );
150
+ $format = apply_filters( 'qm/output/file_link_format', $format );
151
+ if ( empty( $format ) ) {
152
  self::$file_link_format = false;
153
+ } else {
154
  self::$file_link_format = str_replace( array( '%f', '%l' ), array( '%1$s', '%2$d' ), $format );
155
+ }
156
  }
157
 
158
  if ( false === self::$file_link_format ) {
output/headers/php_errors.php CHANGED
@@ -65,8 +65,11 @@ class QM_Output_Headers_PHP_Errors extends QM_Output_Headers {
65
 
66
  }
67
 
68
- function register_qm_output_headers_php_errors( QM_Output $output = null, QM_Collector $collector ) {
69
- return new QM_Output_Headers_PHP_Errors( $collector );
 
 
 
70
  }
71
 
72
- add_filter( 'query_monitor_output_headers_php_errors', 'register_qm_output_headers_php_errors', 10, 2 );
65
 
66
  }
67
 
68
+ function register_qm_output_headers_php_errors( array $output, QM_Collectors $collectors ) {
69
+ if ( $collector = $collectors::get( 'php_errors' ) ) {
70
+ $output['php_errors'] = new QM_Output_Headers_PHP_Errors( $collector );
71
+ }
72
+ return $output;
73
  }
74
 
75
+ add_filter( 'qm/outputter/headers', 'register_qm_output_headers_php_errors', 110, 2 );
output/headers/redirects.php CHANGED
@@ -20,7 +20,7 @@ class QM_Output_Headers_Redirects extends QM_Output_Headers {
20
 
21
  $data = $this->collector->get_data();
22
 
23
- if ( empty( $data ) ) {
24
  return;
25
  }
26
 
@@ -32,8 +32,11 @@ class QM_Output_Headers_Redirects extends QM_Output_Headers {
32
 
33
  }
34
 
35
- function register_qm_output_headers_redirects( QM_Output $output = null, QM_Collector $collector ) {
36
- return new QM_Output_Headers_Redirects( $collector );
 
 
 
37
  }
38
 
39
- add_filter( 'query_monitor_output_headers_redirects', 'register_qm_output_headers_redirects', 10, 2 );
20
 
21
  $data = $this->collector->get_data();
22
 
23
+ if ( empty( $data['trace'] ) ) {
24
  return;
25
  }
26
 
32
 
33
  }
34
 
35
+ function register_qm_output_headers_redirects( array $output, QM_Collectors $collectors ) {
36
+ if ( $collector = $collectors::get( 'redirects' ) ) {
37
+ $output['redirects'] = new QM_Output_Headers_Redirects( $collector );
38
+ }
39
+ return $output;
40
  }
41
 
42
+ add_filter( 'qm/outputter/headers', 'register_qm_output_headers_redirects', 140, 2 );
output/html/admin.php CHANGED
@@ -18,14 +18,14 @@ class QM_Output_Html_Admin extends QM_Output_Html {
18
 
19
  public function __construct( QM_Collector $collector ) {
20
  parent::__construct( $collector );
21
- add_filter( 'query_monitor_menus', array( $this, 'admin_menu' ), 60 );
22
  }
23
 
24
  public function output() {
25
 
26
  $data = $this->collector->get_data();
27
 
28
- if ( empty( $data ) ) {
29
  return;
30
  }
31
 
@@ -122,19 +122,13 @@ class QM_Output_Html_Admin extends QM_Output_Html {
122
 
123
  }
124
 
125
- public function admin_menu( array $menu ) {
126
-
127
- $menu[] = $this->menu( array(
128
- 'title' => __( 'Admin Screen', 'query-monitor' ),
129
- ) );
130
- return $menu;
131
-
132
- }
133
-
134
  }
135
 
136
- function register_qm_output_html_admin( QM_Output $output = null, QM_Collector $collector ) {
137
- return new QM_Output_Html_Admin( $collector );
 
 
 
138
  }
139
 
140
- add_filter( 'query_monitor_output_html_admin', 'register_qm_output_html_admin', 10, 2 );
18
 
19
  public function __construct( QM_Collector $collector ) {
20
  parent::__construct( $collector );
21
+ add_filter( 'qm/output/menus', array( $this, 'admin_menu' ), 60 );
22
  }
23
 
24
  public function output() {
25
 
26
  $data = $this->collector->get_data();
27
 
28
+ if ( empty( $data['current_screen'] ) ) {
29
  return;
30
  }
31
 
122
 
123
  }
124
 
 
 
 
 
 
 
 
 
 
125
  }
126
 
127
+ function register_qm_output_html_admin( array $output, QM_Collectors $collectors ) {
128
+ if ( $collector = $collectors::get( 'admin' ) ) {
129
+ $output['admin'] = new QM_Output_Html_Admin( $collector );
130
+ }
131
+ return $output;
132
  }
133
 
134
+ add_filter( 'qm/outputter/html', 'register_qm_output_html_admin', 70, 2 );
output/html/assets.php CHANGED
@@ -16,85 +16,92 @@ GNU General Public License for more details.
16
 
17
  class QM_Output_Html_Assets extends QM_Output_Html {
18
 
19
- public $id = 'hooks';
20
-
21
  public function __construct( QM_Collector $collector ) {
22
  parent::__construct( $collector );
23
- add_filter( 'query_monitor_menus', array( $this, 'admin_menu' ), 70 );
 
24
  }
25
 
26
  public function output() {
27
 
28
  $data = $this->collector->get_data();
29
 
30
- if ( empty( $data ) ) {
31
  return;
32
  }
33
 
34
  echo '<div class="qm" id="' . esc_attr( $this->collector->id() ) . '">';
35
  echo '<table cellspacing="0">';
36
- echo '<thead>';
37
- echo '<tr>';
38
- echo '<th colspan="2">' . esc_html( $this->collector->name() ) . '</th>';
39
- echo '<th>' . __( 'Dependencies', 'query-monitor' ) . '</th>';
40
- // echo '<th>' . __( 'Component', 'query-monitor' ) . '</th>';
41
- echo '<th>' . __( 'Version', 'query-monitor' ) . '</th>';
42
- echo '</tr>';
43
- echo '</thead>';
44
- echo '<tbody>';
45
-
46
- // @TODO concat, do_concat, concat_version
47
-
48
- $rowspan = count( $data['header_scripts'] );
49
 
50
- echo '<tr>';
51
- echo "<td valign='top' rowspan='{$rowspan}'>" . __( 'Header&nbsp;Scripts', 'query-monitor' ) . "</td>";
 
 
52
 
53
- $this->dependency_rows( $data['header_scripts'], $data['raw_scripts'] );
54
 
55
- $rowspan = count( $data['footer_scripts'] );
56
-
57
- echo '<tr>';
58
- echo "<td valign='top' rowspan='{$rowspan}'>" . __( 'Footer&nbsp;Scripts', 'query-monitor' ) . "</td>";
59
-
60
- $this->dependency_rows( $data['footer_scripts'], $data['raw_scripts'] );
61
 
62
- $rowspan = count( $data['header_styles'] );
 
 
 
 
 
 
 
63
 
64
- echo '<tr>';
65
- echo "<td valign='top' rowspan='{$rowspan}'>" . __( 'Header&nbsp;Styles', 'query-monitor' ) . "</td>";
 
 
 
66
 
67
- $this->dependency_rows( $data['header_styles'], $data['raw_styles'] );
 
 
68
 
69
- $rowspan = count( $data['footer_styles'] );
70
 
71
- echo '<tr>';
72
- echo "<td valign='top' rowspan='{$rowspan}'>" . __( 'Footer&nbsp;Styles', 'query-monitor' ) . "</td>";
73
 
74
- $this->dependency_rows( $data['footer_styles'], $data['raw_styles'] );
75
 
76
- echo '</tbody>';
77
  echo '</table>';
78
  echo '</div>';
79
 
80
  }
81
 
82
- protected function dependency_rows( array $handles, WP_Dependencies $dependencies ) {
83
 
84
  $first = true;
85
 
86
  if ( empty( $handles ) ) {
87
- echo '<td valign="top" colspan="3"><em>' . __( 'none', 'query-monitor' ) . '</em></td>';
 
 
88
  echo '</tr>';
89
  return;
90
  }
91
 
92
  foreach ( $handles as $handle ) {
93
- if ( !$first ) {
94
- echo '<tr>';
 
 
 
 
 
 
 
 
95
  }
96
 
97
- $this->dependency_row( $dependencies->registered[$handle], $dependencies );
98
 
99
  echo '</tr>';
100
  $first = false;
@@ -104,22 +111,8 @@ class QM_Output_Html_Assets extends QM_Output_Html {
104
 
105
  protected function dependency_row( _WP_Dependency $script, WP_Dependencies $dependencies ) {
106
 
107
- // $path = $script->src;
108
-
109
- // if ( preg_match( '#^//#', $path ) ) {
110
- // $path = is_ssl() ? 'https:' . $path : 'http:' . $path;
111
- // } else if ( preg_match( '#^/#', $path ) ) {
112
- // $path = home_url( $path );
113
- // } else {
114
- // $path = set_url_scheme( $path );
115
- // }
116
-
117
- // $path = str_replace( set_url_scheme( WP_PLUGIN_URL ), WP_PLUGIN_DIR, $path );
118
- // $path = str_replace( set_url_scheme( WP_CONTENT_URL ), WP_CONTENT_DIR, $path );
119
- // $component = QM_Util::get_file_component( $path );
120
-
121
  if ( empty( $script->ver ) ) {
122
- $ver = '<em class="qm-info">' . $dependencies->default_version . '</em>';
123
  } else {
124
  $ver = esc_html( $script->ver );
125
  }
@@ -130,26 +123,78 @@ class QM_Output_Html_Assets extends QM_Output_Html {
130
  $src = $script->src;
131
  }
132
 
133
- echo '<td valign="top">' . $script->handle . '<br><span class="qm-info">' . $src . '</span></td>';
134
- echo '<td valign="top">' . implode( '<br>', $script->deps ) . '</td>';
135
- // echo '<td valign="top">' . $component->name . '</td>';
 
 
 
 
 
 
 
 
 
 
136
  echo '<td valign="top">' . $ver . '</td>';
137
 
138
  }
139
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
140
  public function admin_menu( array $menu ) {
141
 
142
- $menu[] = $this->menu( array(
143
- 'title' => $this->collector->name(),
144
- ) );
 
 
 
 
 
 
 
 
145
  return $menu;
146
 
147
  }
148
 
149
  }
150
 
151
- function register_qm_output_html_assets( QM_Output $output = null, QM_Collector $collector ) {
152
- return new QM_Output_Html_Assets( $collector );
 
 
 
153
  }
154
 
155
- add_filter( 'query_monitor_output_html_assets', 'register_qm_output_html_assets', 10, 2 );
16
 
17
  class QM_Output_Html_Assets extends QM_Output_Html {
18
 
 
 
19
  public function __construct( QM_Collector $collector ) {
20
  parent::__construct( $collector );
21
+ add_filter( 'qm/output/menus', array( $this, 'admin_menu' ), 70 );
22
+ add_filter( 'qm/output/menu_class', array( $this, 'admin_class' ) );
23
  }
24
 
25
  public function output() {
26
 
27
  $data = $this->collector->get_data();
28
 
29
+ if ( empty( $data['raw'] ) ) {
30
  return;
31
  }
32
 
33
  echo '<div class="qm" id="' . esc_attr( $this->collector->id() ) . '">';
34
  echo '<table cellspacing="0">';
 
 
 
 
 
 
 
 
 
 
 
 
 
35
 
36
+ foreach ( array(
37
+ 'scripts' => __( 'Scripts', 'query-monitor' ),
38
+ 'styles' => __( 'Styles', 'query-monitor' ),
39
+ ) as $type => $type_label ) {
40
 
41
+ echo '<thead>';
42
 
43
+ if ( 'scripts' != $type ) {
44
+ echo '<tr class="qm-totally-legit-spacer">';
45
+ echo '<td colspan="6"></td>';
46
+ echo '</tr>';
47
+ }
 
48
 
49
+ echo '<tr>';
50
+ echo '<th colspan="2">' . $type_label . '</th>';
51
+ echo '<th>' . __( 'Dependencies', 'query-monitor' ) . '</th>';
52
+ echo '<th>' . __( 'Dependents', 'query-monitor' ) . '</th>';
53
+ echo '<th>' . __( 'Version', 'query-monitor' ) . '</th>';
54
+ echo '</tr>';
55
+ echo '</thead>';
56
+ echo '<tbody>';
57
 
58
+ foreach ( array(
59
+ 'broken' => __( 'Missing Dependencies', 'query-monitor' ),
60
+ 'header' => __( 'Header %s', 'query-monitor' ),
61
+ 'footer' => __( 'Footer %s', 'query-monitor' ),
62
+ ) as $position => $position_label ) {
63
 
64
+ if ( isset( $data[ $position ][ $type ] ) ) {
65
+ $this->dependency_rows( $data[ $position ][ $type ], $data['raw'][ $type ], sprintf( $position_label, $type_label ) );
66
+ }
67
 
68
+ }
69
 
70
+ echo '</tbody>';
 
71
 
72
+ }
73
 
 
74
  echo '</table>';
75
  echo '</div>';
76
 
77
  }
78
 
79
+ protected function dependency_rows( array $handles, WP_Dependencies $dependencies, $label ) {
80
 
81
  $first = true;
82
 
83
  if ( empty( $handles ) ) {
84
+ echo '<tr>';
85
+ echo '<td valign="top" class="qm-nowrap">' . $label . '</td>';
86
+ echo '<td valign="top" colspan="5"><em>' . __( 'none', 'query-monitor' ) . '</em></td>';
87
  echo '</tr>';
88
  return;
89
  }
90
 
91
  foreach ( $handles as $handle ) {
92
+
93
+ if ( in_array( $handle, $dependencies->done ) ) {
94
+ echo '<tr data-qm-subject="' . $handle . '">';
95
+ } else {
96
+ echo '<tr data-qm-subject="' . $handle . '" class="qm-warn">';
97
+ }
98
+
99
+ if ( $first ) {
100
+ $rowspan = count( $handles );
101
+ echo "<th valign='top' rowspan='{$rowspan}' class='qm-nowrap'>" . $label . "</th>";
102
  }
103
 
104
+ $this->dependency_row( $dependencies->query( $handle ), $dependencies );
105
 
106
  echo '</tr>';
107
  $first = false;
111
 
112
  protected function dependency_row( _WP_Dependency $script, WP_Dependencies $dependencies ) {
113
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
114
  if ( empty( $script->ver ) ) {
115
+ $ver = '&nbsp;';
116
  } else {
117
  $ver = esc_html( $script->ver );
118
  }
123
  $src = $script->src;
124
  }
125
 
126
+ $dependents = self::get_dependents( $script, $dependencies );
127
+ $deps = $script->deps;
128
+ sort( $deps );
129
+
130
+ foreach ( $deps as & $dep ) {
131
+ if ( ! $dependencies->query( $dep ) ) {
132
+ $dep = sprintf( __( '%s (missing)', 'query-monitor' ), $dep );
133
+ }
134
+ }
135
+
136
+ echo '<td valign="top" class="qm-wrap">' . $script->handle . '<br><span class="qm-info">' . $src . '</span></td>';
137
+ echo '<td valign="top" class="qm-nowrap qm-highlighter" data-qm-highlight="' . implode( ' ', $deps ) . '">' . implode( '<br>', $deps ) . '</td>';
138
+ echo '<td valign="top" class="qm-nowrap qm-highlighter" data-qm-highlight="' . implode( ' ', $dependents ) . '">' . implode( '<br>', $dependents ) . '</td>';
139
  echo '<td valign="top">' . $ver . '</td>';
140
 
141
  }
142
 
143
+ protected static function get_dependents( _WP_Dependency $script, WP_Dependencies $dependencies ) {
144
+
145
+ // @TODO move this into the collector
146
+ $dependents = array();
147
+ $handles = array_unique( array_merge( $dependencies->queue, $dependencies->done ) );
148
+
149
+ foreach ( $handles as $handle ) {
150
+ $item = $dependencies->query( $handle );
151
+ if ( in_array( $script->handle, $item->deps ) ) {
152
+ $dependents[] = $handle;
153
+ }
154
+ }
155
+
156
+ sort( $dependents );
157
+
158
+ return $dependents;
159
+
160
+ }
161
+
162
+ public function admin_class( array $class ) {
163
+
164
+ $data = $this->collector->get_data();
165
+
166
+ if ( !empty( $data['broken'] ) ) {
167
+ $class[] = 'qm-error';
168
+ }
169
+
170
+ return $class;
171
+
172
+ }
173
+
174
  public function admin_menu( array $menu ) {
175
 
176
+ $data = $this->collector->get_data();
177
+ $args = array(
178
+ 'title' => $this->collector->name()
179
+ );
180
+
181
+ if ( !empty( $data['broken'] ) ) {
182
+ $args['meta']['classname'] = 'qm-error';
183
+ }
184
+
185
+ $menu[] = $this->menu( $args );
186
+
187
  return $menu;
188
 
189
  }
190
 
191
  }
192
 
193
+ function register_qm_output_html_assets( array $output, QM_Collectors $collectors ) {
194
+ if ( $collector = $collectors::get( 'assets' ) ) {
195
+ $output['assets'] = new QM_Output_Html_Assets( $collector );
196
+ }
197
+ return $output;
198
  }
199
 
200
+ add_filter( 'qm/outputter/html', 'register_qm_output_html_assets', 80, 2 );
output/html/conditionals.php CHANGED
@@ -18,14 +18,14 @@ class QM_Output_Html_Conditionals extends QM_Output_Html {
18
 
19
  public function __construct( QM_Collector $collector ) {
20
  parent::__construct( $collector );
21
- add_filter( 'query_monitor_menus', array( $this, 'admin_menu' ), 120 );
22
  }
23
 
24
  public function output() {
25
 
26
  $data = $this->collector->get_data();
27
 
28
- $cols = 5;
29
  $i = 0;
30
  $w = floor( 100 / $cols );
31
 
@@ -90,8 +90,11 @@ class QM_Output_Html_Conditionals extends QM_Output_Html {
90
 
91
  }
92
 
93
- function register_qm_output_html_conditionals( QM_Output $output = null, QM_Collector $collector ) {
94
- return new QM_Output_Html_Conditionals( $collector );
 
 
 
95
  }
96
 
97
- add_filter( 'query_monitor_output_html_conditionals', 'register_qm_output_html_conditionals', 10, 2 );
18
 
19
  public function __construct( QM_Collector $collector ) {
20
  parent::__construct( $collector );
21
+ add_filter( 'qm/output/menus', array( $this, 'admin_menu' ), 1000 );
22
  }
23
 
24
  public function output() {
25
 
26
  $data = $this->collector->get_data();
27
 
28
+ $cols = 6;
29
  $i = 0;
30
  $w = floor( 100 / $cols );
31
 
90
 
91
  }
92
 
93
+ function register_qm_output_html_conditionals( array $output, QM_Collectors $collectors ) {
94
+ if ( $collector = $collectors::get( 'conditionals' ) ) {
95
+ $output['conditionals'] = new QM_Output_Html_Conditionals( $collector );
96
+ }
97
+ return $output;
98
  }
99
 
100
+ add_filter( 'qm/outputter/html', 'register_qm_output_html_conditionals', 50, 2 );
output/html/db_callers.php CHANGED
@@ -18,14 +18,14 @@ class QM_Output_Html_DB_Callers extends QM_Output_Html {
18
 
19
  public function __construct( QM_Collector $collector ) {
20
  parent::__construct( $collector );
21
- add_filter( 'query_monitor_menus', array( $this, 'admin_menu' ), 30 );
22
  }
23
 
24
  public function output() {
25
 
26
  $data = $this->collector->get_data();
27
 
28
- if ( empty( $data ) ) {
29
  return;
30
  }
31
 
@@ -41,10 +41,8 @@ class QM_Output_Html_DB_Callers extends QM_Output_Html {
41
  echo '<tr>';
42
  echo '<th>' . _x( 'Caller', 'Query caller', 'query-monitor' ) . '</th>';
43
 
44
- if ( !empty( $data['types'] ) ) {
45
- foreach ( $data['types'] as $type_name => $type_count ) {
46
- echo '<th class="qm-num">' . $type_name . $this->build_sorter() . '</th>';
47
- }
48
  }
49
 
50
  echo '<th class="qm-num qm-sorted-desc">' . __( 'Time', 'query-monitor' ) . $this->build_sorter() . '</th>';
@@ -64,13 +62,13 @@ class QM_Output_Html_DB_Callers extends QM_Output_Html {
64
 
65
  foreach ( $data['types'] as $type_name => $type_count ) {
66
  if ( isset( $row['types'][$type_name] ) ) {
67
- echo "<td valign='top'>{$row['types'][$type_name]}</td>";
68
  } else {
69
- echo "<td valign='top'>&nbsp;</td>";
70
  }
71
  }
72
 
73
- echo "<td valign='top'>{$stime}</td>";
74
  echo '</tr>';
75
 
76
  }
@@ -84,10 +82,10 @@ class QM_Output_Html_DB_Callers extends QM_Output_Html {
84
  echo '<td>&nbsp;</td>';
85
 
86
  foreach ( $data['types'] as $type_name => $type_count ) {
87
- echo '<td>' . number_format_i18n( $type_count ) . '</td>';
88
  }
89
 
90
- echo "<td>{$total_stime}</td>";
91
  echo '</tr>';
92
 
93
  echo '</tfoot>';
@@ -109,7 +107,7 @@ class QM_Output_Html_DB_Callers extends QM_Output_Html {
109
 
110
  public function admin_menu( array $menu ) {
111
 
112
- if ( $dbq = QueryMonitor::get_collector( 'db_queries' ) ) {
113
  $dbq_data = $dbq->get_data();
114
  if ( isset( $dbq_data['times'] ) ) {
115
  $menu[] = $this->menu( array(
@@ -123,8 +121,11 @@ class QM_Output_Html_DB_Callers extends QM_Output_Html {
123
 
124
  }
125
 
126
- function register_qm_output_html_db_callers( QM_Output $output = null, QM_Collector $collector ) {
127
- return new QM_Output_Html_DB_Callers( $collector );
 
 
 
128
  }
129
 
130
- add_filter( 'query_monitor_output_html_db_callers', 'register_qm_output_html_db_callers', 10, 2 );
18
 
19
  public function __construct( QM_Collector $collector ) {
20
  parent::__construct( $collector );
21
+ add_filter( 'qm/output/menus', array( $this, 'admin_menu' ), 30 );
22
  }
23
 
24
  public function output() {
25
 
26
  $data = $this->collector->get_data();
27
 
28
+ if ( empty( $data['types'] ) ) {
29
  return;
30
  }
31
 
41
  echo '<tr>';
42
  echo '<th>' . _x( 'Caller', 'Query caller', 'query-monitor' ) . '</th>';
43
 
44
+ foreach ( $data['types'] as $type_name => $type_count ) {
45
+ echo '<th class="qm-num">' . $type_name . $this->build_sorter() . '</th>';
 
 
46
  }
47
 
48
  echo '<th class="qm-num qm-sorted-desc">' . __( 'Time', 'query-monitor' ) . $this->build_sorter() . '</th>';
62
 
63
  foreach ( $data['types'] as $type_name => $type_count ) {
64
  if ( isset( $row['types'][$type_name] ) ) {
65
+ echo "<td valign='top' class='qm-num'>{$row['types'][$type_name]}</td>";
66
  } else {
67
+ echo "<td valign='top' class='qm-num'>&nbsp;</td>";
68
  }
69
  }
70
 
71
+ echo "<td valign='top' class='qm-num'>{$stime}</td>";
72
  echo '</tr>';
73
 
74
  }
82
  echo '<td>&nbsp;</td>';
83
 
84
  foreach ( $data['types'] as $type_name => $type_count ) {
85
+ echo '<td class="qm-num">' . number_format_i18n( $type_count ) . '</td>';
86
  }
87
 
88
+ echo "<td class='qm-num'>{$total_stime}</td>";
89
  echo '</tr>';
90
 
91
  echo '</tfoot>';
107
 
108
  public function admin_menu( array $menu ) {
109
 
110
+ if ( $dbq = QM_Collectors::get( 'db_queries' ) ) {
111
  $dbq_data = $dbq->get_data();
112
  if ( isset( $dbq_data['times'] ) ) {
113
  $menu[] = $this->menu( array(
121
 
122
  }
123
 
124
+ function register_qm_output_html_db_callers( array $output, QM_Collectors $collectors ) {
125
+ if ( $collector = $collectors::get( 'db_callers' ) ) {
126
+ $output['db_callers'] = new QM_Output_Html_DB_Callers( $collector );
127
+ }
128
+ return $output;
129
  }
130
 
131
+ add_filter( 'qm/outputter/html', 'register_qm_output_html_db_callers', 30, 2 );
output/html/db_components.php CHANGED
@@ -18,14 +18,14 @@ class QM_Output_Html_DB_Components extends QM_Output_Html {
18
 
19
  public function __construct( QM_Collector $collector ) {
20
  parent::__construct( $collector );
21
- add_filter( 'query_monitor_menus', array( $this, 'admin_menu' ), 40 );
22
  }
23
 
24
  public function output() {
25
 
26
  $data = $this->collector->get_data();
27
 
28
- if ( empty( $data ) ) {
29
  return;
30
  }
31
 
@@ -42,10 +42,8 @@ class QM_Output_Html_DB_Components extends QM_Output_Html {
42
  echo '<tr>';
43
  echo '<th>' . _x( 'Component', 'Query component', 'query-monitor' ) . '</th>';
44
 
45
- if ( !empty( $data['types'] ) ) {
46
- foreach ( $data['types'] as $type_name => $type_count ) {
47
- echo '<th class="qm-num">' . $type_name . $this->build_sorter() . '</th>';
48
- }
49
  }
50
 
51
  echo '<th class="qm-num qm-sorted-desc">' . __( 'Time', 'query-monitor' ) . $this->build_sorter() . '</th>';
@@ -66,13 +64,13 @@ class QM_Output_Html_DB_Components extends QM_Output_Html {
66
 
67
  foreach ( $data['types'] as $type_name => $type_count ) {
68
  if ( isset( $row['types'][$type_name] ) ) {
69
- echo "<td valign='top'>{$row['types'][$type_name]}</td>";
70
  } else {
71
- echo "<td valign='top'>&nbsp;</td>";
72
  }
73
  }
74
 
75
- echo "<td valign='top'>{$stime}</td>";
76
  echo '</tr>';
77
 
78
  }
@@ -86,10 +84,10 @@ class QM_Output_Html_DB_Components extends QM_Output_Html {
86
  echo '<td>&nbsp;</td>';
87
 
88
  foreach ( $data['types'] as $type_name => $type_count ) {
89
- echo '<td>' . number_format_i18n( $type_count ) . '</td>';
90
  }
91
 
92
- echo "<td>{$total_stime}</td>";
93
  echo '</tr>';
94
  echo '</tfoot>';
95
 
@@ -110,7 +108,7 @@ class QM_Output_Html_DB_Components extends QM_Output_Html {
110
 
111
  public function admin_menu( array $menu ) {
112
 
113
- if ( $dbq = QueryMonitor::get_collector( 'db_queries' ) ) {
114
  $dbq_data = $dbq->get_data();
115
  if ( isset( $dbq_data['component_times'] ) ) {
116
  $menu[] = $this->menu( array(
@@ -124,8 +122,11 @@ class QM_Output_Html_DB_Components extends QM_Output_Html {
124
 
125
  }
126
 
127
- function register_qm_output_html_db_components( QM_Output $output = null, QM_Collector $collector ) {
128
- return new QM_Output_Html_DB_Components( $collector );
 
 
 
129
  }
130
 
131
- add_filter( 'query_monitor_output_html_db_components', 'register_qm_output_html_db_components', 10, 2 );
18
 
19
  public function __construct( QM_Collector $collector ) {
20
  parent::__construct( $collector );
21
+ add_filter( 'qm/output/menus', array( $this, 'admin_menu' ), 40 );
22
  }
23
 
24
  public function output() {
25
 
26
  $data = $this->collector->get_data();
27
 
28
+ if ( empty( $data['types'] ) ) {
29
  return;
30
  }
31
 
42
  echo '<tr>';
43
  echo '<th>' . _x( 'Component', 'Query component', 'query-monitor' ) . '</th>';
44
 
45
+ foreach ( $data['types'] as $type_name => $type_count ) {
46
+ echo '<th class="qm-num">' . $type_name . $this->build_sorter() . '</th>';
 
 
47
  }
48
 
49
  echo '<th class="qm-num qm-sorted-desc">' . __( 'Time', 'query-monitor' ) . $this->build_sorter() . '</th>';
64
 
65
  foreach ( $data['types'] as $type_name => $type_count ) {
66
  if ( isset( $row['types'][$type_name] ) ) {
67
+ echo "<td valign='top' class='qm-num'>{$row['types'][$type_name]}</td>";
68
  } else {
69
+ echo "<td valign='top' class='qm-num'>&nbsp;</td>";
70
  }
71
  }
72
 
73
+ echo "<td valign='top' class='qm-num'>{$stime}</td>";
74
  echo '</tr>';
75
 
76
  }
84
  echo '<td>&nbsp;</td>';
85
 
86
  foreach ( $data['types'] as $type_name => $type_count ) {
87
+ echo '<td class="qm-num">' . number_format_i18n( $type_count ) . '</td>';
88
  }
89
 
90
+ echo "<td class='qm-num'>{$total_stime}</td>";
91
  echo '</tr>';
92
  echo '</tfoot>';
93
 
108
 
109
  public function admin_menu( array $menu ) {
110
 
111
+ if ( $dbq = QM_Collectors::get( 'db_queries' ) ) {
112
  $dbq_data = $dbq->get_data();
113
  if ( isset( $dbq_data['component_times'] ) ) {
114
  $menu[] = $this->menu( array(
122
 
123
  }
124
 
125
+ function register_qm_output_html_db_components( array $output, QM_Collectors $collectors ) {
126
+ if ( $collector = $collectors::get( 'db_components' ) ) {
127
+ $output['db_components'] = new QM_Output_Html_DB_Components( $collector );
128
+ }
129
+ return $output;
130
  }
131
 
132
+ add_filter( 'qm/outputter/html', 'register_qm_output_html_db_components', 40, 2 );
output/html/db_queries.php CHANGED
@@ -20,9 +20,9 @@ class QM_Output_Html_DB_Queries extends QM_Output_Html {
20
 
21
  public function __construct( QM_Collector $collector ) {
22
  parent::__construct( $collector );
23
- add_filter( 'query_monitor_menus', array( $this, 'admin_menu' ), 20 );
24
- add_filter( 'query_monitor_title', array( $this, 'admin_title' ), 20 );
25
- add_filter( 'query_monitor_class', array( $this, 'admin_class' ) );
26
  }
27
 
28
  public function output() {
@@ -115,7 +115,7 @@ class QM_Output_Html_DB_Queries extends QM_Output_Html {
115
  }
116
 
117
  if ( isset( $expensive[0]['result'] ) ) {
118
- echo '<th scope="col">' . __( 'Affected Rows', 'query-monitor' ) . '</th>';
119
  }
120
 
121
  echo '<th class="qm-num">' . __( 'Time', 'query-monitor' ) . '</th>';
@@ -171,7 +171,12 @@ class QM_Output_Html_DB_Queries extends QM_Output_Html {
171
  }
172
 
173
  if ( $db->has_result ) {
174
- echo '<th scope="col">' . __( 'Rows', 'query-monitor' ) . $this->build_sorter() . '</th>';
 
 
 
 
 
175
  }
176
 
177
  echo '<th scope="col" class="qm-num">' . __( 'Time', 'query-monitor' ) . $this->build_sorter() . '</th>';
@@ -196,12 +201,12 @@ class QM_Output_Html_DB_Queries extends QM_Output_Html {
196
 
197
  echo '<tr class="qm-items-shown qm-hide">';
198
  echo '<td valign="top" colspan="' . ( $span - 1 ) . '">' . sprintf( __( 'Queries in filter: %s', 'query-monitor' ), '<span class="qm-items-number">' . number_format_i18n( $db->total_qs ) . '</span>' ) . '</td>';
199
- echo "<td valign='top' class='qm-items-time'>{$total_stime}</td>";
200
  echo '</tr>';
201
 
202
  echo '<tr>';
203
  echo '<td valign="top" colspan="' . ( $span - 1 ) . '">' . sprintf( __( 'Total Queries: %s', 'query-monitor' ), number_format_i18n( $db->total_qs ) ) . '</td>';
204
- echo "<td valign='top'>{$total_stime}</td>";
205
  echo '</tr>';
206
  echo '</tfoot>';
207
 
@@ -249,7 +254,7 @@ class QM_Output_Html_DB_Queries extends QM_Output_Html {
249
  $result = "<td valign='top' class='qm-row-result qm-row-error'>{$error}</td>\n";
250
  $row_attr['class'] = 'qm-warn';
251
  } else {
252
- $result = "<td valign='top' class='qm-row-result'>{$row['result']}</td>\n";
253
  }
254
 
255
  if ( isset( $row['trace'] ) ) {
@@ -274,16 +279,15 @@ class QM_Output_Html_DB_Queries extends QM_Output_Html {
274
  }
275
 
276
  if ( isset( $cols['sql'] ) ) {
277
- $row_attr['data-qm-db_queries-type'] = $row['type'];
278
  }
279
  if ( isset( $cols['component'] ) ) {
280
- $row_attr['data-qm-db_queries-component'] = $row['component']->name;
281
  }
282
  if ( isset( $cols['caller'] ) ) {
283
- $row_attr['data-qm-db_queries-caller'] = $row['caller_name'];
284
  }
285
  if ( isset( $cols['time'] ) ) {
286
- $row_attr['data-qm-db_queries-time'] = $row['ltime'];
287
  $row_attr['data-qm-time'] = $row['ltime'];
288
  }
289
 
@@ -296,11 +300,11 @@ class QM_Output_Html_DB_Queries extends QM_Output_Html {
296
  echo "<tr{$attr}>";
297
 
298
  if ( isset( $cols['row'] ) ) {
299
- echo "<td valign='top'>" . ++$this->query_row . "</td>";
300
  }
301
 
302
  if ( isset( $cols['sql'] ) ) {
303
- echo "<td valign='top' class='qm-row-sql qm-ltr qm-sql'>{$sql}</td>";
304
  }
305
 
306
  if ( isset( $cols['caller'] ) ) {
@@ -317,11 +321,11 @@ class QM_Output_Html_DB_Queries extends QM_Output_Html {
317
  }
318
 
319
  if ( isset( $cols['stack'] ) ) {
320
- echo '<td valign="top" class="qm-row-caller qm-row-stack qm-ltr">' . implode( '<br>', $stack ) . '</td>';
321
  }
322
 
323
  if ( isset( $cols['component'] ) ) {
324
- echo "<td valign='top' class='qm-row-component'>{$row['component']->name}</td>\n";
325
  }
326
 
327
  if ( isset( $cols['result'] ) ) {
@@ -329,7 +333,7 @@ class QM_Output_Html_DB_Queries extends QM_Output_Html {
329
  }
330
 
331
  if ( isset( $cols['time'] ) ) {
332
- echo "<td valign='top' class='qm-row-time{$td}'>{$stime}</td>\n";
333
  }
334
 
335
  echo '</tr>';
@@ -406,8 +410,11 @@ class QM_Output_Html_DB_Queries extends QM_Output_Html {
406
 
407
  }
408
 
409
- function register_qm_output_html_db_queries( QM_Output $output = null, QM_Collector $collector ) {
410
- return new QM_Output_Html_DB_Queries( $collector );
 
 
 
411
  }
412
 
413
- add_filter( 'query_monitor_output_html_db_queries', 'register_qm_output_html_db_queries', 10, 2 );
20
 
21
  public function __construct( QM_Collector $collector ) {
22
  parent::__construct( $collector );
23
+ add_filter( 'qm/output/menus', array( $this, 'admin_menu' ), 20 );
24
+ add_filter( 'qm/output/title', array( $this, 'admin_title' ), 20 );
25
+ add_filter( 'qm/output/menu_class', array( $this, 'admin_class' ) );
26
  }
27
 
28
  public function output() {
115
  }
116
 
117
  if ( isset( $expensive[0]['result'] ) ) {
118
+ echo '<th scope="col" class="qm-num">' . __( 'Affected Rows', 'query-monitor' ) . '</th>';
119
  }
120
 
121
  echo '<th class="qm-num">' . __( 'Time', 'query-monitor' ) . '</th>';
171
  }
172
 
173
  if ( $db->has_result ) {
174
+ if ( empty( $data['errors'] ) ) {
175
+ $class = 'qm-num';
176
+ } else {
177
+ $class = '';
178
+ }
179
+ echo '<th scope="col" class="' . $class . '">' . __( 'Rows', 'query-monitor' ) . $this->build_sorter() . '</th>';
180
  }
181
 
182
  echo '<th scope="col" class="qm-num">' . __( 'Time', 'query-monitor' ) . $this->build_sorter() . '</th>';
201
 
202
  echo '<tr class="qm-items-shown qm-hide">';
203
  echo '<td valign="top" colspan="' . ( $span - 1 ) . '">' . sprintf( __( 'Queries in filter: %s', 'query-monitor' ), '<span class="qm-items-number">' . number_format_i18n( $db->total_qs ) . '</span>' ) . '</td>';
204
+ echo "<td valign='top' class='qm-items-time qm-num'>{$total_stime}</td>";
205
  echo '</tr>';
206
 
207
  echo '<tr>';
208
  echo '<td valign="top" colspan="' . ( $span - 1 ) . '">' . sprintf( __( 'Total Queries: %s', 'query-monitor' ), number_format_i18n( $db->total_qs ) ) . '</td>';
209
+ echo "<td valign='top' class='qm-num'>{$total_stime}</td>";
210
  echo '</tr>';
211
  echo '</tfoot>';
212
 
254
  $result = "<td valign='top' class='qm-row-result qm-row-error'>{$error}</td>\n";
255
  $row_attr['class'] = 'qm-warn';
256
  } else {
257
+ $result = "<td valign='top' class='qm-row-result qm-num'>{$row['result']}</td>\n";
258
  }
259
 
260
  if ( isset( $row['trace'] ) ) {
279
  }
280
 
281
  if ( isset( $cols['sql'] ) ) {
282
+ $row_attr['data-qm-type'] = $row['type'];
283
  }
284
  if ( isset( $cols['component'] ) ) {
285
+ $row_attr['data-qm-component'] = $row['component']->name;
286
  }
287
  if ( isset( $cols['caller'] ) ) {
288
+ $row_attr['data-qm-caller'] = $row['caller_name'];
289
  }
290
  if ( isset( $cols['time'] ) ) {
 
291
  $row_attr['data-qm-time'] = $row['ltime'];
292
  }
293
 
300
  echo "<tr{$attr}>";
301
 
302
  if ( isset( $cols['row'] ) ) {
303
+ echo "<td valign='top' class='qm-row-num qm-num'>" . ++$this->query_row . "</td>";
304
  }
305
 
306
  if ( isset( $cols['sql'] ) ) {
307
+ echo "<td valign='top' class='qm-row-sql qm-ltr qm-wrap'>{$sql}</td>";
308
  }
309
 
310
  if ( isset( $cols['caller'] ) ) {
321
  }
322
 
323
  if ( isset( $cols['stack'] ) ) {
324
+ echo '<td valign="top" class="qm-row-caller qm-row-stack qm-nowrap qm-ltr">' . $caller_name . '<br>' . implode( '<br>', $stack ) . '</td>';
325
  }
326
 
327
  if ( isset( $cols['component'] ) ) {
328
+ echo "<td valign='top' class='qm-row-component qm-nowrap'>{$row['component']->name}</td>\n";
329
  }
330
 
331
  if ( isset( $cols['result'] ) ) {
333
  }
334
 
335
  if ( isset( $cols['time'] ) ) {
336
+ echo "<td valign='top' class='qm-num qm-row-time{$td}'>{$stime}</td>\n";
337
  }
338
 
339
  echo '</tr>';
410
 
411
  }
412
 
413
+ function register_qm_output_html_db_queries( array $output, QM_Collectors $collectors ) {
414
+ if ( $collector = $collectors::get( 'db_queries' ) ) {
415
+ $output['db_queries'] = new QM_Output_Html_DB_Queries( $collector );
416
+ }
417
+ return $output;
418
  }
419
 
420
+ add_filter( 'qm/outputter/html', 'register_qm_output_html_db_queries', 20, 2 );
output/html/debug_bar.php ADDED
@@ -0,0 +1,74 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ Copyright 2009-2015 John Blackbourn
4
+
5
+ This program is free software; you can redistribute it and/or modify
6
+ it under the terms of the GNU General Public License as published by
7
+ the Free Software Foundation; either version 2 of the License, or
8
+ (at your option) any later version.
9
+
10
+ This program is distributed in the hope that it will be useful,
11
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ GNU General Public License for more details.
14
+
15
+ */
16
+
17
+ class QM_Output_Html_Debug_Bar extends QM_Output_Html {
18
+
19
+ public function __construct( QM_Collector $collector ) {
20
+ parent::__construct( $collector );
21
+ add_filter( 'qm/output/menus', array( $this, 'admin_menu' ), 200 );
22
+ }
23
+
24
+ public function output() {
25
+
26
+ $target = get_class( $this->collector->get_panel() );
27
+
28
+ echo '<div class="qm qm-debug-bar" id="' . esc_attr( $this->collector->id() ) . '">';
29
+ echo '<table cellspacing="0">';
30
+ echo '<thead>';
31
+ echo '<tr>';
32
+ echo '<th>' . esc_html( $this->collector->name() ) . '</th>';
33
+ echo '</tr>';
34
+ echo '</thead>';
35
+ echo '<tbody>';
36
+
37
+ echo '<tr>';
38
+ echo '<td valign="top">';
39
+ echo '<div id="debug-menu-target-' . esc_attr( $target ) . '" class="debug-menu-target qm-debug-bar-output">';
40
+
41
+ $this->collector->render();
42
+
43
+ echo '</div>';
44
+ echo '</td>';
45
+ echo '</tr>';
46
+
47
+ echo '</tbody>';
48
+ echo '</table>';
49
+ echo '</div>';
50
+
51
+ }
52
+
53
+ }
54
+
55
+ function register_qm_output_html_debug_bar( array $output, QM_Collectors $collectors ) {
56
+ global $debug_bar;
57
+
58
+ if ( empty( $debug_bar ) ) {
59
+ return $output;
60
+ }
61
+
62
+ foreach ( $debug_bar->panels as $panel ) {
63
+ $panel_id = strtolower( get_class( $panel ) );
64
+ $collector = $collectors::get( "debug_bar_{$panel_id}" );
65
+
66
+ if ( $collector and $collector->is_visible() ) {
67
+ $output["debug_bar_{$panel_id}"] = new QM_Output_Html_Debug_Bar( $collector );
68
+ }
69
+ }
70
+
71
+ return $output;
72
+ }
73
+
74
+ add_filter( 'qm/outputter/html', 'register_qm_output_html_debug_bar', 200, 2 );
output/html/environment.php CHANGED
@@ -18,7 +18,7 @@ class QM_Output_Html_Environment extends QM_Output_Html {
18
 
19
  public function __construct( QM_Collector $collector ) {
20
  parent::__construct( $collector );
21
- add_filter( 'query_monitor_menus', array( $this, 'admin_menu' ), 100 );
22
  }
23
 
24
  public function output() {
@@ -238,19 +238,13 @@ class QM_Output_Html_Environment extends QM_Output_Html {
238
 
239
  }
240
 
241
- public function admin_menu( array $menu ) {
242
-
243
- $menu[] = $this->menu( array(
244
- 'title' => __( 'Environment', 'query-monitor' )
245
- ) );
246
- return $menu;
247
-
248
- }
249
-
250
  }
251
 
252
- function register_qm_output_html_environment( QM_Output $output = null, QM_Collector $collector ) {
253
- return new QM_Output_Html_Environment( $collector );
 
 
 
254
  }
255
 
256
- add_filter( 'query_monitor_output_html_environment', 'register_qm_output_html_environment', 10, 2 );
18
 
19
  public function __construct( QM_Collector $collector ) {
20
  parent::__construct( $collector );
21
+ add_filter( 'qm/output/menus', array( $this, 'admin_menu' ), 110 );
22
  }
23
 
24
  public function output() {
238
 
239
  }
240
 
 
 
 
 
 
 
 
 
 
241
  }
242
 
243
+ function register_qm_output_html_environment( array $output, QM_Collectors $collectors ) {
244
+ if ( $collector = $collectors::get( 'environment' ) ) {
245
+ $output['environment'] = new QM_Output_Html_Environment( $collector );
246
+ }
247
+ return $output;
248
  }
249
 
250
+ add_filter( 'qm/outputter/html', 'register_qm_output_html_environment', 120, 2 );
output/html/hooks.php CHANGED
@@ -20,14 +20,15 @@ class QM_Output_Html_Hooks extends QM_Output_Html {
20
 
21
  public function __construct( QM_Collector $collector ) {
22
  parent::__construct( $collector );
23
- add_filter( 'query_monitor_menus', array( $this, 'admin_menu' ), 70 );
 
24
  }
25
 
26
  public function output() {
27
 
28
  $data = $this->collector->get_data();
29
 
30
- if ( empty( $data ) ) {
31
  return;
32
  }
33
 
@@ -44,7 +45,7 @@ class QM_Output_Html_Hooks extends QM_Output_Html {
44
  echo '<thead>';
45
  echo '<tr>';
46
  echo '<th>' . __( 'Hook', 'query-monitor' ) . $this->build_filter( 'name', $data['parts'] ) . '</th>';
47
- echo '<th colspan="3">' . __( 'Actions', 'query-monitor' ) . $this->build_filter( 'component', $data['components'] ) . '</th>';
48
  echo '</tr>';
49
  echo '</thead>';
50
  echo '<tbody>';
@@ -61,8 +62,8 @@ class QM_Output_Html_Hooks extends QM_Output_Html {
61
 
62
  }
63
 
64
- $row_attr['data-qm-hooks-name'] = implode( ' ', $hook['parts'] );
65
- $row_attr['data-qm-hooks-component'] = implode( ' ', $hook['components'] );
66
 
67
  $attr = '';
68
 
@@ -76,9 +77,6 @@ class QM_Output_Html_Hooks extends QM_Output_Html {
76
  $attr .= ' ' . $a . '="' . esc_attr( $v ) . '"';
77
  }
78
 
79
- echo "<tr{$attr}>";
80
-
81
- echo "<td valign='top' rowspan='{$rowspan}'>{$hook['name']}</td>";
82
  if ( !empty( $hook['actions'] ) ) {
83
 
84
  $first = true;
@@ -91,11 +89,24 @@ class QM_Output_Html_Hooks extends QM_Output_Html {
91
  $component = '';
92
  }
93
 
94
- if ( !$first ) {
95
- echo "<tr{$attr}>";
 
 
 
 
 
 
 
 
 
 
 
 
 
96
  }
97
 
98
- echo '<td valign="top" class="qm-priority">' . $action['priority'] . '</td>';
99
  echo '<td valign="top" class="qm-ltr">';
100
 
101
  if ( isset( $action['callback']['file'] ) ) {
@@ -113,7 +124,7 @@ class QM_Output_Html_Hooks extends QM_Output_Html {
113
  }
114
 
115
  echo '</td>';
116
- echo '<td valign="top">';
117
  echo esc_html( $component );
118
  echo '</td>';
119
  echo '</tr>';
@@ -121,9 +132,14 @@ class QM_Output_Html_Hooks extends QM_Output_Html {
121
  }
122
 
123
  } else {
 
 
 
 
124
  echo '<td colspan="3">&nbsp;</td>';
 
125
  }
126
- echo '</tr>';
127
  }
128
 
129
  echo '</tbody>';
@@ -132,19 +148,42 @@ class QM_Output_Html_Hooks extends QM_Output_Html {
132
 
133
  }
134
 
 
 
 
 
 
 
 
 
 
 
 
 
135
  public function admin_menu( array $menu ) {
136
 
137
- $menu[] = $this->menu( array(
138
- 'title' => __( 'Hooks', 'query-monitor' )
139
- ) );
 
 
 
 
 
 
 
 
140
  return $menu;
141
 
142
  }
143
 
144
  }
145
 
146
- function register_qm_output_html_hooks( QM_Output $output = null, QM_Collector $collector ) {
147
- return new QM_Output_Html_Hooks( $collector );
 
 
 
148
  }
149
 
150
- add_filter( 'query_monitor_output_html_hooks', 'register_qm_output_html_hooks', 10, 2 );
20
 
21
  public function __construct( QM_Collector $collector ) {
22
  parent::__construct( $collector );
23
+ add_filter( 'qm/output/menus', array( $this, 'admin_menu' ), 80 );
24
+ add_filter( 'qm/output/menu_class', array( $this, 'admin_class' ) );
25
  }
26
 
27
  public function output() {
28
 
29
  $data = $this->collector->get_data();
30
 
31
+ if ( empty( $data['hooks'] ) ) {
32
  return;
33
  }
34
 
45
  echo '<thead>';
46
  echo '<tr>';
47
  echo '<th>' . __( 'Hook', 'query-monitor' ) . $this->build_filter( 'name', $data['parts'] ) . '</th>';
48
+ echo '<th colspan="3">' . __( 'Actions', 'query-monitor' ) . $this->build_filter( 'component', $data['components'], 'subject' ) . '</th>';
49
  echo '</tr>';
50
  echo '</thead>';
51
  echo '<tbody>';
62
 
63
  }
64
 
65
+ $row_attr['data-qm-name'] = implode( ' ', $hook['parts'] );
66
+ $row_attr['data-qm-component'] = implode( ' ', $hook['components'] );
67
 
68
  $attr = '';
69
 
77
  $attr .= ' ' . $a . '="' . esc_attr( $v ) . '"';
78
  }
79
 
 
 
 
80
  if ( !empty( $hook['actions'] ) ) {
81
 
82
  $first = true;
89
  $component = '';
90
  }
91
 
92
+ $trattr = $attr . ' data-qm-subject="' . esc_attr( $component ) . '"';
93
+
94
+ echo "<tr{$trattr}>";
95
+
96
+ if ( $first ) {
97
+
98
+ echo "<th valign='top' rowspan='{$rowspan}'>";
99
+ echo $hook['name'];
100
+ if ( 'all' === $hook['name'] ) {
101
+ echo '<br><span class="qm-warn">';
102
+ _e( 'Warning: The <code>all</code> action is extremely resource intensive. Try to avoid using it.', 'query-monitor' );
103
+ echo '<span>';
104
+ }
105
+ echo '</th>';
106
+
107
  }
108
 
109
+ echo '<td valign="top" class="qm-num">' . $action['priority'] . '</td>';
110
  echo '<td valign="top" class="qm-ltr">';
111
 
112
  if ( isset( $action['callback']['file'] ) ) {
124
  }
125
 
126
  echo '</td>';
127
+ echo '<td valign="top" class="qm-nowrap">';
128
  echo esc_html( $component );
129
  echo '</td>';
130
  echo '</tr>';
132
  }
133
 
134
  } else {
135
+ echo "<tr{$attr}>";
136
+ echo "<th valign='top'>";
137
+ echo $hook['name'];
138
+ echo '</th>';
139
  echo '<td colspan="3">&nbsp;</td>';
140
+ echo '</tr>';
141
  }
142
+
143
  }
144
 
145
  echo '</tbody>';
148
 
149
  }
150
 
151
+ public function admin_class( array $class ) {
152
+
153
+ $data = $this->collector->get_data();
154
+
155
+ if ( isset( $data['warnings'] ) ) {
156
+ $class[] = 'qm-warning';
157
+ }
158
+
159
+ return $class;
160
+
161
+ }
162
+
163
  public function admin_menu( array $menu ) {
164
 
165
+ $data = $this->collector->get_data();
166
+ $args = array(
167
+ 'title' => $this->collector->name(),
168
+ );
169
+
170
+ if ( isset( $data['warnings'] ) ) {
171
+ $args['meta']['classname'] = 'qm-warning';
172
+ }
173
+
174
+ $menu[] = $this->menu( $args );
175
+
176
  return $menu;
177
 
178
  }
179
 
180
  }
181
 
182
+ function register_qm_output_html_hooks( array $output, QM_Collectors $collectors ) {
183
+ if ( $collector = $collectors::get( 'hooks' ) ) {
184
+ $output['hooks'] = new QM_Output_Html_Hooks( $collector );
185
+ }
186
+ return $output;
187
  }
188
 
189
+ add_filter( 'qm/outputter/html', 'register_qm_output_html_hooks', 80, 2 );
output/html/http.php CHANGED
@@ -18,8 +18,8 @@ class QM_Output_Html_HTTP extends QM_Output_Html {
18
 
19
  public function __construct( QM_Collector $collector ) {
20
  parent::__construct( $collector );
21
- add_filter( 'query_monitor_menus', array( $this, 'admin_menu' ), 90 );
22
- add_filter( 'query_monitor_class', array( $this, 'admin_class' ) );
23
  }
24
 
25
  public function output() {
@@ -29,16 +29,17 @@ class QM_Output_Html_HTTP extends QM_Output_Html {
29
  $total_time = 0;
30
 
31
  echo '<div class="qm" id="' . esc_attr( $this->collector->id() ) . '">';
32
- echo '<table cellspacing="0">';
33
  echo '<thead>';
34
  echo '<tr>';
35
- echo '<th>' . __( 'HTTP Request', 'query-monitor' ) . '</th>';
36
- echo '<th>' . __( 'Response', 'query-monitor' ) . '</th>';
37
- echo '<th>' . __( 'Transport', 'query-monitor' ) . '</th>';
38
- echo '<th>' . __( 'Call Stack', 'query-monitor' ) . '</th>';
39
- echo '<th>' . __( 'Component', 'query-monitor' ) . '</th>';
40
- echo '<th>' . __( 'Timeout', 'query-monitor' ) . '</th>';
41
- echo '<th>' . __( 'Time', 'query-monitor' ) . '</th>';
 
42
  echo '</tr>';
43
  echo '</thead>';
44
 
@@ -49,15 +50,19 @@ class QM_Output_Html_HTTP extends QM_Output_Html {
49
  foreach ( $data['vars'] as $key => $value ) {
50
  $vars[] = $key . ': ' . esc_html( $value );
51
  }
52
- $vars = implode( ', ', $vars );
53
  }
54
 
55
  if ( !empty( $data['http'] ) ) {
56
 
57
  echo '<tbody>';
 
58
 
59
  foreach ( $data['http'] as $key => $row ) {
60
  $ltime = $row['ltime'];
 
 
 
61
 
62
  if ( empty( $ltime ) ) {
63
  $stime = '';
@@ -98,18 +103,27 @@ class QM_Output_Html_HTTP extends QM_Output_Html {
98
  }
99
 
100
  $stack = $row['trace']->get_stack();
101
- $component = $row['trace']->get_component();
 
 
 
 
 
 
 
 
102
 
103
  $stack = implode( '<br>', $stack );
104
  echo "
105
- <tr class='{$css}'>\n
106
- <td valign='top' class='qm-url qm-ltr'>{$method}<br>{$url}</td>\n
 
107
  <td valign='top'>{$response}</td>\n
108
  <td valign='top'>{$transport}</td>\n
109
- <td valign='top' class='qm-ltr'>{$stack}</td>\n
110
- <td valign='top'>{$component->name}</td>\n
111
- <td valign='top'>{$row['args']['timeout']}</td>\n
112
- <td valign='top'>{$stime}</td>\n
113
  </tr>\n
114
  ";
115
  }
@@ -120,8 +134,8 @@ class QM_Output_Html_HTTP extends QM_Output_Html {
120
  $total_stime = number_format_i18n( $data['ltime'], 4 );
121
 
122
  echo '<tr>';
123
- echo '<td colspan="6">' . $vars . '</td>';
124
- echo "<td>{$total_stime}</td>";
125
  echo '</tr>';
126
  echo '</tfoot>';
127
 
@@ -129,11 +143,11 @@ class QM_Output_Html_HTTP extends QM_Output_Html {
129
 
130
  echo '<tbody>';
131
  echo '<tr>';
132
- echo '<td colspan="7" style="text-align:center !important"><em>' . __( 'none', 'query-monitor' ) . '</em></td>';
133
  echo '</tr>';
134
  if ( !empty( $vars ) ) {
135
  echo '<tr>';
136
- echo '<td colspan="7">' . $vars . '</td>';
137
  echo '</tr>';
138
  }
139
  echo '</tbody>';
@@ -187,8 +201,11 @@ class QM_Output_Html_HTTP extends QM_Output_Html {
187
 
188
  }
189
 
190
- function register_qm_output_html_http( QM_Output $output = null, QM_Collector $collector ) {
191
- return new QM_Output_Html_HTTP( $collector );
 
 
 
192
  }
193
 
194
- add_filter( 'query_monitor_output_html_http', 'register_qm_output_html_http', 10, 2 );
18
 
19
  public function __construct( QM_Collector $collector ) {
20
  parent::__construct( $collector );
21
+ add_filter( 'qm/output/menus', array( $this, 'admin_menu' ), 90 );
22
+ add_filter( 'qm/output/menu_class', array( $this, 'admin_class' ) );
23
  }
24
 
25
  public function output() {
29
  $total_time = 0;
30
 
31
  echo '<div class="qm" id="' . esc_attr( $this->collector->id() ) . '">';
32
+ echo '<table cellspacing="0" class="qm-sortable">';
33
  echo '<thead>';
34
  echo '<tr>';
35
+ echo '<th class="qm-sorted-asc">&nbsp;' . $this->build_sorter() . '</th>';
36
+ echo '<th scope="col">' . __( 'HTTP Request', 'query-monitor' ) . '</th>';
37
+ echo '<th scope="col">' . __( 'Response', 'query-monitor' ) . $this->build_filter( 'type', array_keys( $data['types'] ) ) . '</th>';
38
+ echo '<th scope="col">' . __( 'Transport', 'query-monitor' ) . '</th>';
39
+ echo '<th scope="col">' . __( 'Call Stack', 'query-monitor' ) . '</th>';
40
+ echo '<th scope="col">' . __( 'Component', 'query-monitor' ) . $this->build_filter( 'component', wp_list_pluck( $data['component_times'], 'component' ) ) . '</th>';
41
+ echo '<th scope="col" class="qm-num">' . __( 'Timeout', 'query-monitor' ) . $this->build_sorter() . '</th>';
42
+ echo '<th scope="col" class="qm-num">' . __( 'Time', 'query-monitor' ) . $this->build_sorter() . '</th>';
43
  echo '</tr>';
44
  echo '</thead>';
45
 
50
  foreach ( $data['vars'] as $key => $value ) {
51
  $vars[] = $key . ': ' . esc_html( $value );
52
  }
53
+ $vars = implode( '<br>', $vars );
54
  }
55
 
56
  if ( !empty( $data['http'] ) ) {
57
 
58
  echo '<tbody>';
59
+ $i = 0;
60
 
61
  foreach ( $data['http'] as $key => $row ) {
62
  $ltime = $row['ltime'];
63
+ $i++;
64
+
65
+ $row_attr = array();
66
 
67
  if ( empty( $ltime ) ) {
68
  $stime = '';
103
  }
104
 
105
  $stack = $row['trace']->get_stack();
106
+ $component = $row['component'];
107
+
108
+ $row_attr['data-qm-component'] = $component->name;
109
+ $row_attr['data-qm-type'] = $row['type'];
110
+
111
+ $attr = '';
112
+ foreach ( $row_attr as $a => $v ) {
113
+ $attr .= ' ' . $a . '="' . esc_attr( $v ) . '"';
114
+ }
115
 
116
  $stack = implode( '<br>', $stack );
117
  echo "
118
+ <tr{$attr} class='{$css}'>\n
119
+ <td valign='top' class='qm-num'>{$i}</td>
120
+ <td valign='top' class='qm-url qm-ltr qm-wrap'>{$method}<br>{$url}</td>\n
121
  <td valign='top'>{$response}</td>\n
122
  <td valign='top'>{$transport}</td>\n
123
+ <td valign='top' class='qm-nowrap qm-ltr'>{$stack}</td>\n
124
+ <td valign='top' class='qm-nowrap'>{$component->name}</td>\n
125
+ <td valign='top' class='qm-num'>{$row['args']['timeout']}</td>\n
126
+ <td valign='top' class='qm-num'>{$stime}</td>\n
127
  </tr>\n
128
  ";
129
  }
134
  $total_stime = number_format_i18n( $data['ltime'], 4 );
135
 
136
  echo '<tr>';
137
+ echo '<td colspan="7">' . $vars . '</td>';
138
+ echo "<td class='qm-num'>{$total_stime}</td>";
139
  echo '</tr>';
140
  echo '</tfoot>';
141
 
143
 
144
  echo '<tbody>';
145
  echo '<tr>';
146
+ echo '<td colspan="8" style="text-align:center !important"><em>' . __( 'none', 'query-monitor' ) . '</em></td>';
147
  echo '</tr>';
148
  if ( !empty( $vars ) ) {
149
  echo '<tr>';
150
+ echo '<td colspan="8">' . $vars . '</td>';
151
  echo '</tr>';
152
  }
153
  echo '</tbody>';
201
 
202
  }
203
 
204
+ function register_qm_output_html_http( array $output, QM_Collectors $collectors ) {
205
+ if ( $collector = $collectors::get( 'http' ) ) {
206
+ $output['http'] = new QM_Output_Html_HTTP( $collector );
207
+ }
208
+ return $output;
209
  }
210
 
211
+ add_filter( 'qm/outputter/html', 'register_qm_output_html_http', 90, 2 );
output/html/overview.php CHANGED
@@ -18,7 +18,7 @@ class QM_Output_Html_Overview extends QM_Output_Html {
18
 
19
  public function __construct( QM_Collector $collector ) {
20
  parent::__construct( $collector );
21
- add_filter( 'query_monitor_title', array( $this, 'admin_title' ), 10 );
22
  }
23
 
24
  public function output() {
@@ -27,10 +27,10 @@ class QM_Output_Html_Overview extends QM_Output_Html {
27
 
28
  $db_query_num = null;
29
  $db_query_types = array();
30
- # @TODO: make this less derpy:
31
- $db_queries = QueryMonitor::get_collector( 'db_queries' );
32
 
33
  if ( $db_queries ) {
 
34
  $db_queries_data = $db_queries->get_data();
35
  if ( isset( $db_queries_data['types'] ) ) {
36
  $db_query_num = $db_queries_data['types'];
@@ -111,8 +111,11 @@ class QM_Output_Html_Overview extends QM_Output_Html {
111
 
112
  }
113
 
114
- function register_qm_output_html_overview( QM_Output $output = null, QM_Collector $collector ) {
115
- return new QM_Output_Html_Overview( $collector );
 
 
 
116
  }
117
 
118
- add_filter( 'query_monitor_output_html_overview', 'register_qm_output_html_overview', 10, 2 );
18
 
19
  public function __construct( QM_Collector $collector ) {
20
  parent::__construct( $collector );
21
+ add_filter( 'qm/output/title', array( $this, 'admin_title' ), 10 );
22
  }
23
 
24
  public function output() {
27
 
28
  $db_query_num = null;
29
  $db_query_types = array();
30
+ $db_queries = QM_Collectors::get( 'db_queries' );
 
31
 
32
  if ( $db_queries ) {
33
+ # @TODO: make this less derpy:
34
  $db_queries_data = $db_queries->get_data();
35
  if ( isset( $db_queries_data['types'] ) ) {
36
  $db_query_num = $db_queries_data['types'];
111
 
112
  }
113
 
114
+ function register_qm_output_html_overview( array $output, QM_Collectors $collectors ) {
115
+ if ( $collector = $collectors::get( 'overview' ) ) {
116
+ $output['overview'] = new QM_Output_Html_Overview( $collector );
117
+ }
118
+ return $output;
119
  }
120
 
121
+ add_filter( 'qm/outputter/html', 'register_qm_output_html_overview', 10, 2 );
output/html/php_errors.php CHANGED
@@ -18,8 +18,8 @@ class QM_Output_Html_PHP_Errors extends QM_Output_Html {
18
 
19
  public function __construct( QM_Collector $collector ) {
20
  parent::__construct( $collector );
21
- add_filter( 'query_monitor_menus', array( $this, 'admin_menu' ), 10 );
22
- add_filter( 'query_monitor_class', array( $this, 'admin_class' ) );
23
  }
24
 
25
  public function output() {
@@ -35,7 +35,7 @@ class QM_Output_Html_PHP_Errors extends QM_Output_Html {
35
  echo '<thead>';
36
  echo '<tr>';
37
  echo '<th colspan="2">' . __( 'PHP Error', 'query-monitor' ) . '</th>';
38
- echo '<th>' . __( 'Count', 'query-monitor' ) . '</th>';
39
  echo '<th>' . __( 'Location', 'query-monitor' ) . '</th>';
40
  echo '<th>' . __( 'Call Stack', 'query-monitor' ) . '</th>';
41
  echo '<th>' . __( 'Component', 'query-monitor' ) . '</th>';
@@ -81,8 +81,8 @@ class QM_Output_Html_PHP_Errors extends QM_Output_Html {
81
  echo '<td>';
82
  echo self::output_filename( $output, $error->file, $error->line );
83
  echo '</td>';
84
- echo '<td class="qm-ltr">' . $stack . '</td>';
85
- echo '<td>' . $name . '</td>';
86
  echo '</tr>';
87
 
88
  $first = false;
@@ -151,8 +151,11 @@ class QM_Output_Html_PHP_Errors extends QM_Output_Html {
151
 
152
  }
153
 
154
- function register_qm_output_html_php_errors( QM_Output $output = null, QM_Collector $collector ) {
155
- return new QM_Output_Html_PHP_Errors( $collector );
 
 
 
156
  }
157
 
158
- add_filter( 'query_monitor_output_html_php_errors', 'register_qm_output_html_php_errors', 10, 2 );
18
 
19
  public function __construct( QM_Collector $collector ) {
20
  parent::__construct( $collector );
21
+ add_filter( 'qm/output/menus', array( $this, 'admin_menu' ), 10 );
22
+ add_filter( 'qm/output/menu_class', array( $this, 'admin_class' ) );
23
  }
24
 
25
  public function output() {
35
  echo '<thead>';
36
  echo '<tr>';
37
  echo '<th colspan="2">' . __( 'PHP Error', 'query-monitor' ) . '</th>';
38
+ echo '<th class="qm-num">' . __( 'Count', 'query-monitor' ) . '</th>';
39
  echo '<th>' . __( 'Location', 'query-monitor' ) . '</th>';
40
  echo '<th>' . __( 'Call Stack', 'query-monitor' ) . '</th>';
41
  echo '<th>' . __( 'Component', 'query-monitor' ) . '</th>';
81
  echo '<td>';
82
  echo self::output_filename( $output, $error->file, $error->line );
83
  echo '</td>';
84
+ echo '<td class="qm-nowrap qm-ltr">' . $stack . '</td>';
85
+ echo '<td class="qm-nowrap">' . $name . '</td>';
86
  echo '</tr>';
87
 
88
  $first = false;
151
 
152
  }
153
 
154
+ function register_qm_output_html_php_errors( array $output, QM_Collectors $collectors ) {
155
+ if ( $collector = $collectors::get( 'php_errors' ) ) {
156
+ $output['php_errors'] = new QM_Output_Html_PHP_Errors( $collector );
157
+ }
158
+ return $output;
159
  }
160
 
161
+ add_filter( 'qm/outputter/html', 'register_qm_output_html_php_errors', 110, 2 );
output/html/request.php CHANGED
@@ -18,7 +18,7 @@ class QM_Output_Html_Request extends QM_Output_Html {
18
 
19
  public function __construct( QM_Collector $collector ) {
20
  parent::__construct( $collector );
21
- add_filter( 'query_monitor_menus', array( $this, 'admin_menu' ), 50 );
22
  }
23
 
24
  public function output() {
@@ -99,6 +99,34 @@ class QM_Output_Html_Request extends QM_Output_Html {
99
 
100
  }
101
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
102
  if ( !empty( $data['queried_object'] ) ) {
103
 
104
  $vars = get_object_vars( $data['queried_object'] );
@@ -141,8 +169,11 @@ class QM_Output_Html_Request extends QM_Output_Html {
141
 
142
  }
143
 
144
- function register_qm_output_html_request( QM_Output $output = null, QM_Collector $collector ) {
145
- return new QM_Output_Html_Request( $collector );
 
 
 
146
  }
147
 
148
- add_filter( 'query_monitor_output_html_request', 'register_qm_output_html_request', 10, 2 );
18
 
19
  public function __construct( QM_Collector $collector ) {
20
  parent::__construct( $collector );
21
+ add_filter( 'qm/output/menus', array( $this, 'admin_menu' ), 50 );
22
  }
23
 
24
  public function output() {
99
 
100
  }
101
 
102
+ if ( !empty( $data['multisite'] ) ) {
103
+
104
+ $rowspan = count( $data['multisite'] );
105
+
106
+ echo '<tr>';
107
+ echo '<td rowspan="' . $rowspan . '">' . __( 'Multisite', 'query-monitor' ) . '</td>';
108
+
109
+ $first = true;
110
+
111
+ foreach( $data['multisite'] as $var => $value ) {
112
+
113
+ if ( !$first ) {
114
+ echo '<tr>';
115
+ }
116
+
117
+ echo "<td valign='top'>{$var}</td>";
118
+
119
+ echo '<td valign="top"><pre>';
120
+ print_r( $value );
121
+ echo '</pre></td>';
122
+
123
+ echo '</tr>';
124
+
125
+ $first = false;
126
+
127
+ }
128
+ }
129
+
130
  if ( !empty( $data['queried_object'] ) ) {
131
 
132
  $vars = get_object_vars( $data['queried_object'] );
169
 
170
  }
171
 
172
+ function register_qm_output_html_request( array $output, QM_Collectors $collectors ) {
173
+ if ( $collector = $collectors::get( 'request' ) ) {
174
+ $output['request'] = new QM_Output_Html_Request( $collector );
175
+ }
176
+ return $output;
177
  }
178
 
179
+ add_filter( 'qm/outputter/html', 'register_qm_output_html_request', 60, 2 );
output/html/theme.php CHANGED
@@ -18,38 +18,48 @@ class QM_Output_Html_Theme extends QM_Output_Html {
18
 
19
  public function __construct( QM_Collector $collector ) {
20
  parent::__construct( $collector );
21
- add_filter( 'query_monitor_menus', array( $this, 'admin_menu' ), 60 );
22
  }
23
 
24
  public function output() {
25
 
26
  $data = $this->collector->get_data();
27
 
28
- if ( empty( $data ) ) {
29
  return;
30
  }
31
 
 
 
32
  echo '<div class="qm qm-half" id="' . esc_attr( $this->collector->id() ) . '">';
33
  echo '<table cellspacing="0">';
34
  echo '<tbody>';
35
 
36
  echo '<tr>';
37
- echo '<td>' . __( 'Theme', 'query-monitor' ) . '</td>';
 
 
 
 
 
 
 
 
 
 
 
 
 
38
  echo '<td>' . esc_html( $data['stylesheet'] ) . '</td>';
39
  echo '</tr>';
40
 
41
- if ( $data['stylesheet'] != $data['template'] ) {
42
  echo '<tr>';
43
  echo '<td>' . __( 'Parent Theme', 'query-monitor' ) . '</td>';
44
  echo '<td>' . esc_html( $data['template'] ) . '</td>';
45
  echo '</tr>';
46
  }
47
 
48
- echo '<tr>';
49
- echo '<td>' . __( 'Template File', 'query-monitor' ) . '</td>';
50
- echo '<td>' . self::output_filename( $data['template_file'], $data['template_path'] ) . '</td>';
51
- echo '</tr>';
52
-
53
  if ( !empty( $data['body_class'] ) ) {
54
 
55
  echo '<tr>';
@@ -92,8 +102,11 @@ class QM_Output_Html_Theme extends QM_Output_Html {
92
 
93
  }
94
 
95
- function register_qm_output_html_theme( QM_Output $output = null, QM_Collector $collector ) {
96
- return new QM_Output_Html_Theme( $collector );
 
 
 
97
  }
98
 
99
- add_filter( 'query_monitor_output_html_theme', 'register_qm_output_html_theme', 10, 2 );
18
 
19
  public function __construct( QM_Collector $collector ) {
20
  parent::__construct( $collector );
21
+ add_filter( 'qm/output/menus', array( $this, 'admin_menu' ), 60 );
22
  }
23
 
24
  public function output() {
25
 
26
  $data = $this->collector->get_data();
27
 
28
+ if ( empty( $data['stylesheet'] ) ) {
29
  return;
30
  }
31
 
32
+ $child_theme = ( $data['stylesheet'] != $data['template'] );
33
+
34
  echo '<div class="qm qm-half" id="' . esc_attr( $this->collector->id() ) . '">';
35
  echo '<table cellspacing="0">';
36
  echo '<tbody>';
37
 
38
  echo '<tr>';
39
+ echo '<td>' . __( 'Template File', 'query-monitor' ) . '</td>';
40
+ if ( $child_theme ) {
41
+ echo '<td>' . self::output_filename( $data['theme_template'], $data['template_path'] ) . '</td>';
42
+ } else {
43
+ echo '<td>' . self::output_filename( $data['template_file'], $data['template_path'] ) . '</td>';
44
+ }
45
+ echo '</tr>';
46
+
47
+ echo '<tr>';
48
+ if ( $child_theme ) {
49
+ echo '<td>' . __( 'Child Theme', 'query-monitor' ) . '</td>';
50
+ } else {
51
+ echo '<td>' . __( 'Theme', 'query-monitor' ) . '</td>';
52
+ }
53
  echo '<td>' . esc_html( $data['stylesheet'] ) . '</td>';
54
  echo '</tr>';
55
 
56
+ if ( $child_theme ) {
57
  echo '<tr>';
58
  echo '<td>' . __( 'Parent Theme', 'query-monitor' ) . '</td>';
59
  echo '<td>' . esc_html( $data['template'] ) . '</td>';
60
  echo '</tr>';
61
  }
62
 
 
 
 
 
 
63
  if ( !empty( $data['body_class'] ) ) {
64
 
65
  echo '<tr>';
102
 
103
  }
104
 
105
+ function register_qm_output_html_theme( array $output, QM_Collectors $collectors ) {
106
+ if ( $collector = $collectors::get( 'theme' ) ) {
107
+ $output['theme'] = new QM_Output_Html_Theme( $collector );
108
+ }
109
+ return $output;
110
  }
111
 
112
+ add_filter( 'qm/outputter/html', 'register_qm_output_html_theme', 70, 2 );
output/html/transients.php CHANGED
@@ -18,7 +18,7 @@ class QM_Output_Html_Transients extends QM_Output_Html {
18
 
19
  public function __construct( QM_Collector $collector ) {
20
  parent::__construct( $collector );
21
- add_filter( 'query_monitor_menus', array( $this, 'admin_menu' ), 80 );
22
  }
23
 
24
  public function output() {
@@ -65,8 +65,8 @@ class QM_Output_Html_Transients extends QM_Output_Html {
65
  <td valign='top'>{$transient}</td>\n
66
  {$type}
67
  {$expiration}
68
- <td valign='top' class='qm-ltr'>{$stack}</td>\n
69
- <td valign='top'>{$component->name}</td>\n
70
  </tr>\n
71
  ";
72
  }
@@ -106,8 +106,11 @@ class QM_Output_Html_Transients extends QM_Output_Html {
106
 
107
  }
108
 
109
- function register_qm_output_html_transients( QM_Output $output = null, QM_Collector $collector ) {
110
- return new QM_Output_Html_Transients( $collector );
 
 
 
111
  }
112
 
113
- add_filter( 'query_monitor_output_html_transients', 'register_qm_output_html_transients', 10, 2 );
18
 
19
  public function __construct( QM_Collector $collector ) {
20
  parent::__construct( $collector );
21
+ add_filter( 'qm/output/menus', array( $this, 'admin_menu' ), 100 );
22
  }
23
 
24
  public function output() {
65
  <td valign='top'>{$transient}</td>\n
66
  {$type}
67
  {$expiration}
68
+ <td valign='top' class='qm-nowrap qm-ltr'>{$stack}</td>\n
69
+ <td valign='top' class='qm-nowrap'>{$component->name}</td>\n
70
  </tr>\n
71
  ";
72
  }
106
 
107
  }
108
 
109
+ function register_qm_output_html_transients( array $output, QM_Collectors $collectors ) {
110
+ if ( $collector = $collectors::get( 'transients' ) ) {
111
+ $output['transients'] = new QM_Output_Html_Transients( $collector );
112
+ }
113
+ return $output;
114
  }
115
 
116
+ add_filter( 'qm/outputter/html', 'register_qm_output_html_transients', 100, 2 );
query-monitor.php CHANGED
@@ -2,7 +2,7 @@
2
  /*
3
  Plugin Name: Query Monitor
4
  Description: Monitoring of database queries, hooks, conditionals and more.
5
- Version: 2.6.10
6
  Plugin URI: https://querymonitor.com/
7
  Author: John Blackbourn
8
  Author URI: https://johnblackbourn.com/
@@ -32,15 +32,12 @@ if ( defined( 'QM_DISABLED' ) and QM_DISABLED ) {
32
 
33
  # No autoloaders for us. See https://github.com/johnbillion/QueryMonitor/issues/7
34
  $qm_dir = dirname( __FILE__ );
35
- foreach ( array( 'Backtrace', 'Collector', 'Plugin', 'Util', 'Dispatcher', 'Output' ) as $qm_class ) {
36
- require_once "{$qm_dir}/{$qm_class}.php";
37
  }
38
 
39
  class QueryMonitor extends QM_Plugin {
40
 
41
- protected $collectors = array();
42
- protected $dispatchers = array();
43
-
44
  protected function __construct( $file ) {
45
 
46
  # Actions
@@ -59,50 +56,28 @@ class QueryMonitor extends QM_Plugin {
59
  # Parent setup:
60
  parent::__construct( $file );
61
 
62
- # Collectors:
63
  QM_Util::include_files( $this->plugin_path( 'collectors' ) );
64
 
65
- foreach ( apply_filters( 'query_monitor_collectors', array() ) as $collector ) {
66
- $this->add_collector( $collector );
67
- }
68
-
69
  }
70
 
71
  public function action_plugins_loaded() {
72
 
 
 
 
 
 
73
  # Dispatchers:
74
  QM_Util::include_files( $this->plugin_path( 'dispatchers' ) );
75
 
76
- foreach ( apply_filters( 'query_monitor_dispatchers', array(), $this ) as $dispatcher ) {
77
- $this->add_dispatcher( $dispatcher );
 
78
  }
79
 
80
  }
81
 
82
- public function add_collector( QM_Collector $collector ) {
83
- $this->collectors[$collector->id] = $collector;
84
- }
85
-
86
- public function add_dispatcher( QM_Dispatcher $dispatcher ) {
87
- $this->dispatchers[$dispatcher->id] = $dispatcher;
88
- }
89
-
90
- public static function get_collector( $id ) {
91
- $qm = self::init();
92
- if ( isset( $qm->collectors[$id] ) ) {
93
- return $qm->collectors[$id];
94
- }
95
- return false;
96
- }
97
-
98
- public function get_collectors() {
99
- return $this->collectors;
100
- }
101
-
102
- public function get_dispatchers() {
103
- return $this->dispatchers;
104
- }
105
-
106
  public function activate( $sitewide = false ) {
107
 
108
  if ( $admins = QM_Util::get_admins() ) {
@@ -128,7 +103,7 @@ class QueryMonitor extends QM_Plugin {
128
  }
129
 
130
  # Only delete db.php if it belongs to Query Monitor
131
- if ( class_exists( 'QueryMonitorDB' ) ) {
132
  unlink( WP_CONTENT_DIR . '/db.php' );
133
  }
134
 
@@ -136,6 +111,8 @@ class QueryMonitor extends QM_Plugin {
136
 
137
  public function should_process() {
138
 
 
 
139
  # Don't process if the minimum required actions haven't fired:
140
 
141
  if ( is_admin() ) {
@@ -158,8 +135,15 @@ class QueryMonitor extends QM_Plugin {
158
  if ( ! empty( $e ) and ( $e['type'] & ( E_ERROR | E_USER_ERROR | E_RECOVERABLE_ERROR ) ) ) {
159
  return false;
160
  }
 
 
 
 
 
 
 
161
 
162
- foreach ( $this->get_dispatchers() as $dispatcher ) {
163
 
164
  # At least one dispatcher is active, so we need to process:
165
  if ( $dispatcher->is_active() ) {
@@ -174,16 +158,22 @@ class QueryMonitor extends QM_Plugin {
174
 
175
  public function action_shutdown() {
176
 
 
 
 
177
  if ( ! $this->should_process() ) {
178
  return;
179
  }
180
 
181
- foreach ( $this->get_collectors() as $collector ) {
 
 
 
182
  $collector->tear_down();
183
  $collector->process();
184
  }
185
 
186
- foreach ( $this->get_dispatchers() as $dispatcher ) {
187
 
188
  if ( ! $dispatcher->is_active() ) {
189
  continue;
@@ -191,8 +181,10 @@ class QueryMonitor extends QM_Plugin {
191
 
192
  $dispatcher->before_output();
193
 
194
- foreach ( $this->get_collectors() as $collector ) {
195
- $dispatcher->output( $collector );
 
 
196
  }
197
 
198
  $dispatcher->after_output();
@@ -205,7 +197,9 @@ class QueryMonitor extends QM_Plugin {
205
 
206
  load_plugin_textdomain( 'query-monitor', false, dirname( $this->plugin_base() ) . '/languages' );
207
 
208
- foreach ( $this->get_dispatchers() as $dispatcher ) {
 
 
209
  $dispatcher->init();
210
  }
211
 
2
  /*
3
  Plugin Name: Query Monitor
4
  Description: Monitoring of database queries, hooks, conditionals and more.
5
+ Version: 2.7.0
6
  Plugin URI: https://querymonitor.com/
7
  Author: John Blackbourn
8
  Author URI: https://johnblackbourn.com/
32
 
33
  # No autoloaders for us. See https://github.com/johnbillion/QueryMonitor/issues/7
34
  $qm_dir = dirname( __FILE__ );
35
+ foreach ( array( 'Backtrace', 'Collectors', 'Collector', 'Plugin', 'Util', 'Dispatchers', 'Dispatcher', 'Output' ) as $qm_class ) {
36
+ require_once "{$qm_dir}/classes/{$qm_class}.php";
37
  }
38
 
39
  class QueryMonitor extends QM_Plugin {
40
 
 
 
 
41
  protected function __construct( $file ) {
42
 
43
  # Actions
56
  # Parent setup:
57
  parent::__construct( $file );
58
 
59
+ # Load and register built-in collectors:
60
  QM_Util::include_files( $this->plugin_path( 'collectors' ) );
61
 
 
 
 
 
62
  }
63
 
64
  public function action_plugins_loaded() {
65
 
66
+ # Register additional collectors:
67
+ foreach ( apply_filters( 'qm/collectors', array(), $this ) as $collector ) {
68
+ QM_Collectors::add( $collector );
69
+ }
70
+
71
  # Dispatchers:
72
  QM_Util::include_files( $this->plugin_path( 'dispatchers' ) );
73
 
74
+ # Register built-in and additional dispatchers:
75
+ foreach ( apply_filters( 'qm/dispatchers', array(), $this ) as $dispatcher ) {
76
+ QM_Dispatchers::add( $dispatcher );
77
  }
78
 
79
  }
80
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
81
  public function activate( $sitewide = false ) {
82
 
83
  if ( $admins = QM_Util::get_admins() ) {
103
  }
104
 
105
  # Only delete db.php if it belongs to Query Monitor
106
+ if ( class_exists( 'QM_DB' ) ) {
107
  unlink( WP_CONTENT_DIR . '/db.php' );
108
  }
109
 
111
 
112
  public function should_process() {
113
 
114
+ # @TODO this decision should be moved to each dispatcher
115
+
116
  # Don't process if the minimum required actions haven't fired:
117
 
118
  if ( is_admin() ) {
135
  if ( ! empty( $e ) and ( $e['type'] & ( E_ERROR | E_USER_ERROR | E_RECOVERABLE_ERROR ) ) ) {
136
  return false;
137
  }
138
+
139
+ # Allow users to disable the processing and output
140
+ if ( ! apply_filters( 'qm/process', true, is_admin_bar_showing() ) ) {
141
+ return false;
142
+ }
143
+
144
+ $dispatchers = QM_Dispatchers::init();
145
 
146
+ foreach ( $dispatchers as $dispatcher ) {
147
 
148
  # At least one dispatcher is active, so we need to process:
149
  if ( $dispatcher->is_active() ) {
158
 
159
  public function action_shutdown() {
160
 
161
+ # @TODO this should move to each dispatcher so it can decide when it wants to do its output
162
+ # eg. the JSON dispatcher needs to output inside the 'json_post_dispatch' filter, not on shutdown
163
+
164
  if ( ! $this->should_process() ) {
165
  return;
166
  }
167
 
168
+ $collectors = QM_Collectors::init();
169
+ $dispatchers = QM_Dispatchers::init();
170
+
171
+ foreach ( $collectors as $collector ) {
172
  $collector->tear_down();
173
  $collector->process();
174
  }
175
 
176
+ foreach ( $dispatchers as $dispatcher ) {
177
 
178
  if ( ! $dispatcher->is_active() ) {
179
  continue;
181
 
182
  $dispatcher->before_output();
183
 
184
+ $outputters = apply_filters( "qm/outputter/{$dispatcher->id}", array(), $collectors );
185
+
186
+ foreach ( $outputters as $outputter ) {
187
+ $outputter->output();
188
  }
189
 
190
  $dispatcher->after_output();
197
 
198
  load_plugin_textdomain( 'query-monitor', false, dirname( $this->plugin_base() ) . '/languages' );
199
 
200
+ $dispatchers = QM_Dispatchers::init();
201
+
202
+ foreach ( $dispatchers as $dispatcher ) {
203
  $dispatcher->init();
204
  }
205
 
readme.txt CHANGED
@@ -1,9 +1,9 @@
1
  === Query Monitor ===
2
  Contributors: johnbillion
3
- Tags: debug, debugging, development, developer, performance, profiler, profiling, queries, query monitor
4
  Requires at least: 3.5
5
- Tested up to: 4.1
6
- Stable tag: 2.6.10
7
  License: GPLv2 or later
8
 
9
  View debugging and performance information on database queries, hooks, conditionals, HTTP requests, redirects and more.
@@ -31,7 +31,7 @@ Filtering queries by component or calling function makes it easy to see which pl
31
 
32
  = Hooks =
33
 
34
- * Shows all hooks fired on the current page, along with hooked actions and their priorities
35
  * Filter hooks by **part of their name**
36
  * Filter actions by **component** (WordPress core, Plugin X, Plugin Y, theme)
37
 
@@ -51,6 +51,12 @@ Filtering queries by component or calling function makes it easy to see which pl
51
  * Shows **matched rewrite rules** and associated query strings
52
  * Shows **query vars** for the current request, and highlights **custom query vars**
53
  * Shows the **queried object** details (collapsed by default)
 
 
 
 
 
 
54
 
55
  = HTTP Requests =
56
 
@@ -89,7 +95,7 @@ Hands up who can remember the correct names for the filters and actions for cust
89
  * Shows any **transients that were set**, along with their timeout, component, and call stack
90
  * Shows all **WordPress conditionals** on the current page, highlighted nicely
91
  * Shows an overview including page generation time and memory limit as absolute values and as % of their respective limits
92
- * Shows all *scripts and styles* which were enqueued on the current page, along with their path, dependencies, and version number
93
 
94
  = Authentication =
95
 
@@ -136,7 +142,9 @@ On pages that have an especially high number of database queries (in the hundred
136
 
137
  = Are there any add-on plugins for Query Monitor? =
138
 
139
- Yep, the first one was released recently: [Query Monitor bbPress & BuddyPress Conditionals](https://wordpress.org/plugins/query-monitor-bbpress-buddypress-conditionals/) by Stephen Edgar.
 
 
140
 
141
  = Where can I suggest a new feature or report a bug? =
142
 
@@ -146,20 +154,31 @@ Please use [the issue tracker on Query Monitor's GitHub repo](https://github.com
146
 
147
  No, I do not accept donations. If you like the plugin, I'd love for you to [leave a review](https://wordpress.org/support/view/plugin-reviews/query-monitor). Tell all your friends about the plugin too!
148
 
149
- == Upgrade Notice ==
150
-
151
- = 2.6.10 =
152
- * Fix some PHP 5.2 compatibility issues introduced in 2.6.9; More tweaks to the CSS so QM avoids being covered up by the admin menu.
153
-
154
  == Changelog ==
155
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
156
  = 2.6.10 =
157
  * Add compatibility with PHP <5.3.6. `DirectoryIterator::getExtension()` isn't available on this version (and also as it's part of SPL it can be disabled).
158
  * Simplify the admin CSS to avoid QM's output being covered by the admin menu.
159
  * Add support for footer styles in the scripts and styles component.
160
  * Update the authentication JavaScript so it works cross-protocol.
161
  * Add support for footer styles in the scripts and styles component.
162
- * Update the authentication JavaScript so it works cross-protocol.
163
 
164
  = 2.6.9 =
165
  * New Scripts & Styles component
1
  === Query Monitor ===
2
  Contributors: johnbillion
3
+ Tags: debug, debug-bar, debugging, development, developer, performance, profiler, profiling, queries, query monitor
4
  Requires at least: 3.5
5
+ Tested up to: 4.1.1
6
+ Stable tag: 2.7.0
7
  License: GPLv2 or later
8
 
9
  View debugging and performance information on database queries, hooks, conditionals, HTTP requests, redirects and more.
31
 
32
  = Hooks =
33
 
34
+ * Shows all hooks fired on the current page, along with hooked actions, their priorities, and their components
35
  * Filter hooks by **part of their name**
36
  * Filter actions by **component** (WordPress core, Plugin X, Plugin Y, theme)
37
 
51
  * Shows **matched rewrite rules** and associated query strings
52
  * Shows **query vars** for the current request, and highlights **custom query vars**
53
  * Shows the **queried object** details (collapsed by default)
54
+ * Shows details of the **current blog** (multisite only) and **current site** (multi-network only)
55
+
56
+ = Scripts & Styles =
57
+
58
+ * Shows all **enqueued scripts and styles** on the current page, along with their URL and version
59
+ * Shows their **dependencies and dependents**, and alerts you to any **broken dependencies**
60
 
61
  = HTTP Requests =
62
 
95
  * Shows any **transients that were set**, along with their timeout, component, and call stack
96
  * Shows all **WordPress conditionals** on the current page, highlighted nicely
97
  * Shows an overview including page generation time and memory limit as absolute values and as % of their respective limits
98
+ * Shows all *scripts and styles* which were enqueued on the current page, along with their URL, dependencies, dependents, and version number
99
 
100
  = Authentication =
101
 
142
 
143
  = Are there any add-on plugins for Query Monitor? =
144
 
145
+ Query Monitor transparently supports add-ons for the Debug Bar plugin. If you have any Debug Bar add-ons installed, just deactivate Debug Bar and the add-ons will show up in Query Monitor's menu.
146
+
147
+ There's also [Query Monitor bbPress & BuddyPress Conditionals](https://wordpress.org/plugins/query-monitor-bbpress-buddypress-conditionals/) by Stephen Edgar.
148
 
149
  = Where can I suggest a new feature or report a bug? =
150
 
154
 
155
  No, I do not accept donations. If you like the plugin, I'd love for you to [leave a review](https://wordpress.org/support/view/plugin-reviews/query-monitor). Tell all your friends about the plugin too!
156
 
 
 
 
 
 
157
  == Changelog ==
158
 
159
+ = 2.7.0 =
160
+ * Detect broken dependencies for scripts and styles.
161
+ * Calculate and output the dependents of scripts and styles.
162
+ * Add transparent support for Debug Bar add-on panels.
163
+ * Add support for WordPress.com VIP plugins in the component detection.
164
+ * Sortable and filterable columns for HTTP requests.
165
+ * Display a warning when something's hooked onto the `all` action.
166
+ * Clearer output for the template file and component names when a child theme is in use.
167
+ * Move the current blog information to the Request component. Display current site information if we're running a multi-network.
168
+ * Allow default error handlers, such as error logging, to continue to function as expected.
169
+ * Don't skip outputting the calling function name in the database error list.
170
+ * New namespaced filter names for a bunch of filterable things.
171
+ * Add a `qm/process` filter to allow users to disable QM's processing and output.
172
+ * Display the value of `WP_HTTP_BLOCK_EXTERNAL` and `WP_ACCESSIBLE_HOSTS` in the HTTP component.
173
+ * New storage and registration mechanisms for collectors, dispatchers, and output handlers.
174
+ * CSS tweaks to better match wp-admin styles.
175
+
176
  = 2.6.10 =
177
  * Add compatibility with PHP <5.3.6. `DirectoryIterator::getExtension()` isn't available on this version (and also as it's part of SPL it can be disabled).
178
  * Simplify the admin CSS to avoid QM's output being covered by the admin menu.
179
  * Add support for footer styles in the scripts and styles component.
180
  * Update the authentication JavaScript so it works cross-protocol.
181
  * Add support for footer styles in the scripts and styles component.
 
182
 
183
  = 2.6.9 =
184
  * New Scripts & Styles component
wp-content/db.php CHANGED
@@ -31,18 +31,16 @@ if ( defined( 'QM_DISABLED' ) and QM_DISABLED ) {
31
 
32
  # No autoloaders for us. See https://github.com/johnbillion/QueryMonitor/issues/7
33
  $qm_dir = dirname( dirname( __FILE__ ) );
34
- foreach ( array( 'Backtrace', 'Collector', 'Plugin', 'Util' ) as $qm_class ) {
35
- if ( ! is_readable( $qm_file = "{$qm_dir}/{$qm_class}.php" ) ) {
36
- return;
37
- }
38
- require_once $qm_file;
39
  }
 
40
 
41
  if ( !defined( 'SAVEQUERIES' ) ) {
42
  define( 'SAVEQUERIES', true );
43
  }
44
 
45
- class QueryMonitorDB extends wpdb {
46
 
47
  public $qm_php_vars = array(
48
  'max_execution_time' => null,
@@ -105,4 +103,4 @@ class QueryMonitorDB extends wpdb {
105
 
106
  }
107
 
108
- $wpdb = new QueryMonitorDB( DB_USER, DB_PASSWORD, DB_NAME, DB_HOST );
31
 
32
  # No autoloaders for us. See https://github.com/johnbillion/QueryMonitor/issues/7
33
  $qm_dir = dirname( dirname( __FILE__ ) );
34
+ if ( ! is_readable( $backtrace = "{$qm_dir}/classes/Backtrace.php" ) ) {
35
+ return;
 
 
 
36
  }
37
+ require_once $backtrace;
38
 
39
  if ( !defined( 'SAVEQUERIES' ) ) {
40
  define( 'SAVEQUERIES', true );
41
  }
42
 
43
+ class QM_DB extends wpdb {
44
 
45
  public $qm_php_vars = array(
46
  'max_execution_time' => null,
103
 
104
  }
105
 
106
+ $wpdb = new QM_DB( DB_USER, DB_PASSWORD, DB_NAME, DB_HOST );