Query Monitor - Version 2.6

Version Description

  • Toggleable stack traces for queries
  • Show deprecated errors in the PHP Errors panel
  • Replace the Query Vars panel with a Request panel with more information
  • Display a warning when db.php isn't in place
  • Fix some PHP 5.2 compatibility
  • Considerable restructuring of the underlying code to increase abstraction
Download this release

Release Info

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

Code changes from version 2.5.6 to 2.6

Files changed (58) hide show
  1. Component.php → Collector.php +3 -5
  2. Dispatcher.php +54 -0
  3. Output.php +25 -0
  4. Plugin.php +1 -1
  5. Util.php +14 -1
  6. assets/query-monitor.css +35 -12
  7. assets/query-monitor.js +12 -1
  8. collectors/admin.php +61 -0
  9. collectors/authentication.php +70 -0
  10. collectors/conditionals.php +71 -0
  11. collectors/db_callers.php +49 -0
  12. collectors/db_components.php +49 -0
  13. collectors/db_queries.php +229 -0
  14. collectors/environment.php +203 -0
  15. collectors/hooks.php +101 -0
  16. collectors/http.php +106 -0
  17. collectors/overview.php +56 -0
  18. collectors/php_errors.php +123 -0
  19. {components → collectors}/redirects.php +11 -9
  20. collectors/request.php +123 -0
  21. collectors/theme.php +63 -0
  22. collectors/transients.php +60 -0
  23. components/conditionals.php +0 -126
  24. components/environment.php +0 -371
  25. components/php_errors.php +0 -253
  26. components/query_vars.php +0 -126
  27. components/theme.php +0 -128
  28. composer.json +1 -1
  29. dispatchers/Headers.php +77 -0
  30. dispatchers/Html.php +176 -0
  31. autoloader.php → output/Headers.php +12 -14
  32. output/Html.php +89 -0
  33. output/headers/php_errors.php +71 -0
  34. output/headers/redirects.php +46 -0
  35. {components → output/html}/admin.php +21 -48
  36. {components → output/html}/authentication.php +10 -50
  37. output/html/conditionals.php +94 -0
  38. {components → output/html}/db_callers.php +28 -34
  39. {components → output/html}/db_components.php +29 -35
  40. {components → output/html}/db_queries.php +105 -270
  41. output/html/environment.php +208 -0
  42. {components → output/html}/hooks.php +31 -84
  43. {components → output/html}/http.php +51 -125
  44. {components → output/html}/overview.php +40 -50
  45. output/html/php_errors.php +155 -0
  46. output/html/request.php +133 -0
  47. output/html/theme.php +103 -0
  48. {components → output/html}/transients.php +14 -38
  49. query-monitor.php +67 -165
  50. readme.txt +21 -3
  51. screenshot-1.png +0 -0
  52. screenshot-2.png +0 -0
  53. screenshot-3.png +0 -0
  54. screenshot-4.png +0 -0
  55. screenshot-5.png +0 -0
  56. screenshot-6.png +0 -0
  57. screenshot-7.png +0 -0
  58. wp-content/db.php +1 -1
Component.php → Collector.php RENAMED
@@ -14,7 +14,7 @@ GNU General Public License for more details.
14
 
15
  */
16
 
17
- abstract class QM_Component {
18
 
19
  protected $data = array();
20
 
@@ -33,10 +33,8 @@ abstract class QM_Component {
33
 
34
  }
35
 
36
- final protected function get_component( $id ) {
37
- # @TODO use singleton?
38
- global $querymonitor;
39
- return $querymonitor->get_component( $id );
40
  }
41
 
42
  protected function build_filter( $name, array $values ) {
14
 
15
  */
16
 
17
+ abstract class QM_Collector {
18
 
19
  protected $data = array();
20
 
33
 
34
  }
35
 
36
+ public function name() {
37
+ return null;
 
 
38
  }
39
 
40
  protected function build_filter( $name, array $values ) {
Dispatcher.php ADDED
@@ -0,0 +1,54 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+
4
+ Copyright 2013 John Blackbourn
5
+
6
+ This program is free software; you can redistribute it and/or modify
7
+ it under the terms of the GNU General Public License as published by
8
+ the Free Software Foundation; either version 2 of the License, or
9
+ (at your option) any later version.
10
+
11
+ This program is distributed in the hope that it will be useful,
12
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
+ GNU General Public License for more details.
15
+
16
+ */
17
+
18
+ abstract class QM_Dispatcher {
19
+
20
+ public function __construct( QM_Plugin $qm ) {
21
+ $this->qm = $qm;
22
+ }
23
+
24
+ abstract public function active();
25
+
26
+ public function init() {
27
+ // nothing
28
+ }
29
+
30
+ public function before_output() {
31
+ // nothing
32
+ }
33
+
34
+ public function after_output() {
35
+ // nothing
36
+ }
37
+
38
+ abstract public function get_outputter( QM_Collector $collector );
39
+
40
+ public function output( QM_Collector $collector ) {
41
+
42
+ $filter = 'query_monitor_output_' . $this->id . '_' . $collector->id;
43
+
44
+ $output = apply_filters( $filter, null, $collector );
45
+
46
+ if ( !is_a( $output, 'QM_Output' ) ) {
47
+ $output = $this->get_outputter( $collector );
48
+ }
49
+
50
+ $output->output();
51
+
52
+ }
53
+
54
+ }
Output.php ADDED
@@ -0,0 +1,25 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ Copyright 2013 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
+ interface QM_Output {
18
+
19
+ public function __construct( QM_Collector $collector );
20
+
21
+ public function output();
22
+
23
+ public function get_type();
24
+
25
+ }
Plugin.php CHANGED
@@ -21,7 +21,7 @@ abstract class QM_Plugin {
21
  *
22
  * @author John Blackbourn
23
  **/
24
- public function __construct( $file ) {
25
  $this->file = $file;
26
  }
27
 
21
  *
22
  * @author John Blackbourn
23
  **/
24
+ protected function __construct( $file ) {
25
  $this->file = $file;
26
  }
27
 
Util.php CHANGED
@@ -1,7 +1,7 @@
1
  <?php
2
  /*
3
 
4
- © 2013 John Blackbourn
5
 
6
  This program is free software; you can redistribute it and/or modify
7
  it under the terms of the GNU General Public License as published by
@@ -242,4 +242,17 @@ class QM_Util {
242
  return 'true';
243
  }
244
 
 
 
 
 
 
 
 
 
 
 
 
 
 
245
  }
1
  <?php
2
  /*
3
 
4
+ Copyright 2013 John Blackbourn
5
 
6
  This program is free software; you can redistribute it and/or modify
7
  it under the terms of the GNU General Public License as published by
242
  return 'true';
243
  }
244
 
245
+ public static function format_url( $url ) {
246
+ $url = str_replace( array(
247
+ '=',
248
+ '&',
249
+ '?',
250
+ ), array(
251
+ '<span class="qm-equals">=</span>',
252
+ '<br /><span class="qm-param">&amp;</span>',
253
+ '<br /><span class="qm-param">?</span>',
254
+ ), $url );
255
+ return $url;
256
+ }
257
+
258
  }
assets/query-monitor.css CHANGED
@@ -1,6 +1,6 @@
1
  /*
2
 
3
- © 2013 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
@@ -34,16 +34,20 @@ body:not(.mp6) #wpadminbar .quicklinks .menupop.qm-wp-37 ul li.qm-true > a {
34
  background-color: #740;
35
  }
36
 
 
37
  #wp-admin-bar-query-monitor-stricts {
38
  background-color: #555 !important;
39
  }
 
40
  body:not(.mp6) .qm-wp-37 #wp-admin-bar-query-monitor-stricts {
41
  background-color: #eee !important;
42
  }
43
 
 
44
  #wpadminbar .qm-strict {
45
  background-color: #3c3c3c;
46
  }
 
47
  body:not(.mp6) #wpadminbar .qm-wp-37 .qm-strict {
48
  background-color: #000;
49
  }
@@ -80,6 +84,7 @@ body:not(.mp6) #wpadminbar .qm-wp-37 .qm-strict {
80
  color: #fff !important;
81
  }
82
 
 
83
  #wp-admin-bar-query-monitor-stricts a,
84
  #wp-admin-bar-query-monitor-notices a,
85
  #wp-admin-bar-query-monitor-expensive a,
@@ -88,6 +93,7 @@ body:not(.mp6) #wpadminbar .qm-wp-37 .qm-strict {
88
  color: #eee !important;
89
  }
90
 
 
91
  body:not(.mp6) .qm-wp-37 #wp-admin-bar-query-monitor-stricts a {
92
  color: #555 !important;
93
  }
@@ -176,11 +182,11 @@ body.wp-admin #qm {
176
  margin: 0 !important;
177
  }
178
 
179
- body.sticky-menu #qm {
180
  margin-left: 150px !important;
181
  }
182
 
183
- body.sticky-menu.folded #qm {
184
  margin-left: 36px !important;
185
  }
186
 
@@ -306,20 +312,25 @@ body.sticky-menu.folded #qm {
306
  color: #a0a !important;
307
  }
308
 
309
- .qm .qm-url span {
310
- color: #ccc !important;
311
- }
312
-
313
  .qm .qm-info {
314
  color: #999 !important;
315
  }
316
 
 
 
 
 
 
 
 
 
317
  .qm a {
318
  color: #0074a2 !important;
319
  text-decoration: none !important;
320
  text-shadow: none !important;
321
  font-weight: normal !important;
322
  }
 
323
  .qm a:hover {
324
  text-decoration: underline !important;
325
  color: #2ea2cc !important;
@@ -329,6 +340,22 @@ body.sticky-menu.folded #qm {
329
  text-decoration: underline !important;
330
  }
331
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
332
  .qm .qm-warn,
333
  .qm .qm-warn span.qm-na {
334
  color: #f00 !important;
@@ -348,10 +375,6 @@ body.sticky-menu.folded #qm {
348
  padding: 1px 1.5em 1px 0 !important;
349
  }
350
 
351
- .qm-param {
352
- padding: 0 6px !important;
353
- }
354
-
355
  /* Filters */
356
 
357
  select.qm-filter {
@@ -399,7 +422,7 @@ html[dir="rtl"] .qm td.qm-var {
399
  text-align: left !important;
400
  }
401
 
402
- html[dir="rtl"] body.sticky-menu #qm {
403
  margin-right: 150px !important;
404
  margin-left: 0 !important;
405
  }
1
  /*
2
 
3
+ Copyright 2013 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
34
  background-color: #740;
35
  }
36
 
37
+ #wp-admin-bar-query-monitor-deprecated,
38
  #wp-admin-bar-query-monitor-stricts {
39
  background-color: #555 !important;
40
  }
41
+ body:not(.mp6) .qm-wp-37 #wp-admin-bar-query-monitor-deprecated,
42
  body:not(.mp6) .qm-wp-37 #wp-admin-bar-query-monitor-stricts {
43
  background-color: #eee !important;
44
  }
45
 
46
+ #wpadminbar .qm-deprecated,
47
  #wpadminbar .qm-strict {
48
  background-color: #3c3c3c;
49
  }
50
+ body:not(.mp6) #wpadminbar .qm-wp-37 .qm-deprecated,
51
  body:not(.mp6) #wpadminbar .qm-wp-37 .qm-strict {
52
  background-color: #000;
53
  }
84
  color: #fff !important;
85
  }
86
 
87
+ #wp-admin-bar-query-monitor-deprecated a,
88
  #wp-admin-bar-query-monitor-stricts a,
89
  #wp-admin-bar-query-monitor-notices a,
90
  #wp-admin-bar-query-monitor-expensive a,
93
  color: #eee !important;
94
  }
95
 
96
+ body:not(.mp6) .qm-wp-37 #wp-admin-bar-query-monitor-deprecated a,
97
  body:not(.mp6) .qm-wp-37 #wp-admin-bar-query-monitor-stricts a {
98
  color: #555 !important;
99
  }
182
  margin: 0 !important;
183
  }
184
 
185
+ body:not(.iframe).sticky-menu #qm {
186
  margin-left: 150px !important;
187
  }
188
 
189
+ body:not(.iframe).sticky-menu.folded #qm {
190
  margin-left: 36px !important;
191
  }
192
 
312
  color: #a0a !important;
313
  }
314
 
 
 
 
 
315
  .qm .qm-info {
316
  color: #999 !important;
317
  }
318
 
319
+ .qm td.qm-has-toggle {
320
+ position: relative !important;
321
+ padding-right: 21px !important;
322
+ }
323
+ .qm td .qm-toggled {
324
+ display: none;
325
+ }
326
+
327
  .qm a {
328
  color: #0074a2 !important;
329
  text-decoration: none !important;
330
  text-shadow: none !important;
331
  font-weight: normal !important;
332
  }
333
+ .qm a:focus,
334
  .qm a:hover {
335
  text-decoration: underline !important;
336
  color: #2ea2cc !important;
340
  text-decoration: underline !important;
341
  }
342
 
343
+ .qm a.qm-toggle {
344
+ position: absolute !important;
345
+ top: 2px !important;
346
+ right: 2px !important;
347
+ color: #ddd !important;
348
+ padding: 1px 5px !important;
349
+ border: 1px solid transparent !important;
350
+ }
351
+
352
+ .qm a.qm-toggle:hover {
353
+ text-decoration: none !important;
354
+ border-color: #e1e1e1 !important;
355
+ color: #999 !important;
356
+ background: #eee !important;
357
+ }
358
+
359
  .qm .qm-warn,
360
  .qm .qm-warn span.qm-na {
361
  color: #f00 !important;
375
  padding: 1px 1.5em 1px 0 !important;
376
  }
377
 
 
 
 
 
378
  /* Filters */
379
 
380
  select.qm-filter {
422
  text-align: left !important;
423
  }
424
 
425
+ html[dir="rtl"] body:not(.iframe).sticky-menu #qm {
426
  margin-right: 150px !important;
427
  margin-left: 0 !important;
428
  }
assets/query-monitor.js CHANGED
@@ -1,6 +1,6 @@
1
  /*
2
 
3
- © 2013 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
@@ -124,6 +124,17 @@ jQuery( function($) {
124
 
125
  });
126
 
 
 
 
 
 
 
 
 
 
 
 
127
  $( document ).ajaxSuccess( function( event, response, options ) {
128
 
129
  var errors = response.getResponseHeader( 'X-QM-Errors' );
1
  /*
2
 
3
+ Copyright 2013 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
124
 
125
  });
126
 
127
+ $('#qm').find('.qm-toggle').on('click',function(e){
128
+ var el = $(this);
129
+ $(this).parent().find('.qm-toggled').toggle(0,function(){
130
+ if ( '+' == el.text() )
131
+ el.text('-');
132
+ else
133
+ el.text('+');
134
+ });
135
+ e.preventDefault();
136
+ });
137
+
138
  $( document ).ajaxSuccess( function( event, response, options ) {
139
 
140
  var errors = response.getResponseHeader( 'X-QM-Errors' );
collectors/admin.php ADDED
@@ -0,0 +1,61 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ Copyright 2013 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_Collector_Admin extends QM_Collector {
18
+
19
+ public $id = 'admin';
20
+
21
+ public function name() {
22
+ return __( 'Admin Screen', 'query-monitor' );
23
+ }
24
+
25
+ public function __construct() {
26
+ parent::__construct();
27
+ add_filter( 'current_screen', array( $this, 'filter_current_screen' ), 99 );
28
+ }
29
+
30
+ public function filter_current_screen( WP_Screen $screen ) {
31
+ if ( empty( $this->data['admin'] ) )
32
+ $this->data['admin'] = wp_clone( $screen );
33
+ return $screen;
34
+ }
35
+
36
+ public function process() {
37
+
38
+ global $pagenow;
39
+
40
+ if ( isset( $_GET['page'] ) )
41
+ $this->data['base'] = get_current_screen()->base;
42
+ else
43
+ $this->data['base'] = $pagenow;
44
+
45
+ if ( !isset( $this->data['admin'] ) )
46
+ $this->data['admin'] = __( 'n/a', 'query-monitor' );
47
+
48
+ $this->data['pagenow'] = $pagenow;
49
+ $this->data['current_screen'] = get_current_screen();
50
+
51
+ }
52
+
53
+ }
54
+
55
+ function register_qm_collector_admin( array $qm ) {
56
+ if ( is_admin() )
57
+ $qm['admin'] = new QM_Collector_Admin;
58
+ return $qm;
59
+ }
60
+
61
+ add_filter( 'query_monitor_collectors', 'register_qm_collector_admin', 70 );
collectors/authentication.php ADDED
@@ -0,0 +1,70 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ Copyright 2013 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_Collector_Authentication extends QM_Collector {
18
+
19
+ public $id = 'authentication';
20
+
21
+ public function name() {
22
+ return __( 'Authentication', 'query-monitor' );
23
+ }
24
+
25
+ public function __construct() {
26
+ parent::__construct();
27
+ add_action( 'plugins_loaded', array( $this, 'action_plugins_loaded' ) );
28
+ }
29
+
30
+ public function action_plugins_loaded() {
31
+
32
+ if ( !defined( 'QM_COOKIE' ) )
33
+ define( 'QM_COOKIE', 'qm_' . COOKIEHASH );
34
+
35
+ }
36
+
37
+ public function show_query_monitor() {
38
+ if ( isset( $_COOKIE[QM_COOKIE] ) )
39
+ return $this->verify_nonce( $_COOKIE[QM_COOKIE], 'view_query_monitor' );
40
+ return false;
41
+ }
42
+
43
+ public function create_nonce( $action ) {
44
+ # This is just WordPress' nonce implementation minus the user ID
45
+ # check so a nonce can be set in a cookie and used cross-user
46
+ $i = wp_nonce_tick();
47
+ return substr( wp_hash( $i . $action, 'nonce' ), -12, 10 );
48
+ }
49
+
50
+ public function verify_nonce( $nonce, $action ) {
51
+
52
+ $i = wp_nonce_tick();
53
+
54
+ if ( substr( wp_hash( $i . $action, 'nonce' ), -12, 10 ) === $nonce )
55
+ return true;
56
+ if ( substr( wp_hash( ( $i - 1 ) . $action, 'nonce' ), -12, 10 ) === $nonce )
57
+ return true;
58
+
59
+ return false;
60
+
61
+ }
62
+
63
+ }
64
+
65
+ function register_qm_collector_authentication( array $qm ) {
66
+ $qm['authentication'] = new QM_Collector_Authentication;
67
+ return $qm;
68
+ }
69
+
70
+ add_filter( 'query_monitor_collectors', 'register_qm_collector_authentication', 130 );
collectors/conditionals.php ADDED
@@ -0,0 +1,71 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ Copyright 2013 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_Collector_Conditionals extends QM_Collector {
18
+
19
+ public $id = 'conditionals';
20
+
21
+ public function name() {
22
+ return __( 'Conditionals', 'query-monitor' );
23
+ }
24
+
25
+ public function __construct() {
26
+ parent::__construct();
27
+ }
28
+
29
+ public function process() {
30
+
31
+ $conds = apply_filters( 'query_monitor_conditionals', array(
32
+ 'is_404', 'is_archive', 'is_admin', 'is_attachment', 'is_author', 'is_blog_admin', 'is_category', 'is_comments_popup', 'is_date',
33
+ 'is_day', 'is_feed', 'is_front_page', 'is_home', 'is_main_network', 'is_main_site', 'is_month', 'is_network_admin',
34
+ 'is_page', 'is_page_template', 'is_paged', 'is_post_type_archive', 'is_preview', 'is_robots', 'is_rtl', 'is_search', 'is_single',
35
+ 'is_singular', 'is_ssl', 'is_sticky', 'is_tag', 'is_tax', 'is_time', 'is_trackback', 'is_year'
36
+ ) );
37
+
38
+ $true = $false = $na = array();
39
+
40
+ foreach ( $conds as $cond ) {
41
+ if ( function_exists( $cond ) ) {
42
+
43
+ if ( ( 'is_sticky' == $cond ) and !get_post( $id = null ) ) {
44
+ # Special case for is_sticky to prevent PHP notices
45
+ $false[] = $cond;
46
+ } else if ( ( 'is_main_site' == $cond ) and !is_multisite() ) {
47
+ # Special case for is_main_site to prevent it from being annoying on single site installs
48
+ $na[] = $cond;
49
+ } else {
50
+ if ( call_user_func( $cond ) )
51
+ $true[] = $cond;
52
+ else
53
+ $false[] = $cond;
54
+ }
55
+
56
+ } else {
57
+ $na[] = $cond;
58
+ }
59
+ }
60
+ $this->data['conds'] = compact( 'true', 'false', 'na' );
61
+
62
+ }
63
+
64
+ }
65
+
66
+ function register_qm_collector_conditionals( array $qm ) {
67
+ $qm['conditionals'] = new QM_Collector_Conditionals;
68
+ return $qm;
69
+ }
70
+
71
+ add_filter( 'query_monitor_collectors', 'register_qm_collector_conditionals', 50 );
collectors/db_callers.php ADDED
@@ -0,0 +1,49 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ Copyright 2013 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_Collector_DB_Callers extends QM_Collector {
18
+
19
+ public $id = 'db_callers';
20
+
21
+ public function name() {
22
+ return __( 'Queries by Caller', 'query-monitor' );
23
+ }
24
+
25
+ public function __construct() {
26
+ parent::__construct();
27
+ }
28
+
29
+ public function process() {
30
+
31
+ if ( $dbq = QueryMonitor::get_collector( 'db_queries' ) ) {
32
+ if ( isset( $dbq->data['times'] ) ) {
33
+ $this->data['times'] = $dbq->data['times'];
34
+ }
35
+ if ( isset( $dbq->data['types'] ) ) {
36
+ $this->data['types'] = $dbq->data['types'];
37
+ }
38
+ }
39
+
40
+ }
41
+
42
+ }
43
+
44
+ function register_qm_collector_db_callers( array $qm ) {
45
+ $qm['db_callers'] = new QM_Collector_DB_Callers;
46
+ return $qm;
47
+ }
48
+
49
+ add_filter( 'query_monitor_collectors', 'register_qm_collector_db_callers', 30 );
collectors/db_components.php ADDED
@@ -0,0 +1,49 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ Copyright 2013 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_Collector_DB_Components extends QM_Collector {
18
+
19
+ public $id = 'db_components';
20
+
21
+ public function name() {
22
+ return __( 'Queries by Component', 'query-monitor' );
23
+ }
24
+
25
+ public function __construct() {
26
+ parent::__construct();
27
+ }
28
+
29
+ public function process() {
30
+
31
+ if ( $dbq = QueryMonitor::get_collector( 'db_queries' ) ) {
32
+ if ( isset( $dbq->data['component_times'] ) ) {
33
+ $this->data['times'] = $dbq->data['component_times'];
34
+ }
35
+ if ( isset( $dbq->data['types'] ) ) {
36
+ $this->data['types'] = $dbq->data['types'];
37
+ }
38
+ }
39
+
40
+ }
41
+
42
+ }
43
+
44
+ function register_qm_collector_db_components( array $qm ) {
45
+ $qm['db_components'] = new QM_Collector_DB_Components;
46
+ return $qm;
47
+ }
48
+
49
+ add_filter( 'query_monitor_collectors', 'register_qm_collector_db_components', 40 );
collectors/db_queries.php ADDED
@@ -0,0 +1,229 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ Copyright 2013 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 ( !defined( 'SAVEQUERIES' ) )
18
+ define( 'SAVEQUERIES', true );
19
+ if ( !defined( 'QM_DB_EXPENSIVE' ) )
20
+ define( 'QM_DB_EXPENSIVE', 0.05 );
21
+
22
+ # QM_DB_LIMIT used to be a hard limit but proved to be more of an annoyance than anything. It now
23
+ # just adds a nag to the top of the query table. I might remove it altogether at some point.
24
+ if ( !defined( 'QM_DB_LIMIT' ) )
25
+ define( 'QM_DB_LIMIT', 100 );
26
+
27
+ class QM_Collector_DB_Queries extends QM_Collector {
28
+
29
+ public $id = 'db_queries';
30
+ public $db_objects = array();
31
+
32
+ public function name() {
33
+ return __( 'Database Queries', 'query-monitor' );
34
+ }
35
+
36
+ public function __construct() {
37
+ parent::__construct();
38
+ }
39
+
40
+ public function get_errors() {
41
+ if ( !empty( $this->data['errors'] ) )
42
+ return $this->data['errors'];
43
+ return false;
44
+ }
45
+
46
+ public function get_expensive() {
47
+ if ( !empty( $this->data['expensive'] ) )
48
+ return $this->data['expensive'];
49
+ return false;
50
+ }
51
+
52
+ public static function is_expensive( array $row ) {
53
+ return $row['ltime'] > QM_DB_EXPENSIVE;
54
+ }
55
+
56
+ public function process() {
57
+
58
+ if ( !SAVEQUERIES )
59
+ return;
60
+
61
+ $this->data['total_qs'] = 0;
62
+ $this->data['total_time'] = 0;
63
+ $this->data['errors'] = array();
64
+
65
+ $this->db_objects = apply_filters( 'query_monitor_db_objects', array(
66
+ '$wpdb' => $GLOBALS['wpdb']
67
+ ) );
68
+
69
+ foreach ( $this->db_objects as $name => $db ) {
70
+ if ( is_a( $db, 'wpdb' ) )
71
+ $this->process_db_object( $name, $db );
72
+ }
73
+
74
+ }
75
+
76
+ protected function log_type( $type ) {
77
+
78
+ if ( isset( $this->data['types'][$type] ) )
79
+ $this->data['types'][$type]++;
80
+ else
81
+ $this->data['types'][$type] = 1;
82
+
83
+ }
84
+
85
+ protected function log_caller( $caller, $ltime, $type ) {
86
+
87
+ if ( !isset( $this->data['times'][$caller] ) ) {
88
+ $this->data['times'][$caller] = array(
89
+ 'caller' => $caller,
90
+ 'calls' => 0,
91
+ 'ltime' => 0,
92
+ 'types' => array()
93
+ );
94
+ }
95
+
96
+ $this->data['times'][$caller]['calls']++;
97
+ $this->data['times'][$caller]['ltime'] += $ltime;
98
+
99
+ if ( isset( $this->data['times'][$caller]['types'][$type] ) )
100
+ $this->data['times'][$caller]['types'][$type]++;
101
+ else
102
+ $this->data['times'][$caller]['types'][$type] = 1;
103
+
104
+ }
105
+
106
+ protected function log_component( $component, $ltime, $type ) {
107
+
108
+ if ( !isset( $this->data['component_times'][$component->name] ) ) {
109
+ $this->data['component_times'][$component->name] = array(
110
+ 'component' => $component->name,
111
+ 'calls' => 0,
112
+ 'ltime' => 0,
113
+ 'types' => array()
114
+ );
115
+ }
116
+
117
+ $this->data['component_times'][$component->name]['calls']++;
118
+ $this->data['component_times'][$component->name]['ltime'] += $ltime;
119
+
120
+ if ( isset( $this->data['component_times'][$component->name]['types'][$type] ) )
121
+ $this->data['component_times'][$component->name]['types'][$type]++;
122
+ else
123
+ $this->data['component_times'][$component->name]['types'][$type] = 1;
124
+
125
+ }
126
+
127
+ protected static function query_compat( array & $query ) {
128
+
129
+ list( $query['sql'], $query['ltime'], $query['stack'] ) = $query;
130
+
131
+ }
132
+
133
+ public function process_db_object( $id, wpdb $db ) {
134
+
135
+ $rows = array();
136
+ $types = array();
137
+ $total_time = 0;
138
+
139
+ foreach ( (array) $db->queries as $query ) {
140
+
141
+ if ( ! isset( $query['sql'] ) )
142
+ self::query_compat( $query );
143
+
144
+ if ( false !== strpos( $query['stack'], 'wp_admin_bar' ) and !isset( $_REQUEST['qm_display_admin_bar'] ) )
145
+ continue;
146
+
147
+ $sql = $query['sql'];
148
+ $ltime = $query['ltime'];
149
+ $stack = $query['stack'];
150
+ $has_component = isset( $query['trace'] );
151
+ $has_results = isset( $query['result'] );
152
+
153
+ if ( $has_results )
154
+ $result = $query['result'];
155
+ else
156
+ $result = null;
157
+
158
+ $total_time += $ltime;
159
+
160
+ if ( isset( $query['trace'] ) )
161
+ $component = QM_Util::get_backtrace_component( $query['trace'] );
162
+ else
163
+ $component = null;
164
+
165
+ # @TODO we should grab this from the trace instead for increased accuracy in case
166
+ # the caller contains multiple comma separated arguments (see QM_Backtrace::$show_args)
167
+ $callers = explode( ',', $stack );
168
+ $caller = trim( end( $callers ) );
169
+
170
+ if ( false !== strpos( $caller, '(' ) )
171
+ $caller_name = substr( $caller, 0, strpos( $caller, '(' ) ) . '()';
172
+ else
173
+ $caller_name = $caller;
174
+
175
+ # @TODO this formatting should move to JIT when outputting as html
176
+ $sql = QM_Util::format_sql( $sql );
177
+ $type = preg_split( '/\b/', $sql );
178
+ $type = strtoupper( $type[1] );
179
+
180
+ $this->log_type( $type );
181
+ $this->log_caller( $caller_name, $ltime, $type );
182
+
183
+ if ( $component )
184
+ $this->log_component( $component, $ltime, $type );
185
+
186
+ if ( !isset( $types[$type]['total'] ) )
187
+ $types[$type]['total'] = 1;
188
+ else
189
+ $types[$type]['total']++;
190
+
191
+ if ( !isset( $types[$type]['callers'][$caller] ) )
192
+ $types[$type]['callers'][$caller] = 1;
193
+ else
194
+ $types[$type]['callers'][$caller]++;
195
+
196
+ $row = compact( 'caller', 'caller_name', 'stack', 'sql', 'ltime', 'result', 'type', 'component' );
197
+
198
+ if ( is_wp_error( $result ) )
199
+ $this->data['errors'][] = $row;
200
+
201
+ if ( self::is_expensive( $row ) )
202
+ $this->data['expensive'][] = $row;
203
+
204
+ $rows[] = $row;
205
+
206
+ }
207
+
208
+ if ( isset( $_REQUEST['qm_sort'] ) and ( 'time' == $_REQUEST['qm_sort'] ) )
209
+ usort( $rows, 'QM_Util::sort' );
210
+
211
+ $total_qs = count( $rows );
212
+
213
+ $this->data['total_qs'] += $total_qs;
214
+ $this->data['total_time'] += $total_time;
215
+
216
+ # @TODO put errors in here too:
217
+ # @TODO proper class instead of (object)
218
+ $this->data['dbs'][$id] = (object) compact( 'rows', 'types', 'has_results', 'has_component', 'total_time', 'total_qs' );
219
+
220
+ }
221
+
222
+ }
223
+
224
+ function register_qm_collector_db_queries( array $qm ) {
225
+ $qm['db_queries'] = new QM_Collector_DB_Queries;
226
+ return $qm;
227
+ }
228
+
229
+ add_filter( 'query_monitor_collectors', 'register_qm_collector_db_queries', 20 );
collectors/environment.php ADDED
@@ -0,0 +1,203 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ Copyright 2013 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_Collector_Environment extends QM_Collector {
18
+
19
+ public $id = 'environment';
20
+ protected $php_vars = array(
21
+ 'max_execution_time',
22
+ 'memory_limit',
23
+ 'upload_max_filesize',
24
+ 'post_max_size',
25
+ 'display_errors',
26
+ 'log_errors',
27
+ );
28
+
29
+ public function name() {
30
+ return __( 'Environment', 'query-monitor' );
31
+ }
32
+
33
+ public function __construct() {
34
+
35
+ global $wpdb;
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 ) {
43
+ if ( isset( $wpdb->qm_php_vars ) and isset( $wpdb->qm_php_vars[$setting] ) )
44
+ $val = $wpdb->qm_php_vars[$setting];
45
+ else
46
+ $val = ini_get( $setting );
47
+ $this->data['php']['variables'][$setting]['before'] = $val;
48
+ }
49
+
50
+ }
51
+
52
+ public static function get_error_levels( $error_reporting ) {
53
+
54
+ $levels = array();
55
+
56
+ $constants = array(
57
+ 'E_ERROR',
58
+ 'E_WARNING',
59
+ 'E_PARSE',
60
+ 'E_NOTICE',
61
+ 'E_CORE_ERROR',
62
+ 'E_CORE_WARNING',
63
+ 'E_COMPILE_ERROR',
64
+ 'E_COMPILE_WARNING',
65
+ 'E_USER_ERROR',
66
+ 'E_USER_WARNING',
67
+ 'E_USER_NOTICE',
68
+ 'E_STRICT',
69
+ 'E_RECOVERABLE_ERROR',
70
+ 'E_DEPRECATED',
71
+ 'E_USER_DEPRECATED',
72
+ 'E_ALL'
73
+ );
74
+
75
+ foreach ( $constants as $level ) {
76
+ if ( defined( $level ) ) {
77
+ $c = constant( $level );
78
+ if ( $error_reporting & $c )
79
+ $levels[$c] = $level;
80
+ }
81
+ }
82
+
83
+ return $levels;
84
+
85
+ }
86
+
87
+ public function process() {
88
+
89
+ global $wp_version, $blog_id;
90
+
91
+ $mysql_vars = array(
92
+ 'key_buffer_size' => true, # Key cache size limit
93
+ 'max_allowed_packet' => false, # Individual query size limit
94
+ 'max_connections' => false, # Max number of client connections
95
+ 'query_cache_limit' => true, # Individual query cache size limit
96
+ 'query_cache_size' => true, # Total cache size limit
97
+ 'query_cache_type' => 'ON' # Query cache on or off
98
+ );
99
+ $php_u = '';
100
+
101
+ if ( $dbq = QueryMonitor::get_collector( 'db_queries' ) ) {
102
+
103
+ foreach ( $dbq->db_objects as $id => $db ) {
104
+
105
+ if ( !is_a( $db, 'wpdb' ) )
106
+ continue;
107
+
108
+ $variables = $db->get_results( "
109
+ SHOW VARIABLES
110
+ WHERE Variable_name IN ( '" . implode( "', '", array_keys( $mysql_vars ) ) . "' )
111
+ " );
112
+
113
+ if ( is_resource( $db->dbh ) ) {
114
+ $version = mysql_get_server_info( $db->dbh );
115
+ $driver = 'mysql';
116
+ } else if ( is_object( $db->dbh ) and method_exists( $db->dbh, 'db_version' ) ) {
117
+ $version = $db->dbh->db_version();
118
+ $driver = get_class( $db->dbh );
119
+ } else {
120
+ $version = $driver = '<span class="qm-warn">' . __( 'Unknown', 'query-monitor' ) . '</span>';
121
+ }
122
+
123
+ $this->data['db'][$id] = array(
124
+ 'version' => $version,
125
+ 'driver' => $driver,
126
+ 'user' => $db->dbuser,
127
+ 'host' => $db->dbhost,
128
+ 'name' => $db->dbname,
129
+ 'vars' => $mysql_vars,
130
+ 'variables' => $variables
131
+ );
132
+
133
+ }
134
+
135
+ }
136
+
137
+ if ( function_exists( 'posix_getpwuid' ) ) {
138
+
139
+ $u = posix_getpwuid( posix_getuid() );
140
+ $g = posix_getgrgid( $u['gid'] );
141
+ $php_u = esc_html( $u['name'] . ':' . $g['name'] );
142
+
143
+ } else if ( isset( $_SERVER['USER'] ) ) {
144
+
145
+ $php_u = esc_html( $_SERVER['USER'] );
146
+
147
+ } else if ( function_exists( 'exec' ) ) {
148
+
149
+ $php_u = esc_html( exec( 'whoami' ) );
150
+
151
+ }
152
+
153
+ if ( empty( $php_u ) )
154
+ $php_u = '<em>' . __( 'Unknown', 'query-monitor' ) . '</em>';
155
+
156
+ $this->data['php']['version'] = phpversion();
157
+ $this->data['php']['user'] = $php_u;
158
+
159
+ foreach ( $this->php_vars as $setting )
160
+ $this->data['php']['variables'][$setting]['after'] = ini_get( $setting );
161
+
162
+ $this->data['php']['error_reporting'] = error_reporting();
163
+
164
+ # @TODO put WP's other debugging constants in here, eg. SCRIPT_DEBUG
165
+ $this->data['wp'] = array(
166
+ 'version' => $wp_version,
167
+ 'WP_DEBUG' => QM_Util::format_bool_constant( 'WP_DEBUG' ),
168
+ 'WP_LOCAL_DEV' => QM_Util::format_bool_constant( 'WP_LOCAL_DEV' ),
169
+ );
170
+
171
+ if ( is_multisite() )
172
+ $this->data['wp']['blog_id'] = $blog_id;
173
+
174
+ $server = explode( ' ', $_SERVER['SERVER_SOFTWARE'] );
175
+ $server = explode( '/', reset( $server ) );
176
+
177
+ if ( isset( $server[1] ) )
178
+ $server_version = $server[1];
179
+ else
180
+ $server_version = '<em>' . __( 'Unknown', 'query-monitor' ) . '</em>';
181
+
182
+ if ( isset( $_SERVER['SERVER_ADDR'] ) )
183
+ $address = $_SERVER['SERVER_ADDR'];
184
+ else
185
+ $address = '<em>' . __( 'Unknown', 'query-monitor' ) . '</em>';
186
+
187
+ $this->data['server'] = array(
188
+ 'name' => $server[0],
189
+ 'version' => $server_version,
190
+ 'address' => $address,
191
+ 'host' => php_uname( 'n' )
192
+ );
193
+
194
+ }
195
+
196
+ }
197
+
198
+ function register_qm_collector_environment( array $qm ) {
199
+ $qm['environment'] = new QM_Collector_Environment;
200
+ return $qm;
201
+ }
202
+
203
+ add_filter( 'query_monitor_collectors', 'register_qm_collector_environment', 120 );
collectors/hooks.php ADDED
@@ -0,0 +1,101 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ Copyright 2013 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_Collector_Hooks extends QM_Collector {
18
+
19
+ public $id = 'hooks';
20
+
21
+ public function name() {
22
+ return __( 'Hooks', 'query-monitor' );
23
+ }
24
+
25
+ public function __construct() {
26
+ parent::__construct();
27
+ }
28
+
29
+ public function process() {
30
+
31
+ global $wp_actions, $wp_filter;
32
+
33
+ # @TODO this is a band-aid for a deeper problem which I haven't had time to look
34
+ # into. The customizer hooks onto 'shutdown' at priority 1000 and the act of
35
+ # looping over the filters below kills it somehow. Argh. Look into it.
36
+ if ( '/wp-admin/customize.php' == $_SERVER['REQUEST_URI'] )
37
+ return;
38
+
39
+ if ( is_admin() and ( $admin = QueryMonitor::get_collector( 'admin' ) ) )
40
+ $this->data['screen'] = $admin->data['base'];
41
+ else
42
+ $this->data['screen'] = '';
43
+
44
+ $hooks = $parts = $components = array();
45
+
46
+ foreach ( $wp_actions as $name => $count ) {
47
+
48
+ $actions = array();
49
+ # @TODO better variable name:
50
+ $c = array();
51
+
52
+ if ( isset( $wp_filter[$name] ) ) {
53
+
54
+ foreach( $wp_filter[$name] as $priority => $callbacks ) {
55
+
56
+ foreach ( $callbacks as $callback ) {
57
+
58
+ $callback = QM_Util::populate_callback( $callback );
59
+
60
+ if ( isset( $callback['component'] ) )
61
+ $c[$callback['component']->name] = $callback['component']->name;
62
+
63
+ $actions[] = array(
64
+ 'priority' => $priority,
65
+ 'callback' => $callback,
66
+ );
67
+
68
+ }
69
+
70
+ }
71
+
72
+ }
73
+
74
+ # @TODO better variable name:
75
+ $p = array_filter( preg_split( '/[_\/-]/', $name ) );
76
+ $parts = array_merge( $parts, $p );
77
+ $components = array_merge( $components, $c );
78
+
79
+ $hooks[$name] = array(
80
+ 'name' => $name,
81
+ 'actions' => $actions,
82
+ 'parts' => $p,
83
+ 'components' => $c,
84
+ );
85
+
86
+ }
87
+
88
+ $this->data['hooks'] = $hooks;
89
+ $this->data['parts'] = array_unique( array_filter( $parts ) );
90
+ $this->data['components'] = array_unique( array_filter( $components ) );
91
+
92
+ }
93
+
94
+ }
95
+
96
+ function register_qm_collector_hooks( array $qm ) {
97
+ $qm['hooks'] = new QM_Collector_Hooks;
98
+ return $qm;
99
+ }
100
+
101
+ add_filter( 'query_monitor_collectors', 'register_qm_collector_hooks', 80 );
collectors/http.php ADDED
@@ -0,0 +1,106 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ Copyright 2013 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_Collector_HTTP extends QM_Collector {
18
+
19
+ public $id = 'http';
20
+
21
+ public function name() {
22
+ return __( 'HTTP Requests', 'query-monitor' );
23
+ }
24
+
25
+ public function __construct() {
26
+
27
+ parent::__construct();
28
+
29
+ add_action( 'http_api_debug', array( $this, 'action_http_debug' ), 99, 5 );
30
+ add_filter( 'http_request_args', array( $this, 'filter_http_request' ), 99, 2 );
31
+ add_filter( 'http_response', array( $this, 'filter_http_response' ), 99, 3 );
32
+ # http://core.trac.wordpress.org/ticket/25747
33
+ add_filter( 'pre_http_request', array( $this, 'filter_http_response' ), 99, 3 );
34
+
35
+ }
36
+
37
+ public function filter_http_request( array $args, $url ) {
38
+ $m_start = microtime( true );
39
+ $key = $m_start . $url;
40
+ $this->data['http'][$key] = array(
41
+ 'url' => $url,
42
+ 'args' => $args,
43
+ 'start' => $m_start,
44
+ 'trace' => new QM_Backtrace
45
+ );
46
+ $args['_qm_key'] = $key;
47
+ return $args;
48
+ }
49
+
50
+ public function action_http_debug( $param, $action ) {
51
+
52
+ switch ( $action ) {
53
+
54
+ case 'response':
55
+
56
+ $fga = func_get_args();
57
+
58
+ list( $response, $action, $class ) = $fga;
59
+
60
+ # http://core.trac.wordpress.org/ticket/18732
61
+ if ( isset( $fga[3] ) )
62
+ $args = $fga[3];
63
+ if ( isset( $fga[4] ) )
64
+ $url = $fga[4];
65
+ if ( !isset( $args['_qm_key'] ) )
66
+ return;
67
+
68
+ if ( !empty( $class ) )
69
+ $this->data['http'][$args['_qm_key']]['transport'] = str_replace( 'wp_http_', '', strtolower( $class ) );
70
+ else
71
+ $this->data['http'][$args['_qm_key']]['transport'] = false;
72
+
73
+ if ( is_wp_error( $response ) )
74
+ $this->filter_http_response( $response, $args, $url );
75
+
76
+ break;
77
+
78
+ case 'transports_list':
79
+ # Nothing
80
+ break;
81
+
82
+ }
83
+
84
+ }
85
+
86
+ public function filter_http_response( $response, array $args, $url ) {
87
+ $this->data['http'][$args['_qm_key']]['end'] = microtime( true );
88
+ $this->data['http'][$args['_qm_key']]['response'] = $response;
89
+
90
+ if ( is_wp_error( $response ) ) {
91
+ $this->data['errors']['error'][] = $args['_qm_key'];
92
+ } else {
93
+ if ( intval( wp_remote_retrieve_response_code( $response ) ) >= 400 )
94
+ $this->data['errors']['warning'][] = $args['_qm_key'];
95
+ }
96
+ return $response;
97
+ }
98
+
99
+ }
100
+
101
+ function register_qm_collector_http( array $qm ) {
102
+ $qm['http'] = new QM_Collector_HTTP;
103
+ return $qm;
104
+ }
105
+
106
+ add_filter( 'query_monitor_collectors', 'register_qm_collector_http', 100 );
collectors/overview.php ADDED
@@ -0,0 +1,56 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ Copyright 2013 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_Collector_Overview extends QM_Collector {
18
+
19
+ public $id = 'overview';
20
+
21
+ public function name() {
22
+ return __( 'Overview', 'query-monitor' );
23
+ }
24
+
25
+ public function __construct() {
26
+ parent::__construct();
27
+ }
28
+
29
+ public function process() {
30
+
31
+ $this->data['time'] = QM_Util::timer_stop_float();
32
+ $this->data['time_limit'] = ini_get( 'max_execution_time' );
33
+
34
+ if ( !empty( $this->data['time_limit'] ) )
35
+ $this->data['time_usage'] = ( 100 / $this->data['time_limit'] ) * $this->data['time'];
36
+ else
37
+ $this->data['time_usage'] = 0;
38
+
39
+ if ( function_exists( 'memory_get_peak_usage' ) )
40
+ $this->data['memory'] = memory_get_peak_usage();
41
+ else
42
+ $this->data['memory'] = memory_get_usage();
43
+
44
+ $this->data['memory_limit'] = QM_Util::convert_hr_to_bytes( ini_get( 'memory_limit' ) );
45
+ $this->data['memory_usage'] = ( 100 / $this->data['memory_limit'] ) * $this->data['memory'];
46
+
47
+ }
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 );
collectors/php_errors.php ADDED
@@ -0,0 +1,123 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ Copyright 2013 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
+ # E_DEPRECATED and E_USER_DEPRECATED were introduced in PHP 5.3 so we need to use back-compat constants that work on 5.2.
18
+ if ( defined( 'E_DEPRECATED' ) )
19
+ define( 'QM_E_DEPRECATED', E_DEPRECATED );
20
+ else
21
+ define( 'QM_E_DEPRECATED', 0 );
22
+
23
+ if ( defined( 'E_USER_DEPRECATED' ) )
24
+ define( 'QM_E_USER_DEPRECATED', E_USER_DEPRECATED );
25
+ else
26
+ define( 'QM_E_USER_DEPRECATED', 0 );
27
+
28
+ class QM_Collector_PHP_Errors extends QM_Collector {
29
+
30
+ public $id = 'php_errors';
31
+
32
+ public function name() {
33
+ return __( 'PHP Errors', 'query-monitor' );
34
+ }
35
+
36
+ public function __construct() {
37
+
38
+ parent::__construct();
39
+ set_error_handler( array( $this, 'error_handler' ) );
40
+
41
+ }
42
+
43
+ public function error_handler( $errno, $message, $file = null, $line = null ) {
44
+
45
+ #if ( !( error_reporting() & $errno ) )
46
+ # return false;
47
+
48
+ switch ( $errno ) {
49
+
50
+ case E_WARNING:
51
+ case E_USER_WARNING:
52
+ $type = 'warning';
53
+ break;
54
+
55
+ case E_NOTICE:
56
+ case E_USER_NOTICE:
57
+ $type = 'notice';
58
+ break;
59
+
60
+ case E_STRICT:
61
+ $type = 'strict';
62
+ break;
63
+
64
+ case QM_E_DEPRECATED:
65
+ case QM_E_USER_DEPRECATED:
66
+ $type = 'deprecated';
67
+ break;
68
+
69
+ default:
70
+ return false;
71
+ break;
72
+
73
+ }
74
+
75
+ if ( error_reporting() > 0 ) {
76
+
77
+ $trace = new QM_Backtrace;
78
+ $stack = $trace->get_stack();
79
+ $func = reset( $stack );
80
+ $key = md5( $message . $file . $line . $func );
81
+
82
+ $filename = QM_Util::standard_dir( $file, '' );
83
+
84
+ if ( isset( $this->data['errors'][$type][$key] ) ) {
85
+ $this->data['errors'][$type][$key]->calls++;
86
+ } else {
87
+ $this->data['errors'][$type][$key] = (object) array(
88
+ 'errno' => $errno,
89
+ 'type' => $type,
90
+ 'message' => $message,
91
+ 'file' => $file,
92
+ 'filename' => $filename,
93
+ 'line' => $line,
94
+ 'trace' => $trace,
95
+ 'calls' => 1
96
+ );
97
+ }
98
+
99
+ }
100
+
101
+ return apply_filters( 'query_monitor_php_errors_return_value', true );
102
+
103
+ }
104
+
105
+ }
106
+
107
+ function register_qm_collector_php_errors( array $qm ) {
108
+ $qm['php_errors'] = new QM_Collector_PHP_Errors;
109
+ return $qm;
110
+ }
111
+
112
+ function qm_php_errors_return_value( $return ) {
113
+ if ( QM_Util::is_ajax() )
114
+ return true;
115
+ # If Xdebug is enabled we'll return false so Xdebug's error handler can do its thing.
116
+ if ( function_exists( 'xdebug_is_enabled' ) and xdebug_is_enabled() )
117
+ return false;
118
+ else
119
+ return $return;
120
+ }
121
+
122
+ add_filter( 'query_monitor_collectors', 'register_qm_collector_php_errors', 110 );
123
+ add_filter( 'query_monitor_php_errors_return_value', 'qm_php_errors_return_value' );
{components → collectors}/redirects.php RENAMED
@@ -14,22 +14,24 @@ GNU General Public License for more details.
14
 
15
  */
16
 
17
- class QM_Component_Redirects extends QM_Component {
18
 
19
- var $id = 'redirects';
20
 
21
- function __construct() {
 
 
 
 
22
  parent::__construct();
23
  add_filter( 'wp_redirect', array( $this, 'filter_wp_redirect' ), 999, 2 );
24
  }
25
 
26
  public function filter_wp_redirect( $location, $status ) {
27
 
28
- global $querymonitor;
29
-
30
  if ( !$location )
31
  return $location;
32
- if ( !$querymonitor->show_query_monitor() )
33
  return $location;
34
  if ( headers_sent() )
35
  return $location;
@@ -46,9 +48,9 @@ class QM_Component_Redirects extends QM_Component {
46
 
47
  }
48
 
49
- function register_qm_redirects( array $qm ) {
50
- $qm['redirects'] = new QM_Component_Redirects;
51
  return $qm;
52
  }
53
 
54
- add_filter( 'query_monitor_components', 'register_qm_redirects', 140 );
14
 
15
  */
16
 
17
+ class QM_Collector_Redirects extends QM_Collector {
18
 
19
+ public $id = 'redirects';
20
 
21
+ public function name() {
22
+ return __( 'Redirects', 'query-monitor' );
23
+ }
24
+
25
+ public function __construct() {
26
  parent::__construct();
27
  add_filter( 'wp_redirect', array( $this, 'filter_wp_redirect' ), 999, 2 );
28
  }
29
 
30
  public function filter_wp_redirect( $location, $status ) {
31
 
 
 
32
  if ( !$location )
33
  return $location;
34
+ if ( !QueryMonitor::init()->show_query_monitor() )
35
  return $location;
36
  if ( headers_sent() )
37
  return $location;
48
 
49
  }
50
 
51
+ function register_qm_collector_redirects( array $qm ) {
52
+ $qm['redirects'] = new QM_Collector_Redirects;
53
  return $qm;
54
  }
55
 
56
+ add_filter( 'query_monitor_collectors', 'register_qm_collector_redirects', 140 );
collectors/request.php ADDED
@@ -0,0 +1,123 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ Copyright 2013 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_Collector_Request extends QM_Collector {
18
+
19
+ public $id = 'request';
20
+
21
+ public function __construct() {
22
+ parent::__construct();
23
+ }
24
+
25
+ public function name() {
26
+ return __( 'Request', 'query-monitor' );
27
+ }
28
+
29
+ public function process() {
30
+
31
+ global $wp, $wp_query;
32
+
33
+ $qo = get_queried_object();
34
+
35
+ if ( is_admin() ) {
36
+ $this->data['request']['request'] = $_SERVER['REQUEST_URI'];
37
+ foreach ( array( 'query_string' ) as $item ) {
38
+ $this->data['request'][$item] = $wp->$item;
39
+ }
40
+ } else {
41
+ foreach ( array( 'request', 'matched_rule', 'matched_query', 'query_string' ) as $item ) {
42
+ $this->data['request'][$item] = $wp->$item;
43
+ }
44
+ }
45
+
46
+ $plugin_qvars = array_flip( apply_filters( 'query_vars', array() ) );
47
+ $qvars = $wp_query->query_vars;
48
+ $query_vars = array();
49
+
50
+ foreach ( $qvars as $k => $v ) {
51
+ if ( isset( $plugin_qvars[$k] ) ) {
52
+ if ( '' !== $v )
53
+ $query_vars[$k] = $v;
54
+ } else {
55
+ if ( !empty( $v ) )
56
+ $query_vars[$k] = $v;
57
+ }
58
+ }
59
+
60
+ ksort( $query_vars );
61
+
62
+ # First add plugin vars to $this->data['qvars']:
63
+ foreach ( $query_vars as $k => $v ) {
64
+ if ( isset( $plugin_qvars[$k] ) ) {
65
+ $this->data['qvars'][$k] = $v;
66
+ $this->data['plugin_qvars'][$k] = $v;
67
+ }
68
+ }
69
+
70
+ # Now add all other vars to $this->data['qvars']:
71
+ foreach ( $query_vars as $k => $v ) {
72
+ if ( !isset( $plugin_qvars[$k] ) )
73
+ $this->data['qvars'][$k] = $v;
74
+ }
75
+
76
+ switch ( true ) {
77
+
78
+ case is_null( $qo ):
79
+ // Nada
80
+ break;
81
+
82
+ case is_a( $qo, 'WP_Post' ):
83
+ // Single post
84
+ $this->data['queried_object_type'] = 'post';
85
+ $this->data['queried_object_name'] = get_post_type_object( $qo->post_type )->labels->singular_name;
86
+ $this->data['queried_object_id'] = $qo->ID;
87
+ break;
88
+
89
+ case is_a( $qo, 'WP_User' ):
90
+ // Author archive
91
+ $this->data['queried_object_type'] = 'user';
92
+ $this->data['queried_object_name'] = __( 'User', 'query-monitor' );
93
+ $this->data['queried_object_id'] = $qo->ID;
94
+ break;
95
+
96
+ case property_exists( $qo, 'term_id' ):
97
+ // Term archive
98
+ $this->data['queried_object_type'] = 'term';
99
+ $this->data['queried_object_name'] = get_taxonomy( $qo->taxonomy )->labels->singular_name;
100
+ $this->data['queried_object_id'] = $qo->term_id;
101
+ break;
102
+
103
+ case property_exists( $qo, 'has_archive' ):
104
+ // Post type archive
105
+ $this->data['queried_object_type'] = 'archive';
106
+ $this->data['queried_object_name'] = $qo->labels->singular_name;
107
+ $this->data['queried_object_id'] = $qo->name;
108
+ break;
109
+
110
+ }
111
+
112
+ $this->data['queried_object'] = $qo;
113
+
114
+ }
115
+
116
+ }
117
+
118
+ function register_qm_collector_request( array $qm ) {
119
+ $qm['request'] = new QM_Collector_Request;
120
+ return $qm;
121
+ }
122
+
123
+ add_filter( 'query_monitor_collectors', 'register_qm_collector_request', 60 );
collectors/theme.php ADDED
@@ -0,0 +1,63 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ Copyright 2013 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_Collector_Theme extends QM_Collector {
18
+
19
+ public $id = 'theme';
20
+
21
+ public function name() {
22
+ return __( 'Theme', 'query-monitor' );
23
+ }
24
+
25
+ public function __construct() {
26
+ parent::__construct();
27
+ add_filter( 'body_class', array( $this, 'filter_body_class' ), 99 );
28
+ }
29
+
30
+ public function filter_body_class( $class ) {
31
+ $this->data['body_class'] = $class;
32
+ return $class;
33
+ }
34
+
35
+ public function process() {
36
+
37
+ global $template;
38
+
39
+ $template_file = 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_file );
44
+ $template_file = ltrim( $template_file, '/' );
45
+
46
+ $this->data['template_file'] = apply_filters( 'query_monitor_template', $template_file, $template );
47
+ $this->data['stylesheet'] = get_stylesheet();
48
+ $this->data['template'] = get_template();
49
+
50
+ if ( isset( $this->data['body_class'] ) )
51
+ asort( $this->data['body_class'] );
52
+
53
+ }
54
+
55
+ }
56
+
57
+ function register_qm_collector_theme( array $qm ) {
58
+ if ( !is_admin() )
59
+ $qm['theme'] = new QM_Collector_Theme;
60
+ return $qm;
61
+ }
62
+
63
+ add_filter( 'query_monitor_collectors', 'register_qm_collector_theme', 70 );
collectors/transients.php ADDED
@@ -0,0 +1,60 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ Copyright 2013 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_Collector_Transients extends QM_Collector {
18
+
19
+ public $id = 'transients';
20
+
21
+ public function name() {
22
+ return __( 'Transients', 'query-monitor' );
23
+ }
24
+
25
+ public function __construct() {
26
+ parent::__construct();
27
+ # See http://core.trac.wordpress.org/ticket/24583
28
+ add_action( 'setted_site_transient', array( $this, 'action_setted_site_transient' ), 10, 3 );
29
+ add_action( 'setted_transient', array( $this, 'action_setted_blog_transient' ), 10, 3 );
30
+ }
31
+
32
+ public function action_setted_site_transient( $transient, $value = null, $expiration = null ) {
33
+ $this->setted_transient( $transient, 'site', $value, $expiration );
34
+ }
35
+
36
+ public function action_setted_blog_transient( $transient, $value = null, $expiration = null ) {
37
+ $this->setted_transient( $transient, 'blog', $value, $expiration );
38
+ }
39
+
40
+ public function setted_transient( $transient, $type, $value = null, $expiration = null ) {
41
+ $trace = new QM_Backtrace( array(
42
+ 'ignore_items' => 1 # Ignore the action_setted_(site|blog)_transient method
43
+ ) );
44
+ $this->data['trans'][] = array(
45
+ 'transient' => $transient,
46
+ 'trace' => $trace,
47
+ 'type' => $type,
48
+ 'value' => $value,
49
+ 'expiration' => $expiration,
50
+ );
51
+ }
52
+
53
+ }
54
+
55
+ function register_qm_collector_transients( array $qm ) {
56
+ $qm['transients'] = new QM_Collector_Transients;
57
+ return $qm;
58
+ }
59
+
60
+ add_filter( 'query_monitor_collectors', 'register_qm_collector_transients', 90 );
components/conditionals.php DELETED
@@ -1,126 +0,0 @@
1
- <?php
2
- /*
3
- Copyright 2013 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_Component_Conditionals extends QM_Component {
18
-
19
- var $id = 'conditionals';
20
-
21
- function __construct() {
22
- parent::__construct();
23
- add_filter( 'query_monitor_menus', array( $this, 'admin_menu' ), 120 );
24
- }
25
-
26
- function admin_menu( array $menu ) {
27
-
28
- foreach ( $this->data['conds']['true'] as $cond ) {
29
- $menu[] = $this->menu( array(
30
- 'title' => $cond . '()',
31
- 'id' => 'query-monitor-' . $cond,
32
- 'meta' => array( 'classname' => 'qm-true qm-ltr' )
33
- ) );
34
- }
35
-
36
- return $menu;
37
-
38
- }
39
-
40
- function output_html( array $args, array $data ) {
41
-
42
- $cols = 5;
43
- $i = 0;
44
- $w = floor( 100 / $cols );
45
-
46
- echo '<div class="qm" id="' . $args['id'] . '">';
47
- echo '<table cellspacing="0">';
48
- echo '<thead>';
49
- echo '<tr>';
50
- echo '<th colspan="' . $cols . '">' . __( 'Conditionals', 'query-monitor' ) . '</th>';
51
- echo '</tr>';
52
- echo '</thead>';
53
- echo '<tbody>';
54
-
55
- foreach ( $data['conds']['true'] as $cond ) {
56
- $i++;
57
- if ( 1 === $i%$cols )
58
- echo '<tr>';
59
- echo '<td class="qm-ltr qm-true" width="' . $w . '%">' . $cond . '()</td>';
60
- if ( 0 === $i%$cols )
61
- echo '</tr>';
62
- }
63
-
64
- foreach ( $data['conds']['false'] as $cond ) {
65
- $i++;
66
- if ( 1 === $i%$cols )
67
- echo '<tr>';
68
- echo '<td class="qm-ltr qm-false" width="' . $w . '%">' . $cond . '()</td>';
69
- if ( 0 === $i%$cols )
70
- echo '</tr>';
71
- }
72
- $fill = ($cols-($i%$cols));
73
- if ( $fill ) {
74
- echo '<td colspan="' . $fill . '">&nbsp;</td>';
75
- echo '</tr>';
76
- }
77
-
78
- echo '</tbody>';
79
- echo '</table>';
80
- echo '</div>';
81
-
82
- }
83
-
84
- function process() {
85
-
86
- $conds = apply_filters( 'query_monitor_conditionals', array(
87
- 'is_404', 'is_archive', 'is_admin', 'is_attachment', 'is_author', 'is_blog_admin', 'is_category', 'is_comments_popup', 'is_date',
88
- 'is_day', 'is_feed', 'is_front_page', 'is_home', 'is_main_network', 'is_main_site', 'is_month', 'is_multitax', 'is_network_admin',
89
- 'is_page', 'is_page_template', 'is_paged', 'is_post_type_archive', 'is_preview', 'is_robots', 'is_rtl', 'is_search', 'is_single',
90
- 'is_singular', 'is_ssl', 'is_sticky', 'is_tag', 'is_tax', 'is_time', 'is_trackback', 'is_year'
91
- ) );
92
-
93
- $true = $false = $na = array();
94
-
95
- foreach ( $conds as $cond ) {
96
- if ( function_exists( $cond ) ) {
97
-
98
- if ( ( 'is_sticky' == $cond ) and !get_post( $id = null ) ) {
99
- # Special case for is_sticky to prevent PHP notices
100
- $false[] = $cond;
101
- } else if ( ( 'is_main_site' == $cond ) and !is_multisite() ) {
102
- # Special case for is_main_site to prevent it from being annoying on single site installs
103
- $na[] = $cond;
104
- } else {
105
- if ( call_user_func( $cond ) )
106
- $true[] = $cond;
107
- else
108
- $false[] = $cond;
109
- }
110
-
111
- } else {
112
- $na[] = $cond;
113
- }
114
- }
115
- $this->data['conds'] = compact( 'true', 'false', 'na' );
116
-
117
- }
118
-
119
- }
120
-
121
- function register_qm_conditionals( array $qm ) {
122
- $qm['conditionals'] = new QM_Component_Conditionals;
123
- return $qm;
124
- }
125
-
126
- add_filter( 'query_monitor_components', 'register_qm_conditionals', 40 );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
components/environment.php DELETED
@@ -1,371 +0,0 @@
1
- <?php
2
- /*
3
- Copyright 2013 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_Component_Environment extends QM_Component {
18
-
19
- var $id = 'environment';
20
- var $php_vars = array(
21
- 'max_execution_time',
22
- 'memory_limit',
23
- 'upload_max_filesize',
24
- 'post_max_size',
25
- 'display_errors',
26
- 'log_errors',
27
- );
28
-
29
- function __construct() {
30
-
31
- global $wpdb;
32
-
33
- parent::__construct();
34
-
35
- add_filter( 'query_monitor_menus', array( $this, 'admin_menu' ), 110 );
36
-
37
- # If QueryMonitorDB is in place then we'll use the values which were
38
- # caught early before any plugins had a chance to alter them
39
-
40
- foreach ( $this->php_vars as $setting ) {
41
- if ( isset( $wpdb->qm_php_vars ) and isset( $wpdb->qm_php_vars[$setting] ) )
42
- $val = $wpdb->qm_php_vars[$setting];
43
- else
44
- $val = ini_get( $setting );
45
- $this->data['php']['variables'][$setting]['before'] = $val;
46
- }
47
-
48
- }
49
-
50
- public static function get_error_levels( $error_reporting ) {
51
-
52
- $levels = array();
53
-
54
- $constants = array(
55
- 'E_ERROR',
56
- 'E_WARNING',
57
- 'E_PARSE',
58
- 'E_NOTICE',
59
- 'E_CORE_ERROR',
60
- 'E_CORE_WARNING',
61
- 'E_COMPILE_ERROR',
62
- 'E_COMPILE_WARNING',
63
- 'E_USER_ERROR',
64
- 'E_USER_WARNING',
65
- 'E_USER_NOTICE',
66
- 'E_STRICT',
67
- 'E_RECOVERABLE_ERROR',
68
- 'E_DEPRECATED',
69
- 'E_USER_DEPRECATED',
70
- 'E_ALL'
71
- );
72
-
73
- foreach ( $constants as $level ) {
74
- if ( defined( $level ) ) {
75
- $c = constant( $level );
76
- if ( $error_reporting & $c )
77
- $levels[$c] = $level;
78
- }
79
- }
80
-
81
- return $levels;
82
-
83
- }
84
-
85
- function admin_menu( array $menu ) {
86
-
87
- $menu[] = $this->menu( array(
88
- 'title' => __( 'Environment', 'query-monitor' )
89
- ) );
90
- return $menu;
91
-
92
- }
93
-
94
- function process() {
95
-
96
- global $wp_version, $blog_id;
97
-
98
- $mysql_vars = array(
99
- 'key_buffer_size' => true, # Key cache size limit
100
- 'max_allowed_packet' => false, # Individual query size limit
101
- 'max_connections' => false, # Max number of client connections
102
- 'query_cache_limit' => true, # Individual query cache size limit
103
- 'query_cache_size' => true, # Total cache size limit
104
- 'query_cache_type' => 'ON' # Query cache on or off
105
- );
106
- $php_u = '';
107
-
108
- if ( $dbq = $this->get_component( 'db_queries' ) ) {
109
-
110
- foreach ( $dbq->db_objects as $id => $db ) {
111
-
112
- if ( !is_a( $db, 'wpdb' ) )
113
- continue;
114
-
115
- $variables = $db->get_results( "
116
- SHOW VARIABLES
117
- WHERE Variable_name IN ( '" . implode( "', '", array_keys( $mysql_vars ) ) . "' )
118
- " );
119
-
120
- if ( is_resource( $db->dbh ) ) {
121
- $version = mysql_get_server_info( $db->dbh );
122
- $driver = 'mysql';
123
- } else if ( is_object( $db->dbh ) and method_exists( $db->dbh, 'db_version' ) ) {
124
- $version = $db->dbh->db_version();
125
- $driver = get_class( $db->dbh );
126
- } else {
127
- $version = $driver = '<span class="qm-warn">' . __( 'Unknown', 'query-monitor' ) . '</span>';
128
- }
129
-
130
- $this->data['db'][$id] = array(
131
- 'version' => $version,
132
- 'driver' => $driver,
133
- 'user' => $db->dbuser,
134
- 'host' => $db->dbhost,
135
- 'name' => $db->dbname,
136
- 'vars' => $mysql_vars,
137
- 'variables' => $variables
138
- );
139
-
140
- }
141
-
142
- }
143
-
144
- if ( function_exists( 'posix_getpwuid' ) ) {
145
-
146
- $u = posix_getpwuid( posix_getuid() );
147
- $g = posix_getgrgid( $u['gid'] );
148
- $php_u = esc_html( $u['name'] . ':' . $g['name'] );
149
-
150
- } else if ( isset( $_SERVER['USER'] ) ) {
151
-
152
- $php_u = esc_html( $_SERVER['USER'] );
153
-
154
- } else if ( function_exists( 'exec' ) ) {
155
-
156
- $php_u = esc_html( exec( 'whoami' ) );
157
-
158
- }
159
-
160
- if ( empty( $php_u ) )
161
- $php_u = '<em>' . __( 'Unknown', 'query-monitor' ) . '</em>';
162
-
163
- $this->data['php']['version'] = phpversion();
164
- $this->data['php']['user'] = $php_u;
165
-
166
- foreach ( $this->php_vars as $setting )
167
- $this->data['php']['variables'][$setting]['after'] = ini_get( $setting );
168
-
169
- $this->data['php']['error_reporting'] = error_reporting();
170
-
171
- # @TODO put WP's other debugging constants in here, eg. SCRIPT_DEBUG
172
- $this->data['wp'] = array(
173
- 'version' => $wp_version,
174
- 'WP_DEBUG' => QM_Util::format_bool_constant( 'WP_DEBUG' ),
175
- 'WP_LOCAL_DEV' => QM_Util::format_bool_constant( 'WP_LOCAL_DEV' ),
176
- );
177
-
178
- if ( is_multisite() )
179
- $this->data['wp']['blog_id'] = $blog_id;
180
-
181
- $server = explode( ' ', $_SERVER['SERVER_SOFTWARE'] );
182
- $server = explode( '/', reset( $server ) );
183
-
184
- if ( isset( $server[1] ) )
185
- $server_version = $server[1];
186
- else
187
- $server_version = '<em>' . __( 'Unknown', 'query-monitor' ) . '</em>';
188
-
189
- $this->data['server'] = array(
190
- 'name' => $server[0],
191
- 'version' => $server_version,
192
- 'address' => $_SERVER['SERVER_ADDR'],
193
- 'host' => php_uname( 'n' )
194
- );
195
-
196
- }
197
-
198
- function output_html( array $args, array $data ) {
199
-
200
- echo '<div class="qm" id="' . $args['id'] . '">';
201
- echo '<table cellspacing="0">';
202
- echo '<thead>';
203
- echo '<tr>';
204
- echo '<th colspan="3">' . __( 'Environment', 'query-monitor' ) . '</th>';
205
- echo '</tr>';
206
- echo '</thead>';
207
- echo '<tbody>';
208
-
209
- echo '<tr>';
210
- echo '<td rowspan="' . ( 3 + count( $data['php']['variables'] ) ) . '">PHP</td>';
211
- echo '<td>version</td>';
212
- echo "<td>{$data['php']['version']}</td>";
213
- echo '</tr>';
214
- echo '<tr>';
215
- echo '<td>user</td>';
216
- echo "<td>{$data['php']['user']}</td>";
217
- echo '</tr>';
218
-
219
- foreach ( $data['php']['variables'] as $key => $val ) {
220
-
221
- $append = '';
222
-
223
- if ( $val['after'] != $val['before'] )
224
- $append .= '<br /><span class="qm-info">' . sprintf( __( 'Overridden at runtime from %s', 'query-monitor' ), $val['before'] ) . '</span>';
225
-
226
- echo '<tr>';
227
- echo "<td>{$key}</td>";
228
- echo "<td>{$val['after']}{$append}</td>";
229
- echo '</tr>';
230
- }
231
-
232
- $error_levels = implode( '<br/>', self::get_error_levels( $data['php']['error_reporting'] ) );
233
-
234
- echo '<tr>';
235
- echo '<td>error_reporting</td>';
236
- echo "<td>{$data['php']['error_reporting']}<br><span class='qm-info'>{$error_levels}</span></td>";
237
- echo '</tr>';
238
-
239
- if ( isset( $data['db'] ) ) {
240
-
241
- foreach ( $data['db'] as $id => $db ) {
242
-
243
- if ( 1 == count( $data['db'] ) )
244
- $name = 'MySQL';
245
- else
246
- $name = $id . '<br />MySQL';
247
-
248
- echo '<tr>';
249
- echo '<td rowspan="' . ( 5 + count( $db['variables'] ) ) . '">' . $name . '</td>';
250
- echo '<td>version</td>';
251
- echo '<td>' . $db['version'] . '</td>';
252
- echo '</tr>';
253
-
254
- echo '<tr>';
255
- echo '<td>driver</td>';
256
- echo '<td>' . $db['driver'] . '</td>';
257
- echo '</tr>';
258
-
259
- echo '<tr>';
260
- echo '<td>user</td>';
261
- echo '<td>' . $db['user'] . '</td>';
262
- echo '</tr>';
263
-
264
- echo '<tr>';
265
- echo '<td>host</td>';
266
- echo '<td>' . $db['host'] . '</td>';
267
- echo '</tr>';
268
-
269
- echo '<tr>';
270
- echo '<td>database</td>';
271
- echo '<td>' . $db['name'] . '</td>';
272
- echo '</tr>';
273
-
274
- echo '<tr>';
275
-
276
- $first = true;
277
- $warn = __( "This value may not be optimal. Check the recommended configuration for '%s'.", 'query-monitor' );
278
- $search = __( 'https://www.google.com/search?q=mysql+performance+%s', 'query-monitor' );
279
-
280
- foreach ( $db['variables'] as $setting ) {
281
-
282
- $key = $setting->Variable_name;
283
- $val = $setting->Value;
284
- $prepend = '';
285
- $show_warning = false;
286
-
287
- if ( ( true === $db['vars'][$key] ) and empty( $val ) )
288
- $show_warning = true;
289
- else if ( is_string( $db['vars'][$key] ) and ( $val !== $db['vars'][$key] ) )
290
- $show_warning = true;
291
-
292
- if ( $show_warning )
293
- $prepend .= '&nbsp;<span class="qm-info">(<a href="' . esc_url( sprintf( $search, $key ) ) . '" target="_blank" title="' . esc_attr( sprintf( $warn, $key ) ) . '">' . __( 'Help', 'query-monitor' ) . '</a>)</span>';
294
-
295
- if ( is_numeric( $val ) and ( $val >= ( 1024*1024 ) ) )
296
- $prepend .= '<br /><span class="qm-info">~' . size_format( $val ) . '</span>';
297
-
298
- $class = ( $show_warning ) ? 'qm-warn' : '';
299
-
300
- if ( !$first )
301
- echo "<tr class='{$class}'>";
302
-
303
- $key = esc_html( $key );
304
- $val = esc_html( $val );
305
-
306
- echo "<td>{$key}</td>";
307
- echo "<td>{$val}{$prepend}</td>";
308
-
309
- echo '</tr>';
310
-
311
- $first = false;
312
-
313
- }
314
-
315
- }
316
-
317
- }
318
-
319
- echo '<tr>';
320
- echo '<td rowspan="' . count( $data['wp'] ). '">WordPress</td>';
321
-
322
- $first = true;
323
-
324
- foreach ( $data['wp'] as $key => $val ) {
325
-
326
- if ( !$first )
327
- echo "<tr>";
328
-
329
- echo "<td>{$key}</td>";
330
- echo "<td>{$val}</td>";
331
- echo '</tr>';
332
-
333
- $first = false;
334
-
335
- }
336
-
337
- echo '<tr>';
338
- echo '<td rowspan="4">' . __( 'Server', 'query-monitor' ) . '</td>';
339
- echo '<td>software</td>';
340
- echo "<td>{$data['server']['name']}</td>";
341
- echo '</tr>';
342
-
343
- echo '<tr>';
344
- echo '<td>version</td>';
345
- echo "<td>{$data['server']['version']}</td>";
346
- echo '</tr>';
347
-
348
- echo '<tr>';
349
- echo '<td>address</td>';
350
- echo "<td>{$data['server']['address']}</td>";
351
- echo '</tr>';
352
-
353
- echo '<tr>';
354
- echo '<td>host</td>';
355
- echo "<td>{$data['server']['host']}</td>";
356
- echo '</tr>';
357
-
358
- echo '</tbody>';
359
- echo '</table>';
360
- echo '</div>';
361
-
362
- }
363
-
364
- }
365
-
366
- function register_qm_environment( array $qm ) {
367
- $qm['environment'] = new QM_Component_Environment;
368
- return $qm;
369
- }
370
-
371
- add_filter( 'query_monitor_components', 'register_qm_environment', 90 );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
components/php_errors.php DELETED
@@ -1,253 +0,0 @@
1
- <?php
2
- /*
3
- Copyright 2013 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_Component_PHP_Errors extends QM_Component {
18
-
19
- var $id = 'php_errors';
20
-
21
- function __construct() {
22
-
23
- parent::__construct();
24
- set_error_handler( array( $this, 'error_handler' ) );
25
- add_filter( 'query_monitor_menus', array( $this, 'admin_menu' ), 10 );
26
- add_filter( 'query_monitor_class', array( $this, 'admin_class' ) );
27
-
28
- }
29
-
30
- function admin_class( array $class ) {
31
-
32
- if ( isset( $this->data['errors']['warning'] ) )
33
- $class[] = 'qm-warning';
34
- else if ( isset( $this->data['errors']['notice'] ) )
35
- $class[] = 'qm-notice';
36
- else if ( isset( $this->data['errors']['strict'] ) )
37
- $class[] = 'qm-strict';
38
-
39
- return $class;
40
-
41
- }
42
-
43
- function admin_menu( array $menu ) {
44
-
45
- if ( isset( $this->data['errors']['warning'] ) ) {
46
- $menu[] = $this->menu( array(
47
- 'id' => 'query-monitor-warnings',
48
- 'title' => sprintf( __( 'PHP Warnings (%s)', 'query-monitor' ), number_format_i18n( count( $this->data['errors']['warning'] ) ) )
49
- ) );
50
- }
51
- if ( isset( $this->data['errors']['notice'] ) ) {
52
- $menu[] = $this->menu( array(
53
- 'id' => 'query-monitor-notices',
54
- 'title' => sprintf( __( 'PHP Notices (%s)', 'query-monitor' ), number_format_i18n( count( $this->data['errors']['notice'] ) ) )
55
- ) );
56
- }
57
- if ( isset( $this->data['errors']['strict'] ) ) {
58
- $menu[] = $this->menu( array(
59
- 'id' => 'query-monitor-stricts',
60
- 'title' => sprintf( __( 'PHP Stricts (%s)', 'query-monitor' ), number_format_i18n( count( $this->data['errors']['strict'] ) ) )
61
- ) );
62
- }
63
- return $menu;
64
-
65
- }
66
-
67
- function output_headers( array $args, array $data ) {
68
-
69
- if ( empty( $data['errors'] ) )
70
- return;
71
-
72
- $count = 0;
73
-
74
- foreach ( $data['errors'] as $type => $errors ) {
75
-
76
- foreach ( $errors as $key => $error ) {
77
-
78
- $count++;
79
-
80
- # @TODO we should calculate the component during process() so we don't need to do it
81
- # separately in output_html() and output_headers().
82
- $component = QM_Util::get_backtrace_component( $error->trace );
83
- $output_error = array(
84
- 'type' => $error->type,
85
- 'message' => $error->message,
86
- 'file' => $error->file,
87
- 'line' => $error->line,
88
- 'stack' => $error->trace->get_stack(),
89
- 'component' => $component->name,
90
- );
91
-
92
- header( sprintf( 'X-QM-Error-%d: %s',
93
- $count,
94
- json_encode( $output_error )
95
- ) );
96
-
97
- }
98
-
99
- }
100
-
101
- header( sprintf( 'X-QM-Errors: %d',
102
- $count
103
- ) );
104
-
105
- }
106
-
107
- function output_html( array $args, array $data ) {
108
-
109
- if ( empty( $data['errors'] ) )
110
- return;
111
-
112
- echo '<div class="qm" id="' . $args['id'] . '">';
113
- echo '<table cellspacing="0">';
114
- echo '<thead>';
115
- echo '<tr>';
116
- echo '<th colspan="2">' . __( 'PHP Error', 'query-monitor' ) . '</th>';
117
- echo '<th>' . __( 'File', 'query-monitor' ) . '</th>';
118
- echo '<th>' . __( 'Line', 'query-monitor' ) . '</th>';
119
- echo '<th>' . __( 'Call Stack', 'query-monitor' ) . '</th>';
120
- echo '<th>' . __( 'Component', 'query-monitor' ) . '</th>';
121
- echo '</tr>';
122
- echo '</thead>';
123
- echo '<tbody>';
124
-
125
- $types = array(
126
- 'warning' => __( 'Warning', 'query-monitor' ),
127
- 'notice' => __( 'Notice', 'query-monitor' ),
128
- 'strict' => __( 'Strict', 'query-monitor' ),
129
- );
130
-
131
- foreach ( $types as $type => $title ) {
132
-
133
- if ( isset( $data['errors'][$type] ) ) {
134
-
135
- echo '<tr>';
136
- if ( count( $data['errors'][$type] ) > 1 )
137
- echo '<td rowspan="' . count( $data['errors'][$type] ) . '">' . $title . '</td>';
138
- else
139
- echo '<td>' . $title . '</td>';
140
- $first = true;
141
-
142
- foreach ( $data['errors'][$type] as $error ) {
143
-
144
- if ( !$first )
145
- echo '<tr>';
146
-
147
- $stack = $error->trace->get_stack();
148
- $component = QM_Util::get_backtrace_component( $error->trace );
149
-
150
- if ( empty( $stack ) )
151
- $stack = '<em>' . __( 'none', 'query-monitor' ) . '</em>';
152
- else
153
- $stack = implode( '<br />', $stack );
154
-
155
- $message = str_replace( "href='function.", "target='_blank' href='http://php.net/function.", $error->message );
156
-
157
- echo '<td>' . $message . '</td>';
158
- echo '<td title="' . esc_attr( $error->file ) . '">' . esc_html( $error->filename ) . '</td>';
159
- echo '<td>' . esc_html( $error->line ) . '</td>';
160
- echo '<td class="qm-ltr">' . $stack . '</td>';
161
- echo '<td>' . $component->name . '</td>';
162
- echo '</tr>';
163
-
164
- $first = false;
165
-
166
- }
167
-
168
- }
169
-
170
- }
171
-
172
- echo '</tbody>';
173
- echo '</table>';
174
- echo '</div>';
175
-
176
- }
177
-
178
- function error_handler( $errno, $message, $file = null, $line = null ) {
179
-
180
- #if ( !( error_reporting() & $errno ) )
181
- # return false;
182
-
183
- switch ( $errno ) {
184
-
185
- case E_WARNING:
186
- case E_USER_WARNING:
187
- $type = 'warning';
188
- break;
189
-
190
- case E_NOTICE:
191
- case E_USER_NOTICE:
192
- $type = 'notice';
193
- break;
194
-
195
- case E_STRICT:
196
- $type = 'strict';
197
- break;
198
-
199
- default:
200
- return false;
201
- break;
202
-
203
- }
204
-
205
- if ( error_reporting() > 0 ) {
206
-
207
- $trace = new QM_Backtrace;
208
- $stack = $trace->get_stack();
209
- $func = reset( $stack );
210
- $key = md5( $message . $file . $line . $func );
211
-
212
- $filename = QM_Util::standard_dir( $file, '' );
213
-
214
- if ( isset( $this->data['errors'][$type][$key] ) ) {
215
- $this->data['errors'][$type][$key]->calls++;
216
- } else {
217
- $this->data['errors'][$type][$key] = (object) array(
218
- 'errno' => $errno,
219
- 'type' => $type,
220
- 'message' => $message,
221
- 'file' => $file,
222
- 'filename' => $filename,
223
- 'line' => $line,
224
- 'trace' => $trace,
225
- 'calls' => 1
226
- );
227
- }
228
-
229
- }
230
-
231
- return apply_filters( 'query_monitor_php_errors_return_value', true );
232
-
233
- }
234
-
235
- }
236
-
237
- function register_qm_php_errors( array $qm ) {
238
- $qm['php_errors'] = new QM_Component_PHP_Errors;
239
- return $qm;
240
- }
241
-
242
- function qm_php_errors_return_value( $return ) {
243
- if ( QM_Util::is_ajax() )
244
- return true;
245
- # If Xdebug is enabled we'll return false so Xdebug's error handler can do its thing.
246
- if ( function_exists( 'xdebug_is_enabled' ) and xdebug_is_enabled() )
247
- return false;
248
- else
249
- return $return;
250
- }
251
-
252
- add_filter( 'query_monitor_components', 'register_qm_php_errors', 120 );
253
- add_filter( 'query_monitor_php_errors_return_value', 'qm_php_errors_return_value' );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
components/query_vars.php DELETED
@@ -1,126 +0,0 @@
1
- <?php
2
- /*
3
- Copyright 2013 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_Component_Query_Vars extends QM_Component {
18
-
19
- var $id = 'query_vars';
20
-
21
- function __construct() {
22
- parent::__construct();
23
- add_filter( 'query_monitor_menus', array( $this, 'admin_menu' ), 90 );
24
- }
25
-
26
- function process() {
27
-
28
- $plugin_qvars = array_flip( apply_filters( 'query_vars', array() ) );
29
- $qvars = $GLOBALS['wp_query']->query_vars;
30
- $query_vars = array();
31
-
32
- foreach ( $qvars as $k => $v ) {
33
- if ( isset( $plugin_qvars[$k] ) ) {
34
- if ( '' !== $v )
35
- $query_vars[$k] = $v;
36
- } else {
37
- if ( !empty( $v ) )
38
- $query_vars[$k] = $v;
39
- }
40
- }
41
-
42
- ksort( $query_vars );
43
-
44
- # First add plugin vars to $this->data['qvars']:
45
- foreach ( $query_vars as $k => $v ) {
46
- if ( isset( $plugin_qvars[$k] ) ) {
47
- $this->data['qvars'][$k] = $v;
48
- $this->data['plugin_qvars'][$k] = $v;
49
- }
50
- }
51
-
52
- # Now add all other vars to $this->data['qvars']:
53
- foreach ( $query_vars as $k => $v ) {
54
- if ( !isset( $plugin_qvars[$k] ) )
55
- $this->data['qvars'][$k] = $v;
56
- }
57
-
58
- }
59
-
60
- function output_html( array $args, array $data ) {
61
-
62
- echo '<div class="qm qm-half" id="' . $args['id'] . '">';
63
- echo '<table cellspacing="0">';
64
- echo '<thead>';
65
- echo '<tr>';
66
- echo '<th colspan="2">' . __( 'Query Vars', 'query-monitor' ) . '</th>';
67
- echo '</tr>';
68
- echo '</thead>';
69
- echo '<tbody>';
70
-
71
- if ( !empty( $data['qvars'] ) ) {
72
-
73
- foreach( $data['qvars'] as $var => $value ) {
74
- echo '<tr>';
75
- if ( isset( $data['plugin_qvars'][$var] ) )
76
- echo "<td valign='top'><span class='qm-current'>{$var}</span></td>";
77
- else
78
- echo "<td valign='top'>{$var}</td>";
79
- if ( is_array( $value ) or is_object( $value ) ) {
80
- echo '<td valign="top"><pre>';
81
- print_r( $value );
82
- echo '</pre></td>';
83
- } else {
84
- $value = esc_html( $value );
85
- echo "<td valign='top'>{$value}</td>";
86
- }
87
- echo '</tr>';
88
- }
89
-
90
- } else {
91
-
92
- echo '<tr>';
93
- echo '<td colspan="2" style="text-align:center !important"><em>' . __( 'none', 'query-monitor' ) . '</em></td>';
94
- echo '</tr>';
95
-
96
- }
97
-
98
- echo '</tbody>';
99
- echo '</table>';
100
- echo '</div>';
101
-
102
- }
103
-
104
- function admin_menu( array $menu ) {
105
-
106
- $count = isset( $this->data['plugin_qvars'] ) ? count( $this->data['plugin_qvars'] ) : 0;
107
-
108
- $title = ( empty( $count ) )
109
- ? __( 'Query Vars', 'query-monitor' )
110
- : __( 'Query Vars (+%s)', 'query-monitor' );
111
-
112
- $menu[] = $this->menu( array(
113
- 'title' => sprintf( $title, number_format_i18n( $count ) )
114
- ) );
115
- return $menu;
116
-
117
- }
118
-
119
- }
120
-
121
- function register_qm_query_vars( array $qm ) {
122
- $qm['query_vars'] = new QM_Component_Query_Vars;
123
- return $qm;
124
- }
125
-
126
- add_filter( 'query_monitor_components', 'register_qm_query_vars', 70 );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
components/theme.php DELETED
@@ -1,128 +0,0 @@
1
- <?php
2
- /*
3
- Copyright 2013 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_Component_Theme extends QM_Component {
18
-
19
- var $id = 'theme';
20
-
21
- function __construct() {
22
- parent::__construct();
23
- add_filter( 'body_class', array( $this, 'body_class' ), 99 );
24
- add_filter( 'query_monitor_menus', array( $this, 'admin_menu' ), 100 );
25
- }
26
-
27
- function body_class( $class ) {
28
- $this->data['body_class'] = $class;
29
- return $class;
30
- }
31
-
32
- function process() {
33
-
34
- global $template;
35
-
36
- $template_file = QM_Util::standard_dir( $template );
37
- $stylesheet_directory = QM_Util::standard_dir( get_stylesheet_directory() );
38
- $template_directory = QM_Util::standard_dir( get_template_directory() );
39
-
40
- $template_file = str_replace( array( $stylesheet_directory, $template_directory ), '', $template_file );
41
- $template_file = ltrim( $template_file, '/' );
42
-
43
- $this->data['template_file'] = apply_filters( 'query_monitor_template', $template_file, $template );
44
- $this->data['stylesheet'] = get_stylesheet();
45
- $this->data['template'] = get_template();
46
-
47
- if ( isset( $this->data['body_class'] ) )
48
- asort( $this->data['body_class'] );
49
-
50
- }
51
-
52
- function output_html( array $args, array $data ) {
53
-
54
- if ( empty( $data ) )
55
- return;
56
-
57
- echo '<div class="qm qm-half" id="' . $args['id'] . '">';
58
- echo '<table cellspacing="0">';
59
- echo '<thead>';
60
- echo '<tr>';
61
- echo '<th colspan="2">' . __( 'Theme', 'query-monitor' ) . '</th>';
62
- echo '</tr>';
63
- echo '</thead>';
64
-
65
- echo '<tbody>';
66
- echo '<tr>';
67
- echo '<td>' . __( 'Template', 'query-monitor' ) . '</td>';
68
- echo "<td>{$this->data['template_file']}</td>";
69
- echo '</tr>';
70
-
71
- if ( !empty( $data['body_class'] ) ) {
72
-
73
- echo '<tr>';
74
- echo '<td rowspan="' . count( $data['body_class'] ) . '">' . __( 'Body Classes', 'query-monitor' ) . '</td>';
75
- $first = true;
76
-
77
- foreach ( $data['body_class'] as $class ) {
78
-
79
- if ( !$first )
80
- echo '<tr>';
81
-
82
- echo "<td>{$class}</td>";
83
- echo '</tr>';
84
-
85
- $first = false;
86
-
87
- }
88
-
89
- }
90
-
91
- echo '<tr>';
92
- echo '<td>' . __( 'Theme', 'query-monitor' ) . '</td>';
93
- echo "<td>{$this->data['stylesheet']}</td>";
94
- echo '</tr>';
95
-
96
- if ( $this->data['stylesheet'] != $this->data['template'] ) {
97
- echo '<tr>';
98
- echo '<td>' . __( 'Parent Theme', 'query-monitor' ) . '</td>';
99
- echo "<td>{$this->data['template']}</td>";
100
- echo '</tr>';
101
- }
102
-
103
- echo '</tbody>';
104
- echo '</table>';
105
- echo '</div>';
106
-
107
- }
108
-
109
- function admin_menu( array $menu ) {
110
-
111
- if ( isset( $this->data['template_file'] ) ) {
112
- $menu[] = $this->menu( array(
113
- 'title' => sprintf( __( 'Template: %s', 'query-monitor' ), $this->data['template_file'] )
114
- ) );
115
- }
116
- return $menu;
117
-
118
- }
119
-
120
- }
121
-
122
- function register_qm_theme( array $qm ) {
123
- if ( !is_admin() )
124
- $qm['theme'] = new QM_Component_Theme;
125
- return $qm;
126
- }
127
-
128
- add_filter( 'query_monitor_components', 'register_qm_theme', 60 );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
composer.json CHANGED
@@ -1,7 +1,7 @@
1
  {
2
  "name" : "johnbillion/query-monitor",
3
  "description": "WordPress plugin for monitoring database queries, hooks, conditionals, HTTP requests, query vars, environment, redirects, and more.",
4
- "homepage" : "https://github.com/johnbillion/QueryMonitor/",
5
  "type" : "wordpress-plugin",
6
  "license" : "GPL-2.0+",
7
  "authors" : [
1
  {
2
  "name" : "johnbillion/query-monitor",
3
  "description": "WordPress plugin for monitoring database queries, hooks, conditionals, HTTP requests, query vars, environment, redirects, and more.",
4
+ "homepage" : "https://github.com/johnbillion/query-monitor/",
5
  "type" : "wordpress-plugin",
6
  "license" : "GPL-2.0+",
7
  "authors" : [
dispatchers/Headers.php ADDED
@@ -0,0 +1,77 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+
4
+ Copyright 2013 John Blackbourn
5
+
6
+ This program is free software; you can redistribute it and/or modify
7
+ it under the terms of the GNU General Public License as published by
8
+ the Free Software Foundation; either version 2 of the License, or
9
+ (at your option) any later version.
10
+
11
+ This program is distributed in the hope that it will be useful,
12
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
+ GNU General Public License for more details.
15
+
16
+ */
17
+
18
+ class QM_Dispatcher_Headers extends QM_Dispatcher {
19
+
20
+ public $id = 'headers';
21
+
22
+ public function __construct( QM_Plugin $qm ) {
23
+ parent::__construct( $qm );
24
+ }
25
+
26
+ public function init() {
27
+
28
+ if ( QM_Util::is_ajax() )
29
+ ob_start();
30
+
31
+ }
32
+
33
+ public function before_output() {
34
+
35
+ require_once $this->qm->plugin_path( 'output/Headers.php' );
36
+
37
+ foreach ( glob( $this->qm->plugin_path( 'output/headers/*.php' ) ) as $output ) {
38
+ include $output;
39
+ }
40
+
41
+ }
42
+
43
+ public function after_output() {
44
+
45
+ # flush once, because we're nice
46
+ if ( ob_get_length() )
47
+ ob_flush();
48
+
49
+ }
50
+
51
+ public function get_outputter( QM_Collector $collector ) {
52
+ return new QM_Output_Headers( $collector );
53
+ }
54
+
55
+ public function active() {
56
+
57
+ if ( !$this->qm->show_query_monitor() ) {
58
+ return false;
59
+ }
60
+
61
+ # if the headers have already been sent then we can't do anything about it
62
+ if ( headers_sent() ) {
63
+ return false;
64
+ }
65
+
66
+ return true;
67
+
68
+ }
69
+
70
+ }
71
+
72
+ function register_qm_dispatcher_headers( array $dispatchers, QM_Plugin $qm ) {
73
+ $dispatchers['headers'] = new QM_Dispatcher_Headers( $qm );
74
+ return $dispatchers;
75
+ }
76
+
77
+ add_filter( 'query_monitor_dispatchers', 'register_qm_dispatcher_headers', 10, 2 );
dispatchers/Html.php ADDED
@@ -0,0 +1,176 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+
4
+ Copyright 2013 John Blackbourn
5
+
6
+ This program is free software; you can redistribute it and/or modify
7
+ it under the terms of the GNU General Public License as published by
8
+ the Free Software Foundation; either version 2 of the License, or
9
+ (at your option) any later version.
10
+
11
+ This program is distributed in the hope that it will be useful,
12
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
+ GNU General Public License for more details.
15
+
16
+ */
17
+
18
+ class QM_Dispatcher_Html extends QM_Dispatcher {
19
+
20
+ public $id = 'html';
21
+
22
+ public function __construct( QM_Plugin $qm ) {
23
+
24
+ add_action( 'admin_bar_menu', array( $this, 'action_admin_bar_menu' ), 999 );
25
+
26
+ parent::__construct( $qm );
27
+
28
+ }
29
+
30
+ public function action_admin_bar_menu( WP_Admin_Bar $wp_admin_bar ) {
31
+
32
+ if ( !$this->qm->show_query_monitor() )
33
+ return;
34
+
35
+ $class = implode( ' ', array( 'hide-if-js', QM_Util::wpv() ) );
36
+ $title = __( 'Query Monitor', 'query-monitor' );
37
+
38
+ $wp_admin_bar->add_menu( array(
39
+ 'id' => 'query-monitor',
40
+ 'title' => $title,
41
+ 'href' => '#qm-overview',
42
+ 'meta' => array(
43
+ 'classname' => $class
44
+ )
45
+ ) );
46
+
47
+ $wp_admin_bar->add_menu( array(
48
+ 'parent' => 'query-monitor',
49
+ 'id' => 'query-monitor-placeholder',
50
+ 'title' => $title,
51
+ 'href' => '#qm-overview'
52
+ ) );
53
+
54
+ }
55
+
56
+ public function init() {
57
+
58
+ global $wp_locale;
59
+
60
+ if ( !defined( 'DONOTCACHEPAGE' ) )
61
+ define( 'DONOTCACHEPAGE', 1 );
62
+
63
+ wp_enqueue_style(
64
+ 'query-monitor',
65
+ $this->qm->plugin_url( 'assets/query-monitor.css' ),
66
+ null,
67
+ $this->qm->plugin_ver( 'assets/query-monitor.css' )
68
+ );
69
+ wp_enqueue_script(
70
+ 'query-monitor',
71
+ $this->qm->plugin_url( 'assets/query-monitor.js' ),
72
+ array( 'jquery' ),
73
+ $this->qm->plugin_ver( 'assets/query-monitor.js' ),
74
+ true
75
+ );
76
+ wp_localize_script(
77
+ 'query-monitor',
78
+ 'qm_locale',
79
+ (array) $wp_locale
80
+ );
81
+ wp_localize_script(
82
+ 'query-monitor',
83
+ 'qm_l10n',
84
+ array(
85
+ 'ajax_error' => __( 'PHP Error in AJAX Response', 'query-monitor' ),
86
+ )
87
+ );
88
+
89
+ }
90
+
91
+ public function before_output() {
92
+
93
+ # @TODO document why this is needed
94
+ # Flush the output buffer to avoid crashes
95
+ if ( !is_feed() ) {
96
+ while ( ob_get_length() )
97
+ ob_end_flush();
98
+ }
99
+
100
+ require_once $this->qm->plugin_path( 'output/Html.php' );
101
+
102
+ foreach ( glob( $this->qm->plugin_path( 'output/html/*.php' ) ) as $output ) {
103
+ include $output;
104
+ }
105
+
106
+ if ( !function_exists( 'is_admin_bar_showing' ) or !is_admin_bar_showing() )
107
+ $class = 'qm-show';
108
+ else
109
+ $class = '';
110
+
111
+ echo '<div id="qm" class="' . $class . '">';
112
+ echo '<div id="qm-wrapper">';
113
+ echo '<p>' . __( 'Query Monitor', 'query-monitor' ) . '</p>';
114
+
115
+ }
116
+
117
+ public function after_output() {
118
+
119
+ echo '</div>';
120
+ echo '</div>';
121
+
122
+ $json = array(
123
+ 'menu' => $this->js_admin_bar_menu(),
124
+ 'ajax_errors' => array() # @TODO move this into the php_errors collector
125
+ );
126
+
127
+ echo '<script type="text/javascript">' . "\n\n";
128
+ echo 'var qm = ' . json_encode( $json ) . ';' . "\n\n";
129
+ echo '</script>' . "\n\n";
130
+
131
+ }
132
+
133
+ public function get_outputter( QM_Collector $collector ) {
134
+ return new QM_Output_Html( $collector );
135
+ }
136
+
137
+ public function js_admin_bar_menu() {
138
+
139
+ $class = implode( ' ', apply_filters( 'query_monitor_class', array( QM_Util::wpv() ) ) );
140
+ $title = implode( ' &nbsp; ', apply_filters( 'query_monitor_title', array() ) );
141
+
142
+ if ( empty( $title ) )
143
+ $title = __( 'Query Monitor', 'query-monitor' );
144
+
145
+ $admin_bar_menu = array(
146
+ 'top' => array(
147
+ 'title' => sprintf( '<span class="ab-icon">QM</span><span class="ab-label">%s</span>', $title ),
148
+ 'classname' => $class
149
+ ),
150
+ 'sub' => array()
151
+ );
152
+
153
+ foreach ( apply_filters( 'query_monitor_menus', array() ) as $menu )
154
+ $admin_bar_menu['sub'][] = $menu;
155
+
156
+ return $admin_bar_menu;
157
+
158
+ }
159
+
160
+ public function active() {
161
+
162
+ if ( !$this->qm->show_query_monitor() ) {
163
+ return false;
164
+ }
165
+
166
+ return $this->qm->did_footer();
167
+ }
168
+
169
+ }
170
+
171
+ function register_qm_dispatcher_html( array $dispatchers, QM_Plugin $qm ) {
172
+ $dispatchers['html'] = new QM_Dispatcher_Html( $qm );
173
+ return $dispatchers;
174
+ }
175
+
176
+ add_filter( 'query_monitor_dispatchers', 'register_qm_dispatcher_html', 10, 2 );
autoloader.php → output/Headers.php RENAMED
@@ -1,5 +1,6 @@
1
  <?php
2
  /*
 
3
  Copyright 2013 John Blackbourn
4
 
5
  This program is free software; you can redistribute it and/or modify
@@ -14,22 +15,19 @@ GNU General Public License for more details.
14
 
15
  */
16
 
17
- function qm_autoloader( $class ) {
18
-
19
- if ( 0 !== strpos( $class, 'QM_' ) )
20
- return;
21
 
22
- $name = preg_replace( '|^QM_|', '', $class );
23
- $name = str_replace( '_', '/', $name );
 
24
 
25
- $file = sprintf( '%1$s/%2$s.php',
26
- dirname( __FILE__ ),
27
- $name
28
- );
29
 
30
- if ( is_readable( $file ) )
31
- include $file;
 
32
 
33
  }
34
-
35
- spl_autoload_register( 'qm_autoloader' );
1
  <?php
2
  /*
3
+
4
  Copyright 2013 John Blackbourn
5
 
6
  This program is free software; you can redistribute it and/or modify
15
 
16
  */
17
 
18
+ class QM_Output_Headers implements QM_Output {
 
 
 
19
 
20
+ public function __construct( QM_Collector $collector ) {
21
+ $this->collector = $collector;
22
+ }
23
 
24
+ public function output() {
25
+ # Headers output does nothing by default
26
+ return false;
27
+ }
28
 
29
+ final public function get_type() {
30
+ return 'headers';
31
+ }
32
 
33
  }
 
 
output/Html.php ADDED
@@ -0,0 +1,89 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+
4
+ Copyright 2013 John Blackbourn
5
+
6
+ This program is free software; you can redistribute it and/or modify
7
+ it under the terms of the GNU General Public License as published by
8
+ the Free Software Foundation; either version 2 of the License, or
9
+ (at your option) any later version.
10
+
11
+ This program is distributed in the hope that it will be useful,
12
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
+ GNU General Public License for more details.
15
+
16
+ */
17
+
18
+ class QM_Output_Html implements QM_Output {
19
+
20
+ public function __construct( QM_Collector $collector ) {
21
+ $this->collector = $collector;
22
+ }
23
+
24
+ public function output() {
25
+
26
+ $data = $this->collector->get_data();
27
+ $name = $this->collector->name();
28
+
29
+ if ( empty( $data ) )
30
+ return;
31
+
32
+ echo '<div class="qm" id="' . $this->collector->id() . '">';
33
+ echo '<table cellspacing="0">';
34
+ if ( !empty( $name ) ) {
35
+ echo '<thead>';
36
+ echo '<tr>';
37
+ echo '<th colspan="2">' . $name . '</th>';
38
+ echo '</tr>';
39
+ echo '</thead>';
40
+ }
41
+ echo '<tbody>';
42
+
43
+ foreach ( $data as $key => $value ) {
44
+ echo '<tr>';
45
+ echo '<td>' . esc_html( $key ) . '</td>';
46
+ if ( is_object( $value ) or is_array( $value ) ) {
47
+ echo '<td><pre>' . print_r( $value, true ) . '</pre></td>';
48
+ } else {
49
+ echo '<td>' . esc_html( $value ) . '</td>';
50
+ }
51
+ echo '</tr>';
52
+ }
53
+
54
+ echo '</tbody>';
55
+ echo '</table>';
56
+ echo '</div>';
57
+
58
+ }
59
+
60
+ protected function build_filter( $name, array $values ) {
61
+
62
+ usort( $values, 'strcasecmp' );
63
+
64
+ $out = '<select id="qm-filter-' . esc_attr( $this->collector->id . '-' . $name ) . '" class="qm-filter" data-filter="' . esc_attr( $this->collector->id . '-' . $name ) . '">';
65
+ $out .= '<option value="">' . _x( 'All', '"All" option for filters', 'query-monitor' ) . '</option>';
66
+
67
+ foreach ( $values as $value )
68
+ $out .= '<option value="' . esc_attr( $value ) . '">' . esc_html( $value ) . '</option>';
69
+
70
+ $out .= '</select>';
71
+
72
+ return $out;
73
+
74
+ }
75
+
76
+ protected function menu( array $args ) {
77
+
78
+ return array_merge( array(
79
+ 'id' => "query-monitor-{$this->collector->id}",
80
+ 'href' => '#' . $this->collector->id()
81
+ ), $args );
82
+
83
+ }
84
+
85
+ final public function get_type() {
86
+ return 'html';
87
+ }
88
+
89
+ }
output/headers/php_errors.php ADDED
@@ -0,0 +1,71 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+
4
+ Copyright 2013 John Blackbourn
5
+
6
+ This program is free software; you can redistribute it and/or modify
7
+ it under the terms of the GNU General Public License as published by
8
+ the Free Software Foundation; either version 2 of the License, or
9
+ (at your option) any later version.
10
+
11
+ This program is distributed in the hope that it will be useful,
12
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
+ GNU General Public License for more details.
15
+
16
+ */
17
+
18
+ class QM_Output_Headers_PHP_Errors extends QM_Output_Headers {
19
+
20
+ public function output() {
21
+
22
+ if ( ! QM_Util::is_ajax() )
23
+ return;
24
+
25
+ $data = $this->collector->get_data();
26
+
27
+ if ( empty( $data['errors'] ) )
28
+ return;
29
+
30
+ $count = 0;
31
+
32
+ foreach ( $data['errors'] as $type => $errors ) {
33
+
34
+ foreach ( $errors as $key => $error ) {
35
+
36
+ $count++;
37
+
38
+ # @TODO we should calculate the component during process() so we don't need to do it
39
+ # separately in each output.
40
+ $component = QM_Util::get_backtrace_component( $error->trace );
41
+ $output_error = array(
42
+ 'type' => $error->type,
43
+ 'message' => $error->message,
44
+ 'file' => $error->file,
45
+ 'line' => $error->line,
46
+ 'stack' => $error->trace->get_stack(),
47
+ 'component' => $component->name,
48
+ );
49
+
50
+ header( sprintf( 'X-QM-Error-%d: %s',
51
+ $count,
52
+ json_encode( $output_error )
53
+ ) );
54
+
55
+ }
56
+
57
+ }
58
+
59
+ header( sprintf( 'X-QM-Errors: %d',
60
+ $count
61
+ ) );
62
+
63
+ }
64
+
65
+ }
66
+
67
+ function register_qm_output_headers_php_errors( QM_Output $output = null, QM_Collector $collector ) {
68
+ return new QM_Output_Headers_PHP_Errors( $collector );
69
+ }
70
+
71
+ add_filter( 'query_monitor_output_headers_php_errors', 'register_qm_output_headers_php_errors', 10, 2 );
output/headers/redirects.php ADDED
@@ -0,0 +1,46 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+
4
+ Copyright 2013 John Blackbourn
5
+
6
+ This program is free software; you can redistribute it and/or modify
7
+ it under the terms of the GNU General Public License as published by
8
+ the Free Software Foundation; either version 2 of the License, or
9
+ (at your option) any later version.
10
+
11
+ This program is distributed in the hope that it will be useful,
12
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
+ GNU General Public License for more details.
15
+
16
+ */
17
+
18
+ class QM_Output_Headers_Redirects extends QM_Output_Headers {
19
+
20
+ public function output() {
21
+
22
+ $qm = QueryMonitor::init();
23
+
24
+ if ( ! $qm->did_redirect() )
25
+ return;
26
+ if ( ! $qm->show_query_monitor() )
27
+ return;
28
+
29
+ $data = $this->collector->get_data();
30
+
31
+ if ( empty( $data ) )
32
+ return;
33
+
34
+ header( sprintf( 'X-QM-Redirect-Trace: %s',
35
+ implode( ', ', $data['stack'] )
36
+ ) );
37
+
38
+ }
39
+
40
+ }
41
+
42
+ function register_qm_output_headers_redirects( QM_Output $output = null, QM_Collector $collector ) {
43
+ return new QM_Output_Headers_Redirects( $collector );
44
+ }
45
+
46
+ add_filter( 'query_monitor_output_headers_redirects', 'register_qm_output_headers_redirects', 10, 2 );
{components → output/html}/admin.php RENAMED
@@ -1,5 +1,6 @@
1
  <?php
2
  /*
 
3
  Copyright 2013 John Blackbourn
4
 
5
  This program is free software; you can redistribute it and/or modify
@@ -14,60 +15,25 @@ GNU General Public License for more details.
14
 
15
  */
16
 
17
- class QM_Component_Admin extends QM_Component {
18
-
19
- var $id = 'admin';
20
-
21
- function __construct() {
22
- parent::__construct();
23
- add_filter( 'current_screen', array( $this, 'current_screen' ), 99 );
24
- add_filter( 'query_monitor_menus', array( $this, 'admin_menu' ), 100 );
25
- }
26
 
27
- function current_screen( WP_Screen $screen ) {
28
- if ( empty( $this->data['admin'] ) )
29
- $this->data['admin'] = wp_clone( $screen );
30
- return $screen;
31
  }
32
 
33
- function process() {
34
-
35
- global $pagenow;
36
-
37
- if ( isset( $_GET['page'] ) )
38
- $this->data['base'] = get_current_screen()->base;
39
- else
40
- $this->data['base'] = $pagenow;
41
 
42
- if ( !isset( $this->data['admin'] ) )
43
- $this->data['admin'] = __( 'n/a', 'query-monitor' );
44
-
45
- $this->data['pagenow'] = $pagenow;
46
- $this->data['current_screen'] = get_current_screen();
47
-
48
- }
49
-
50
- function admin_menu( array $menu ) {
51
-
52
- if ( isset( $this->data['base'] ) ) {
53
- $menu[] = $this->menu( array(
54
- 'title' => sprintf( __( 'Admin Screen: %s', 'query-monitor' ), $this->data['base'] )
55
- ) );
56
- }
57
- return $menu;
58
-
59
- }
60
-
61
- function output_html( array $args, array $data ) {
62
 
63
  if ( empty( $data ) )
64
  return;
65
 
66
- echo '<div class="qm qm-half" id="' . $args['id'] . '">';
67
  echo '<table cellspacing="0">';
68
  echo '<thead>';
69
  echo '<tr>';
70
- echo '<th colspan="3">' . __( 'Admin', 'query-monitor' ) . '</th>';
71
  echo '</tr>';
72
  echo '</thead>';
73
  echo '<tbody>';
@@ -161,12 +127,19 @@ class QM_Component_Admin extends QM_Component {
161
 
162
  }
163
 
 
 
 
 
 
 
 
 
 
164
  }
165
 
166
- function register_qm_admin( array $qm ) {
167
- if ( is_admin() )
168
- $qm['admin'] = new QM_Component_Admin;
169
- return $qm;
170
  }
171
 
172
- add_filter( 'query_monitor_components', 'register_qm_admin', 50 );
1
  <?php
2
  /*
3
+
4
  Copyright 2013 John Blackbourn
5
 
6
  This program is free software; you can redistribute it and/or modify
15
 
16
  */
17
 
18
+ class QM_Output_Html_Admin extends QM_Output_Html {
 
 
 
 
 
 
 
 
19
 
20
+ public function __construct( QM_Collector $collector ) {
21
+ parent::__construct( $collector );
22
+ add_filter( 'query_monitor_menus', array( $this, 'admin_menu' ), 60 );
 
23
  }
24
 
25
+ public function output() {
 
 
 
 
 
 
 
26
 
27
+ $data = $this->collector->get_data();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
28
 
29
  if ( empty( $data ) )
30
  return;
31
 
32
+ echo '<div class="qm qm-half" id="' . $this->collector->id() . '">';
33
  echo '<table cellspacing="0">';
34
  echo '<thead>';
35
  echo '<tr>';
36
+ echo '<th colspan="3">' . $this->collector->name() . '</th>';
37
  echo '</tr>';
38
  echo '</thead>';
39
  echo '<tbody>';
127
 
128
  }
129
 
130
+ public function admin_menu( array $menu ) {
131
+
132
+ $menu[] = $this->menu( array(
133
+ 'title' => __( 'Admin Screen', 'query-monitor' ),
134
+ ) );
135
+ return $menu;
136
+
137
+ }
138
+
139
  }
140
 
141
+ function register_qm_output_html_admin( QM_Output $output = null, QM_Collector $collector ) {
142
+ return new QM_Output_Html_Admin( $collector );
 
 
143
  }
144
 
145
+ add_filter( 'query_monitor_output_html_admin', 'register_qm_output_html_admin', 10, 2 );
{components → output/html}/authentication.php RENAMED
@@ -1,5 +1,6 @@
1
  <?php
2
  /*
 
3
  Copyright 2013 John Blackbourn
4
 
5
  This program is free software; you can redistribute it and/or modify
@@ -14,35 +15,15 @@ GNU General Public License for more details.
14
 
15
  */
16
 
17
- class QM_Component_Authentication extends QM_Component {
18
-
19
- var $id = 'authentication';
20
-
21
- function __construct() {
22
- parent::__construct();
23
- add_filter( 'plugins_loaded', array( $this, 'action_plugins_loaded' ) );
24
- }
25
-
26
- function action_plugins_loaded() {
27
-
28
- if ( !defined( 'QM_COOKIE' ) )
29
- define( 'QM_COOKIE', 'qm_' . COOKIEHASH );
30
-
31
- }
32
-
33
- function show_query_monitor() {
34
- if ( isset( $_COOKIE[QM_COOKIE] ) )
35
- return self::verify_nonce( $_COOKIE[QM_COOKIE], 'view_query_monitor' );
36
- return false;
37
- }
38
 
39
- function output_html( array $args, array $data ) {
40
 
41
- echo '<div class="qm" id="' . $args['id'] . '">';
42
  echo '<table cellspacing="0">';
43
  echo '<thead>';
44
  echo '<tr>';
45
- echo '<th>' . __( 'Authentication', 'query-monitor' ) . '</th>';
46
  echo '</tr>';
47
  echo '</thead>';
48
  echo '<tbody>';
@@ -51,9 +32,9 @@ class QM_Component_Authentication extends QM_Component {
51
  $domain = COOKIE_DOMAIN;
52
  $path = COOKIEPATH;
53
 
54
- if ( !isset( $_COOKIE[$name] ) or !self::verify_nonce( $_COOKIE[$name], 'view_query_monitor' ) ) {
55
 
56
- $value = self::create_nonce( 'view_query_monitor' );
57
  $text = esc_js( __( 'Authentication cookie set. You can now view Query Monitor output while logged out or while logged in as a different user.', 'query-monitor' ) );
58
  $link = "document.cookie='{$name}={$value}; domain={$domain}; path={$path}'; alert('{$text}'); return false;";
59
 
@@ -84,31 +65,10 @@ class QM_Component_Authentication extends QM_Component {
84
 
85
  }
86
 
87
- public static function create_nonce( $action ) {
88
- # This is just WordPress' nonce implementation minus the user ID
89
- # check so a nonce can be set in a cookie and used cross-user
90
- $i = wp_nonce_tick();
91
- return substr( wp_hash( $i . $action, 'nonce' ), -12, 10 );
92
- }
93
-
94
- public static function verify_nonce( $nonce, $action ) {
95
-
96
- $i = wp_nonce_tick();
97
-
98
- if ( substr( wp_hash( $i . $action, 'nonce' ), -12, 10 ) === $nonce )
99
- return true;
100
- if ( substr( wp_hash( ( $i - 1 ) . $action, 'nonce' ), -12, 10 ) === $nonce )
101
- return true;
102
-
103
- return false;
104
-
105
- }
106
-
107
  }
108
 
109
- function register_qm_authentication( array $qm ) {
110
- $qm['authentication'] = new QM_Component_Authentication;
111
- return $qm;
112
  }
113
 
114
- add_filter( 'query_monitor_components', 'register_qm_authentication', 130 );
1
  <?php
2
  /*
3
+
4
  Copyright 2013 John Blackbourn
5
 
6
  This program is free software; you can redistribute it and/or modify
15
 
16
  */
17
 
18
+ class QM_Output_Html_Authentication extends QM_Output_Html {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
19
 
20
+ public function output() {
21
 
22
+ echo '<div class="qm qm-half" id="' . $this->collector->id() . '">';
23
  echo '<table cellspacing="0">';
24
  echo '<thead>';
25
  echo '<tr>';
26
+ echo '<th>' . $this->collector->name() . '</th>';
27
  echo '</tr>';
28
  echo '</thead>';
29
  echo '<tbody>';
32
  $domain = COOKIE_DOMAIN;
33
  $path = COOKIEPATH;
34
 
35
+ if ( !isset( $_COOKIE[$name] ) or !$this->collector->verify_nonce( $_COOKIE[$name], 'view_query_monitor' ) ) {
36
 
37
+ $value = $this->collector->create_nonce( 'view_query_monitor' );
38
  $text = esc_js( __( 'Authentication cookie set. You can now view Query Monitor output while logged out or while logged in as a different user.', 'query-monitor' ) );
39
  $link = "document.cookie='{$name}={$value}; domain={$domain}; path={$path}'; alert('{$text}'); return false;";
40
 
65
 
66
  }
67
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
68
  }
69
 
70
+ function register_qm_output_html_authentication( QM_Output $output = null, QM_Collector $collector ) {
71
+ return new QM_Output_Html_Authentication( $collector );
 
72
  }
73
 
74
+ add_filter( 'query_monitor_output_html_authentication', 'register_qm_output_html_authentication', 10, 2 );
output/html/conditionals.php ADDED
@@ -0,0 +1,94 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+
4
+ Copyright 2013 John Blackbourn
5
+
6
+ This program is free software; you can redistribute it and/or modify
7
+ it under the terms of the GNU General Public License as published by
8
+ the Free Software Foundation; either version 2 of the License, or
9
+ (at your option) any later version.
10
+
11
+ This program is distributed in the hope that it will be useful,
12
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
+ GNU General Public License for more details.
15
+
16
+ */
17
+
18
+ class QM_Output_Html_Conditionals extends QM_Output_Html {
19
+
20
+ public function __construct( QM_Collector $collector ) {
21
+ parent::__construct( $collector );
22
+ add_filter( 'query_monitor_menus', array( $this, 'admin_menu' ), 120 );
23
+ }
24
+
25
+ public function output() {
26
+
27
+ $data = $this->collector->get_data();
28
+
29
+ $cols = 5;
30
+ $i = 0;
31
+ $w = floor( 100 / $cols );
32
+
33
+ echo '<div class="qm" id="' . $this->collector->id() . '">';
34
+ echo '<table cellspacing="0">';
35
+ echo '<thead>';
36
+ echo '<tr>';
37
+ echo '<th colspan="' . $cols . '">' . $this->collector->name() . '</th>';
38
+ echo '</tr>';
39
+ echo '</thead>';
40
+ echo '<tbody>';
41
+
42
+ foreach ( $data['conds']['true'] as $cond ) {
43
+ $i++;
44
+ if ( 1 === $i%$cols )
45
+ echo '<tr>';
46
+ echo '<td class="qm-ltr qm-true" width="' . $w . '%">' . $cond . '()</td>';
47
+ if ( 0 === $i%$cols )
48
+ echo '</tr>';
49
+ }
50
+
51
+ foreach ( $data['conds']['false'] as $cond ) {
52
+ $i++;
53
+ if ( 1 === $i%$cols )
54
+ echo '<tr>';
55
+ echo '<td class="qm-ltr qm-false" width="' . $w . '%">' . $cond . '()</td>';
56
+ if ( 0 === $i%$cols )
57
+ echo '</tr>';
58
+ }
59
+
60
+ $fill = ( $cols - ( $i % $cols ) );
61
+ if ( $fill and ( $fill != $cols ) ) {
62
+ echo '<td colspan="' . $fill . '">&nbsp;</td>';
63
+ echo '</tr>';
64
+ }
65
+
66
+ echo '</tbody>';
67
+ echo '</table>';
68
+ echo '</div>';
69
+
70
+ }
71
+
72
+ public function admin_menu( array $menu ) {
73
+
74
+ $data = $this->collector->get_data();
75
+
76
+ foreach ( $data['conds']['true'] as $cond ) {
77
+ $menu[] = $this->menu( array(
78
+ 'title' => $cond . '()',
79
+ 'id' => 'query-monitor-' . $cond,
80
+ 'meta' => array( 'classname' => 'qm-true qm-ltr' )
81
+ ) );
82
+ }
83
+
84
+ return $menu;
85
+
86
+ }
87
+
88
+ }
89
+
90
+ function register_qm_output_html_conditionals( QM_Output $output = null, QM_Collector $collector ) {
91
+ return new QM_Output_Html_Conditionals( $collector );
92
+ }
93
+
94
+ add_filter( 'query_monitor_output_html_conditionals', 'register_qm_output_html_conditionals', 10, 2 );
{components → output/html}/db_callers.php RENAMED
@@ -1,5 +1,6 @@
1
  <?php
2
  /*
 
3
  Copyright 2013 John Blackbourn
4
 
5
  This program is free software; you can redistribute it and/or modify
@@ -14,51 +15,31 @@ GNU General Public License for more details.
14
 
15
  */
16
 
17
- class QM_Component_DB_Callers extends QM_Component {
18
-
19
- var $id = 'db_callers';
20
 
21
- function __construct() {
22
- parent::__construct();
23
  add_filter( 'query_monitor_menus', array( $this, 'admin_menu' ), 30 );
24
  }
25
 
26
- function process() {
27
-
28
- if ( $dbq = $this->get_component( 'db_queries' ) ) {
29
- if ( isset( $dbq->data['times'] ) ) {
30
- $this->data['times'] = $dbq->data['times'];
31
- }
32
- if ( isset( $dbq->data['types'] ) ) {
33
- $this->data['types'] = $dbq->data['types'];
34
- }
35
- }
36
-
37
- }
38
-
39
- function admin_menu( array $menu ) {
40
 
41
- if ( $dbq = $this->get_component( 'db_queries' ) and isset( $dbq->data['times'] ) ) {
42
- $menu[] = $this->menu( array(
43
- 'title' => __( 'Queries by Caller', 'query-monitor' )
44
- ) );
45
- }
46
- return $menu;
47
-
48
- }
49
-
50
- function output_html( array $args, array $data ) {
51
 
52
  if ( empty( $data ) )
53
  return;
54
 
55
  $total_time = 0;
56
  $total_calls = 0;
 
57
 
58
- echo '<div class="qm qm-half" id="' . $args['id'] . '">';
59
  echo '<table cellspacing="0">';
60
  echo '<thead>';
61
  echo '<tr>';
 
 
 
62
  echo '<th>' . _x( 'Caller', 'Query caller', 'query-monitor' ) . '</th>';
63
 
64
  if ( !empty( $data['types'] ) ) {
@@ -129,11 +110,24 @@ class QM_Component_DB_Callers extends QM_Component {
129
 
130
  }
131
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
132
  }
133
 
134
- function register_qm_db_callers( array $qm ) {
135
- $qm['db_callers'] = new QM_Component_DB_Callers;
136
- return $qm;
137
  }
138
 
139
- add_filter( 'query_monitor_components', 'register_qm_db_callers', 30 );
1
  <?php
2
  /*
3
+
4
  Copyright 2013 John Blackbourn
5
 
6
  This program is free software; you can redistribute it and/or modify
15
 
16
  */
17
 
18
+ class QM_Output_Html_DB_Callers extends QM_Output_Html {
 
 
19
 
20
+ public function __construct( QM_Collector $collector ) {
21
+ parent::__construct( $collector );
22
  add_filter( 'query_monitor_menus', array( $this, 'admin_menu' ), 30 );
23
  }
24
 
25
+ public function output() {
 
 
 
 
 
 
 
 
 
 
 
 
 
26
 
27
+ $data = $this->collector->get_data();
 
 
 
 
 
 
 
 
 
28
 
29
  if ( empty( $data ) )
30
  return;
31
 
32
  $total_time = 0;
33
  $total_calls = 0;
34
+ $span = count( $data['types'] ) + 2;
35
 
36
+ echo '<div class="qm qm-half" id="' . $this->collector->id() . '">';
37
  echo '<table cellspacing="0">';
38
  echo '<thead>';
39
  echo '<tr>';
40
+ echo '<th colspan="' . $span . '">' . $this->collector->name() . '</th>';
41
+ echo '</tr>';
42
+ echo '<tr>';
43
  echo '<th>' . _x( 'Caller', 'Query caller', 'query-monitor' ) . '</th>';
44
 
45
  if ( !empty( $data['types'] ) ) {
110
 
111
  }
112
 
113
+ public function admin_menu( array $menu ) {
114
+
115
+ if ( $dbq = QueryMonitor::get_collector( 'db_queries' ) ) {
116
+ $dbq_data = $dbq->get_data();
117
+ if ( isset( $dbq_data['times'] ) ) {
118
+ $menu[] = $this->menu( array(
119
+ 'title' => __( 'Queries by Caller', 'query-monitor' )
120
+ ) );
121
+ }
122
+ }
123
+ return $menu;
124
+
125
+ }
126
+
127
  }
128
 
129
+ function register_qm_output_html_db_callers( QM_Output $output = null, QM_Collector $collector ) {
130
+ return new QM_Output_Html_DB_Callers( $collector );
 
131
  }
132
 
133
+ add_filter( 'query_monitor_output_html_db_callers', 'register_qm_output_html_db_callers', 10, 2 );
{components → output/html}/db_components.php RENAMED
@@ -1,5 +1,6 @@
1
  <?php
2
  /*
 
3
  Copyright 2013 John Blackbourn
4
 
5
  This program is free software; you can redistribute it and/or modify
@@ -14,51 +15,31 @@ GNU General Public License for more details.
14
 
15
  */
16
 
17
- class QM_Component_DB_Components extends QM_Component {
18
-
19
- var $id = 'db_components';
20
 
21
- function __construct() {
22
- parent::__construct();
23
  add_filter( 'query_monitor_menus', array( $this, 'admin_menu' ), 40 );
24
  }
25
 
26
- function process() {
27
-
28
- if ( $dbq = $this->get_component( 'db_queries' ) ) {
29
- if ( isset( $dbq->data['component_times'] ) ) {
30
- $this->data['times'] = $dbq->data['component_times'];
31
- }
32
- if ( isset( $dbq->data['types'] ) ) {
33
- $this->data['types'] = $dbq->data['types'];
34
- }
35
- }
36
-
37
- }
38
-
39
- function admin_menu( array $menu ) {
40
 
41
- if ( $dbq = $this->get_component( 'db_queries' ) and isset( $dbq->data['component_times'] ) ) {
42
- $menu[] = $this->menu( array(
43
- 'title' => __( 'Queries by Component', 'query-monitor' )
44
- ) );
45
- }
46
- return $menu;
47
-
48
- }
49
-
50
- function output_html( array $args, array $data ) {
51
 
52
  if ( empty( $data ) )
53
  return;
54
 
55
  $total_time = 0;
56
  $total_calls = 0;
 
57
 
58
- echo '<div class="qm qm-half" id="' . $args['id'] . '">';
59
  echo '<table cellspacing="0">';
60
  echo '<thead>';
61
  echo '<tr>';
 
 
 
62
  echo '<th>' . _x( 'Component', 'Query component', 'query-monitor' ) . '</th>';
63
 
64
  if ( !empty( $data['types'] ) ) {
@@ -117,7 +98,7 @@ class QM_Component_DB_Components extends QM_Component {
117
 
118
  echo '<tbody>';
119
  echo '<tr>';
120
- echo '<td colspan="3" style="text-align:center !important"><em>' . __( 'none', 'query-monitor' ) . '</em></td>';
121
  echo '</tr>';
122
  echo '</tbody>';
123
 
@@ -128,11 +109,24 @@ class QM_Component_DB_Components extends QM_Component {
128
 
129
  }
130
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
131
  }
132
 
133
- function register_qm_db_components( array $qm ) {
134
- $qm['db_components'] = new QM_Component_DB_Components;
135
- return $qm;
136
  }
137
 
138
- add_filter( 'query_monitor_components', 'register_qm_db_components', 35 );
1
  <?php
2
  /*
3
+
4
  Copyright 2013 John Blackbourn
5
 
6
  This program is free software; you can redistribute it and/or modify
15
 
16
  */
17
 
18
+ class QM_Output_Html_DB_Components extends QM_Output_Html {
 
 
19
 
20
+ public function __construct( QM_Collector $collector ) {
21
+ parent::__construct( $collector );
22
  add_filter( 'query_monitor_menus', array( $this, 'admin_menu' ), 40 );
23
  }
24
 
25
+ public function output() {
 
 
 
 
 
 
 
 
 
 
 
 
 
26
 
27
+ $data = $this->collector->get_data();
 
 
 
 
 
 
 
 
 
28
 
29
  if ( empty( $data ) )
30
  return;
31
 
32
  $total_time = 0;
33
  $total_calls = 0;
34
+ $span = count( $data['types'] ) + 2;
35
 
36
+ echo '<div class="qm qm-half" id="' . $this->collector->id() . '">';
37
  echo '<table cellspacing="0">';
38
  echo '<thead>';
39
  echo '<tr>';
40
+ echo '<th colspan="' . $span . '">' . $this->collector->name() . '</th>';
41
+ echo '</tr>';
42
+ echo '<tr>';
43
  echo '<th>' . _x( 'Component', 'Query component', 'query-monitor' ) . '</th>';
44
 
45
  if ( !empty( $data['types'] ) ) {
98
 
99
  echo '<tbody>';
100
  echo '<tr>';
101
+ echo '<td colspan="' . $span . '" style="text-align:center !important"><em>' . __( 'Unknown', 'query-monitor' ) . '</em></td>';
102
  echo '</tr>';
103
  echo '</tbody>';
104
 
109
 
110
  }
111
 
112
+ public function admin_menu( array $menu ) {
113
+
114
+ if ( $dbq = QueryMonitor::get_collector( 'db_queries' ) ) {
115
+ $dbq_data = $dbq->get_data();
116
+ if ( isset( $dbq_data['component_times'] ) ) {
117
+ $menu[] = $this->menu( array(
118
+ 'title' => __( 'Queries by Component', 'query-monitor' )
119
+ ) );
120
+ }
121
+ }
122
+ return $menu;
123
+
124
+ }
125
+
126
  }
127
 
128
+ function register_qm_output_html_db_components( QM_Output $output = null, QM_Collector $collector ) {
129
+ return new QM_Output_Html_DB_Components( $collector );
 
130
  }
131
 
132
+ add_filter( 'query_monitor_output_html_db_components', 'register_qm_output_html_db_components', 10, 2 );
{components → output/html}/db_queries.php RENAMED
@@ -1,5 +1,6 @@
1
  <?php
2
  /*
 
3
  Copyright 2013 John Blackbourn
4
 
5
  This program is free software; you can redistribute it and/or modify
@@ -14,126 +15,18 @@ GNU General Public License for more details.
14
 
15
  */
16
 
17
- if ( !defined( 'SAVEQUERIES' ) )
18
- define( 'SAVEQUERIES', true );
19
- if ( !defined( 'QM_DB_EXPENSIVE' ) )
20
- define( 'QM_DB_EXPENSIVE', 0.05 );
21
-
22
- # QM_DB_LIMIT used to be a hard limit but proved to be more of an annoyance than anything. It now
23
- # just adds a nag to the top of the query table. I might remove it altogether at some point.
24
- if ( !defined( 'QM_DB_LIMIT' ) )
25
- define( 'QM_DB_LIMIT', 100 );
26
-
27
- class QM_Component_DB_Queries extends QM_Component {
28
 
29
- public $id = 'db_queries';
30
- public $db_objects = array();
31
-
32
- function __construct() {
33
- parent::__construct();
34
  add_filter( 'query_monitor_menus', array( $this, 'admin_menu' ), 20 );
35
  add_filter( 'query_monitor_title', array( $this, 'admin_title' ), 20 );
36
  add_filter( 'query_monitor_class', array( $this, 'admin_class' ) );
37
  }
38
 
39
- function admin_title( array $title ) {
40
- if ( isset( $this->data['dbs'] ) ) {
41
- foreach ( $this->data['dbs'] as $db ) {
42
- $title[] = sprintf(
43
- _x( '%s<small>S</small>', 'database query time', 'query-monitor' ),
44
- number_format_i18n( $db->total_time, 4 )
45
- );
46
- $title[] = sprintf(
47
- _x( '%s<small>Q</small>', 'database query number', 'query-monitor' ),
48
- number_format_i18n( $db->total_qs )
49
- );
50
- }
51
- }
52
- return $title;
53
- }
54
-
55
- function admin_class( array $class ) {
56
-
57
- if ( $this->get_errors() )
58
- $class[] = 'qm-error';
59
- if ( $this->get_expensive() )
60
- $class[] = 'qm-expensive';
61
- return $class;
62
-
63
- }
64
-
65
- function admin_menu( array $menu ) {
66
 
67
- if ( $errors = $this->get_errors() ) {
68
- $menu[] = $this->menu( array(
69
- 'id' => 'query-monitor-errors',
70
- 'href' => '#qm-query-errors',
71
- 'title' => sprintf( __( 'Database Errors (%s)', 'query-monitor' ), number_format_i18n( count( $errors ) ) )
72
- ) );
73
- }
74
- if ( $expensive = $this->get_expensive() ) {
75
- $menu[] = $this->menu( array(
76
- 'id' => 'query-monitor-expensive',
77
- 'href' => '#qm-query-expensive',
78
- 'title' => sprintf( __( 'Slow Queries (%s)', 'query-monitor' ), number_format_i18n( count( $expensive ) ) )
79
- ) );
80
- }
81
-
82
- if ( count( $this->data['dbs'] ) > 1 ) {
83
- foreach ( $this->data['dbs'] as $name => $db ) {
84
- $menu[] = $this->menu( array(
85
- 'title' => sprintf( __( 'Queries (%s)', 'query-monitor' ), esc_html( $name ) ),
86
- 'href' => sprintf( '#%s-%s', $this->id(), sanitize_title( $name ) ),
87
- ) );
88
- }
89
- } else {
90
- $menu[] = $this->menu( array(
91
- 'title' => __( 'Queries', 'query-monitor' ),
92
- 'href' => sprintf( '#%s-wpdb', $this->id() ),
93
- ) );
94
- }
95
-
96
- return $menu;
97
-
98
- }
99
-
100
- function get_errors() {
101
- if ( !empty( $this->data['errors'] ) )
102
- return $this->data['errors'];
103
- return false;
104
- }
105
-
106
- function get_expensive() {
107
- if ( !empty( $this->data['expensive'] ) )
108
- return $this->data['expensive'];
109
- return false;
110
- }
111
-
112
- protected static function is_expensive( array $row ) {
113
- return $row['ltime'] > QM_DB_EXPENSIVE;
114
- }
115
-
116
- function process() {
117
-
118
- if ( !SAVEQUERIES )
119
- return;
120
-
121
- $this->data['total_qs'] = 0;
122
- $this->data['total_time'] = 0;
123
- $this->data['errors'] = array();
124
-
125
- $this->db_objects = apply_filters( 'query_monitor_db_objects', array(
126
- '$wpdb' => $GLOBALS['wpdb']
127
- ) );
128
-
129
- foreach ( $this->db_objects as $name => $db ) {
130
- if ( is_a( $db, 'wpdb' ) )
131
- $this->process_db_object( $name, $db );
132
- }
133
-
134
- }
135
-
136
- function output_html( array $args, array $data ) {
137
 
138
  if ( empty( $data['dbs'] ) )
139
  return;
@@ -203,153 +96,7 @@ class QM_Component_DB_Queries extends QM_Component {
203
 
204
  }
205
 
206
- function log_type( $type ) {
207
-
208
- if ( isset( $this->data['types'][$type] ) )
209
- $this->data['types'][$type]++;
210
- else
211
- $this->data['types'][$type] = 1;
212
-
213
- }
214
-
215
- function log_caller( $caller, $ltime, $type ) {
216
-
217
- if ( !isset( $this->data['times'][$caller] ) ) {
218
- $this->data['times'][$caller] = array(
219
- 'caller' => $caller,
220
- 'calls' => 0,
221
- 'ltime' => 0,
222
- 'types' => array()
223
- );
224
- }
225
-
226
- $this->data['times'][$caller]['calls']++;
227
- $this->data['times'][$caller]['ltime'] += $ltime;
228
-
229
- if ( isset( $this->data['times'][$caller]['types'][$type] ) )
230
- $this->data['times'][$caller]['types'][$type]++;
231
- else
232
- $this->data['times'][$caller]['types'][$type] = 1;
233
-
234
- }
235
-
236
- function log_component( $component, $ltime, $type ) {
237
-
238
- if ( !isset( $this->data['component_times'][$component->name] ) ) {
239
- $this->data['component_times'][$component->name] = array(
240
- 'component' => $component->name,
241
- 'calls' => 0,
242
- 'ltime' => 0,
243
- 'types' => array()
244
- );
245
- }
246
-
247
- $this->data['component_times'][$component->name]['calls']++;
248
- $this->data['component_times'][$component->name]['ltime'] += $ltime;
249
-
250
- if ( isset( $this->data['component_times'][$component->name]['types'][$type] ) )
251
- $this->data['component_times'][$component->name]['types'][$type]++;
252
- else
253
- $this->data['component_times'][$component->name]['types'][$type] = 1;
254
-
255
- }
256
-
257
- protected static function query_compat( array & $query ) {
258
-
259
- list( $query['sql'], $query['ltime'], $query['stack'] ) = $query;
260
-
261
- }
262
-
263
- function process_db_object( $id, wpdb $db ) {
264
-
265
- $rows = array();
266
- $types = array();
267
- $total_time = 0;
268
-
269
- foreach ( (array) $db->queries as $query ) {
270
-
271
- if ( ! isset( $query['sql'] ) )
272
- self::query_compat( $query );
273
-
274
- if ( false !== strpos( $query['stack'], 'wp_admin_bar' ) and !isset( $_REQUEST['qm_display_admin_bar'] ) )
275
- continue;
276
-
277
- $sql = $query['sql'];
278
- $ltime = $query['ltime'];
279
- $stack = $query['stack'];
280
- $has_component = isset( $query['trace'] );
281
- $has_results = isset( $query['result'] );
282
-
283
- if ( $has_results )
284
- $result = $query['result'];
285
- else
286
- $result = null;
287
-
288
- $total_time += $ltime;
289
-
290
- if ( isset( $query['trace'] ) )
291
- $component = QM_Util::get_backtrace_component( $query['trace'] );
292
- else
293
- $component = null;
294
-
295
- # @TODO we should grab this from the trace instead for increased accuracy in case
296
- # the caller contains multiple comma separated arguments (see QM_Backtrace::$show_args)
297
- $callers = explode( ',', $stack );
298
- $caller = trim( end( $callers ) );
299
-
300
- if ( false !== strpos( $caller, '(' ) )
301
- $caller_name = strstr( $caller, '(', true ) . '()';
302
- else
303
- $caller_name = $caller;
304
-
305
- # @TODO this formatting should move to JIT when outputting as html
306
- $sql = QM_Util::format_sql( $sql );
307
- $type = preg_split( '/\b/', $sql );
308
- $type = strtoupper( $type[1] );
309
-
310
- $this->log_type( $type );
311
- $this->log_caller( $caller_name, $ltime, $type );
312
-
313
- if ( $component )
314
- $this->log_component( $component, $ltime, $type );
315
-
316
- if ( !isset( $types[$type]['total'] ) )
317
- $types[$type]['total'] = 1;
318
- else
319
- $types[$type]['total']++;
320
-
321
- if ( !isset( $types[$type]['callers'][$caller] ) )
322
- $types[$type]['callers'][$caller] = 1;
323
- else
324
- $types[$type]['callers'][$caller]++;
325
-
326
- $row = compact( 'caller', 'caller_name', 'stack', 'sql', 'ltime', 'result', 'type', 'component' );
327
-
328
- if ( is_wp_error( $result ) )
329
- $this->data['errors'][] = $row;
330
-
331
- if ( self::is_expensive( $row ) )
332
- $this->data['expensive'][] = $row;
333
-
334
- $rows[] = $row;
335
-
336
- }
337
-
338
- if ( isset( $_REQUEST['qm_sort'] ) and ( 'time' == $_REQUEST['qm_sort'] ) )
339
- usort( $rows, 'QM_Util::sort' );
340
-
341
- $total_qs = count( $rows );
342
-
343
- $this->data['total_qs'] += $total_qs;
344
- $this->data['total_time'] += $total_time;
345
-
346
- # @TODO put errors in here too:
347
- # @TODO proper class instead of (object)
348
- $this->data['dbs'][$id] = (object) compact( 'rows', 'types', 'has_results', 'has_component', 'total_time', 'total_qs' );
349
-
350
- }
351
-
352
- function output_queries( $name, stdClass $db, array $data ) {
353
 
354
  $max_exceeded = $db->total_qs > QM_DB_LIMIT;
355
 
@@ -360,13 +107,21 @@ class QM_Component_DB_Queries extends QM_Component {
360
  if ( $db->has_component )
361
  $span++;
362
 
363
- echo '<div class="qm qm-queries" id="' . $this->id() . '-' . sanitize_title( $name ) . '">';
364
  echo '<table cellspacing="0">';
365
  echo '<thead>';
366
  echo '<tr>';
367
- echo '<th colspan="' . $span . '" class="qm-ltr">' . $name . '</th>';
368
  echo '</tr>';
369
 
 
 
 
 
 
 
 
 
370
  if ( $max_exceeded ) {
371
  echo '<tr>';
372
  echo '<td colspan="' . $span . '" class="qm-expensive">' . sprintf( __( '%1$s %2$s queries were performed on this page load. Crikey!', 'query-monitor' ),
@@ -430,7 +185,7 @@ class QM_Component_DB_Queries extends QM_Component {
430
 
431
  }
432
 
433
- function output_query_row( array $row, array $cols ) {
434
 
435
  $cols = array_flip( $cols );
436
 
@@ -444,7 +199,7 @@ class QM_Component_DB_Queries extends QM_Component {
444
  $row_attr = array();
445
  $stime = number_format_i18n( $row['ltime'], 4 );
446
  $ltime = number_format_i18n( $row['ltime'], 10 );
447
- $td = self::is_expensive( $row ) ? ' qm-expensive' : '';
448
 
449
  if ( 'SELECT' != $row['type'] )
450
  $row['sql'] = "<span class='qm-nonselectsql'>{$row['sql']}</span>";
@@ -479,8 +234,23 @@ class QM_Component_DB_Queries extends QM_Component {
479
  if ( isset( $cols['sql'] ) )
480
  echo "<td valign='top' class='qm-row-sql qm-ltr qm-sql'>{$row['sql']}</td>";
481
 
482
- if ( isset( $cols['caller'] ) )
483
- echo "<td valign='top' class='qm-row-caller qm-ltr' title='{$stack}'>{$row['caller']}</td>";
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
484
 
485
  if ( isset( $cols['stack'] ) ) {
486
  # This isn't optimal...
@@ -503,11 +273,76 @@ class QM_Component_DB_Queries extends QM_Component {
503
 
504
  }
505
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
506
  }
507
 
508
- function register_qm_db_queries( array $qm ) {
509
- $qm['db_queries'] = new QM_Component_DB_Queries;
510
- return $qm;
511
  }
512
 
513
- add_filter( 'query_monitor_components', 'register_qm_db_queries', 20 );
1
  <?php
2
  /*
3
+
4
  Copyright 2013 John Blackbourn
5
 
6
  This program is free software; you can redistribute it and/or modify
15
 
16
  */
17
 
18
+ class QM_Output_Html_DB_Queries extends QM_Output_Html {
 
 
 
 
 
 
 
 
 
 
19
 
20
+ public function __construct( QM_Collector $collector ) {
21
+ parent::__construct( $collector );
 
 
 
22
  add_filter( 'query_monitor_menus', array( $this, 'admin_menu' ), 20 );
23
  add_filter( 'query_monitor_title', array( $this, 'admin_title' ), 20 );
24
  add_filter( 'query_monitor_class', array( $this, 'admin_class' ) );
25
  }
26
 
27
+ public function output() {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
28
 
29
+ $data = $this->collector->get_data();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
30
 
31
  if ( empty( $data['dbs'] ) )
32
  return;
96
 
97
  }
98
 
99
+ protected function output_queries( $name, stdClass $db, array $data ) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
100
 
101
  $max_exceeded = $db->total_qs > QM_DB_LIMIT;
102
 
107
  if ( $db->has_component )
108
  $span++;
109
 
110
+ echo '<div class="qm qm-queries" id="' . $this->collector->id() . '-' . sanitize_title( $name ) . '">';
111
  echo '<table cellspacing="0">';
112
  echo '<thead>';
113
  echo '<tr>';
114
+ echo '<th colspan="' . $span . '">' . sprintf( __( '%s Queries', 'query-monitor' ), $name ) . '</th>';
115
  echo '</tr>';
116
 
117
+ if ( ! $db->has_component ) {
118
+ echo '<tr>';
119
+ echo '<td colspan="' . $span . '" class="qm-warn">' . sprintf( __( 'Extended query information such as the component and affected rows is not available. Query Monitor was unable to symlink its db.php file into place. <a href="%s" target="_blank">See this wiki page for more information.</a>', 'query-monitor' ),
120
+ 'https://github.com/johnbillion/query-monitor/wiki/db.php-Symlink'
121
+ ) . '</td>';
122
+ echo '</tr>';
123
+ }
124
+
125
  if ( $max_exceeded ) {
126
  echo '<tr>';
127
  echo '<td colspan="' . $span . '" class="qm-expensive">' . sprintf( __( '%1$s %2$s queries were performed on this page load. Crikey!', 'query-monitor' ),
185
 
186
  }
187
 
188
+ protected function output_query_row( array $row, array $cols ) {
189
 
190
  $cols = array_flip( $cols );
191
 
199
  $row_attr = array();
200
  $stime = number_format_i18n( $row['ltime'], 4 );
201
  $ltime = number_format_i18n( $row['ltime'], 10 );
202
+ $td = $this->collector->is_expensive( $row ) ? ' qm-expensive' : '';
203
 
204
  if ( 'SELECT' != $row['type'] )
205
  $row['sql'] = "<span class='qm-nonselectsql'>{$row['sql']}</span>";
234
  if ( isset( $cols['sql'] ) )
235
  echo "<td valign='top' class='qm-row-sql qm-ltr qm-sql'>{$row['sql']}</td>";
236
 
237
+ if ( isset( $cols['caller'] ) ) {
238
+ echo "<td valign='top' class='qm-row-caller qm-ltr qm-has-toggle'>";
239
+ echo $row['caller'];
240
+
241
+ # This isn't optimal...
242
+ $stack = explode( ', ', $row['stack'] );
243
+ $stack = array_reverse( $stack );
244
+ array_shift( $stack );
245
+ $stack = implode( '<br>', $stack );
246
+
247
+ if ( !empty( $stack ) ) {
248
+ echo '<br><a href="#" class="qm-toggle">+</a>';
249
+ echo '<div class="qm-toggled">' . $stack . '</div>';
250
+ }
251
+
252
+ echo "</td>";
253
+ }
254
 
255
  if ( isset( $cols['stack'] ) ) {
256
  # This isn't optimal...
273
 
274
  }
275
 
276
+ public function admin_title( array $title ) {
277
+
278
+ $data = $this->collector->get_data();
279
+
280
+ if ( isset( $data['dbs'] ) ) {
281
+ foreach ( $data['dbs'] as $db ) {
282
+ $title[] = sprintf(
283
+ _x( '%s<small>S</small>', 'database query time', 'query-monitor' ),
284
+ number_format_i18n( $db->total_time, 4 )
285
+ );
286
+ $title[] = sprintf(
287
+ _x( '%s<small>Q</small>', 'database query number', 'query-monitor' ),
288
+ number_format_i18n( $db->total_qs )
289
+ );
290
+ }
291
+ }
292
+ return $title;
293
+ }
294
+
295
+ public function admin_class( array $class ) {
296
+
297
+ if ( $this->collector->get_errors() )
298
+ $class[] = 'qm-error';
299
+ if ( $this->collector->get_expensive() )
300
+ $class[] = 'qm-expensive';
301
+ return $class;
302
+
303
+ }
304
+
305
+ public function admin_menu( array $menu ) {
306
+
307
+ $data = $this->collector->get_data();
308
+
309
+ if ( $errors = $this->collector->get_errors() ) {
310
+ $menu[] = $this->menu( array(
311
+ 'id' => 'query-monitor-errors',
312
+ 'href' => '#qm-query-errors',
313
+ 'title' => sprintf( __( 'Database Errors (%s)', 'query-monitor' ), number_format_i18n( count( $errors ) ) )
314
+ ) );
315
+ }
316
+ if ( $expensive = $this->collector->get_expensive() ) {
317
+ $menu[] = $this->menu( array(
318
+ 'id' => 'query-monitor-expensive',
319
+ 'href' => '#qm-query-expensive',
320
+ 'title' => sprintf( __( 'Slow Queries (%s)', 'query-monitor' ), number_format_i18n( count( $expensive ) ) )
321
+ ) );
322
+ }
323
+
324
+ if ( count( $data['dbs'] ) > 1 ) {
325
+ foreach ( $data['dbs'] as $name => $db ) {
326
+ $menu[] = $this->menu( array(
327
+ 'title' => sprintf( __( 'Queries (%s)', 'query-monitor' ), esc_html( $name ) ),
328
+ 'href' => sprintf( '#%s-%s', $this->collector->id(), sanitize_title( $name ) ),
329
+ ) );
330
+ }
331
+ } else {
332
+ $menu[] = $this->menu( array(
333
+ 'title' => __( 'Queries', 'query-monitor' ),
334
+ 'href' => sprintf( '#%s-wpdb', $this->collector->id() ),
335
+ ) );
336
+ }
337
+
338
+ return $menu;
339
+
340
+ }
341
+
342
  }
343
 
344
+ function register_qm_output_html_db_queries( QM_Output $output = null, QM_Collector $collector ) {
345
+ return new QM_Output_Html_DB_Queries( $collector );
 
346
  }
347
 
348
+ add_filter( 'query_monitor_output_html_db_queries', 'register_qm_output_html_db_queries', 10, 2 );
output/html/environment.php ADDED
@@ -0,0 +1,208 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+
4
+ Copyright 2013 John Blackbourn
5
+
6
+ This program is free software; you can redistribute it and/or modify
7
+ it under the terms of the GNU General Public License as published by
8
+ the Free Software Foundation; either version 2 of the License, or
9
+ (at your option) any later version.
10
+
11
+ This program is distributed in the hope that it will be useful,
12
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
+ GNU General Public License for more details.
15
+
16
+ */
17
+
18
+ class QM_Output_Html_Environment extends QM_Output_Html {
19
+
20
+ public function __construct( QM_Collector $collector ) {
21
+ parent::__construct( $collector );
22
+ add_filter( 'query_monitor_menus', array( $this, 'admin_menu' ), 100 );
23
+ }
24
+
25
+ public function output() {
26
+
27
+ $data = $this->collector->get_data();
28
+
29
+ echo '<div class="qm" id="' . $this->collector->id() . '">';
30
+ echo '<table cellspacing="0">';
31
+ echo '<thead>';
32
+ echo '<tr>';
33
+ echo '<th colspan="3">' . $this->collector->name() . '</th>';
34
+ echo '</tr>';
35
+ echo '</thead>';
36
+ echo '<tbody>';
37
+
38
+ echo '<tr>';
39
+ echo '<td rowspan="' . ( 3 + count( $data['php']['variables'] ) ) . '">PHP</td>';
40
+ echo '<td>version</td>';
41
+ echo "<td>{$data['php']['version']}</td>";
42
+ echo '</tr>';
43
+ echo '<tr>';
44
+ echo '<td>user</td>';
45
+ echo "<td>{$data['php']['user']}</td>";
46
+ echo '</tr>';
47
+
48
+ foreach ( $data['php']['variables'] as $key => $val ) {
49
+
50
+ $append = '';
51
+
52
+ if ( $val['after'] != $val['before'] )
53
+ $append .= '<br /><span class="qm-info">' . sprintf( __( 'Overridden at runtime from %s', 'query-monitor' ), $val['before'] ) . '</span>';
54
+
55
+ echo '<tr>';
56
+ echo "<td>{$key}</td>";
57
+ echo "<td>{$val['after']}{$append}</td>";
58
+ echo '</tr>';
59
+ }
60
+
61
+ $error_levels = implode( '<br/>', $this->collector->get_error_levels( $data['php']['error_reporting'] ) );
62
+
63
+ echo '<tr>';
64
+ echo '<td>error_reporting</td>';
65
+ echo "<td>{$data['php']['error_reporting']}<br><span class='qm-info'>{$error_levels}</span></td>";
66
+ echo '</tr>';
67
+
68
+ if ( isset( $data['db'] ) ) {
69
+
70
+ foreach ( $data['db'] as $id => $db ) {
71
+
72
+ if ( 1 == count( $data['db'] ) )
73
+ $name = 'MySQL';
74
+ else
75
+ $name = $id . '<br />MySQL';
76
+
77
+ echo '<tr>';
78
+ echo '<td rowspan="' . ( 5 + count( $db['variables'] ) ) . '">' . $name . '</td>';
79
+ echo '<td>version</td>';
80
+ echo '<td>' . $db['version'] . '</td>';
81
+ echo '</tr>';
82
+
83
+ echo '<tr>';
84
+ echo '<td>driver</td>';
85
+ echo '<td>' . $db['driver'] . '</td>';
86
+ echo '</tr>';
87
+
88
+ echo '<tr>';
89
+ echo '<td>user</td>';
90
+ echo '<td>' . $db['user'] . '</td>';
91
+ echo '</tr>';
92
+
93
+ echo '<tr>';
94
+ echo '<td>host</td>';
95
+ echo '<td>' . $db['host'] . '</td>';
96
+ echo '</tr>';
97
+
98
+ echo '<tr>';
99
+ echo '<td>database</td>';
100
+ echo '<td>' . $db['name'] . '</td>';
101
+ echo '</tr>';
102
+
103
+ echo '<tr>';
104
+
105
+ $first = true;
106
+ $warn = __( "This value may not be optimal. Check the recommended configuration for '%s'.", 'query-monitor' );
107
+ $search = __( 'https://www.google.com/search?q=mysql+performance+%s', 'query-monitor' );
108
+
109
+ foreach ( $db['variables'] as $setting ) {
110
+
111
+ $key = $setting->Variable_name;
112
+ $val = $setting->Value;
113
+ $prepend = '';
114
+ $show_warning = false;
115
+
116
+ if ( ( true === $db['vars'][$key] ) and empty( $val ) )
117
+ $show_warning = true;
118
+ else if ( is_string( $db['vars'][$key] ) and ( $val !== $db['vars'][$key] ) )
119
+ $show_warning = true;
120
+
121
+ if ( $show_warning )
122
+ $prepend .= '&nbsp;<span class="qm-info">(<a href="' . esc_url( sprintf( $search, $key ) ) . '" target="_blank" title="' . esc_attr( sprintf( $warn, $key ) ) . '">' . __( 'Help', 'query-monitor' ) . '</a>)</span>';
123
+
124
+ if ( is_numeric( $val ) and ( $val >= ( 1024*1024 ) ) )
125
+ $prepend .= '<br /><span class="qm-info">~' . size_format( $val ) . '</span>';
126
+
127
+ $class = ( $show_warning ) ? 'qm-warn' : '';
128
+
129
+ if ( !$first )
130
+ echo "<tr class='{$class}'>";
131
+
132
+ $key = esc_html( $key );
133
+ $val = esc_html( $val );
134
+
135
+ echo "<td>{$key}</td>";
136
+ echo "<td>{$val}{$prepend}</td>";
137
+
138
+ echo '</tr>';
139
+
140
+ $first = false;
141
+
142
+ }
143
+
144
+ }
145
+
146
+ }
147
+
148
+ echo '<tr>';
149
+ echo '<td rowspan="' . count( $data['wp'] ). '">WordPress</td>';
150
+
151
+ $first = true;
152
+
153
+ foreach ( $data['wp'] as $key => $val ) {
154
+
155
+ if ( !$first )
156
+ echo "<tr>";
157
+
158
+ echo "<td>{$key}</td>";
159
+ echo "<td>{$val}</td>";
160
+ echo '</tr>';
161
+
162
+ $first = false;
163
+
164
+ }
165
+
166
+ echo '<tr>';
167
+ echo '<td rowspan="4">' . __( 'Server', 'query-monitor' ) . '</td>';
168
+ echo '<td>software</td>';
169
+ echo "<td>{$data['server']['name']}</td>";
170
+ echo '</tr>';
171
+
172
+ echo '<tr>';
173
+ echo '<td>version</td>';
174
+ echo "<td>{$data['server']['version']}</td>";
175
+ echo '</tr>';
176
+
177
+ echo '<tr>';
178
+ echo '<td>address</td>';
179
+ echo "<td>{$data['server']['address']}</td>";
180
+ echo '</tr>';
181
+
182
+ echo '<tr>';
183
+ echo '<td>host</td>';
184
+ echo "<td>{$data['server']['host']}</td>";
185
+ echo '</tr>';
186
+
187
+ echo '</tbody>';
188
+ echo '</table>';
189
+ echo '</div>';
190
+
191
+ }
192
+
193
+ public function admin_menu( array $menu ) {
194
+
195
+ $menu[] = $this->menu( array(
196
+ 'title' => __( 'Environment', 'query-monitor' )
197
+ ) );
198
+ return $menu;
199
+
200
+ }
201
+
202
+ }
203
+
204
+ function register_qm_output_html_environment( QM_Output $output = null, QM_Collector $collector ) {
205
+ return new QM_Output_Html_Environment( $collector );
206
+ }
207
+
208
+ add_filter( 'query_monitor_output_html_environment', 'register_qm_output_html_environment', 10, 2 );
{components → output/html}/hooks.php RENAMED
@@ -1,5 +1,6 @@
1
  <?php
2
  /*
 
3
  Copyright 2013 John Blackbourn
4
 
5
  This program is free software; you can redistribute it and/or modify
@@ -14,92 +15,30 @@ GNU General Public License for more details.
14
 
15
  */
16
 
17
- class QM_Component_Hooks extends QM_Component {
18
-
19
- var $id = 'hooks';
20
-
21
- function __construct() {
22
- parent::__construct();
23
- add_filter( 'query_monitor_menus', array( $this, 'admin_menu' ), 80 );
24
- }
25
-
26
- function admin_menu( array $menu ) {
27
 
28
- $menu[] = $this->menu( array(
29
- 'title' => __( 'Hooks', 'query-monitor' )
30
- ) );
31
- return $menu;
32
 
 
 
 
33
  }
34
 
35
- function process() {
36
 
37
- global $wp_actions, $wp_filter;
38
 
39
- if ( is_admin() and ( $admin = $this->get_component( 'admin' ) ) )
40
- $this->data['screen'] = $admin->data['base'];
41
- else
42
- $this->data['screen'] = '';
43
 
44
- $hooks = $parts = $components = array();
45
 
46
- # @TODO why am i doing this here?:
47
  if ( is_multisite() and is_network_admin() )
48
- $this->data['screen'] = preg_replace( '|-network$|', '', $this->data['screen'] );
49
-
50
- foreach ( $wp_actions as $name => $count ) {
51
-
52
- $actions = array();
53
- # @TODO better variable name:
54
- $c = array();
55
-
56
- if ( isset( $wp_filter[$name] ) ) {
57
-
58
- foreach( $wp_filter[$name] as $priority => $callbacks ) {
59
-
60
- foreach ( $callbacks as $callback ) {
61
-
62
- $callback = QM_Util::populate_callback( $callback );
63
-
64
- if ( isset( $callback['component'] ) )
65
- $c[$callback['component']->name] = $callback['component']->name;
66
-
67
- $actions[] = array(
68
- 'priority' => $priority,
69
- 'callback' => $callback,
70
- );
71
-
72
- }
73
-
74
- }
75
-
76
- }
77
-
78
- # @TODO better variable name:
79
- $p = array_filter( preg_split( '/[_\/-]/', $name ) );
80
- $parts = array_merge( $parts, $p );
81
- $components = array_merge( $components, $c );
82
-
83
- $hooks[$name] = array(
84
- 'name' => $name,
85
- 'actions' => $actions,
86
- 'parts' => $p,
87
- 'components' => $c,
88
- );
89
-
90
- }
91
-
92
- $this->data['hooks'] = $hooks;
93
- $this->data['parts'] = array_unique( array_filter( $parts ) );
94
- $this->data['components'] = array_unique( array_filter( $components ) );
95
-
96
- }
97
-
98
- function output_html( array $args, array $data ) {
99
-
100
- $row_attr = array();
101
 
102
- echo '<div class="qm" id="' . $args['id'] . '">';
103
  echo '<table cellspacing="0">';
104
  echo '<thead>';
105
  echo '<tr>';
@@ -111,12 +50,12 @@ class QM_Component_Hooks extends QM_Component {
111
 
112
  foreach ( $data['hooks'] as $hook ) {
113
 
114
- if ( !empty( $data['screen'] ) ) {
115
 
116
- if ( false !== strpos( $hook['name'], $data['screen'] . '.php' ) )
117
- $hook['name'] = str_replace( '-' . $data['screen'] . '.php', '-<span class="qm-current">' . $data['screen'] . '.php</span>', $hook['name'] );
118
  else
119
- $hook['name'] = str_replace( '-' . $data['screen'], '-<span class="qm-current">' . $data['screen'] . '</span>', $hook['name'] );
120
 
121
  }
122
 
@@ -180,11 +119,19 @@ class QM_Component_Hooks extends QM_Component {
180
 
181
  }
182
 
 
 
 
 
 
 
 
 
 
183
  }
184
 
185
- function register_qm_hooks( array $qm ) {
186
- $qm['hooks'] = new QM_Component_Hooks;
187
- return $qm;
188
  }
189
 
190
- add_filter( 'query_monitor_components', 'register_qm_hooks', 80 );
1
  <?php
2
  /*
3
+
4
  Copyright 2013 John Blackbourn
5
 
6
  This program is free software; you can redistribute it and/or modify
15
 
16
  */
17
 
18
+ class QM_Output_Html_Hooks extends QM_Output_Html {
 
 
 
 
 
 
 
 
 
19
 
20
+ public $id = 'hooks';
 
 
 
21
 
22
+ public function __construct( QM_Collector $collector ) {
23
+ parent::__construct( $collector );
24
+ add_filter( 'query_monitor_menus', array( $this, 'admin_menu' ), 70 );
25
  }
26
 
27
+ public function output() {
28
 
29
+ $data = $this->collector->get_data();
30
 
31
+ if ( empty( $data ) )
32
+ return;
 
 
33
 
34
+ $row_attr = array();
35
 
 
36
  if ( is_multisite() and is_network_admin() )
37
+ $screen = preg_replace( '|-network$|', '', $data['screen'] );
38
+ else
39
+ $screen = $data['screen'];
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
40
 
41
+ echo '<div class="qm" id="' . $this->collector->id() . '">';
42
  echo '<table cellspacing="0">';
43
  echo '<thead>';
44
  echo '<tr>';
50
 
51
  foreach ( $data['hooks'] as $hook ) {
52
 
53
+ if ( !empty( $screen ) ) {
54
 
55
+ if ( false !== strpos( $hook['name'], $screen . '.php' ) )
56
+ $hook['name'] = str_replace( '-' . $screen . '.php', '-<span class="qm-current">' . $screen . '.php</span>', $hook['name'] );
57
  else
58
+ $hook['name'] = str_replace( '-' . $screen, '-<span class="qm-current">' . $screen . '</span>', $hook['name'] );
59
 
60
  }
61
 
119
 
120
  }
121
 
122
+ public function admin_menu( array $menu ) {
123
+
124
+ $menu[] = $this->menu( array(
125
+ 'title' => __( 'Hooks', 'query-monitor' )
126
+ ) );
127
+ return $menu;
128
+
129
+ }
130
+
131
  }
132
 
133
+ function register_qm_output_html_hooks( QM_Output $output = null, QM_Collector $collector ) {
134
+ return new QM_Output_Html_Hooks( $collector );
 
135
  }
136
 
137
+ add_filter( 'query_monitor_output_html_hooks', 'register_qm_output_html_hooks', 10, 2 );
{components → output/html}/http.php RENAMED
@@ -1,5 +1,6 @@
1
  <?php
2
  /*
 
3
  Copyright 2013 John Blackbourn
4
 
5
  This program is free software; you can redistribute it and/or modify
@@ -14,125 +15,21 @@ GNU General Public License for more details.
14
 
15
  */
16
 
17
- class QM_Component_HTTP extends QM_Component {
18
-
19
- var $id = 'http';
20
-
21
- function __construct() {
22
 
23
- parent::__construct();
24
-
25
- add_action( 'http_api_debug', array( $this, 'http_debug' ), 99, 5 );
26
- add_filter( 'http_request_args', array( $this, 'http_request' ), 99, 2 );
27
- add_filter( 'http_response', array( $this, 'http_response' ), 99, 3 );
28
- # http://core.trac.wordpress.org/ticket/25747
29
- add_filter( 'pre_http_request', array( $this, 'http_response' ), 99, 3 );
30
- add_filter( 'query_monitor_menus', array( $this, 'admin_menu' ), 60 );
31
  add_filter( 'query_monitor_class', array( $this, 'admin_class' ) );
32
-
33
- }
34
-
35
- function admin_class( array $class ) {
36
-
37
- if ( isset( $this->data['errors']['error'] ) )
38
- $class[] = 'qm-error';
39
- else if ( isset( $this->data['errors']['warning'] ) )
40
- $class[] = 'qm-warning';
41
-
42
- return $class;
43
-
44
- }
45
-
46
- function http_request( array $args, $url ) {
47
- $m_start = microtime( true );
48
- $key = $m_start . $url;
49
- $this->data['http'][$key] = array(
50
- 'url' => $url,
51
- 'args' => $args,
52
- 'start' => $m_start,
53
- 'trace' => new QM_Backtrace
54
- );
55
- $args['_qm_key'] = $key;
56
- return $args;
57
- }
58
-
59
- function http_debug( $param, $action ) {
60
-
61
- switch ( $action ) {
62
-
63
- case 'response':
64
-
65
- $fga = func_get_args();
66
-
67
- list( $response, $action, $class ) = $fga;
68
-
69
- # http://core.trac.wordpress.org/ticket/18732
70
- if ( isset( $fga[3] ) )
71
- $args = $fga[3];
72
- if ( isset( $fga[4] ) )
73
- $url = $fga[4];
74
- if ( !isset( $args['_qm_key'] ) )
75
- return;
76
-
77
- if ( !empty( $class ) )
78
- $this->data['http'][$args['_qm_key']]['transport'] = str_replace( 'wp_http_', '', strtolower( $class ) );
79
- else
80
- $this->data['http'][$args['_qm_key']]['transport'] = false;
81
-
82
- if ( is_wp_error( $response ) )
83
- $this->http_response( $response, $args, $url );
84
-
85
- break;
86
-
87
- case 'transports_list':
88
- # Nothing
89
- break;
90
-
91
- }
92
-
93
  }
94
 
95
- function http_response( $response, array $args, $url ) {
96
- $this->data['http'][$args['_qm_key']]['end'] = microtime( true );
97
- $this->data['http'][$args['_qm_key']]['response'] = $response;
98
 
99
- if ( is_wp_error( $response ) ) {
100
- $this->data['errors']['error'][] = $args['_qm_key'];
101
- } else {
102
- if ( intval( wp_remote_retrieve_response_code( $response ) ) >= 400 )
103
- $this->data['errors']['warning'][] = $args['_qm_key'];
104
- }
105
- return $response;
106
- }
107
-
108
- function admin_menu( array $menu ) {
109
-
110
- $count = isset( $this->data['http'] ) ? count( $this->data['http'] ) : 0;
111
-
112
- $title = ( empty( $count ) )
113
- ? __( 'HTTP Requests', 'query-monitor' )
114
- : __( 'HTTP Requests (%s)', 'query-monitor' );
115
-
116
- $args = array(
117
- 'title' => sprintf( $title, number_format_i18n( $count ) ),
118
- );
119
-
120
- if ( isset( $this->data['errors']['error'] ) )
121
- $args['meta']['classname'] = 'qm-error';
122
- else if ( isset( $this->data['errors']['warning'] ) )
123
- $args['meta']['classname'] = 'qm-warning';
124
-
125
- $menu[] = $this->menu( $args );
126
-
127
- return $menu;
128
-
129
- }
130
-
131
- function output_html( array $args, array $data ) {
132
 
133
  $total_time = 0;
134
 
135
- echo '<div class="qm" id="' . $args['id'] . '">';
136
  echo '<table cellspacing="0">';
137
  echo '<thead>';
138
  echo '<tr>';
@@ -194,15 +91,7 @@ class QM_Component_HTTP extends QM_Component {
194
  $method = $row['args']['method'];
195
  if ( !$row['args']['blocking'] )
196
  $method .= '&nbsp;' . _x( '(non-blocking)', 'non-blocking HTTP transport', 'query-monitor' );
197
- $url = str_replace( array(
198
- '=',
199
- '&',
200
- '?',
201
- ), array(
202
- '<span class="qm-param">=</span>',
203
- '<br /><span class="qm-param">&amp;</span>',
204
- '<br /><span class="qm-param">?</span>',
205
- ), $row['url'] );
206
 
207
  if ( isset( $row['transport'] ) )
208
  $transport = $row['transport'];
@@ -255,7 +144,7 @@ class QM_Component_HTTP extends QM_Component {
255
  echo '<td colspan="7" style="text-align:center !important"><em>' . __( 'none', 'query-monitor' ) . '</em></td>';
256
  echo '</tr>';
257
  echo '</tbody>';
258
-
259
  }
260
 
261
  echo '</table>';
@@ -263,11 +152,48 @@ class QM_Component_HTTP extends QM_Component {
263
 
264
  }
265
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
266
  }
267
 
268
- function register_qm_http( array $qm ) {
269
- $qm['http'] = new QM_Component_HTTP;
270
- return $qm;
271
  }
272
 
273
- add_filter( 'query_monitor_components', 'register_qm_http', 110 );
1
  <?php
2
  /*
3
+
4
  Copyright 2013 John Blackbourn
5
 
6
  This program is free software; you can redistribute it and/or modify
15
 
16
  */
17
 
18
+ class QM_Output_Html_HTTP extends QM_Output_Html {
 
 
 
 
19
 
20
+ public function __construct( QM_Collector $collector ) {
21
+ parent::__construct( $collector );
22
+ add_filter( 'query_monitor_menus', array( $this, 'admin_menu' ), 90 );
 
 
 
 
 
23
  add_filter( 'query_monitor_class', array( $this, 'admin_class' ) );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
24
  }
25
 
26
+ public function output() {
 
 
27
 
28
+ $data = $this->collector->get_data();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
29
 
30
  $total_time = 0;
31
 
32
+ echo '<div class="qm" id="' . $this->collector->id() . '">';
33
  echo '<table cellspacing="0">';
34
  echo '<thead>';
35
  echo '<tr>';
91
  $method = $row['args']['method'];
92
  if ( !$row['args']['blocking'] )
93
  $method .= '&nbsp;' . _x( '(non-blocking)', 'non-blocking HTTP transport', 'query-monitor' );
94
+ $url = QM_Util::format_url( $row['url'] );
 
 
 
 
 
 
 
 
95
 
96
  if ( isset( $row['transport'] ) )
97
  $transport = $row['transport'];
144
  echo '<td colspan="7" style="text-align:center !important"><em>' . __( 'none', 'query-monitor' ) . '</em></td>';
145
  echo '</tr>';
146
  echo '</tbody>';
147
+
148
  }
149
 
150
  echo '</table>';
152
 
153
  }
154
 
155
+ public function admin_class( array $class ) {
156
+
157
+ $data = $this->collector->get_data();
158
+
159
+ if ( isset( $data['errors']['error'] ) )
160
+ $class[] = 'qm-error';
161
+ else if ( isset( $data['errors']['warning'] ) )
162
+ $class[] = 'qm-warning';
163
+
164
+ return $class;
165
+
166
+ }
167
+
168
+ public function admin_menu( array $menu ) {
169
+
170
+ $data = $this->collector->get_data();
171
+
172
+ $count = isset( $data['http'] ) ? count( $data['http'] ) : 0;
173
+
174
+ $title = ( empty( $count ) )
175
+ ? __( 'HTTP Requests', 'query-monitor' )
176
+ : __( 'HTTP Requests (%s)', 'query-monitor' );
177
+
178
+ $args = array(
179
+ 'title' => sprintf( $title, number_format_i18n( $count ) ),
180
+ );
181
+
182
+ if ( isset( $data['errors']['error'] ) )
183
+ $args['meta']['classname'] = 'qm-error';
184
+ else if ( isset( $data['errors']['warning'] ) )
185
+ $args['meta']['classname'] = 'qm-warning';
186
+
187
+ $menu[] = $this->menu( $args );
188
+
189
+ return $menu;
190
+
191
+ }
192
+
193
  }
194
 
195
+ function register_qm_output_html_http( QM_Output $output = null, QM_Collector $collector ) {
196
+ return new QM_Output_Html_HTTP( $collector );
 
197
  }
198
 
199
+ add_filter( 'query_monitor_output_html_http', 'register_qm_output_html_http', 10, 2 );
{components → output/html}/overview.php RENAMED
@@ -1,5 +1,6 @@
1
  <?php
2
  /*
 
3
  Copyright 2013 John Blackbourn
4
 
5
  This program is free software; you can redistribute it and/or modify
@@ -14,56 +15,51 @@ GNU General Public License for more details.
14
 
15
  */
16
 
17
- class QM_Component_Overview extends QM_Component {
18
-
19
- var $id = 'overview';
20
 
21
- function __construct() {
22
- parent::__construct();
23
  add_filter( 'query_monitor_title', array( $this, 'admin_title' ), 10 );
24
  }
25
 
26
- function admin_title( array $title ) {
27
- $title[] = sprintf(
28
- _x( '%s<small>S</small>', 'page load time', 'query-monitor' ),
29
- number_format_i18n( $this->data['time'], 2 )
30
- );
31
- $title[] = sprintf(
32
- _x( '%s<small>MB</small>', 'memory usage', 'query-monitor' ),
33
- number_format_i18n( ( $this->data['memory'] / 1024 / 1024 ), 2 )
34
- );
35
- return $title;
36
- }
37
 
38
- function output_html( array $args, array $data ) {
39
 
40
  $http_time = null;
41
  $db_query_num = null;
42
  $db_query_types = array();
43
- $http = $this->get_component( 'http' );
44
- $db_queries = $this->get_component( 'db_queries' );
 
45
  $time_usage = '';
46
  $memory_usage = '';
47
 
48
- if ( $http and isset( $http->data['http'] ) ) {
49
- foreach ( $http->data['http'] as $row ) {
50
- if ( isset( $row['response'] ) )
51
- $http_time += ( $row['end'] - $row['start'] );
52
- else
53
- $http_time += $row['args']['timeout'];
 
 
 
54
  }
55
  }
56
 
57
- if ( $db_queries and isset( $db_queries->data['types'] ) ) {
58
- $db_query_num = $db_queries->data['types'];
59
- $db_stime = number_format_i18n( $db_queries->data['total_time'], 4 );
60
- $db_ltime = number_format_i18n( $db_queries->data['total_time'], 10 );
 
 
 
61
  }
62
 
63
  $total_stime = number_format_i18n( $data['time'], 4 );
64
  $total_ltime = number_format_i18n( $data['time'], 10 );
65
 
66
- echo '<div class="qm" id="' . $this->id() . '">';
67
  echo '<table cellspacing="0">';
68
 
69
  $memory_usage .= '<br /><span class="qm-info">' . sprintf( __( '%1$s%% of %2$s kB limit', 'query-monitor' ), number_format_i18n( $data['memory_usage'], 1 ), number_format_i18n( $data['memory_limit'] / 1024 ) ) . '</span>';
@@ -104,31 +100,25 @@ class QM_Component_Overview extends QM_Component {
104
 
105
  }
106
 
107
- function process() {
108
 
109
- $this->data['time'] = QM_Util::timer_stop_float();
110
- $this->data['time_limit'] = ini_get( 'max_execution_time' );
111
-
112
- if ( !empty( $this->data['time_limit'] ) )
113
- $this->data['time_usage'] = ( 100 / $this->data['time_limit'] ) * $this->data['time'];
114
- else
115
- $this->data['time_usage'] = 0;
116
-
117
- if ( function_exists( 'memory_get_peak_usage' ) )
118
- $this->data['memory'] = memory_get_peak_usage();
119
- else
120
- $this->data['memory'] = memory_get_usage();
121
-
122
- $this->data['memory_limit'] = QM_Util::convert_hr_to_bytes( ini_get( 'memory_limit' ) );
123
- $this->data['memory_usage'] = ( 100 / $this->data['memory_limit'] ) * $this->data['memory'];
124
 
 
 
 
 
 
 
 
 
 
125
  }
126
 
127
  }
128
 
129
- function register_qm_overview( array $qm ) {
130
- $qm['overview'] = new QM_Component_Overview;
131
- return $qm;
132
  }
133
 
134
- add_filter( 'query_monitor_components', 'register_qm_overview', 10 );
1
  <?php
2
  /*
3
+
4
  Copyright 2013 John Blackbourn
5
 
6
  This program is free software; you can redistribute it and/or modify
15
 
16
  */
17
 
18
+ class QM_Output_Html_Overview extends QM_Output_Html {
 
 
19
 
20
+ public function __construct( QM_Collector $collector ) {
21
+ parent::__construct( $collector );
22
  add_filter( 'query_monitor_title', array( $this, 'admin_title' ), 10 );
23
  }
24
 
25
+ public function output() {
 
 
 
 
 
 
 
 
 
 
26
 
27
+ $data = $this->collector->get_data();
28
 
29
  $http_time = null;
30
  $db_query_num = null;
31
  $db_query_types = array();
32
+ # @TODO: make this less derpy:
33
+ $http = QueryMonitor::get_collector( 'http' );
34
+ $db_queries = QueryMonitor::get_collector( 'db_queries' );
35
  $time_usage = '';
36
  $memory_usage = '';
37
 
38
+ if ( $http ) {
39
+ $http_data = $http->get_data();
40
+ if ( isset( $http_data['http'] ) ) {
41
+ foreach ( $http_data['http'] as $row ) {
42
+ if ( isset( $row['response'] ) )
43
+ $http_time += ( $row['end'] - $row['start'] );
44
+ else
45
+ $http_time += $row['args']['timeout'];
46
+ }
47
  }
48
  }
49
 
50
+ if ( $db_queries ) {
51
+ $db_queries_data = $db_queries->get_data();
52
+ if ( isset( $db_queries_data['types'] ) ) {
53
+ $db_query_num = $db_queries_data['types'];
54
+ $db_stime = number_format_i18n( $db_queries_data['total_time'], 4 );
55
+ $db_ltime = number_format_i18n( $db_queries_data['total_time'], 10 );
56
+ }
57
  }
58
 
59
  $total_stime = number_format_i18n( $data['time'], 4 );
60
  $total_ltime = number_format_i18n( $data['time'], 10 );
61
 
62
+ echo '<div class="qm" id="' . $this->collector->id() . '">';
63
  echo '<table cellspacing="0">';
64
 
65
  $memory_usage .= '<br /><span class="qm-info">' . sprintf( __( '%1$s%% of %2$s kB limit', 'query-monitor' ), number_format_i18n( $data['memory_usage'], 1 ), number_format_i18n( $data['memory_limit'] / 1024 ) ) . '</span>';
100
 
101
  }
102
 
103
+ public function admin_title( array $title ) {
104
 
105
+ $data = $this->collector->get_data();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
106
 
107
+ $title[] = sprintf(
108
+ _x( '%s<small>S</small>', 'page load time', 'query-monitor' ),
109
+ number_format_i18n( $data['time'], 2 )
110
+ );
111
+ $title[] = sprintf(
112
+ _x( '%s<small>MB</small>', 'memory usage', 'query-monitor' ),
113
+ number_format_i18n( ( $data['memory'] / 1024 / 1024 ), 2 )
114
+ );
115
+ return $title;
116
  }
117
 
118
  }
119
 
120
+ function register_qm_output_html_overview( QM_Output $output = null, QM_Collector $collector ) {
121
+ return new QM_Output_Html_Overview( $collector );
 
122
  }
123
 
124
+ add_filter( 'query_monitor_output_html_overview', 'register_qm_output_html_overview', 10, 2 );
output/html/php_errors.php ADDED
@@ -0,0 +1,155 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+
4
+ Copyright 2013 John Blackbourn
5
+
6
+ This program is free software; you can redistribute it and/or modify
7
+ it under the terms of the GNU General Public License as published by
8
+ the Free Software Foundation; either version 2 of the License, or
9
+ (at your option) any later version.
10
+
11
+ This program is distributed in the hope that it will be useful,
12
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
+ GNU General Public License for more details.
15
+
16
+ */
17
+
18
+ class QM_Output_Html_PHP_Errors extends QM_Output_Html {
19
+
20
+ public function __construct( QM_Collector $collector ) {
21
+ parent::__construct( $collector );
22
+ add_filter( 'query_monitor_menus', array( $this, 'admin_menu' ), 10 );
23
+ add_filter( 'query_monitor_class', array( $this, 'admin_class' ) );
24
+ }
25
+
26
+ public function output() {
27
+
28
+ $data = $this->collector->get_data();
29
+
30
+ if ( empty( $data['errors'] ) )
31
+ return;
32
+
33
+ echo '<div class="qm" id="' . $this->collector->id() . '">';
34
+ echo '<table cellspacing="0">';
35
+ echo '<thead>';
36
+ echo '<tr>';
37
+ echo '<th colspan="2">' . __( 'PHP Error', 'query-monitor' ) . '</th>';
38
+ echo '<th>' . __( 'File', 'query-monitor' ) . '</th>';
39
+ echo '<th>' . __( 'Line', 'query-monitor' ) . '</th>';
40
+ echo '<th>' . __( 'Call Stack', 'query-monitor' ) . '</th>';
41
+ echo '<th>' . __( 'Component', 'query-monitor' ) . '</th>';
42
+ echo '</tr>';
43
+ echo '</thead>';
44
+ echo '<tbody>';
45
+
46
+ $types = array(
47
+ 'warning' => __( 'Warning', 'query-monitor' ),
48
+ 'notice' => __( 'Notice', 'query-monitor' ),
49
+ 'strict' => __( 'Strict', 'query-monitor' ),
50
+ 'deprecated' => __( 'Deprecated', 'query-monitor' ),
51
+ );
52
+
53
+ foreach ( $types as $type => $title ) {
54
+
55
+ if ( isset( $data['errors'][$type] ) ) {
56
+
57
+ echo '<tr>';
58
+ if ( count( $data['errors'][$type] ) > 1 )
59
+ echo '<td rowspan="' . count( $data['errors'][$type] ) . '">' . $title . '</td>';
60
+ else
61
+ echo '<td>' . $title . '</td>';
62
+ $first = true;
63
+
64
+ foreach ( $data['errors'][$type] as $error ) {
65
+
66
+ if ( !$first )
67
+ echo '<tr>';
68
+
69
+ $stack = $error->trace->get_stack();
70
+ $component = QM_Util::get_backtrace_component( $error->trace );
71
+
72
+ if ( empty( $stack ) )
73
+ $stack = '<em>' . __( 'none', 'query-monitor' ) . '</em>';
74
+ else
75
+ $stack = implode( '<br />', $stack );
76
+
77
+ $message = str_replace( "href='function.", "target='_blank' href='http://php.net/function.", $error->message );
78
+
79
+ echo '<td>' . $message . '</td>';
80
+ echo '<td title="' . esc_attr( $error->file ) . '">' . esc_html( $error->filename ) . '</td>';
81
+ echo '<td>' . esc_html( $error->line ) . '</td>';
82
+ echo '<td class="qm-ltr">' . $stack . '</td>';
83
+ echo '<td>' . $component->name . '</td>';
84
+ echo '</tr>';
85
+
86
+ $first = false;
87
+
88
+ }
89
+
90
+ }
91
+
92
+ }
93
+
94
+ echo '</tbody>';
95
+ echo '</table>';
96
+ echo '</div>';
97
+
98
+ }
99
+
100
+ public function admin_class( array $class ) {
101
+
102
+ $data = $this->collector->get_data();
103
+
104
+ if ( isset( $data['errors']['warning'] ) )
105
+ $class[] = 'qm-warning';
106
+ else if ( isset( $data['errors']['notice'] ) )
107
+ $class[] = 'qm-notice';
108
+ else if ( isset( $data['errors']['strict'] ) )
109
+ $class[] = 'qm-strict';
110
+ else if ( isset( $data['errors']['deprecated'] ) )
111
+ $class[] = 'qm-deprecated';
112
+
113
+ return $class;
114
+
115
+ }
116
+
117
+ public function admin_menu( array $menu ) {
118
+
119
+ $data = $this->collector->get_data();
120
+
121
+ if ( isset( $data['errors']['warning'] ) ) {
122
+ $menu[] = $this->menu( array(
123
+ 'id' => 'query-monitor-warnings',
124
+ 'title' => sprintf( __( 'PHP Warnings (%s)', 'query-monitor' ), number_format_i18n( count( $data['errors']['warning'] ) ) )
125
+ ) );
126
+ }
127
+ if ( isset( $data['errors']['notice'] ) ) {
128
+ $menu[] = $this->menu( array(
129
+ 'id' => 'query-monitor-notices',
130
+ 'title' => sprintf( __( 'PHP Notices (%s)', 'query-monitor' ), number_format_i18n( count( $data['errors']['notice'] ) ) )
131
+ ) );
132
+ }
133
+ if ( isset( $data['errors']['strict'] ) ) {
134
+ $menu[] = $this->menu( array(
135
+ 'id' => 'query-monitor-stricts',
136
+ 'title' => sprintf( __( 'PHP Stricts (%s)', 'query-monitor' ), number_format_i18n( count( $data['errors']['strict'] ) ) )
137
+ ) );
138
+ }
139
+ if ( isset( $data['errors']['deprecated'] ) ) {
140
+ $menu[] = $this->menu( array(
141
+ 'id' => 'query-monitor-deprecated',
142
+ 'title' => sprintf( __( 'PHP Deprecated (%s)', 'query-monitor' ), number_format_i18n( count( $data['errors']['deprecated'] ) ) )
143
+ ) );
144
+ }
145
+ return $menu;
146
+
147
+ }
148
+
149
+ }
150
+
151
+ function register_qm_output_html_php_errors( QM_Output $output = null, QM_Collector $collector ) {
152
+ return new QM_Output_Html_PHP_Errors( $collector );
153
+ }
154
+
155
+ add_filter( 'query_monitor_output_html_php_errors', 'register_qm_output_html_php_errors', 10, 2 );
output/html/request.php ADDED
@@ -0,0 +1,133 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+
4
+ Copyright 2013 John Blackbourn
5
+
6
+ This program is free software; you can redistribute it and/or modify
7
+ it under the terms of the GNU General Public License as published by
8
+ the Free Software Foundation; either version 2 of the License, or
9
+ (at your option) any later version.
10
+
11
+ This program is distributed in the hope that it will be useful,
12
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
+ GNU General Public License for more details.
15
+
16
+ */
17
+
18
+ class QM_Output_Html_Request extends QM_Output_Html {
19
+
20
+ public function __construct( QM_Collector $collector ) {
21
+ parent::__construct( $collector );
22
+ add_filter( 'query_monitor_menus', array( $this, 'admin_menu' ), 50 );
23
+ }
24
+
25
+ public function output() {
26
+
27
+ $data = $this->collector->get_data();
28
+
29
+ echo '<div class="qm qm-half" id="' . $this->collector->id() . '">';
30
+ echo '<table cellspacing="0">';
31
+ echo '<thead>';
32
+ echo '<tr>';
33
+ echo '<th colspan="3">' . $this->collector->name() . '</th>';
34
+ echo '</tr>';
35
+ echo '</thead>';
36
+ echo '<tbody>';
37
+
38
+ $rowspan = isset( $data['qvars'] ) ? count( $data['qvars'] ) : 1;
39
+
40
+ echo '<tr>';
41
+ echo '<td rowspan="' . $rowspan . '">' . __( 'Query Vars', 'query-monitor' ) . '</td>';
42
+
43
+ if ( !empty( $data['qvars'] ) ) {
44
+
45
+ $first = true;
46
+
47
+ foreach( $data['qvars'] as $var => $value ) {
48
+
49
+ if ( !$first )
50
+ echo '<tr>';
51
+
52
+ if ( isset( $data['plugin_qvars'][$var] ) )
53
+ echo "<td valign='top'><span class='qm-current'>{$var}</span></td>";
54
+ else
55
+ echo "<td valign='top'>{$var}</td>";
56
+
57
+ if ( is_array( $value ) or is_object( $value ) ) {
58
+ echo '<td valign="top"><pre>';
59
+ print_r( $value );
60
+ echo '</pre></td>';
61
+ } else {
62
+ $value = esc_html( $value );
63
+ echo "<td valign='top'>{$value}</td>";
64
+ }
65
+
66
+ echo '</tr>';
67
+
68
+ $first = false;
69
+
70
+ }
71
+
72
+ } else {
73
+
74
+ echo '<td colspan="2"><em>' . __( 'none', 'query-monitor' ) . '</em></td>';
75
+ echo '</tr>';
76
+
77
+ }
78
+
79
+ foreach ( array(
80
+ 'request' => __( 'Request', 'query-monitor' ),
81
+ 'matched_rule' => __( 'Matched Rule', 'query-monitor' ),
82
+ 'matched_query' => __( 'Matched Query', 'query-monitor' ),
83
+ 'query_string' => __( 'Query String', 'query-monitor' ),
84
+ ) as $item => $name ) {
85
+
86
+ if ( !isset( $data['request'][$item] ) )
87
+ continue;
88
+
89
+ if ( ! empty( $data['request'][$item] ) ) {
90
+ if ( in_array( $item, array( 'request', 'matched_query', 'query_string' ) ) ) {
91
+ $value = QM_Util::format_url( $data['request'][$item] );
92
+ } else {
93
+ $value = esc_html( $data['request'][$item] );
94
+ }
95
+ } else {
96
+ $value = '<em>' . __( 'none', 'query-monitor' ) . '</em>';
97
+ }
98
+
99
+ echo '<tr>';
100
+ echo '<td valign="top">' . $name . '</td>';
101
+ echo '<td valign="top" colspan="2">' . $value . '</td>';
102
+ echo '</tr>';
103
+ }
104
+
105
+ echo '</tbody>';
106
+ echo '</table>';
107
+ echo '</div>';
108
+
109
+ }
110
+
111
+ public function admin_menu( array $menu ) {
112
+
113
+ $data = $this->collector->get_data();
114
+ $count = isset( $data['plugin_qvars'] ) ? count( $data['plugin_qvars'] ) : 0;
115
+
116
+ $title = ( empty( $count ) )
117
+ ? __( 'Request', 'query-monitor' )
118
+ : __( 'Request (+%s)', 'query-monitor' );
119
+
120
+ $menu[] = $this->menu( array(
121
+ 'title' => sprintf( $title, number_format_i18n( $count ) )
122
+ ) );
123
+ return $menu;
124
+
125
+ }
126
+
127
+ }
128
+
129
+ function register_qm_output_html_request( QM_Output $output = null, QM_Collector $collector ) {
130
+ return new QM_Output_Html_Request( $collector );
131
+ }
132
+
133
+ add_filter( 'query_monitor_output_html_request', 'register_qm_output_html_request', 10, 2 );
output/html/theme.php ADDED
@@ -0,0 +1,103 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+
4
+ Copyright 2013 John Blackbourn
5
+
6
+ This program is free software; you can redistribute it and/or modify
7
+ it under the terms of the GNU General Public License as published by
8
+ the Free Software Foundation; either version 2 of the License, or
9
+ (at your option) any later version.
10
+
11
+ This program is distributed in the hope that it will be useful,
12
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
+ GNU General Public License for more details.
15
+
16
+ */
17
+
18
+ class QM_Output_Html_Theme extends QM_Output_Html {
19
+
20
+ public function __construct( QM_Collector $collector ) {
21
+ parent::__construct( $collector );
22
+ add_filter( 'query_monitor_menus', array( $this, 'admin_menu' ), 60 );
23
+ }
24
+
25
+ public function output() {
26
+
27
+ $data = $this->collector->get_data();
28
+
29
+ if ( empty( $data ) )
30
+ return;
31
+
32
+ echo '<div class="qm qm-half" id="' . $this->collector->id() . '">';
33
+ echo '<table cellspacing="0">';
34
+ echo '<thead>';
35
+ echo '<tr>';
36
+ echo '<th colspan="2">' . $this->collector->name() . '</th>';
37
+ echo '</tr>';
38
+ echo '</thead>';
39
+
40
+ echo '<tbody>';
41
+ echo '<tr>';
42
+ echo '<td>' . __( 'Template', 'query-monitor' ) . '</td>';
43
+ echo "<td>{$data['template_file']}</td>";
44
+ echo '</tr>';
45
+
46
+ if ( !empty( $data['body_class'] ) ) {
47
+
48
+ echo '<tr>';
49
+ echo '<td rowspan="' . count( $data['body_class'] ) . '">' . __( 'Body Classes', 'query-monitor' ) . '</td>';
50
+ $first = true;
51
+
52
+ foreach ( $data['body_class'] as $class ) {
53
+
54
+ if ( !$first )
55
+ echo '<tr>';
56
+
57
+ echo "<td>{$class}</td>";
58
+ echo '</tr>';
59
+
60
+ $first = false;
61
+
62
+ }
63
+
64
+ }
65
+
66
+ echo '<tr>';
67
+ echo '<td>' . __( 'Theme', 'query-monitor' ) . '</td>';
68
+ echo "<td>{$data['stylesheet']}</td>";
69
+ echo '</tr>';
70
+
71
+ if ( $data['stylesheet'] != $data['template'] ) {
72
+ echo '<tr>';
73
+ echo '<td>' . __( 'Parent Theme', 'query-monitor' ) . '</td>';
74
+ echo "<td>{$data['template']}</td>";
75
+ echo '</tr>';
76
+ }
77
+
78
+ echo '</tbody>';
79
+ echo '</table>';
80
+ echo '</div>';
81
+
82
+ }
83
+
84
+ public function admin_menu( array $menu ) {
85
+
86
+ $data = $this->collector->get_data();
87
+
88
+ if ( isset( $data['template_file'] ) ) {
89
+ $menu[] = $this->menu( array(
90
+ 'title' => sprintf( __( 'Template: %s', 'query-monitor' ), $data['template_file'] )
91
+ ) );
92
+ }
93
+ return $menu;
94
+
95
+ }
96
+
97
+ }
98
+
99
+ function register_qm_output_html_theme( QM_Output $output = null, QM_Collector $collector ) {
100
+ return new QM_Output_Html_Theme( $collector );
101
+ }
102
+
103
+ add_filter( 'query_monitor_output_html_theme', 'register_qm_output_html_theme', 10, 2 );
{components → output/html}/transients.php RENAMED
@@ -1,5 +1,6 @@
1
  <?php
2
  /*
 
3
  Copyright 2013 John Blackbourn
4
 
5
  This program is free software; you can redistribute it and/or modify
@@ -14,42 +15,18 @@ GNU General Public License for more details.
14
 
15
  */
16
 
17
- class QM_Component_Transients extends QM_Component {
18
-
19
- var $id = 'transients';
20
 
21
- function __construct() {
22
- parent::__construct();
23
- # See http://core.trac.wordpress.org/ticket/24583
24
- add_action( 'setted_site_transient', array( $this, 'setted_site_transient' ), 10, 3 );
25
- add_action( 'setted_transient', array( $this, 'setted_blog_transient' ), 10, 3 );
26
- add_filter( 'query_monitor_menus', array( $this, 'admin_menu' ), 70 );
27
  }
28
 
29
- function setted_site_transient( $transient, $value = null, $expiration = null ) {
30
- $this->setted_transient( $transient, 'site', $value, $expiration );
31
- }
32
 
33
- function setted_blog_transient( $transient, $value = null, $expiration = null ) {
34
- $this->setted_transient( $transient, 'blog', $value, $expiration );
35
- }
36
 
37
- function setted_transient( $transient, $type, $value = null, $expiration = null ) {
38
- $trace = new QM_Backtrace( array(
39
- 'ignore_items' => 1 # Ignore the setted_(site|blog)_transient method
40
- ) );
41
- $this->data['trans'][] = array(
42
- 'transient' => $transient,
43
- 'trace' => $trace,
44
- 'type' => $type,
45
- 'value' => $value,
46
- 'expiration' => $expiration,
47
- );
48
- }
49
-
50
- function output_html( array $args, array $data ) {
51
-
52
- echo '<div class="qm" id="' . $args['id'] . '">';
53
  echo '<table cellspacing="0">';
54
  echo '<thead>';
55
  echo '<tr>';
@@ -118,9 +95,10 @@ class QM_Component_Transients extends QM_Component {
118
 
119
  }
120
 
121
- function admin_menu( array $menu ) {
122
 
123
- $count = isset( $this->data['trans'] ) ? count( $this->data['trans'] ) : 0;
 
124
 
125
  $title = ( empty( $count ) )
126
  ? __( 'Transients Set', 'query-monitor' )
@@ -133,12 +111,10 @@ class QM_Component_Transients extends QM_Component {
133
 
134
  }
135
 
136
-
137
  }
138
 
139
- function register_qm_transients( array $qm ) {
140
- $qm['transients'] = new QM_Component_Transients;
141
- return $qm;
142
  }
143
 
144
- add_filter( 'query_monitor_components', 'register_qm_transients', 100 );
1
  <?php
2
  /*
3
+
4
  Copyright 2013 John Blackbourn
5
 
6
  This program is free software; you can redistribute it and/or modify
15
 
16
  */
17
 
18
+ class QM_Output_Html_Transients extends QM_Output_Html {
 
 
19
 
20
+ public function __construct( QM_Collector $collector ) {
21
+ parent::__construct( $collector );
22
+ add_filter( 'query_monitor_menus', array( $this, 'admin_menu' ), 80 );
 
 
 
23
  }
24
 
25
+ public function output() {
 
 
26
 
27
+ $data = $this->collector->get_data();
 
 
28
 
29
+ echo '<div class="qm" id="' . $this->collector->id() . '">';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
30
  echo '<table cellspacing="0">';
31
  echo '<thead>';
32
  echo '<tr>';
95
 
96
  }
97
 
98
+ public function admin_menu( array $menu ) {
99
 
100
+ $data = $this->collector->get_data();
101
+ $count = isset( $data['trans'] ) ? count( $data['trans'] ) : 0;
102
 
103
  $title = ( empty( $count ) )
104
  ? __( 'Transients Set', 'query-monitor' )
111
 
112
  }
113
 
 
114
  }
115
 
116
+ function register_qm_output_html_transients( QM_Output $output = null, QM_Collector $collector ) {
117
+ return new QM_Output_Html_Transients( $collector );
 
118
  }
119
 
120
+ add_filter( 'query_monitor_output_html_transients', 'register_qm_output_html_transients', 10, 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.5.6
6
  Plugin URI: https://github.com/johnbillion/QueryMonitor
7
  Author: John Blackbourn
8
  Author URI: https://johnblackbourn.com/
@@ -27,22 +27,22 @@ GNU General Public License for more details.
27
  defined( 'ABSPATH' ) or die();
28
 
29
  # No autoloaders for us. See https://github.com/johnbillion/QueryMonitor/issues/7
30
- foreach ( array( 'Backtrace', 'Component', 'Plugin', 'Util' ) as $f )
31
  require_once dirname( __FILE__ ) . "/{$f}.php";
32
 
33
  class QueryMonitor extends QM_Plugin {
34
 
35
- protected $components = array();
 
36
  protected $did_footer = false;
37
 
38
- public function __construct( $file ) {
39
 
40
  # Actions
41
  add_action( 'init', array( $this, 'action_init' ) );
42
  add_action( 'admin_footer', array( $this, 'action_footer' ), 999 );
43
  add_action( 'wp_footer', array( $this, 'action_footer' ), 999 );
44
  add_action( 'login_footer', array( $this, 'action_footer' ), 999 );
45
- add_action( 'admin_bar_menu', array( $this, 'action_admin_bar_menu' ), 999 );
46
  add_action( 'shutdown', array( $this, 'action_shutdown' ), 0 );
47
 
48
  # Filters
@@ -56,26 +56,45 @@ class QueryMonitor extends QM_Plugin {
56
  # Parent setup:
57
  parent::__construct( $file );
58
 
59
- foreach ( glob( $this->plugin_path( 'components/*.php' ) ) as $component )
60
- include $component;
61
 
62
- foreach ( apply_filters( 'query_monitor_components', array() ) as $component )
63
- $this->add_component( $component );
64
 
 
 
 
 
 
 
 
 
 
 
65
  }
66
 
67
- public function add_component( QM_Component $component ) {
68
- $this->components[$component->id] = $component;
69
  }
70
 
71
- public function get_component( $id ) {
72
- if ( isset( $this->components[$id] ) )
73
- return $this->components[$id];
 
74
  return false;
75
  }
76
 
77
- public function get_components() {
78
- return $this->components;
 
 
 
 
 
 
 
 
79
  }
80
 
81
  public function activate( $sitewide = false ) {
@@ -104,55 +123,6 @@ class QueryMonitor extends QM_Plugin {
104
 
105
  }
106
 
107
- public function action_admin_bar_menu( WP_Admin_Bar $wp_admin_bar ) {
108
-
109
- if ( !$this->show_query_monitor() )
110
- return;
111
-
112
- $class = implode( ' ', array( 'hide-if-js', QM_Util::wpv() ) );
113
- $title = __( 'Query Monitor', 'query-monitor' );
114
-
115
- $wp_admin_bar->add_menu( array(
116
- 'id' => 'query-monitor',
117
- 'title' => $title,
118
- 'href' => '#qm-overview',
119
- 'meta' => array(
120
- 'classname' => $class
121
- )
122
- ) );
123
-
124
- $wp_admin_bar->add_menu( array(
125
- 'parent' => 'query-monitor',
126
- 'id' => 'query-monitor-placeholder',
127
- 'title' => $title,
128
- 'href' => '#qm-overview'
129
- ) );
130
-
131
- }
132
-
133
- public function js_admin_bar_menu() {
134
-
135
- $class = implode( ' ', apply_filters( 'query_monitor_class', array( QM_Util::wpv() ) ) );
136
- $title = implode( ' &nbsp; ', apply_filters( 'query_monitor_title', array() ) );
137
-
138
- if ( empty( $title ) )
139
- $title = __( 'Query Monitor', 'query-monitor' );
140
-
141
- $admin_bar_menu = array(
142
- 'top' => array(
143
- 'title' => sprintf( '<span class="ab-icon">QM</span><span class="ab-label">%s</span>', $title ),
144
- 'classname' => $class
145
- ),
146
- 'sub' => array()
147
- );
148
-
149
- foreach ( apply_filters( 'query_monitor_menus', array() ) as $menu )
150
- $admin_bar_menu['sub'][] = $menu;
151
-
152
- return $admin_bar_menu;
153
-
154
- }
155
-
156
  public function show_query_monitor() {
157
 
158
  if ( !did_action( 'plugins_loaded' ) )
@@ -171,7 +141,7 @@ class QueryMonitor extends QM_Plugin {
171
  return $this->show_query_monitor = true;
172
  }
173
 
174
- if ( $auth = $this->get_component( 'authentication' ) )
175
  return $this->show_query_monitor = $auth->show_query_monitor();
176
 
177
  return $this->show_query_monitor = false;
@@ -186,120 +156,41 @@ class QueryMonitor extends QM_Plugin {
186
 
187
  public function action_shutdown() {
188
 
189
- if ( !$this->show_query_monitor() )
190
- return;
191
-
192
- if ( QM_Util::is_ajax() )
193
- $this->output_ajax();
194
- else if ( $this->did_footer )
195
- $this->output_footer();
196
-
197
- }
198
-
199
- public function action_init() {
200
-
201
- global $wp_locale;
202
-
203
- load_plugin_textdomain( 'query-monitor', false, dirname( $this->plugin_base() ) . '/languages' );
204
-
205
- if ( !$this->show_query_monitor() )
206
- return;
207
-
208
- if ( QM_Util::is_ajax() )
209
- ob_start();
210
-
211
- # @todo move into output_html
212
- if ( !defined( 'DONOTCACHEPAGE' ) )
213
- define( 'DONOTCACHEPAGE', 1 );
214
-
215
- wp_enqueue_style(
216
- 'query-monitor',
217
- $this->plugin_url( 'assets/query-monitor.css' ),
218
- null,
219
- $this->plugin_ver( 'assets/query-monitor.css' )
220
- );
221
- wp_enqueue_script(
222
- 'query-monitor',
223
- $this->plugin_url( 'assets/query-monitor.js' ),
224
- array( 'jquery' ),
225
- $this->plugin_ver( 'assets/query-monitor.js' ),
226
- true
227
- );
228
- wp_localize_script(
229
- 'query-monitor',
230
- 'qm_locale',
231
- (array) $wp_locale
232
- );
233
- wp_localize_script(
234
- 'query-monitor',
235
- 'qm_l10n',
236
- array(
237
- 'ajax_error' => __( 'PHP Error in AJAX Response', 'query-monitor' ),
238
- )
239
- );
240
-
241
- }
242
-
243
- public function output_footer() {
244
-
245
- # @TODO document why this is needed
246
- # Flush the output buffer to avoid crashes
247
- if ( !is_feed() ) {
248
- while ( ob_get_length() )
249
- ob_end_flush();
250
  }
251
 
252
- foreach ( $this->get_components() as $component )
253
- $component->process();
254
 
255
- if ( !function_exists( 'is_admin_bar_showing' ) or !is_admin_bar_showing() )
256
- $class = 'qm-show';
257
- else
258
- $class = '';
259
 
260
- $qm = array(
261
- 'menu' => $this->js_admin_bar_menu(),
262
- 'ajax_errors' => array() # @TODO move this into the php_errors component
263
- );
264
 
265
- echo '<script type="text/javascript">' . "\n\n";
266
- echo 'var qm = ' . json_encode( $qm ) . ';' . "\n\n";
267
- echo '</script>' . "\n\n";
268
 
269
- echo '<div id="qm" class="' . $class . '">';
270
- echo '<div id="qm-wrapper">';
271
- echo '<p>' . __( 'Query Monitor', 'query-monitor' ) . '</p>';
272
 
273
- foreach ( $this->get_components() as $component ) {
274
- $component->output_html( array(
275
- 'id' => $component->id()
276
- ), $component->get_data() );
277
  }
278
 
279
- echo '</div>';
280
- echo '</div>';
281
-
282
  }
283
 
284
- public function output_ajax() {
 
 
285
 
286
- # if the headers have already been sent then we can't do anything about it
287
- if ( headers_sent() )
288
  return;
289
 
290
- foreach ( $this->get_components() as $component )
291
- $component->process();
292
-
293
- foreach ( $this->get_components() as $component ) {
294
- $component->output_headers( array(
295
- 'id' => $component->id()
296
- ), $component->get_data() );
297
  }
298
 
299
- # flush once, because we're nice
300
- if ( ob_get_length() )
301
- ob_flush();
302
-
303
  }
304
 
305
  public function filter_active_plugins( array $plugins ) {
@@ -331,6 +222,17 @@ class QueryMonitor extends QM_Plugin {
331
 
332
  }
333
 
 
 
 
 
 
 
 
 
 
 
 
334
  }
335
 
336
- $GLOBALS['querymonitor'] = new QueryMonitor( __FILE__ );
2
  /*
3
  Plugin Name: Query Monitor
4
  Description: Monitoring of database queries, hooks, conditionals and more.
5
+ Version: 2.6
6
  Plugin URI: https://github.com/johnbillion/QueryMonitor
7
  Author: John Blackbourn
8
  Author URI: https://johnblackbourn.com/
27
  defined( 'ABSPATH' ) or die();
28
 
29
  # No autoloaders for us. See https://github.com/johnbillion/QueryMonitor/issues/7
30
+ foreach ( array( 'Backtrace', 'Collector', 'Plugin', 'Util', 'Dispatcher', 'Output' ) as $f )
31
  require_once dirname( __FILE__ ) . "/{$f}.php";
32
 
33
  class QueryMonitor extends QM_Plugin {
34
 
35
+ protected $collectors = array();
36
+ protected $dispatchers = array();
37
  protected $did_footer = false;
38
 
39
+ protected function __construct( $file ) {
40
 
41
  # Actions
42
  add_action( 'init', array( $this, 'action_init' ) );
43
  add_action( 'admin_footer', array( $this, 'action_footer' ), 999 );
44
  add_action( 'wp_footer', array( $this, 'action_footer' ), 999 );
45
  add_action( 'login_footer', array( $this, 'action_footer' ), 999 );
 
46
  add_action( 'shutdown', array( $this, 'action_shutdown' ), 0 );
47
 
48
  # Filters
56
  # Parent setup:
57
  parent::__construct( $file );
58
 
59
+ foreach ( glob( $this->plugin_path( 'collectors/*.php' ) ) as $collector )
60
+ include $collector;
61
 
62
+ foreach ( apply_filters( 'query_monitor_collectors', array() ) as $collector )
63
+ $this->add_collector( $collector );
64
 
65
+ foreach ( glob( $this->plugin_path( 'dispatchers/*.php' ) ) as $dispatcher )
66
+ include $dispatcher;
67
+
68
+ foreach ( apply_filters( 'query_monitor_dispatchers', array(), $this ) as $dispatcher )
69
+ $this->add_dispatcher( $dispatcher );
70
+
71
+ }
72
+
73
+ public function add_collector( QM_Collector $collector ) {
74
+ $this->collectors[$collector->id] = $collector;
75
  }
76
 
77
+ public function add_dispatcher( QM_Dispatcher $dispatcher ) {
78
+ $this->dispatchers[$dispatcher->id] = $dispatcher;
79
  }
80
 
81
+ public static function get_collector( $id ) {
82
+ $qm = self::init();
83
+ if ( isset( $qm->collectors[$id] ) )
84
+ return $qm->collectors[$id];
85
  return false;
86
  }
87
 
88
+ public function get_collectors() {
89
+ return $this->collectors;
90
+ }
91
+
92
+ public function get_dispatchers() {
93
+ return $this->dispatchers;
94
+ }
95
+
96
+ public function did_footer() {
97
+ return $this->did_footer;
98
  }
99
 
100
  public function activate( $sitewide = false ) {
123
 
124
  }
125
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
126
  public function show_query_monitor() {
127
 
128
  if ( !did_action( 'plugins_loaded' ) )
141
  return $this->show_query_monitor = true;
142
  }
143
 
144
+ if ( $auth = self::get_collector( 'authentication' ) )
145
  return $this->show_query_monitor = $auth->show_query_monitor();
146
 
147
  return $this->show_query_monitor = false;
156
 
157
  public function action_shutdown() {
158
 
159
+ # @TODO introduce a method on dispatchers which defaults to not processing
160
+ # qm and then a persistent outputter can switch it on
161
+ foreach ( $this->get_collectors() as $collector ) {
162
+ $collector->process();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
163
  }
164
 
165
+ foreach ( $this->get_dispatchers() as $dispatcher ) {
 
166
 
167
+ if ( ! $dispatcher->active() ) {
168
+ continue;
169
+ }
 
170
 
171
+ $dispatcher->before_output();
 
 
 
172
 
173
+ foreach ( $this->get_collectors() as $collector ) {
174
+ $dispatcher->output( $collector );
175
+ }
176
 
177
+ $dispatcher->after_output();
 
 
178
 
 
 
 
 
179
  }
180
 
 
 
 
181
  }
182
 
183
+ public function action_init() {
184
+
185
+ load_plugin_textdomain( 'query-monitor', false, dirname( $this->plugin_base() ) . '/languages' );
186
 
187
+ if ( !$this->show_query_monitor() )
 
188
  return;
189
 
190
+ foreach ( $this->get_dispatchers() as $dispatcher ) {
191
+ $dispatcher->init();
 
 
 
 
 
192
  }
193
 
 
 
 
 
194
  }
195
 
196
  public function filter_active_plugins( array $plugins ) {
222
 
223
  }
224
 
225
+ public static function init( $file = null ) {
226
+
227
+ static $instance = null;
228
+
229
+ if ( ! $instance )
230
+ $instance = new QueryMonitor( $file );
231
+
232
+ return $instance;
233
+
234
+ }
235
+
236
  }
237
 
238
+ QueryMonitor::init( __FILE__ );
readme.txt CHANGED
@@ -3,7 +3,7 @@ Contributors: johnbillion
3
  Tags: debug, debugging, development, developer, performance, profiler, profiling, queries
4
  Requires at least: 3.5
5
  Tested up to: 3.8
6
- Stable tag: 2.5.6
7
  License: GPLv2 or later
8
 
9
  View debugging and performance information on database queries, hooks, conditionals, HTTP requests, redirects and more.
@@ -47,6 +47,11 @@ Filtering queries by component or calling function makes it easy to see which pl
47
  * Shows an easily visible warning in the admin toolbar
48
  * Plays nicely with Xdebug
49
 
 
 
 
 
 
50
  = HTTP Requests =
51
 
52
  * Shows all HTTP requests performed on the current page (as long as they use WordPress' HTTP API)
@@ -81,7 +86,6 @@ Hands up who can remember the correct names for the filters and hooks for custom
81
 
82
  = Everything Else =
83
 
84
- * Shows the names and values for **query vars** on the current page, and highlights **custom query vars**
85
  * Shows any **transients that were set**, along with their timeout, component, and call stack
86
  * Shows all **WordPress conditionals** on the current page, highlighted nicely
87
  * Shows an overview at the top, including page generation time and memory limit as absolute values and as % of their respective limits
@@ -100,7 +104,13 @@ Alternatively, see the guide to [Manually Installing Plugins](http://codex.wordp
100
 
101
  == Screenshots ==
102
 
103
- 1. An example of Query Monitor's output
 
 
 
 
 
 
104
 
105
  == Frequently Asked Questions ==
106
 
@@ -110,6 +120,14 @@ I know!
110
 
111
  == Changelog ==
112
 
 
 
 
 
 
 
 
 
113
  = 2.5.6 =
114
  * Fix the "Invalid header" issue. Woo!
115
 
3
  Tags: debug, debugging, development, developer, performance, profiler, profiling, queries
4
  Requires at least: 3.5
5
  Tested up to: 3.8
6
+ Stable tag: 2.6
7
  License: GPLv2 or later
8
 
9
  View debugging and performance information on database queries, hooks, conditionals, HTTP requests, redirects and more.
47
  * Shows an easily visible warning in the admin toolbar
48
  * Plays nicely with Xdebug
49
 
50
+ = Request =
51
+
52
+ * Shows **matched rewrite rules** and associated query strings
53
+ * Shows **query vars** for the current request, and highlights **custom query vars**
54
+
55
  = HTTP Requests =
56
 
57
  * Shows all HTTP requests performed on the current page (as long as they use WordPress' HTTP API)
86
 
87
  = Everything Else =
88
 
 
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 at the top, including page generation time and memory limit as absolute values and as % of their respective limits
104
 
105
  == Screenshots ==
106
 
107
+ 1. The admin toolbar menu showing an overview
108
+ 2. Aggregate database queries by component
109
+ 3. Slow database queries highlighted in a separate panel
110
+ 4. Database queries complete with filter controls
111
+ 5. Hooks and actions
112
+ 6. HTTP requests (showing an HTTP error)
113
+ 7. Aggregate database queries grouped by calling function
114
 
115
  == Frequently Asked Questions ==
116
 
120
 
121
  == Changelog ==
122
 
123
+ = 2.6 =
124
+ * Toggleable stack traces for queries
125
+ * Show deprecated errors in the PHP Errors panel
126
+ * Replace the Query Vars panel with a Request panel with more information
127
+ * Display a warning when `db.php` isn't in place
128
+ * Fix some PHP 5.2 compatibility
129
+ * Considerable restructuring of the underlying code to increase abstraction
130
+
131
  = 2.5.6 =
132
  * Fix the "Invalid header" issue. Woo!
133
 
screenshot-1.png ADDED
Binary file
screenshot-2.png ADDED
Binary file
screenshot-3.png ADDED
Binary file
screenshot-4.png ADDED
Binary file
screenshot-5.png ADDED
Binary file
screenshot-6.png ADDED
Binary file
screenshot-7.png ADDED
Binary file
wp-content/db.php CHANGED
@@ -26,7 +26,7 @@ GNU General Public License for more details.
26
  defined( 'ABSPATH' ) or die();
27
 
28
  # No autoloaders for us. See https://github.com/johnbillion/QueryMonitor/issues/7
29
- foreach ( array( 'Backtrace', 'Component', 'Plugin', 'Util' ) as $f ) {
30
  if ( ! is_readable( $file = dirname( __FILE__ ) . "/../{$f}.php" ) )
31
  return;
32
  require_once $file;
26
  defined( 'ABSPATH' ) or die();
27
 
28
  # No autoloaders for us. See https://github.com/johnbillion/QueryMonitor/issues/7
29
+ foreach ( array( 'Backtrace', 'Collector', 'Plugin', 'Util' ) as $f ) {
30
  if ( ! is_readable( $file = dirname( __FILE__ ) . "/../{$f}.php" ) )
31
  return;
32
  require_once $file;