Query Monitor - Version 2.9.1

Version Description

  • Query callers and query components can now be clicked to filter the main query list by that caller or component.
  • Add support for pausing Jetpack's Infinite Scroll module when viewing QM output in the footer.
  • Add support for WordPress.com VIP Go shared plugins as an explicit component.
  • Send nocache headers when QM is active.
  • Various minor tweaks.
Download this release

Release Info

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

Code changes from version 2.9.0 to 2.9.1

assets/query-monitor.css CHANGED
@@ -157,7 +157,7 @@ body.wp-admin.folded #qm {
157
  }
158
 
159
  #qm-wrapper {
160
- margin: 0 auto;
161
  }
162
 
163
  #qm-wrapper > p {
@@ -168,17 +168,31 @@ body.wp-admin.folded #qm {
168
  }
169
 
170
  .qm {
171
- margin: 0 1% !important;
172
- padding: 40px 0 0 !important;
 
173
  clear: both !important;
174
  }
175
 
176
  .qm-half {
177
  float: left !important;
178
- width: 48% !important;
179
  clear: none !important;
180
  }
181
 
 
 
 
 
 
 
 
 
 
 
 
 
 
182
  @media all and (max-width: 900px) {
183
  .qm-half {
184
  float: none !important;
@@ -211,10 +225,11 @@ body.wp-admin.folded #qm {
211
  font-style: normal !important;
212
  line-height: 16px !important;
213
  border: 1px solid #e8e8e8 !important;
214
- padding: 5px 8px 4px !important;
215
  vertical-align: top !important;
216
  text-shadow: none !important;
217
  text-transform: none !important;
 
218
  }
219
 
220
  .qm .qm-totally-legit-spacer td {
@@ -257,12 +272,12 @@ body.wp-admin.folded #qm {
257
  }
258
 
259
  .qm td .qm-toggler {
260
- padding: 5px 8px 4px !important;
261
  position: relative !important;
262
  }
263
 
264
  .qm .qm-inner-toggle {
265
- padding: 5px 8px 4px !important;
266
  }
267
 
268
  .qm-has-inner .qm-toggled > table {
@@ -331,7 +346,7 @@ body.wp-admin.folded #qm {
331
 
332
  .qm span.qm-false,
333
  .qm td.qm-false {
334
- color: #ccc !important;
335
  }
336
 
337
  .qm .qm-wrap {
@@ -376,10 +391,10 @@ body.wp-admin.folded #qm {
376
  }
377
 
378
  .qm a.qm-toggle {
379
- color: #bbb !important;
380
- padding: 2px 7px !important;
381
- border-left: 1px solid #e1e1e1 !important;
382
- border-bottom: 1px solid #e1e1e1 !important;
383
  position: absolute !important;
384
  top: 0 !important;
385
  right: 0 !important;
@@ -389,8 +404,8 @@ body.wp-admin.folded #qm {
389
  .qm a.qm-toggle:focus,
390
  .qm a.qm-toggle:hover {
391
  text-decoration: none !important;
392
- border-color: #e1e1e1 !important;
393
- color: #888 !important;
394
  background: #eee !important;
395
  }
396
 
@@ -452,7 +467,7 @@ select.qm-filter {
452
  }
453
 
454
  .qm .qm-sort {
455
- color: #ddd !important;
456
  display: block !important;
457
  font-size: 14px !important;
458
  line-height: 11px !important;
@@ -463,7 +478,7 @@ select.qm-filter {
463
  .qm .qm-sort:focus,
464
  .qm .qm-sorted-asc .qm-sort-asc,
465
  .qm .qm-sorted-desc .qm-sort-desc {
466
- color: #777 !important;
467
  text-decoration: none !important;
468
  }
469
 
157
  }
158
 
159
  #qm-wrapper {
160
+ margin: 0 auto 60px !important;
161
  }
162
 
163
  #qm-wrapper > p {
168
  }
169
 
170
  .qm {
171
+ margin: 0 0 -20px !important;
172
+ padding: 40px 10px 0 !important;
173
+ box-sizing: border-box !important;
174
  clear: both !important;
175
  }
176
 
177
  .qm-half {
178
  float: left !important;
179
+ width: 50% !important;
180
  clear: none !important;
181
  }
182
 
183
+ .qm:focus {
184
+ outline: 0 !important;
185
+ }
186
+
187
+ #qm.qm-theme-twentysixteen .qm {
188
+ padding-top: 65px !important;
189
+ margin-bottom: -45px !important;
190
+ }
191
+
192
+ #qm.qm-theme-twentysixteen #qm-wrapper > p {
193
+ margin-bottom: -45px !important;
194
+ }
195
+
196
  @media all and (max-width: 900px) {
197
  .qm-half {
198
  float: none !important;
225
  font-style: normal !important;
226
  line-height: 16px !important;
227
  border: 1px solid #e8e8e8 !important;
228
+ padding: 4px 6px 3px !important;
229
  vertical-align: top !important;
230
  text-shadow: none !important;
231
  text-transform: none !important;
232
+ -webkit-font-smoothing: auto !important;
233
  }
234
 
235
  .qm .qm-totally-legit-spacer td {
272
  }
273
 
274
  .qm td .qm-toggler {
275
+ padding: 4px 6px 3px !important;
276
  position: relative !important;
277
  }
278
 
279
  .qm .qm-inner-toggle {
280
+ padding: 4px 6px 3px !important;
281
  }
282
 
283
  .qm-has-inner .qm-toggled > table {
346
 
347
  .qm span.qm-false,
348
  .qm td.qm-false {
349
+ color: #bbb !important;
350
  }
351
 
352
  .qm .qm-wrap {
391
  }
392
 
393
  .qm a.qm-toggle {
394
+ color: #999 !important;
395
+ padding: 4px 8px 3px !important;
396
+ border-left: 1px solid #e8e8e8 !important;
397
+ border-bottom: 1px solid #e8e8e8 !important;
398
  position: absolute !important;
399
  top: 0 !important;
400
  right: 0 !important;
404
  .qm a.qm-toggle:focus,
405
  .qm a.qm-toggle:hover {
406
  text-decoration: none !important;
407
+ border-color: #e8e8e8 !important;
408
+ color: #444 !important;
409
  background: #eee !important;
410
  }
411
 
467
  }
468
 
469
  .qm .qm-sort {
470
+ color: #ccc !important;
471
  display: block !important;
472
  font-size: 14px !important;
473
  line-height: 11px !important;
478
  .qm .qm-sort:focus,
479
  .qm .qm-sorted-asc .qm-sort-asc,
480
  .qm .qm-sorted-desc .qm-sort-desc {
481
+ color: #444 !important;
482
  text-decoration: none !important;
483
  }
484
 
assets/query-monitor.js CHANGED
@@ -95,11 +95,23 @@ jQuery( function($) {
95
  $('#wpfooter').css('position','relative');
96
  }
97
  if ( window.infinite_scroll && infinite_scroll.contentSelector ) {
 
98
 
99
  $( infinite_scroll.contentSelector ).infinitescroll('pause');
100
 
101
  if ( window.console ) {
102
- console.log( qm_l10n.infinitescroll_paused );
 
 
 
 
 
 
 
 
 
 
 
103
  }
104
 
105
  }
@@ -110,12 +122,12 @@ jQuery( function($) {
110
 
111
  }
112
 
113
- $('#qm').find('select.qm-filter').on('change',function(e){
114
 
115
  var filter = $(this).attr('data-filter'),
116
  table = $(this).closest('table'),
117
  tr = table.find('tbody tr[data-qm-' + filter + ']'),
118
- val = $(this).val().replace(/[[\]()'"]/g, "\\$&"),
119
  total = tr.removeClass('qm-hide-' + filter).length,
120
  hilite = $(this).attr('data-highlight'),
121
  time = 0;
@@ -148,6 +160,19 @@ jQuery( function($) {
148
 
149
  });
150
 
 
 
 
 
 
 
 
 
 
 
 
 
 
151
  $('#qm').find('.qm-toggle').on('click',function(e){
152
  var el = $(this);
153
  $(this).closest('td').find('.qm-toggled').slideToggle(100,function(){
95
  $('#wpfooter').css('position','relative');
96
  }
97
  if ( window.infinite_scroll && infinite_scroll.contentSelector ) {
98
+ // Infinite Scroll plugin
99
 
100
  $( infinite_scroll.contentSelector ).infinitescroll('pause');
101
 
102
  if ( window.console ) {
103
+ console.debug( qm_l10n.infinitescroll_paused );
104
+ }
105
+
106
+ } else if ( window.infiniteScroll && infiniteScroll.scroller ) {
107
+ // Jetpack Infinite Scroll module
108
+
109
+ infiniteScroll.scroller.check = function(){
110
+ return false;
111
+ };
112
+
113
+ if ( window.console ) {
114
+ console.debug( qm_l10n.infinitescroll_paused );
115
  }
116
 
117
  }
122
 
123
  }
124
 
125
+ $('#qm').find('.qm-filter').on('change',function(e){
126
 
127
  var filter = $(this).attr('data-filter'),
128
  table = $(this).closest('table'),
129
  tr = table.find('tbody tr[data-qm-' + filter + ']'),
130
+ val = $(this).val().replace(/[[\]()'"\\]/g, "\\$&"),
131
  total = tr.removeClass('qm-hide-' + filter).length,
132
  hilite = $(this).attr('data-highlight'),
133
  time = 0;
160
 
161
  });
162
 
163
+ $('#qm').find('.qm-filter-trigger').on('click',function(e){
164
+ var filter = $(this).data('qm-filter'),
165
+ value = $(this).data('qm-value'),
166
+ target = $(this).data('qm-target');
167
+ $('#qm-' + target).find('.qm-filter').not('[data-filter="' + filter + '"]').val('').change();
168
+ $('#qm-' + target).find('[data-filter="' + filter + '"]').val(value).change();
169
+ $('html, body').scrollTop( $(this).closest('.qm').offset().top );
170
+ $('html, body').animate({
171
+ scrollTop: $('#qm-' + target).offset().top
172
+ }, 500);
173
+ e.preventDefault();
174
+ });
175
+
176
  $('#qm').find('.qm-toggle').on('click',function(e){
177
  var el = $(this);
178
  $(this).closest('td').find('.qm-toggled').slideToggle(100,function(){
classes/Util.php CHANGED
@@ -46,12 +46,11 @@ class QM_Util {
46
 
47
  public static function standard_dir( $dir, $abspath_replace = null ) {
48
 
49
- $dir = str_replace( '\\', '/', $dir );
50
- $dir = str_replace( '//', '/', $dir );
51
 
52
  if ( is_string( $abspath_replace ) ) {
53
  if ( !self::$abspath ) {
54
- self::$abspath = self::standard_dir( ABSPATH );
55
  }
56
  $dir = str_replace( self::$abspath, $abspath_replace, $dir );
57
  }
@@ -63,6 +62,7 @@ class QM_Util {
63
  public static function get_file_dirs() {
64
  if ( empty( self::$file_dirs ) ) {
65
  self::$file_dirs['plugin'] = self::standard_dir( WP_PLUGIN_DIR );
 
66
  self::$file_dirs['mu-plugin'] = self::standard_dir( WPMU_PLUGIN_DIR );
67
  self::$file_dirs['vip-plugin'] = self::standard_dir( get_theme_root() . '/vip/plugins' );
68
  self::$file_dirs['stylesheet'] = self::standard_dir( get_stylesheet_directory() );
@@ -105,8 +105,9 @@ class QM_Util {
105
  $name = sprintf( __( 'Plugin: %s', 'query-monitor' ), $plug );
106
  $context = $plug;
107
  break;
 
108
  case 'vip-plugin':
109
- $plug = str_replace( self::$file_dirs['vip-plugin'], '', $file );
110
  $plug = trim( $plug, '/' );
111
  if ( strpos( $plug, '/' ) ) {
112
  $plug = explode( '/', $plug );
46
 
47
  public static function standard_dir( $dir, $abspath_replace = null ) {
48
 
49
+ $dir = wp_normalize_path( $dir );
 
50
 
51
  if ( is_string( $abspath_replace ) ) {
52
  if ( !self::$abspath ) {
53
+ self::$abspath = wp_normalize_path( ABSPATH );
54
  }
55
  $dir = str_replace( self::$abspath, $abspath_replace, $dir );
56
  }
62
  public static function get_file_dirs() {
63
  if ( empty( self::$file_dirs ) ) {
64
  self::$file_dirs['plugin'] = self::standard_dir( WP_PLUGIN_DIR );
65
+ self::$file_dirs['go-plugin'] = self::standard_dir( WPMU_PLUGIN_DIR . '/shared-plugins' );
66
  self::$file_dirs['mu-plugin'] = self::standard_dir( WPMU_PLUGIN_DIR );
67
  self::$file_dirs['vip-plugin'] = self::standard_dir( get_theme_root() . '/vip/plugins' );
68
  self::$file_dirs['stylesheet'] = self::standard_dir( get_stylesheet_directory() );
105
  $name = sprintf( __( 'Plugin: %s', 'query-monitor' ), $plug );
106
  $context = $plug;
107
  break;
108
+ case 'go-plugin':
109
  case 'vip-plugin':
110
+ $plug = str_replace( self::$file_dirs[ $type ], '', $file );
111
  $plug = trim( $plug, '/' );
112
  if ( strpos( $plug, '/' ) ) {
113
  $plug = explode( '/', $plug );
collectors/db_queries.php CHANGED
@@ -146,8 +146,14 @@ class QM_Collector_DB_Queries extends QM_Collector {
146
 
147
  }
148
 
149
- $sql = trim( $sql );
150
- $type = preg_split( '/\b/', $sql, 2, PREG_SPLIT_NO_EMPTY );
 
 
 
 
 
 
151
  $type = strtoupper( $type[0] );
152
 
153
  $this->log_type( $type );
146
 
147
  }
148
 
149
+ $sql = $type = trim( $sql );
150
+
151
+ if ( 0 === strpos( $sql, '/*' ) ) {
152
+ // Strip out leading comments such as `/*NO_SELECT_FOUND_ROWS*/` before calculating the query type
153
+ $type = preg_replace( '|^/\*[^\*/]+\*/|', '', $sql );
154
+ }
155
+
156
+ $type = preg_split( '/\b/', trim( $type ), 2, PREG_SPLIT_NO_EMPTY );
157
  $type = strtoupper( $type[0] );
158
 
159
  $this->log_type( $type );
collectors/languages.php CHANGED
@@ -30,6 +30,9 @@ class QM_Collector_Languages extends QM_Collector {
30
 
31
  }
32
 
 
 
 
33
 
34
  /**
35
  * Store log data.
30
 
31
  }
32
 
33
+ public function process() {
34
+ $this->data['locale'] = get_locale();
35
+ }
36
 
37
  /**
38
  * Store log data.
collectors/php_errors.php CHANGED
@@ -85,7 +85,9 @@ class QM_Collector_PHP_Errors extends QM_Collector {
85
  return false;
86
  }
87
 
88
- $trace = new QM_Backtrace;
 
 
89
  $caller = $trace->get_caller();
90
  $key = md5( $message . $file . $line . $caller['id'] );
91
 
85
  return false;
86
  }
87
 
88
+ $trace = new QM_Backtrace( array(
89
+ 'ignore_current_filter' => false,
90
+ ) );
91
  $caller = $trace->get_caller();
92
  $key = md5( $message . $file . $line . $caller['id'] );
93
 
collectors/theme.php CHANGED
@@ -47,14 +47,14 @@ class QM_Collector_Theme extends QM_Collector {
47
  $template_directory = QM_Util::standard_dir( get_template_directory() );
48
  $theme_directory = QM_Util::standard_dir( get_theme_root() );
49
 
50
- $template_file = str_replace( array( $stylesheet_directory, $template_directory ), '', $template_path );
51
- $template_file = ltrim( $template_file, '/' );
52
- $theme_template = str_replace( $theme_directory, '', $template_path );
53
- $theme_template = ltrim( $theme_template, '/' );
54
-
55
- $this->data['template_path'] = $template_path;
56
- $this->data['template_file'] = $template_file;
57
- $this->data['theme_template'] = $theme_template;
58
 
59
  }
60
 
47
  $template_directory = QM_Util::standard_dir( get_template_directory() );
48
  $theme_directory = QM_Util::standard_dir( get_theme_root() );
49
 
50
+ $template_file = str_replace( array( $stylesheet_directory, $template_directory ), '', $template_path );
51
+ $template_file = ltrim( $template_file, '/' );
52
+ $theme_template_file = str_replace( $theme_directory, '', $template_path );
53
+ $theme_template_file = ltrim( $theme_template_file, '/' );
54
+
55
+ $this->data['template_path'] = $template_path;
56
+ $this->data['template_file'] = $template_file;
57
+ $this->data['theme_template_file'] = $theme_template_file;
58
 
59
  }
60
 
dispatchers/Html.php CHANGED
@@ -122,6 +122,7 @@ class QM_Dispatcher_Html extends QM_Dispatcher {
122
  add_action( 'wp_enqueue_scripts', array( $this, 'enqueue_assets' ) );
123
  add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_assets' ) );
124
  add_action( 'login_enqueue_scripts', array( $this, 'enqueue_assets' ) );
 
125
 
126
  }
127
 
@@ -206,6 +207,9 @@ class QM_Dispatcher_Html extends QM_Dispatcher {
206
  if ( apply_filters( 'qm/output/absolute_position', $absolute ) ) {
207
  $class[] = 'qm-absolute';
208
  }
 
 
 
209
  }
210
 
211
  if ( !is_admin_bar_showing() ) {
122
  add_action( 'wp_enqueue_scripts', array( $this, 'enqueue_assets' ) );
123
  add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_assets' ) );
124
  add_action( 'login_enqueue_scripts', array( $this, 'enqueue_assets' ) );
125
+ add_action( 'send_headers', 'nocache_headers' );
126
 
127
  }
128
 
207
  if ( apply_filters( 'qm/output/absolute_position', $absolute ) ) {
208
  $class[] = 'qm-absolute';
209
  }
210
+
211
+ $class[] = sprintf( 'qm-theme-%s', get_template() );
212
+ $class[] = sprintf( 'qm-theme-%s', get_stylesheet() );
213
  }
214
 
215
  if ( !is_admin_bar_showing() ) {
output/html/conditionals.php CHANGED
@@ -43,7 +43,7 @@ class QM_Output_Html_Conditionals extends QM_Output_Html {
43
  if ( 1 === $i % $cols ) {
44
  echo '<tr>';
45
  }
46
- echo '<td class="qm-ltr qm-true" width="' . absint( $w ) . '%">' . esc_html( $cond ) . '()</td>';
47
  if ( 0 === $i % $cols ) {
48
  echo '</tr>';
49
  }
43
  if ( 1 === $i % $cols ) {
44
  echo '<tr>';
45
  }
46
+ echo '<td class="qm-ltr qm-true" width="' . absint( $w ) . '%">' . esc_html( $cond ) . '()&nbsp;&#x2713;</td>';
47
  if ( 0 === $i % $cols ) {
48
  echo '</tr>';
49
  }
output/html/db_callers.php CHANGED
@@ -64,7 +64,7 @@ class QM_Output_Html_DB_Callers extends QM_Output_Html {
64
  $stime = number_format_i18n( $row['ltime'], 4 );
65
 
66
  echo '<tr>';
67
- echo '<td class="qm-ltr">' . esc_html( $row['caller'] ) . '</td>';
68
 
69
  foreach ( $data['types'] as $type_name => $type_count ) {
70
  if ( isset( $row['types'][$type_name] ) ) {
64
  $stime = number_format_i18n( $row['ltime'], 4 );
65
 
66
  echo '<tr>';
67
+ echo '<td class="qm-ltr"><a href="#" class="qm-filter-trigger" data-qm-target="db_queries-wpdb" data-qm-filter="caller" data-qm-value="' . esc_attr( $row['caller'] ) . '">' . esc_html( $row['caller'] ) . '</a></td>';
68
 
69
  foreach ( $data['types'] as $type_name => $type_count ) {
70
  if ( isset( $row['types'][$type_name] ) ) {
output/html/db_components.php CHANGED
@@ -65,7 +65,7 @@ class QM_Output_Html_DB_Components extends QM_Output_Html {
65
  $total_calls += $row['calls'];
66
 
67
  echo '<tr>';
68
- echo '<td>' . esc_html( $row['component'] ) . '</td>';
69
 
70
  foreach ( $data['types'] as $type_name => $type_count ) {
71
  if ( isset( $row['types'][$type_name] ) ) {
65
  $total_calls += $row['calls'];
66
 
67
  echo '<tr>';
68
+ echo '<td><a href="#" class="qm-filter-trigger" data-qm-target="db_queries-wpdb" data-qm-filter="component" data-qm-value="' . esc_attr( $row['component'] ) . '">' . esc_html( $row['component'] ) . '</a></td>';
69
 
70
  foreach ( $data['types'] as $type_name => $type_count ) {
71
  if ( isset( $row['types'][$type_name] ) ) {
output/html/db_queries.php CHANGED
@@ -122,7 +122,7 @@ class QM_Output_Html_DB_Queries extends QM_Output_Html {
122
  }
123
 
124
  if ( isset( $expensive[0]['result'] ) ) {
125
- echo '<th scope="col" class="qm-num">' . esc_html__( 'Affected Rows', 'query-monitor' ) . '</th>';
126
  }
127
 
128
  echo '<th class="qm-num">' . esc_html__( 'Time', 'query-monitor' ) . '</th>';
122
  }
123
 
124
  if ( isset( $expensive[0]['result'] ) ) {
125
+ echo '<th scope="col" class="qm-num">' . esc_html__( 'Rows', 'query-monitor' ) . '</th>';
126
  }
127
 
128
  echo '<th class="qm-num">' . esc_html__( 'Time', 'query-monitor' ) . '</th>';
output/html/languages.php CHANGED
@@ -35,18 +35,18 @@ class QM_Output_Html_Languages extends QM_Output_Html {
35
  echo '<table cellspacing="0">';
36
  echo '<thead>';
37
  echo '<tr>';
38
- echo '<th>' . esc_html__( 'Languages', 'query-monitor' ) . '</th>';
39
- echo '<th colspan="3">' . esc_html__( 'Language Setting:', 'query-monitor' ) . ' ' . esc_html( get_locale() ) . '</th>';
40
  echo '</tr>';
41
  echo '<tr>';
42
  echo '<td>' . esc_html__( 'Text Domain', 'query-monitor' ) . '</td>';
43
  echo '<td>' . esc_html__( 'Caller', 'query-monitor' ) . '</td>';
44
- echo '<td>' . esc_html__( 'MO File', 'query-monitor' ) . '</td>';
45
- echo '<td>' . esc_html__( 'Loaded', 'query-monitor' ) . '</td>';
46
  echo '</tr>';
47
  echo '</thead>';
48
  echo '<tbody>';
49
 
 
 
50
  foreach ( $data['languages'] as $mofile ) {
51
 
52
  echo '<tr>';
@@ -61,11 +61,10 @@ class QM_Output_Html_Languages extends QM_Output_Html {
61
 
62
  if ( $mofile['found'] ) {
63
  echo '<td class="qm-nowrap">';
64
- echo esc_html__( 'Found', 'query-monitor' ) . '<br />';
65
  echo esc_html( size_format( $mofile['found'] ) );
66
  echo '</td>';
67
  } else {
68
- echo '<td class="qm-warn">';
69
  echo esc_html__( 'Not Found', 'query-monitor' );
70
  echo '</td>';
71
  }
35
  echo '<table cellspacing="0">';
36
  echo '<thead>';
37
  echo '<tr>';
38
+ echo '<th colspan="4">' . esc_html__( 'Language Setting:', 'query-monitor' ) . ' ' . esc_html( $data['locale'] ) . '</th>';
 
39
  echo '</tr>';
40
  echo '<tr>';
41
  echo '<td>' . esc_html__( 'Text Domain', 'query-monitor' ) . '</td>';
42
  echo '<td>' . esc_html__( 'Caller', 'query-monitor' ) . '</td>';
43
+ echo '<td colspan="2">' . esc_html__( 'MO File', 'query-monitor' ) . '</td>';
 
44
  echo '</tr>';
45
  echo '</thead>';
46
  echo '<tbody>';
47
 
48
+ $not_found_class = ( 'en_US' === $data['locale'] ) ? '' : 'qm-warn';
49
+
50
  foreach ( $data['languages'] as $mofile ) {
51
 
52
  echo '<tr>';
61
 
62
  if ( $mofile['found'] ) {
63
  echo '<td class="qm-nowrap">';
 
64
  echo esc_html( size_format( $mofile['found'] ) );
65
  echo '</td>';
66
  } else {
67
+ echo '<td class="' . esc_attr( $not_found_class ) . '">';
68
  echo esc_html__( 'Not Found', 'query-monitor' );
69
  echo '</td>';
70
  }
output/html/php_errors.php CHANGED
@@ -72,10 +72,27 @@ class QM_Output_Html_PHP_Errors extends QM_Output_Html {
72
  echo '<td>';
73
  echo self::output_filename( $error->filename . ':' . $error->line, $error->file, $error->line ); // WPCS: XSS ok.
74
  echo '</td>';
75
- printf(
76
- '<td class="qm-nowrap qm-ltr">%s</td>',
77
- implode( '<br>', array_map( 'esc_html', $error->trace->get_stack() ) )
78
- );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
79
 
80
  if ( $component ) {
81
  echo '<td class="qm-nowrap">' . esc_html( $component->name ) . '</td>';
72
  echo '<td>';
73
  echo self::output_filename( $error->filename . ':' . $error->line, $error->file, $error->line ); // WPCS: XSS ok.
74
  echo '</td>';
75
+
76
+ $stack = array();
77
+ $filtered_trace = $error->trace->get_filtered_trace();
78
+
79
+ // debug_backtrace() (used within QM_Backtrace) doesn't like being used within an error handler so
80
+ // we need to handle its somewhat unreliable stack trace items.
81
+ // https://bugs.php.net/bug.php?id=39070
82
+ // https://bugs.php.net/bug.php?id=64987
83
+ foreach ( $filtered_trace as $i => $item ) {
84
+ if ( isset( $item['file'] ) && isset( $item['line'] ) ) {
85
+ $stack[] = self::output_filename( $item['display'], $item['file'], $item['line'] );
86
+ } else if ( 0 === $i ) {
87
+ $stack[] = self::output_filename( $item['display'], $error->file, $error->line );
88
+ } else {
89
+ $stack[] = $item['display'] . '<br>&nbsp;<span class="qm-info"><em>' . __( 'Unknown location', 'query-monitor' ) . '</em></span>';
90
+ }
91
+ }
92
+
93
+ echo '<td class="qm-row-caller qm-row-stack qm-nowrap qm-ltr">';
94
+ echo implode( '<br>', $stack ); // WPCS: XSS ok.
95
+ echo '</td>';
96
 
97
  if ( $component ) {
98
  echo '<td class="qm-nowrap">' . esc_html( $component->name ) . '</td>';
output/html/theme.php CHANGED
@@ -40,7 +40,7 @@ class QM_Output_Html_Theme extends QM_Output_Html {
40
  echo '<tr>';
41
  echo '<td>' . esc_html__( 'Template File', 'query-monitor' ) . '</td>';
42
  if ( $child_theme ) {
43
- echo '<td>' . self::output_filename( $data['theme_template'], $data['template_path'] ) . '</td>'; // WPCS: XSS ok.
44
  } else {
45
  echo '<td>' . self::output_filename( $data['template_file'], $data['template_path'] ) . '</td>'; // WPCS: XSS ok.
46
  }
40
  echo '<tr>';
41
  echo '<td>' . esc_html__( 'Template File', 'query-monitor' ) . '</td>';
42
  if ( $child_theme ) {
43
+ echo '<td>' . self::output_filename( $data['theme_template_file'], $data['template_path'] ) . '</td>'; // WPCS: XSS ok.
44
  } else {
45
  echo '<td>' . self::output_filename( $data['template_file'], $data['template_path'] ) . '</td>'; // WPCS: XSS ok.
46
  }
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.9.0
6
  Plugin URI: https://querymonitor.com/
7
  Author: John Blackbourn
8
  Author URI: https://johnblackbourn.com/
2
  /*
3
  Plugin Name: Query Monitor
4
  Description: Monitoring of database queries, hooks, conditionals and more.
5
+ Version: 2.9.1
6
  Plugin URI: https://querymonitor.com/
7
  Author: John Blackbourn
8
  Author URI: https://johnblackbourn.com/
readme.txt CHANGED
@@ -3,7 +3,7 @@ Contributors: johnbillion
3
  Tags: ajax, debug, debug-bar, debugging, development, developer, performance, profiler, profiling, queries, query monitor, rest-api
4
  Requires at least: 3.7
5
  Tested up to: 4.4
6
- Stable tag: 2.9.0
7
  License: GPLv2 or later
8
 
9
  View debugging and performance information on database queries, hooks, conditionals, HTTP requests, redirects and more.
@@ -173,6 +173,14 @@ No, I do not accept donations. If you like the plugin, I'd love for you to [leav
173
 
174
  == Changelog ==
175
 
 
 
 
 
 
 
 
 
176
  = 2.9.0 =
177
 
178
  * Introduce a new panel which displays all matching rewrite rules for the current request.
@@ -247,11 +255,10 @@ No, I do not accept donations. If you like the plugin, I'd love for you to [leav
247
  * CSS tweaks to better match wp-admin styles.
248
 
249
  = 2.6.10 =
250
- * Add compatibility with PHP <5.3.6. `DirectoryIterator::getExtension()` isn't available on this version (and also as it's part of SPL it can be disabled).
251
  * Simplify the admin CSS to avoid QM's output being covered by the admin menu.
252
  * Add support for footer styles in the scripts and styles component.
253
  * Update the authentication JavaScript so it works cross-protocol.
254
- * Add support for footer styles in the scripts and styles component.
255
 
256
  = 2.6.9 =
257
  * New Scripts & Styles component
3
  Tags: ajax, debug, debug-bar, debugging, development, developer, performance, profiler, profiling, queries, query monitor, rest-api
4
  Requires at least: 3.7
5
  Tested up to: 4.4
6
+ Stable tag: 2.9.1
7
  License: GPLv2 or later
8
 
9
  View debugging and performance information on database queries, hooks, conditionals, HTTP requests, redirects and more.
173
 
174
  == Changelog ==
175
 
176
+ = 2.9.1 =
177
+
178
+ * Query callers and query components can now be clicked to filter the main query list by that caller or component.
179
+ * Add support for pausing Jetpack's Infinite Scroll module when viewing QM output in the footer.
180
+ * Add support for WordPress.com VIP Go shared plugins as an explicit component.
181
+ * Send nocache headers when QM is active.
182
+ * Various minor tweaks.
183
+
184
  = 2.9.0 =
185
 
186
  * Introduce a new panel which displays all matching rewrite rules for the current request.
255
  * CSS tweaks to better match wp-admin styles.
256
 
257
  = 2.6.10 =
258
+ * Add compatibility with PHP 5.3.6 and lower. `DirectoryIterator::getExtension()` isn't available on this version (and also as it's part of SPL it can be disabled).
259
  * Simplify the admin CSS to avoid QM's output being covered by the admin menu.
260
  * Add support for footer styles in the scripts and styles component.
261
  * Update the authentication JavaScript so it works cross-protocol.
 
262
 
263
  = 2.6.9 =
264
  * New Scripts & Styles component