Version Description
- Template parts used in the current request are now listed along with the template file.
- Fix the REST API output for embedded requests and internal API calls.
- Enable QM's output to appear in customiser preview responses.
- Add support for the AMP plugin by Automattic, which short-circuits template output.
- Highlight the fact when an HTTP request has disabled certificate verification.
- Take into account custom content directory locations that are outside of ABSPATH when removing leading paths from file names.
- Even more fallback support for when jQuery is broken or isn't available.
- Introduce a collector for the object cache. Only outputs an overview at the moment.
- Better formatting in the Duplicate Queries panel.
- Introduce a fallback method of detecting errors in queries when
QM_DB
is not in use. - Improve the initial state of QM's output when the admin toolbar is not in use.
Download this release
Release Info
Developer | johnbillion |
Plugin | Query Monitor |
Version | 2.11.0 |
Comparing to | |
See all releases |
Code changes from version 2.10.0 to 2.11.0
- assets/query-monitor.css +49 -3
- assets/query-monitor.js +21 -1
- classes/Collector.php +1 -1
- classes/Util.php +24 -5
- collectors/cache.php +65 -0
- collectors/db_queries.php +20 -9
- collectors/http.php +1 -0
- collectors/theme.php +27 -4
- dispatchers/Html.php +22 -7
- dispatchers/REST.php +5 -1
- output/Html.php +2 -11
- output/html/conditionals.php +2 -3
- output/html/db_dupes.php +14 -5
- output/html/db_queries.php +5 -1
- output/html/http.php +16 -4
- output/html/overview.php +26 -0
- output/html/theme.php +43 -9
- query-monitor.php +2 -2
- readme.txt +49 -34
assets/query-monitor.css
CHANGED
@@ -130,11 +130,16 @@ GNU General Public License for more details.
|
|
130 |
}
|
131 |
|
132 |
#qm.qm-show,
|
|
|
133 |
.no-js #qm,
|
134 |
.nojs #qm {
|
135 |
display: block;
|
136 |
}
|
137 |
|
|
|
|
|
|
|
|
|
138 |
#qm:after {
|
139 |
display: block !important;
|
140 |
content: '' !important;
|
@@ -168,11 +173,43 @@ body.wp-admin.folded #qm {
|
|
168 |
margin: 0 auto 60px !important;
|
169 |
}
|
170 |
|
171 |
-
#qm-wrapper
|
|
|
|
|
|
|
|
|
172 |
color: #777 !important;
|
173 |
font: 13px/15px 'Open Sans', Arial !important;
|
174 |
-
margin:
|
|
|
|
|
|
|
175 |
font-style: italic !important;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
176 |
}
|
177 |
|
178 |
.qm {
|
@@ -203,7 +240,7 @@ body.wp-admin.folded #qm {
|
|
203 |
margin-bottom: -45px !important;
|
204 |
}
|
205 |
|
206 |
-
#qm.qm-theme-twentysixteen #qm-
|
207 |
margin-bottom: -45px !important;
|
208 |
}
|
209 |
|
@@ -229,6 +266,11 @@ body.wp-admin.folded #qm {
|
|
229 |
margin: 0 !important;
|
230 |
}
|
231 |
|
|
|
|
|
|
|
|
|
|
|
232 |
.qm td,
|
233 |
.qm th {
|
234 |
background: #fff !important;
|
@@ -389,12 +431,16 @@ body.wp-admin.folded #qm {
|
|
389 |
display: none;
|
390 |
}
|
391 |
|
|
|
392 |
.qm a {
|
393 |
color: #00a0d2 !important;
|
394 |
text-decoration: none !important;
|
395 |
text-shadow: none !important;
|
396 |
font-weight: normal !important;
|
397 |
}
|
|
|
|
|
|
|
398 |
.qm a:focus,
|
399 |
.qm a:hover {
|
400 |
text-decoration: underline !important;
|
130 |
}
|
131 |
|
132 |
#qm.qm-show,
|
133 |
+
#qm.qm-peek,
|
134 |
.no-js #qm,
|
135 |
.nojs #qm {
|
136 |
display: block;
|
137 |
}
|
138 |
|
139 |
+
#qm.qm-peek .qm {
|
140 |
+
display: none;
|
141 |
+
}
|
142 |
+
|
143 |
#qm:after {
|
144 |
display: block !important;
|
145 |
content: '' !important;
|
173 |
margin: 0 auto 60px !important;
|
174 |
}
|
175 |
|
176 |
+
#qm.qm-peek #qm-wrapper {
|
177 |
+
margin: 0 auto !important;
|
178 |
+
}
|
179 |
+
|
180 |
+
#qm-title {
|
181 |
color: #777 !important;
|
182 |
font: 13px/15px 'Open Sans', Arial !important;
|
183 |
+
margin: 35px 0 -15px !important;
|
184 |
+
}
|
185 |
+
|
186 |
+
#qm-title p {
|
187 |
font-style: italic !important;
|
188 |
+
margin: 0 20px !important;
|
189 |
+
}
|
190 |
+
|
191 |
+
#qm-title ul {
|
192 |
+
margin: 10px 10px 0 !important;
|
193 |
+
font-family: Menlo, Monaco, Consolas, monospace !important;
|
194 |
+
font-size: 11px !important;
|
195 |
+
font-weight: normal !important;
|
196 |
+
font-style: normal !important;
|
197 |
+
line-height: 16px !important;
|
198 |
+
list-style: none !important;
|
199 |
+
padding: 0 !important;
|
200 |
+
}
|
201 |
+
|
202 |
+
#qm-title li {
|
203 |
+
display: inline-block !important;
|
204 |
+
width: 24em !important;
|
205 |
+
background: #fff !important;
|
206 |
+
border: 1px solid #e8e8e8 !important;
|
207 |
+
margin: 0 5px 5px 0 !important;
|
208 |
+
}
|
209 |
+
|
210 |
+
#qm-title li a {
|
211 |
+
display: block !important;
|
212 |
+
padding: 4px 7px !important;
|
213 |
}
|
214 |
|
215 |
.qm {
|
240 |
margin-bottom: -45px !important;
|
241 |
}
|
242 |
|
243 |
+
#qm.qm-theme-twentysixteen #qm-title {
|
244 |
margin-bottom: -45px !important;
|
245 |
}
|
246 |
|
266 |
margin: 0 !important;
|
267 |
}
|
268 |
|
269 |
+
#qm-conditionals table,
|
270 |
+
#qm-overview table {
|
271 |
+
table-layout: fixed !important;
|
272 |
+
}
|
273 |
+
|
274 |
.qm td,
|
275 |
.qm th {
|
276 |
background: #fff !important;
|
431 |
display: none;
|
432 |
}
|
433 |
|
434 |
+
#qm-title a,
|
435 |
.qm a {
|
436 |
color: #00a0d2 !important;
|
437 |
text-decoration: none !important;
|
438 |
text-shadow: none !important;
|
439 |
font-weight: normal !important;
|
440 |
}
|
441 |
+
|
442 |
+
#qm-title a:focus,
|
443 |
+
#qm-title a:hover,
|
444 |
.qm a:focus,
|
445 |
.qm a:hover {
|
446 |
text-decoration: underline !important;
|
assets/query-monitor.js
CHANGED
@@ -122,11 +122,31 @@ jQuery( function($) {
|
|
122 |
console.debug( qm_l10n.infinitescroll_paused );
|
123 |
}
|
124 |
|
125 |
-
$('#qm').show();
|
126 |
});
|
127 |
|
128 |
$('#wp-admin-bar-query-monitor,#wp-admin-bar-query-monitor-default').show();
|
129 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
130 |
}
|
131 |
|
132 |
$('#qm').find('.qm-filter').on('change',function(e){
|
122 |
console.debug( qm_l10n.infinitescroll_paused );
|
123 |
}
|
124 |
|
125 |
+
$('#qm').addClass('qm-show').removeClass('qm-hide');
|
126 |
});
|
127 |
|
128 |
$('#wp-admin-bar-query-monitor,#wp-admin-bar-query-monitor-default').show();
|
129 |
|
130 |
+
} else {
|
131 |
+
|
132 |
+
var container = document.createDocumentFragment();
|
133 |
+
|
134 |
+
$.each( qm.menu.sub, function( i, el ) {
|
135 |
+
|
136 |
+
var new_menu = $('<li><a/></li>');
|
137 |
+
new_menu
|
138 |
+
.find('a').eq(0)
|
139 |
+
.html(el.title)
|
140 |
+
.attr('href',el.href)
|
141 |
+
;
|
142 |
+
|
143 |
+
container.appendChild( new_menu.get(0) );
|
144 |
+
|
145 |
+
} );
|
146 |
+
|
147 |
+
$('<ul/>').appendTo('#qm-title').append(container).find('a').on('click',function(e){
|
148 |
+
$('#qm').addClass('qm-show').removeClass('qm-hide qm-peek');
|
149 |
+
} );
|
150 |
}
|
151 |
|
152 |
$('#qm').find('.qm-filter').on('change',function(e){
|
classes/Collector.php
CHANGED
@@ -43,7 +43,7 @@ abstract class QM_Collector {
|
|
43 |
protected function maybe_log_dupe( $sql, $i ) {
|
44 |
|
45 |
$sql = str_replace( array( "\r\n", "\r", "\n" ), ' ', $sql );
|
46 |
-
$sql = str_replace( array( "\t" ), '', $sql );
|
47 |
$sql = preg_replace( '/[ ]+/', ' ', $sql );
|
48 |
$sql = trim( $sql );
|
49 |
|
43 |
protected function maybe_log_dupe( $sql, $i ) {
|
44 |
|
45 |
$sql = str_replace( array( "\r\n", "\r", "\n" ), ' ', $sql );
|
46 |
+
$sql = str_replace( array( "\t", '`' ), '', $sql );
|
47 |
$sql = preg_replace( '/[ ]+/', ' ', $sql );
|
48 |
$sql = trim( $sql );
|
49 |
|
classes/Util.php
CHANGED
@@ -20,6 +20,7 @@ class QM_Util {
|
|
20 |
protected static $file_components = array();
|
21 |
protected static $file_dirs = array();
|
22 |
protected static $abspath = null;
|
|
|
23 |
|
24 |
private function __construct() {}
|
25 |
|
@@ -44,15 +45,19 @@ class QM_Util {
|
|
44 |
|
45 |
}
|
46 |
|
47 |
-
public static function standard_dir( $dir, $
|
48 |
|
49 |
$dir = wp_normalize_path( $dir );
|
50 |
|
51 |
-
if ( is_string( $
|
52 |
-
if ( !self::$abspath ) {
|
53 |
-
self::$abspath
|
|
|
54 |
}
|
55 |
-
$dir = str_replace(
|
|
|
|
|
|
|
56 |
}
|
57 |
|
58 |
return $dir;
|
@@ -282,5 +287,19 @@ class QM_Util {
|
|
282 |
|
283 |
}
|
284 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
285 |
}
|
286 |
}
|
20 |
protected static $file_components = array();
|
21 |
protected static $file_dirs = array();
|
22 |
protected static $abspath = null;
|
23 |
+
protected static $contentpath = null;
|
24 |
|
25 |
private function __construct() {}
|
26 |
|
45 |
|
46 |
}
|
47 |
|
48 |
+
public static function standard_dir( $dir, $path_replace = null ) {
|
49 |
|
50 |
$dir = wp_normalize_path( $dir );
|
51 |
|
52 |
+
if ( is_string( $path_replace ) ) {
|
53 |
+
if ( ! self::$abspath ) {
|
54 |
+
self::$abspath = wp_normalize_path( ABSPATH );
|
55 |
+
self::$contentpath = wp_normalize_path( dirname( WP_CONTENT_DIR ) . '/' );
|
56 |
}
|
57 |
+
$dir = str_replace( array(
|
58 |
+
self::$abspath,
|
59 |
+
self::$contentpath,
|
60 |
+
), $path_replace, $dir );
|
61 |
}
|
62 |
|
63 |
return $dir;
|
287 |
|
288 |
}
|
289 |
|
290 |
+
public static function get_query_type( $sql ) {
|
291 |
+
$sql = $type = trim( $sql );
|
292 |
+
|
293 |
+
if ( 0 === strpos( $sql, '/*' ) ) {
|
294 |
+
// Strip out leading comments such as `/*NO_SELECT_FOUND_ROWS*/` before calculating the query type
|
295 |
+
$type = preg_replace( '|^/\*[^\*/]+\*/|', '', $sql );
|
296 |
+
}
|
297 |
+
|
298 |
+
$type = preg_split( '/\b/', trim( $type ), 2, PREG_SPLIT_NO_EMPTY );
|
299 |
+
$type = strtoupper( $type[0] );
|
300 |
+
|
301 |
+
return $type;
|
302 |
+
}
|
303 |
+
|
304 |
}
|
305 |
}
|
collectors/cache.php
ADDED
@@ -0,0 +1,65 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/*
|
3 |
+
Copyright 2009-2016 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_Cache extends QM_Collector {
|
18 |
+
|
19 |
+
public $id = 'cache';
|
20 |
+
|
21 |
+
public function name() {
|
22 |
+
return __( 'Cache', 'query-monitor' );
|
23 |
+
}
|
24 |
+
|
25 |
+
public function process() {
|
26 |
+
global $wp_object_cache;
|
27 |
+
|
28 |
+
$this->data['ext_object_cache'] = (bool) wp_using_ext_object_cache();
|
29 |
+
|
30 |
+
if ( is_object( $wp_object_cache ) ) {
|
31 |
+
|
32 |
+
if ( isset( $wp_object_cache->cache_hits ) ) {
|
33 |
+
$this->data['stats']['cache_hits'] = $wp_object_cache->cache_hits;
|
34 |
+
}
|
35 |
+
|
36 |
+
if ( isset( $wp_object_cache->cache_misses ) ) {
|
37 |
+
$this->data['stats']['cache_misses'] = $wp_object_cache->cache_misses;
|
38 |
+
}
|
39 |
+
|
40 |
+
if ( isset( $wp_object_cache->stats ) ) {
|
41 |
+
foreach ( $wp_object_cache->stats as $key => $value ) {
|
42 |
+
if ( ! is_scalar( $value ) ) {
|
43 |
+
continue;
|
44 |
+
}
|
45 |
+
$this->data['stats'][ $key ] = $value;
|
46 |
+
}
|
47 |
+
}
|
48 |
+
|
49 |
+
}
|
50 |
+
|
51 |
+
if ( isset( $this->data['stats']['cache_hits'] ) && $this->data['stats']['cache_misses'] ) {
|
52 |
+
$total = $this->data['stats']['cache_misses'] + $this->data['stats']['cache_hits'];
|
53 |
+
$this->data['cache_hit_percentage'] = ( 100 / $total ) * $this->data['stats']['cache_hits'];
|
54 |
+
}
|
55 |
+
|
56 |
+
}
|
57 |
+
|
58 |
+
}
|
59 |
+
|
60 |
+
function register_qm_collector_cache( array $collectors, QueryMonitor $qm ) {
|
61 |
+
$collectors['cache'] = new QM_Collector_Cache;
|
62 |
+
return $collectors;
|
63 |
+
}
|
64 |
+
|
65 |
+
add_filter( 'qm/collectors', 'register_qm_collector_cache', 20, 2 );
|
collectors/db_queries.php
CHANGED
@@ -95,6 +95,7 @@ class QM_Collector_DB_Queries extends QM_Collector {
|
|
95 |
}
|
96 |
|
97 |
public function process_db_object( $id, wpdb $db ) {
|
|
|
98 |
|
99 |
$rows = array();
|
100 |
$types = array();
|
@@ -147,15 +148,8 @@ class QM_Collector_DB_Queries extends QM_Collector {
|
|
147 |
|
148 |
}
|
149 |
|
150 |
-
$sql
|
151 |
-
|
152 |
-
if ( 0 === strpos( $sql, '/*' ) ) {
|
153 |
-
// Strip out leading comments such as `/*NO_SELECT_FOUND_ROWS*/` before calculating the query type
|
154 |
-
$type = preg_replace( '|^/\*[^\*/]+\*/|', '', $sql );
|
155 |
-
}
|
156 |
-
|
157 |
-
$type = preg_split( '/\b/', trim( $type ), 2, PREG_SPLIT_NO_EMPTY );
|
158 |
-
$type = strtoupper( $type[0] );
|
159 |
|
160 |
$this->log_type( $type );
|
161 |
$this->log_caller( $caller_name, $ltime, $type );
|
@@ -193,6 +187,23 @@ class QM_Collector_DB_Queries extends QM_Collector {
|
|
193 |
|
194 |
}
|
195 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
196 |
$total_qs = count( $rows );
|
197 |
|
198 |
$this->data['total_qs'] += $total_qs;
|
95 |
}
|
96 |
|
97 |
public function process_db_object( $id, wpdb $db ) {
|
98 |
+
global $EZSQL_ERROR;
|
99 |
|
100 |
$rows = array();
|
101 |
$types = array();
|
148 |
|
149 |
}
|
150 |
|
151 |
+
$sql = trim( $sql );
|
152 |
+
$type = QM_Util::get_query_type( $sql );
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
153 |
|
154 |
$this->log_type( $type );
|
155 |
$this->log_caller( $caller_name, $ltime, $type );
|
187 |
|
188 |
}
|
189 |
|
190 |
+
if ( '$wpdb' === $id && ! $has_result && ! empty( $EZSQL_ERROR ) && is_array( $EZSQL_ERROR ) ) {
|
191 |
+
// Fallback for displaying database errors when wp-content/db.php isn't in place
|
192 |
+
foreach ( $EZSQL_ERROR as $error ) {
|
193 |
+
$row = array(
|
194 |
+
'caller' => 'Unknown',
|
195 |
+
'caller_name' => 'Unknown',
|
196 |
+
'stack' => array(),
|
197 |
+
'sql' => $error['query'],
|
198 |
+
'result' => new WP_Error( 'qmdb', $error['error_str'] ),
|
199 |
+
'type' => '',
|
200 |
+
'component' => false,
|
201 |
+
'trace' => null,
|
202 |
+
);
|
203 |
+
$this->data['errors'][] = $row;
|
204 |
+
}
|
205 |
+
}
|
206 |
+
|
207 |
$total_qs = count( $rows );
|
208 |
|
209 |
$this->data['total_qs'] += $total_qs;
|
collectors/http.php
CHANGED
@@ -130,6 +130,7 @@ class QM_Collector_HTTP extends QM_Collector {
|
|
130 |
public function log_http_response( $response, array $args, $url ) {
|
131 |
$this->data['http'][$args['_qm_key']]['end'] = microtime( true );
|
132 |
$this->data['http'][$args['_qm_key']]['response'] = $response;
|
|
|
133 |
if ( isset( $args['_qm_original_key'] ) ) {
|
134 |
$this->data['http'][$args['_qm_original_key']]['end'] = $this->data['http'][$args['_qm_original_key']]['start'];
|
135 |
$this->data['http'][$args['_qm_original_key']]['response'] = new WP_Error( 'http_request_not_executed', __( 'Request not executed due to a filter on pre_http_request', 'query-monitor' ) );
|
130 |
public function log_http_response( $response, array $args, $url ) {
|
131 |
$this->data['http'][$args['_qm_key']]['end'] = microtime( true );
|
132 |
$this->data['http'][$args['_qm_key']]['response'] = $response;
|
133 |
+
$this->data['http'][$args['_qm_key']]['args'] = $args;
|
134 |
if ( isset( $args['_qm_original_key'] ) ) {
|
135 |
$this->data['http'][$args['_qm_original_key']]['end'] = $this->data['http'][$args['_qm_original_key']]['start'];
|
136 |
$this->data['http'][$args['_qm_original_key']]['response'] = new WP_Error( 'http_request_not_executed', __( 'Request not executed due to a filter on pre_http_request', 'query-monitor' ) );
|
collectors/theme.php
CHANGED
@@ -28,7 +28,7 @@ class QM_Collector_Theme extends QM_Collector {
|
|
28 |
add_filter( 'template_include', array( $this, 'filter_template_include' ), 999 );
|
29 |
}
|
30 |
|
31 |
-
public function filter_body_class( $class ) {
|
32 |
$this->data['body_class'] = $class;
|
33 |
return $class;
|
34 |
}
|
@@ -47,7 +47,7 @@ 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_file = str_replace( array( $theme_directory, ABSPATH ), '', $template_path );
|
53 |
$theme_template_file = ltrim( $theme_template_file, '/' );
|
@@ -56,10 +56,33 @@ class QM_Collector_Theme extends QM_Collector {
|
|
56 |
$this->data['template_file'] = $template_file;
|
57 |
$this->data['theme_template_file'] = $theme_template_file;
|
58 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
59 |
}
|
60 |
|
61 |
-
$this->data['stylesheet']
|
62 |
-
$this->data['template']
|
|
|
63 |
|
64 |
if ( isset( $this->data['body_class'] ) ) {
|
65 |
asort( $this->data['body_class'] );
|
28 |
add_filter( 'template_include', array( $this, 'filter_template_include' ), 999 );
|
29 |
}
|
30 |
|
31 |
+
public function filter_body_class( array $class ) {
|
32 |
$this->data['body_class'] = $class;
|
33 |
return $class;
|
34 |
}
|
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, ABSPATH ), '', $template_path );
|
51 |
$template_file = ltrim( $template_file, '/' );
|
52 |
$theme_template_file = str_replace( array( $theme_directory, ABSPATH ), '', $template_path );
|
53 |
$theme_template_file = ltrim( $theme_template_file, '/' );
|
56 |
$this->data['template_file'] = $template_file;
|
57 |
$this->data['theme_template_file'] = $theme_template_file;
|
58 |
|
59 |
+
foreach ( get_included_files() as $file ) {
|
60 |
+
$filename = str_replace( array(
|
61 |
+
$stylesheet_directory,
|
62 |
+
$template_directory,
|
63 |
+
), '', $file );
|
64 |
+
if ( $filename !== $file ) {
|
65 |
+
$slug = trim( str_replace( '.php', '', $filename ), '/' );
|
66 |
+
$display = trim( $filename, '/' );
|
67 |
+
$theme_display = trim( str_replace( $theme_directory, '', $file ), '/' );
|
68 |
+
if ( did_action( "get_template_part_{$slug}" ) ) {
|
69 |
+
$this->data['template_parts'][ $file ] = $display;
|
70 |
+
$this->data['theme_template_parts'][ $file ] = $theme_display;
|
71 |
+
} else {
|
72 |
+
$slug = trim( preg_replace( '|\-[^\-]+$|', '', $slug ), '/' );
|
73 |
+
if ( did_action( "get_template_part_{$slug}" ) ) {
|
74 |
+
$this->data['template_parts'][ $file ] = $display;
|
75 |
+
$this->data['theme_template_parts'][ $file ] = $theme_display;
|
76 |
+
}
|
77 |
+
}
|
78 |
+
}
|
79 |
+
}
|
80 |
+
|
81 |
}
|
82 |
|
83 |
+
$this->data['stylesheet'] = get_stylesheet();
|
84 |
+
$this->data['template'] = get_template();
|
85 |
+
$this->data['is_child_theme'] = ( $this->data['stylesheet'] != $this->data['template'] );
|
86 |
|
87 |
if ( isset( $this->data['body_class'] ) ) {
|
88 |
asort( $this->data['body_class'] );
|
dispatchers/Html.php
CHANGED
@@ -32,6 +32,7 @@ class QM_Dispatcher_Html extends QM_Dispatcher {
|
|
32 |
add_action( 'admin_footer', array( $this, 'action_footer' ) );
|
33 |
add_action( 'login_footer', array( $this, 'action_footer' ) );
|
34 |
add_action( 'embed_footer', array( $this, 'action_footer' ) );
|
|
|
35 |
|
36 |
parent::__construct( $qm );
|
37 |
|
@@ -95,7 +96,7 @@ class QM_Dispatcher_Html extends QM_Dispatcher {
|
|
95 |
$wp_admin_bar->add_menu( array(
|
96 |
'id' => 'query-monitor',
|
97 |
'title' => esc_html( $title ),
|
98 |
-
'href' => '#qm
|
99 |
'meta' => array(
|
100 |
'classname' => 'hide-if-js',
|
101 |
),
|
@@ -105,7 +106,7 @@ class QM_Dispatcher_Html extends QM_Dispatcher {
|
|
105 |
'parent' => 'query-monitor',
|
106 |
'id' => 'query-monitor-placeholder',
|
107 |
'title' => esc_html( $title ),
|
108 |
-
'href' => '#qm
|
109 |
) );
|
110 |
|
111 |
}
|
@@ -126,6 +127,18 @@ class QM_Dispatcher_Html extends QM_Dispatcher {
|
|
126 |
add_action( 'enqueue_embed_scripts', array( $this, 'enqueue_assets' ) );
|
127 |
add_action( 'send_headers', 'nocache_headers' );
|
128 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
129 |
}
|
130 |
|
131 |
public function enqueue_assets() {
|
@@ -215,19 +228,19 @@ class QM_Dispatcher_Html extends QM_Dispatcher {
|
|
215 |
}
|
216 |
|
217 |
if ( !is_admin_bar_showing() ) {
|
218 |
-
$class[] = 'qm-
|
219 |
}
|
220 |
|
221 |
echo '<div id="qm" class="' . implode( ' ', array_map( 'esc_attr', $class ) ) . '">';
|
222 |
echo '<div id="qm-wrapper">';
|
|
|
223 |
echo '<p>' . esc_html__( 'Query Monitor', 'query-monitor' ) . '</p>';
|
|
|
224 |
|
225 |
}
|
226 |
|
227 |
protected function after_output() {
|
228 |
|
229 |
-
$collectors = QM_Collectors::init();
|
230 |
-
|
231 |
echo '<div class="qm qm-half qm-clear" id="qm-authentication">';
|
232 |
echo '<table cellspacing="0">';
|
233 |
echo '<thead>';
|
@@ -272,8 +285,10 @@ class QM_Dispatcher_Html extends QM_Dispatcher {
|
|
272 |
echo '<script type="text/javascript">' . "\n\n";
|
273 |
echo 'var qm = ' . json_encode( $json ) . ';' . "\n\n";
|
274 |
?>
|
275 |
-
if ( 'undefined' === typeof QM_i18n ) {
|
276 |
document.getElementById( 'qm' ).style.display = 'block';
|
|
|
|
|
277 |
}
|
278 |
<?php
|
279 |
echo '</script>' . "\n\n";
|
@@ -315,7 +330,7 @@ class QM_Dispatcher_Html extends QM_Dispatcher {
|
|
315 |
return false;
|
316 |
}
|
317 |
|
318 |
-
if ( QM_Util::is_async() ) {
|
319 |
return false;
|
320 |
}
|
321 |
|
32 |
add_action( 'admin_footer', array( $this, 'action_footer' ) );
|
33 |
add_action( 'login_footer', array( $this, 'action_footer' ) );
|
34 |
add_action( 'embed_footer', array( $this, 'action_footer' ) );
|
35 |
+
add_action( 'amp_post_template_footer', array( $this, 'action_footer' ) );
|
36 |
|
37 |
parent::__construct( $qm );
|
38 |
|
96 |
$wp_admin_bar->add_menu( array(
|
97 |
'id' => 'query-monitor',
|
98 |
'title' => esc_html( $title ),
|
99 |
+
'href' => '#qm',
|
100 |
'meta' => array(
|
101 |
'classname' => 'hide-if-js',
|
102 |
),
|
106 |
'parent' => 'query-monitor',
|
107 |
'id' => 'query-monitor-placeholder',
|
108 |
'title' => esc_html( $title ),
|
109 |
+
'href' => '#qm',
|
110 |
) );
|
111 |
|
112 |
}
|
127 |
add_action( 'enqueue_embed_scripts', array( $this, 'enqueue_assets' ) );
|
128 |
add_action( 'send_headers', 'nocache_headers' );
|
129 |
|
130 |
+
add_action( 'amp_post_template_head', array( $this, 'enqueue_assets' ) );
|
131 |
+
add_action( 'amp_post_template_head', array( $this, 'manually_print_assets' ), 11 );
|
132 |
+
|
133 |
+
}
|
134 |
+
|
135 |
+
public function manually_print_assets() {
|
136 |
+
wp_print_scripts( array(
|
137 |
+
'query-monitor',
|
138 |
+
) );
|
139 |
+
wp_print_styles( array(
|
140 |
+
'query-monitor',
|
141 |
+
) );
|
142 |
}
|
143 |
|
144 |
public function enqueue_assets() {
|
228 |
}
|
229 |
|
230 |
if ( !is_admin_bar_showing() ) {
|
231 |
+
$class[] = 'qm-peek';
|
232 |
}
|
233 |
|
234 |
echo '<div id="qm" class="' . implode( ' ', array_map( 'esc_attr', $class ) ) . '">';
|
235 |
echo '<div id="qm-wrapper">';
|
236 |
+
echo '<div id="qm-title">';
|
237 |
echo '<p>' . esc_html__( 'Query Monitor', 'query-monitor' ) . '</p>';
|
238 |
+
echo '</div>';
|
239 |
|
240 |
}
|
241 |
|
242 |
protected function after_output() {
|
243 |
|
|
|
|
|
244 |
echo '<div class="qm qm-half qm-clear" id="qm-authentication">';
|
245 |
echo '<table cellspacing="0">';
|
246 |
echo '<thead>';
|
285 |
echo '<script type="text/javascript">' . "\n\n";
|
286 |
echo 'var qm = ' . json_encode( $json ) . ';' . "\n\n";
|
287 |
?>
|
288 |
+
if ( ( 'undefined' === typeof QM_i18n ) || ( 'undefined' === typeof jQuery ) || ! jQuery ) {
|
289 |
document.getElementById( 'qm' ).style.display = 'block';
|
290 |
+
} else if ( ! document.getElementById( 'wpadminbar' ) ) {
|
291 |
+
document.getElementById( 'qm' ).className += ' qm-peek';
|
292 |
}
|
293 |
<?php
|
294 |
echo '</script>' . "\n\n";
|
330 |
return false;
|
331 |
}
|
332 |
|
333 |
+
if ( QM_Util::is_async() && ! is_customize_preview() ) {
|
334 |
return false;
|
335 |
}
|
336 |
|
dispatchers/REST.php
CHANGED
@@ -56,7 +56,7 @@ class QM_Dispatcher_REST extends QM_Dispatcher {
|
|
56 |
require_once $this->qm->plugin_path( 'output/Headers.php' );
|
57 |
|
58 |
foreach ( glob( $this->qm->plugin_path( 'output/headers/*.php' ) ) as $file ) {
|
59 |
-
|
60 |
}
|
61 |
}
|
62 |
|
@@ -67,6 +67,10 @@ class QM_Dispatcher_REST extends QM_Dispatcher {
|
|
67 |
return false;
|
68 |
}
|
69 |
|
|
|
|
|
|
|
|
|
70 |
if ( ! $this->user_can_view() ) {
|
71 |
return false;
|
72 |
}
|
56 |
require_once $this->qm->plugin_path( 'output/Headers.php' );
|
57 |
|
58 |
foreach ( glob( $this->qm->plugin_path( 'output/headers/*.php' ) ) as $file ) {
|
59 |
+
include_once $file;
|
60 |
}
|
61 |
}
|
62 |
|
67 |
return false;
|
68 |
}
|
69 |
|
70 |
+
if ( ! defined( 'REST_REQUEST' ) || ! REST_REQUEST ) {
|
71 |
+
return false;
|
72 |
+
}
|
73 |
+
|
74 |
if ( ! $this->user_can_view() ) {
|
75 |
return false;
|
76 |
}
|
output/Html.php
CHANGED
@@ -131,17 +131,8 @@ abstract class QM_Output_Html extends QM_Output {
|
|
131 |
$sql = esc_html( $sql );
|
132 |
$sql = trim( $sql );
|
133 |
|
134 |
-
|
135 |
-
|
136 |
-
'HAVING', 'INNER', 'INSERT', 'LEFT', 'LIMIT', 'ON', 'OR', 'ORDER', 'OUTER', 'REPLACE', 'RIGHT', 'ROLLBACK', 'SELECT', 'SET',
|
137 |
-
'SHOW', 'START', 'THEN', 'TRUNCATE', 'UPDATE', 'VALUES', 'WHEN', 'WHERE'
|
138 |
-
) as $cmd ) {
|
139 |
-
// Why does this trim() every time?
|
140 |
-
$sql = trim( str_replace( " $cmd ", "<br>$cmd ", $sql ) );
|
141 |
-
}
|
142 |
-
|
143 |
-
# @TODO profile this as an alternative:
|
144 |
-
# $sql = preg_replace( '# (ALTER|AND|COMMIT|CREATE|DESCRIBE) #', '<br>$1 ', $sql );
|
145 |
|
146 |
return $sql;
|
147 |
|
131 |
$sql = esc_html( $sql );
|
132 |
$sql = trim( $sql );
|
133 |
|
134 |
+
$regex = 'ADD|AFTER|ALTER|AND|BEGIN|COMMIT|CREATE|DESCRIBE|DELETE|DROP|ELSE|END|EXCEPT|FROM|GROUP|HAVING|INNER|INSERT|INTERSECT|LEFT|LIMIT|ON|OR|ORDER|OUTER|REPLACE|RIGHT|ROLLBACK|SELECT|SET|SHOW|START|THEN|TRUNCATE|UNION|UPDATE|USING|VALUES|WHEN|WHERE|XOR';
|
135 |
+
$sql = preg_replace( '# (' . $regex . ') #', '<br>$1 ', $sql );
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
136 |
|
137 |
return $sql;
|
138 |
|
output/html/conditionals.php
CHANGED
@@ -27,7 +27,6 @@ class QM_Output_Html_Conditionals extends QM_Output_Html {
|
|
27 |
|
28 |
$cols = 6;
|
29 |
$i = 0;
|
30 |
-
$w = floor( 100 / $cols );
|
31 |
|
32 |
echo '<div class="qm" id="' . esc_attr( $this->collector->id() ) . '">';
|
33 |
echo '<table cellspacing="0">';
|
@@ -43,7 +42,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"
|
47 |
if ( 0 === $i % $cols ) {
|
48 |
echo '</tr>';
|
49 |
}
|
@@ -54,7 +53,7 @@ class QM_Output_Html_Conditionals extends QM_Output_Html {
|
|
54 |
if ( 1 === $i % $cols ) {
|
55 |
echo '<tr>';
|
56 |
}
|
57 |
-
echo '<td class="qm-ltr qm-false"
|
58 |
if ( 0 === $i % $cols ) {
|
59 |
echo '</tr>';
|
60 |
}
|
27 |
|
28 |
$cols = 6;
|
29 |
$i = 0;
|
|
|
30 |
|
31 |
echo '<div class="qm" id="' . esc_attr( $this->collector->id() ) . '">';
|
32 |
echo '<table cellspacing="0">';
|
42 |
if ( 1 === $i % $cols ) {
|
43 |
echo '<tr>';
|
44 |
}
|
45 |
+
echo '<td class="qm-ltr qm-true">' . esc_html( $cond ) . '() ✓</td>';
|
46 |
if ( 0 === $i % $cols ) {
|
47 |
echo '</tr>';
|
48 |
}
|
53 |
if ( 1 === $i % $cols ) {
|
54 |
echo '<tr>';
|
55 |
}
|
56 |
+
echo '<td class="qm-ltr qm-false">' . esc_html( $cond ) . '()</td>';
|
57 |
if ( 0 === $i % $cols ) {
|
58 |
echo '</tr>';
|
59 |
}
|
output/html/db_dupes.php
CHANGED
@@ -53,14 +53,23 @@ class QM_Output_Html_DB_Dupes extends QM_Output_Html {
|
|
53 |
echo '<tbody>';
|
54 |
|
55 |
foreach ( $data['dupes'] as $sql => $queries ) {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
56 |
echo '<tr>';
|
57 |
-
echo '<td>';
|
58 |
-
echo
|
59 |
echo '</td>';
|
60 |
echo '<td class="qm-num">';
|
61 |
echo esc_html( number_format_i18n( count( $queries ), 0 ) );
|
62 |
echo '</td>';
|
63 |
-
echo '<td class="qm-nowrap qm-ltr">';
|
64 |
foreach ( $data['dupe_callers'][ $sql ] as $caller => $calls ) {
|
65 |
printf(
|
66 |
'<a href="#" class="qm-filter-trigger" data-qm-target="db_queries-wpdb" data-qm-filter="caller" data-qm-value="%s">%s</a><br><span class="qm-info"> %s</span><br>',
|
@@ -74,7 +83,7 @@ class QM_Output_Html_DB_Dupes extends QM_Output_Html {
|
|
74 |
}
|
75 |
echo '</td>';
|
76 |
if ( isset( $data['dupe_components'][ $sql ] ) ) {
|
77 |
-
echo '<td class="qm-nowrap">';
|
78 |
foreach ( $data['dupe_components'][ $sql ] as $component => $calls ) {
|
79 |
printf(
|
80 |
'%s<br><span class="qm-info"> %s</span><br>',
|
@@ -87,7 +96,7 @@ class QM_Output_Html_DB_Dupes extends QM_Output_Html {
|
|
87 |
}
|
88 |
echo '</td>';
|
89 |
}
|
90 |
-
echo '<td class="qm-nowrap qm-ltr">';
|
91 |
foreach ( $data['dupe_sources'][ $sql ] as $source => $calls ) {
|
92 |
printf(
|
93 |
'%s<br><span class="qm-info"> %s</span><br>',
|
53 |
echo '<tbody>';
|
54 |
|
55 |
foreach ( $data['dupes'] as $sql => $queries ) {
|
56 |
+
|
57 |
+
// This should probably happen in the collector's processor
|
58 |
+
$type = QM_Util::get_query_type( $sql );
|
59 |
+
$sql_out = self::format_sql( $sql );
|
60 |
+
|
61 |
+
if ( 'SELECT' !== $type ) {
|
62 |
+
$sql_out = "<span class='qm-nonselectsql'>{$sql_out}</span>";
|
63 |
+
}
|
64 |
+
|
65 |
echo '<tr>';
|
66 |
+
echo '<td class="qm-row-sql qm-ltr qm-wrap">';
|
67 |
+
echo $sql_out; // WPCS: XSS ok;
|
68 |
echo '</td>';
|
69 |
echo '<td class="qm-num">';
|
70 |
echo esc_html( number_format_i18n( count( $queries ), 0 ) );
|
71 |
echo '</td>';
|
72 |
+
echo '<td class="qm-row-caller qm-nowrap qm-ltr">';
|
73 |
foreach ( $data['dupe_callers'][ $sql ] as $caller => $calls ) {
|
74 |
printf(
|
75 |
'<a href="#" class="qm-filter-trigger" data-qm-target="db_queries-wpdb" data-qm-filter="caller" data-qm-value="%s">%s</a><br><span class="qm-info"> %s</span><br>',
|
83 |
}
|
84 |
echo '</td>';
|
85 |
if ( isset( $data['dupe_components'][ $sql ] ) ) {
|
86 |
+
echo '<td class="qm-row-component qm-nowrap">';
|
87 |
foreach ( $data['dupe_components'][ $sql ] as $component => $calls ) {
|
88 |
printf(
|
89 |
'%s<br><span class="qm-info"> %s</span><br>',
|
96 |
}
|
97 |
echo '</td>';
|
98 |
}
|
99 |
+
echo '<td class="qm-row-caller qm-nowrap qm-ltr">';
|
100 |
foreach ( $data['dupe_sources'][ $sql ] as $source => $calls ) {
|
101 |
printf(
|
102 |
'%s<br><span class="qm-info"> %s</span><br>',
|
output/html/db_queries.php
CHANGED
@@ -329,7 +329,7 @@ class QM_Output_Html_DB_Queries extends QM_Output_Html {
|
|
329 |
if ( isset( $cols['sql'] ) ) {
|
330 |
$row_attr['data-qm-type'] = $row['type'];
|
331 |
}
|
332 |
-
if ( isset( $cols['component'] ) ) {
|
333 |
$row_attr['data-qm-component'] = $row['component']->name;
|
334 |
}
|
335 |
if ( isset( $cols['caller'] ) ) {
|
@@ -378,7 +378,11 @@ class QM_Output_Html_DB_Queries extends QM_Output_Html {
|
|
378 |
}
|
379 |
|
380 |
if ( isset( $cols['component'] ) ) {
|
|
|
381 |
echo "<td class='qm-row-component qm-nowrap'>" . esc_html( $row['component']->name ) . "</td>\n";
|
|
|
|
|
|
|
382 |
}
|
383 |
|
384 |
if ( isset( $cols['result'] ) ) {
|
329 |
if ( isset( $cols['sql'] ) ) {
|
330 |
$row_attr['data-qm-type'] = $row['type'];
|
331 |
}
|
332 |
+
if ( isset( $cols['component'] ) && $row['component'] ) {
|
333 |
$row_attr['data-qm-component'] = $row['component']->name;
|
334 |
}
|
335 |
if ( isset( $cols['caller'] ) ) {
|
378 |
}
|
379 |
|
380 |
if ( isset( $cols['component'] ) ) {
|
381 |
+
if ( $row['component'] ) {
|
382 |
echo "<td class='qm-row-component qm-nowrap'>" . esc_html( $row['component']->name ) . "</td>\n";
|
383 |
+
} else {
|
384 |
+
echo "<td class='qm-row-component qm-nowrap'>" . esc_html__( 'Unknown', 'query-monitor' ) . "</td>\n";
|
385 |
+
}
|
386 |
}
|
387 |
|
388 |
if ( isset( $cols['result'] ) ) {
|
output/html/http.php
CHANGED
@@ -92,10 +92,22 @@ class QM_Output_Html_HTTP extends QM_Output_Html {
|
|
92 |
|
93 |
}
|
94 |
|
95 |
-
$method = $row['args']['method'];
|
96 |
-
|
97 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
98 |
}
|
|
|
99 |
$url = self::format_url( $row['url'] );
|
100 |
|
101 |
if ( isset( $row['transport'] ) ) {
|
@@ -133,7 +145,7 @@ class QM_Output_Html_HTTP extends QM_Output_Html {
|
|
133 |
);
|
134 |
printf( // WPCS: XSS ok.
|
135 |
'<td class="qm-url qm-ltr qm-wrap">%s<br>%s</td>',
|
136 |
-
|
137 |
$url
|
138 |
);
|
139 |
printf(
|
92 |
|
93 |
}
|
94 |
|
95 |
+
$method = esc_html( $row['args']['method'] );
|
96 |
+
|
97 |
+
if ( empty( $row['args']['blocking'] ) ) {
|
98 |
+
$method .= '<br><span class="qm-info">' . esc_html( sprintf(
|
99 |
+
_x( '(Non-blocking request: %s)', 'non-blocking HTTP transport', 'query-monitor' ),
|
100 |
+
'blocking=false'
|
101 |
+
) ) . '</span>';
|
102 |
+
}
|
103 |
+
|
104 |
+
if ( ! empty( $row['args']['ssl'] ) && empty( $row['args']['sslverify'] ) && empty( $row['args']['local'] ) ) {
|
105 |
+
$method .= '<br><span class="qm-warn">' . esc_html( sprintf(
|
106 |
+
__( '(Certificate verification disabled: %s)', 'query-monitor' ),
|
107 |
+
'sslverify=false'
|
108 |
+
) ) . '</span>';
|
109 |
}
|
110 |
+
|
111 |
$url = self::format_url( $row['url'] );
|
112 |
|
113 |
if ( isset( $row['transport'] ) ) {
|
145 |
);
|
146 |
printf( // WPCS: XSS ok.
|
147 |
'<td class="qm-url qm-ltr qm-wrap">%s<br>%s</td>',
|
148 |
+
$method,
|
149 |
$url
|
150 |
);
|
151 |
printf(
|
output/html/overview.php
CHANGED
@@ -37,6 +37,15 @@ class QM_Output_Html_Overview extends QM_Output_Html {
|
|
37 |
}
|
38 |
}
|
39 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
40 |
echo '<div class="qm" id="' . esc_attr( $this->collector->id() ) . '">';
|
41 |
echo '<table cellspacing="0">';
|
42 |
|
@@ -48,6 +57,9 @@ class QM_Output_Html_Overview extends QM_Output_Html {
|
|
48 |
echo '<th scope="col">' . esc_html__( 'Database query time', 'query-monitor' ) . '</th>';
|
49 |
echo '<th scope="col">' . esc_html__( 'Database queries', 'query-monitor' ) . '</th>';
|
50 |
}
|
|
|
|
|
|
|
51 |
echo '</tr>';
|
52 |
echo '</thead>';
|
53 |
|
@@ -96,6 +108,20 @@ class QM_Output_Html_Overview extends QM_Output_Html {
|
|
96 |
|
97 |
echo '</td>';
|
98 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
99 |
echo '</tr>';
|
100 |
echo '</tbody>';
|
101 |
|
37 |
}
|
38 |
}
|
39 |
|
40 |
+
$cache = QM_Collectors::get( 'cache' );
|
41 |
+
|
42 |
+
if ( $cache ) {
|
43 |
+
$cache_data = $cache->get_data();
|
44 |
+
if ( isset( $cache_data['stats'] ) && isset( $cache_data['cache_hit_percentage'] ) ) {
|
45 |
+
$cache_hit_percentage = $cache_data['cache_hit_percentage'];
|
46 |
+
}
|
47 |
+
}
|
48 |
+
|
49 |
echo '<div class="qm" id="' . esc_attr( $this->collector->id() ) . '">';
|
50 |
echo '<table cellspacing="0">';
|
51 |
|
57 |
echo '<th scope="col">' . esc_html__( 'Database query time', 'query-monitor' ) . '</th>';
|
58 |
echo '<th scope="col">' . esc_html__( 'Database queries', 'query-monitor' ) . '</th>';
|
59 |
}
|
60 |
+
if ( isset( $cache_hit_percentage ) ) {
|
61 |
+
echo '<th scope="col">' . esc_html__( 'Object cache', 'query-monitor' ) . '</th>';
|
62 |
+
}
|
63 |
echo '</tr>';
|
64 |
echo '</thead>';
|
65 |
|
108 |
|
109 |
echo '</td>';
|
110 |
}
|
111 |
+
|
112 |
+
if ( isset( $cache_hit_percentage ) ) {
|
113 |
+
echo '<td>';
|
114 |
+
echo esc_html( sprintf(
|
115 |
+
'%s%% hit rate',
|
116 |
+
number_format_i18n( $cache_hit_percentage, 1 )
|
117 |
+
) );
|
118 |
+
echo '<br>' . esc_html( sprintf(
|
119 |
+
__( 'External object cache: %s'),
|
120 |
+
( $cache_data['ext_object_cache'] ? 'true' : 'false' )
|
121 |
+
) );
|
122 |
+
echo '</td>';
|
123 |
+
}
|
124 |
+
|
125 |
echo '</tr>';
|
126 |
echo '</tbody>';
|
127 |
|
output/html/theme.php
CHANGED
@@ -29,27 +29,61 @@ class QM_Output_Html_Theme extends QM_Output_Html {
|
|
29 |
return;
|
30 |
}
|
31 |
|
32 |
-
$child_theme = ( $data['stylesheet'] !== $data['template'] );
|
33 |
-
|
34 |
echo '<div class="qm qm-half" id="' . esc_attr( $this->collector->id() ) . '">';
|
35 |
echo '<table cellspacing="0">';
|
36 |
echo '<tbody>';
|
37 |
|
|
|
|
|
38 |
if ( ! empty( $data['template_path'] ) ) {
|
39 |
|
40 |
-
|
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 |
}
|
47 |
-
echo '</tr>';
|
48 |
|
|
|
|
|
49 |
}
|
50 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
51 |
echo '<tr>';
|
52 |
-
if ( $
|
53 |
echo '<td>' . esc_html__( 'Child Theme', 'query-monitor' ) . '</td>';
|
54 |
} else {
|
55 |
echo '<td>' . esc_html__( 'Theme', 'query-monitor' ) . '</td>';
|
@@ -57,7 +91,7 @@ class QM_Output_Html_Theme extends QM_Output_Html {
|
|
57 |
echo '<td>' . esc_html( $data['stylesheet'] ) . '</td>';
|
58 |
echo '</tr>';
|
59 |
|
60 |
-
if ( $
|
61 |
echo '<tr>';
|
62 |
echo '<td>' . esc_html__( 'Parent Theme', 'query-monitor' ) . '</td>';
|
63 |
echo '<td>' . esc_html( $data['template'] ) . '</td>';
|
@@ -99,7 +133,7 @@ class QM_Output_Html_Theme extends QM_Output_Html {
|
|
99 |
$menu[] = $this->menu( array(
|
100 |
'title' => esc_html( sprintf(
|
101 |
__( 'Template: %s', 'query-monitor' ),
|
102 |
-
$data['template_file']
|
103 |
) ),
|
104 |
) );
|
105 |
}
|
29 |
return;
|
30 |
}
|
31 |
|
|
|
|
|
32 |
echo '<div class="qm qm-half" id="' . esc_attr( $this->collector->id() ) . '">';
|
33 |
echo '<table cellspacing="0">';
|
34 |
echo '<tbody>';
|
35 |
|
36 |
+
echo '<tr>';
|
37 |
+
echo '<td>' . esc_html__( 'Template File', 'query-monitor' ) . '</td>';
|
38 |
if ( ! empty( $data['template_path'] ) ) {
|
39 |
|
40 |
+
if ( $data['is_child_theme'] ) {
|
|
|
|
|
41 |
echo '<td>' . self::output_filename( $data['theme_template_file'], $data['template_path'] ) . '</td>'; // WPCS: XSS ok.
|
42 |
} else {
|
43 |
echo '<td>' . self::output_filename( $data['template_file'], $data['template_path'] ) . '</td>'; // WPCS: XSS ok.
|
44 |
}
|
|
|
45 |
|
46 |
+
} else {
|
47 |
+
echo '<td><em>' . esc_html__( 'Unknown', 'query-monitor' ) . '</em></td>';
|
48 |
}
|
49 |
|
50 |
+
echo '</tr>';
|
51 |
+
|
52 |
+
if ( ! empty( $data['template_parts'] ) ) {
|
53 |
+
|
54 |
+
$count = count( $data['template_parts'] );
|
55 |
+
echo '<tr>';
|
56 |
+
echo '<td rowspan="' . absint( $count ) . '">' . esc_html__( 'Template Parts', 'query-monitor' ) . '</td>';
|
57 |
+
if ( $data['is_child_theme'] ) {
|
58 |
+
$parts = $data['theme_template_parts'];
|
59 |
+
} else {
|
60 |
+
$parts = $data['template_parts'];
|
61 |
+
}
|
62 |
+
$first = true;
|
63 |
+
|
64 |
+
foreach ( $parts as $filename => $display ) {
|
65 |
+
|
66 |
+
if ( ! $first ) {
|
67 |
+
echo '<tr>';
|
68 |
+
}
|
69 |
+
|
70 |
+
echo '<td>' . self::output_filename( $display, $filename ) . '</td>'; // WPCS: XSS ok.
|
71 |
+
echo '</tr>';
|
72 |
+
|
73 |
+
$first = false;
|
74 |
+
|
75 |
+
}
|
76 |
+
|
77 |
+
} else {
|
78 |
+
echo '<tr>';
|
79 |
+
echo '<td>' . esc_html__( 'Template Parts', 'query-monitor' ) . '</td>';
|
80 |
+
echo '<td><em>' . esc_html__( 'None', 'query-monitor' ) . '</em></td>';
|
81 |
+
echo '</tr>';
|
82 |
+
}
|
83 |
+
|
84 |
+
|
85 |
echo '<tr>';
|
86 |
+
if ( $data['is_child_theme'] ) {
|
87 |
echo '<td>' . esc_html__( 'Child Theme', 'query-monitor' ) . '</td>';
|
88 |
} else {
|
89 |
echo '<td>' . esc_html__( 'Theme', 'query-monitor' ) . '</td>';
|
91 |
echo '<td>' . esc_html( $data['stylesheet'] ) . '</td>';
|
92 |
echo '</tr>';
|
93 |
|
94 |
+
if ( $data['is_child_theme'] ) {
|
95 |
echo '<tr>';
|
96 |
echo '<td>' . esc_html__( 'Parent Theme', 'query-monitor' ) . '</td>';
|
97 |
echo '<td>' . esc_html( $data['template'] ) . '</td>';
|
133 |
$menu[] = $this->menu( array(
|
134 |
'title' => esc_html( sprintf(
|
135 |
__( 'Template: %s', 'query-monitor' ),
|
136 |
+
( $data['is_child_theme'] ? $data['theme_template_file'] : $data['template_file'] )
|
137 |
) ),
|
138 |
) );
|
139 |
}
|
query-monitor.php
CHANGED
@@ -2,8 +2,8 @@
|
|
2 |
/*
|
3 |
Plugin Name: Query Monitor
|
4 |
Description: Monitoring of database queries, hooks, conditionals and more.
|
5 |
-
Version: 2.
|
6 |
-
Plugin URI: https://
|
7 |
Author: John Blackbourn
|
8 |
Author URI: https://johnblackbourn.com/
|
9 |
Text Domain: query-monitor
|
2 |
/*
|
3 |
Plugin Name: Query Monitor
|
4 |
Description: Monitoring of database queries, hooks, conditionals and more.
|
5 |
+
Version: 2.11.0
|
6 |
+
Plugin URI: https://github.com/johnbillion/querymonitor
|
7 |
Author: John Blackbourn
|
8 |
Author URI: https://johnblackbourn.com/
|
9 |
Text Domain: query-monitor
|
readme.txt
CHANGED
@@ -3,14 +3,14 @@ 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.5
|
6 |
-
Stable tag: 2.
|
7 |
License: GPLv2 or later
|
8 |
|
9 |
View debugging and performance information on database queries, hooks, conditionals, HTTP requests, redirects and more.
|
10 |
|
11 |
== Description ==
|
12 |
|
13 |
-
Query Monitor is a debugging plugin for anyone developing with WordPress. It has some advanced features not available in other debugging plugins, including
|
14 |
|
15 |
For complete information, please see [Query Monitor's GitHub repo](https://github.com/johnbillion/query-monitor).
|
16 |
|
@@ -18,27 +18,28 @@ Here's an overview of what's shown:
|
|
18 |
|
19 |
= Database Queries =
|
20 |
|
21 |
-
* Shows all database queries performed on the current
|
22 |
-
* Shows
|
23 |
-
* Shows notifications for
|
24 |
-
* Filter queries by
|
25 |
-
* Filter queries by
|
26 |
-
* Filter queries by
|
27 |
-
* View
|
28 |
-
* Super advanced: Supports
|
29 |
|
30 |
Filtering queries by component or calling function makes it easy to see which plugins, themes, or functions on your site are making the most (or the slowest) database queries.
|
31 |
|
32 |
= Hooks =
|
33 |
|
34 |
-
* Shows all hooks fired on the current
|
35 |
-
* Filter hooks by
|
36 |
-
* Filter actions by
|
37 |
|
38 |
= Theme =
|
39 |
|
40 |
-
* Shows the
|
41 |
-
* Shows
|
|
|
42 |
* Shows the active theme name
|
43 |
|
44 |
= PHP Errors =
|
@@ -48,30 +49,30 @@ Filtering queries by component or calling function makes it easy to see which pl
|
|
48 |
|
49 |
= Request =
|
50 |
|
51 |
-
* Shows
|
52 |
-
* Shows
|
53 |
-
* Shows the
|
54 |
-
* Shows details of the
|
55 |
|
56 |
= Rewrite Rules =
|
57 |
|
58 |
-
* Shows
|
59 |
|
60 |
= Scripts & Styles =
|
61 |
|
62 |
-
* Shows all
|
63 |
-
* Shows their
|
64 |
|
65 |
= Languages =
|
66 |
|
67 |
-
* Shows you
|
68 |
-
* Shows you the
|
69 |
|
70 |
= HTTP Requests =
|
71 |
|
72 |
-
* Shows all HTTP requests performed on the current
|
73 |
* Shows the response code, call stack, transport, component, timeout, and time taken
|
74 |
-
* Highlights
|
75 |
|
76 |
= Redirects =
|
77 |
|
@@ -79,7 +80,7 @@ Filtering queries by component or calling function makes it easy to see which pl
|
|
79 |
|
80 |
= AJAX =
|
81 |
|
82 |
-
The response from any jQuery AJAX request on the page will contain various debugging information in its headers. Any errors also get output to the developer console.
|
83 |
|
84 |
Currently this includes PHP errors and some overview information such as memory usage, but this will be built upon in future versions.
|
85 |
|
@@ -91,22 +92,22 @@ Currently this includes PHP errors and some overview information such as memory
|
|
91 |
|
92 |
= Admin Screen =
|
93 |
|
94 |
-
* Shows the correct names for
|
95 |
* Shows the state of `get_current_screen()` and a few variables
|
96 |
|
97 |
= Environment Information =
|
98 |
|
99 |
-
* Shows
|
100 |
* Highlights the fact when any of these are overridden at runtime
|
101 |
-
* Shows
|
102 |
* Highlights the fact when any performance related configurations are not optimal
|
103 |
-
* Shows various details about
|
104 |
* Shows version numbers for all the things
|
105 |
|
106 |
= Everything Else =
|
107 |
|
108 |
-
* Shows any
|
109 |
-
* Shows all
|
110 |
* Shows an overview at the top, including page generation time and memory limit as absolute values and as % of their respective limits
|
111 |
|
112 |
= Authentication =
|
@@ -173,6 +174,20 @@ No, I do not accept donations. If you like the plugin, I'd love for you to [leav
|
|
173 |
|
174 |
== Changelog ==
|
175 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
176 |
= 2.10.0 =
|
177 |
|
178 |
* Add a new panel which lists duplicated database queries.
|
@@ -419,7 +434,7 @@ No, I do not accept donations. If you like the plugin, I'd love for you to [leav
|
|
419 |
* Show QM output on the log in screen
|
420 |
|
421 |
= 2.2.4 =
|
422 |
-
* Add filtering to the
|
423 |
|
424 |
= 2.2.3 =
|
425 |
* Show component information indicating whether a plugin, theme or core was responsible for each database query
|
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.5
|
6 |
+
Stable tag: 2.11.0
|
7 |
License: GPLv2 or later
|
8 |
|
9 |
View debugging and performance information on database queries, hooks, conditionals, HTTP requests, redirects and more.
|
10 |
|
11 |
== Description ==
|
12 |
|
13 |
+
Query Monitor is a debugging plugin for anyone developing with WordPress. It has some advanced features not available in other debugging plugins, including debugging of AJAX calls, REST API requests, redirects, and the ability to narrow down its output by plugin or theme.
|
14 |
|
15 |
For complete information, please see [Query Monitor's GitHub repo](https://github.com/johnbillion/query-monitor).
|
16 |
|
18 |
|
19 |
= Database Queries =
|
20 |
|
21 |
+
* Shows all database queries performed on the current request
|
22 |
+
* Shows affected rows and time for all queries
|
23 |
+
* Shows notifications for slow queries, duplicate queries, and queries with errors
|
24 |
+
* Filter queries by query type (`SELECT`, `UPDATE`, `DELETE`, etc)
|
25 |
+
* Filter queries by component (WordPress core, Plugin X, Plugin Y, theme)
|
26 |
+
* Filter queries by calling function
|
27 |
+
* View aggregate query information grouped by component, calling function, and type
|
28 |
+
* Super advanced: Supports multiple instances of wpdb on one page (more info in the FAQ)
|
29 |
|
30 |
Filtering queries by component or calling function makes it easy to see which plugins, themes, or functions on your site are making the most (or the slowest) database queries.
|
31 |
|
32 |
= Hooks =
|
33 |
|
34 |
+
* Shows all hooks fired on the current request, along with hooked actions, their priorities, and their components
|
35 |
+
* Filter hooks by part of their name
|
36 |
+
* Filter actions by component (WordPress core, Plugin X, Plugin Y, theme)
|
37 |
|
38 |
= Theme =
|
39 |
|
40 |
+
* Shows the template filename for the current request
|
41 |
+
* Shows all template parts used on the current request
|
42 |
+
* Shows the available body classes for the current request
|
43 |
* Shows the active theme name
|
44 |
|
45 |
= PHP Errors =
|
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 |
+
* Shows the queried object details
|
55 |
+
* Shows details of the current blog (multisite only) and current site (multi-network only)
|
56 |
|
57 |
= Rewrite Rules =
|
58 |
|
59 |
+
* Shows all matching rewrite rules for a given request
|
60 |
|
61 |
= Scripts & Styles =
|
62 |
|
63 |
+
* Shows all enqueued scripts and styles on the current request, along with their URL and version
|
64 |
+
* Shows their dependencies and dependents, and alerts you to any broken dependencies
|
65 |
|
66 |
= Languages =
|
67 |
|
68 |
+
* Shows you language settings and text domains
|
69 |
+
* Shows you the MO files for each text domain and which ones were loaded or not
|
70 |
|
71 |
= HTTP Requests =
|
72 |
|
73 |
+
* Shows all HTTP requests performed on the current request (as long as they use WordPress' HTTP API)
|
74 |
* Shows the response code, call stack, transport, component, timeout, and time taken
|
75 |
+
* Highlights erroneous responses, such as failed requests and anything without a `200` response code
|
76 |
|
77 |
= Redirects =
|
78 |
|
80 |
|
81 |
= AJAX =
|
82 |
|
83 |
+
The response from any jQuery AJAX request on the page will contain various debugging information in its headers. Any errors also get output to the developer console. No hooking required.
|
84 |
|
85 |
Currently this includes PHP errors and some overview information such as memory usage, but this will be built upon in future versions.
|
86 |
|
92 |
|
93 |
= Admin Screen =
|
94 |
|
95 |
+
* Shows the correct names for custom column filters and actions on all admin screens that have a listing table
|
96 |
* Shows the state of `get_current_screen()` and a few variables
|
97 |
|
98 |
= Environment Information =
|
99 |
|
100 |
+
* Shows various PHP information such as memory limit and error reporting levels
|
101 |
* Highlights the fact when any of these are overridden at runtime
|
102 |
+
* Shows various MySQL information, including caching and performance related configuration
|
103 |
* Highlights the fact when any performance related configurations are not optimal
|
104 |
+
* Shows various details about WordPress and the web server
|
105 |
* Shows version numbers for all the things
|
106 |
|
107 |
= Everything Else =
|
108 |
|
109 |
+
* Shows any transients that were set, along with their timeout, component, and call stack
|
110 |
+
* Shows all WordPress conditionals on the current request, highlighted nicely
|
111 |
* Shows an overview at the top, including page generation time and memory limit as absolute values and as % of their respective limits
|
112 |
|
113 |
= Authentication =
|
174 |
|
175 |
== Changelog ==
|
176 |
|
177 |
+
= 2.11.0 =
|
178 |
+
|
179 |
+
* Template parts used in the current request are now listed along with the template file.
|
180 |
+
* Fix the REST API output for embedded requests and internal API calls.
|
181 |
+
* Enable QM's output to appear in customiser preview responses.
|
182 |
+
* Add support for the AMP plugin by Automattic, which short-circuits template output.
|
183 |
+
* Highlight the fact when an HTTP request has disabled certificate verification.
|
184 |
+
* Take into account custom content directory locations that are outside of ABSPATH when removing leading paths from file names.
|
185 |
+
* Even more fallback support for when jQuery is broken or isn't available.
|
186 |
+
* Introduce a collector for the object cache. Only outputs an overview at the moment.
|
187 |
+
* Better formatting in the Duplicate Queries panel.
|
188 |
+
* Introduce a fallback method of detecting errors in queries when `QM_DB` is not in use.
|
189 |
+
* Improve the initial state of QM's output when the admin toolbar is not in use.
|
190 |
+
|
191 |
= 2.10.0 =
|
192 |
|
193 |
* Add a new panel which lists duplicated database queries.
|
434 |
* Show QM output on the log in screen
|
435 |
|
436 |
= 2.2.4 =
|
437 |
+
* Add filtering to the query panel
|
438 |
|
439 |
= 2.2.3 =
|
440 |
* Show component information indicating whether a plugin, theme or core was responsible for each database query
|